Skip to content

Commit

Permalink
added semantic error for mismatch types on match with literal bool (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerStarkware authored Dec 25, 2023
1 parent ee1fe88 commit 1c02dc5
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 31 deletions.
85 changes: 56 additions & 29 deletions crates/cairo-lang-semantic/src/expr/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::sync::Arc;
use ast::PathSegment;
use cairo_lang_defs::db::validate_attributes_flat;
use cairo_lang_defs::ids::{
FunctionTitleId, FunctionWithBodyId, GenericKind, LanguageElementId, LocalVarLongId, MemberId,
TraitFunctionId, TraitId,
EnumId, FunctionTitleId, FunctionWithBodyId, GenericKind, LanguageElementId, LocalVarLongId,
MemberId, TraitFunctionId, TraitId,
};
use cairo_lang_diagnostics::{Maybe, ToOption};
use cairo_lang_filesystem::ids::{FileKind, FileLongId, VirtualFile};
Expand Down Expand Up @@ -59,8 +59,8 @@ use crate::semantic::{self, FunctionId, LocalVariable, TypeId, TypeLongId, Varia
use crate::substitution::SemanticRewriter;
use crate::types::{peel_snapshots, resolve_type, wrap_in_snapshots, ConcreteTypeId};
use crate::{
GenericArgumentId, Member, Mutability, Parameter, PatternStringLiteral, PatternStruct,
Signature,
ConcreteEnumId, GenericArgumentId, Member, Mutability, Parameter, PatternStringLiteral,
PatternStruct, Signature,
};

/// Expression with its id.
Expand Down Expand Up @@ -1202,21 +1202,6 @@ fn maybe_compute_pattern_semantic(
})
}
ast::Pattern::Enum(enum_pattern) => {
// Peel all snapshot wrappers.
let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);

// Check that type is an enum, and get the concrete enum from it.
let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
.and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
.ok_or(())
.or_else(|_| {
// Don't add a diagnostic if the type is missing.
// A diagnostic should've already been added.
ty.check_not_missing(ctx.db)?;
Err(ctx.diagnostics.report(enum_pattern, UnexpectedEnumPattern { ty }))
})?;

// Extract the enum variant from the path syntax.
let path = enum_pattern.path(syntax_db);
let item = ctx.resolver.resolve_generic_path(
ctx.diagnostics,
Expand All @@ -1226,16 +1211,13 @@ fn maybe_compute_pattern_semantic(
let generic_variant = try_extract_matches!(item, ResolvedGenericItem::Variant)
.ok_or_else(|| ctx.diagnostics.report(&path, NotAVariant))?;

// Check that these are the same enums.
if generic_variant.enum_id != concrete_enum.enum_id(ctx.db) {
return Err(ctx.diagnostics.report(
&path,
WrongEnum {
expected_enum: concrete_enum.enum_id(ctx.db),
actual_enum: generic_variant.enum_id,
},
));
}
let (concrete_enum, n_snapshots) = extract_concrete_enum_from_pattern_and_validate(
ctx,
pattern_syntax,
ty,
generic_variant.enum_id,
)?;

// TODO(lior): Should we report a diagnostic here?
let concrete_variant = ctx
.db
Expand Down Expand Up @@ -1412,6 +1394,14 @@ fn maybe_compute_pattern_semantic(
false_literal_expr(ctx, pattern_false.stable_ptr().into()),
Expr::EnumVariantCtor
);

extract_concrete_enum_from_pattern_and_validate(
ctx,
pattern_syntax,
ty,
enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
)?;

Pattern::EnumVariant(PatternEnumVariant {
variant: enum_expr.variant,
stable_ptr: pattern_false.stable_ptr().into(),
Expand All @@ -1424,6 +1414,13 @@ fn maybe_compute_pattern_semantic(
true_literal_expr(ctx, pattern_true.stable_ptr().into()),
Expr::EnumVariantCtor
);
extract_concrete_enum_from_pattern_and_validate(
ctx,
pattern_syntax,
ty,
enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
)?;

Pattern::EnumVariant(PatternEnumVariant {
variant: enum_expr.variant,
stable_ptr: pattern_true.stable_ptr().into(),
Expand All @@ -1439,6 +1436,36 @@ fn maybe_compute_pattern_semantic(
Ok(pattern)
}

/// Validates that the semantic type of an enum pattern is an enum, and returns the concrete enum.
fn extract_concrete_enum_from_pattern_and_validate(
ctx: &mut ComputationContext<'_>,
pattern: &ast::Pattern,
ty: TypeId,
enum_id: EnumId,
) -> Maybe<(ConcreteEnumId, usize)> {
// Peel all snapshot wrappers.
let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);

// Check that type is an enum, and get the concrete enum from it.
let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
.and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
.ok_or(())
.or_else(|_| {
// Don't add a diagnostic if the type is missing.
// A diagnostic should've already been added.
ty.check_not_missing(ctx.db)?;
Err(ctx.diagnostics.report(pattern, UnexpectedEnumPattern { ty }))
})?;
// Check that these are the same enums.
if enum_id != concrete_enum.enum_id(ctx.db) {
return Err(ctx.diagnostics.report(
pattern,
WrongEnum { expected_enum: concrete_enum.enum_id(ctx.db), actual_enum: enum_id },
));
}
Ok((concrete_enum, n_snapshots))
}

/// Creates a local variable pattern.
fn create_variable_pattern(
ctx: &mut ComputationContext<'_>,
Expand Down
39 changes: 37 additions & 2 deletions crates/cairo-lang-semantic/src/expr/test_data/match
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ enum A {
error: Wrong enum in pattern. Expected: "core::bool". Got: "test::A".
--> lib.cairo:7:9
A::a(_) => 0,
^**^
^*****^

error: Wrong enum in pattern. Expected: "core::bool". Got: "test::A".
--> lib.cairo:8:9
A::b(_) => 1,
^**^
^*****^

error: Mismatched types. The type `core::bool` cannot be created from a numeric literal.
--> lib.cairo:6:15
Expand Down Expand Up @@ -115,3 +115,38 @@ error: Match arms have incompatible types: "core::felt252" and "core::bool"
--> lib.cairo:8:14
_ => b,
^

//! > ==========================================================================

//! > Match incompatible literal bool patterns

//! > test_runner_name
test_function_diagnostics(expect_diagnostics: true)

//! > function
fn foo(a: A) -> felt252 {
match a {
true => 2,
false => 3,
}
}

//! > function_name
foo

//! > module_code
enum A {
a: (),
b: felt252,
}

//! > expected_diagnostics
error: Wrong enum in pattern. Expected: "test::A". Got: "core::bool".
--> lib.cairo:7:9
true => 2,
^**^

error: Wrong enum in pattern. Expected: "test::A". Got: "core::bool".
--> lib.cairo:8:9
false => 3,
^***^

0 comments on commit 1c02dc5

Please sign in to comment.