Skip to content

Commit

Permalink
updated semantic to handle variants (#6951)
Browse files Browse the repository at this point in the history
  • Loading branch information
dean-starkware authored Jan 4, 2025
1 parent 4e834eb commit c02c49d
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 7 deletions.
35 changes: 33 additions & 2 deletions crates/cairo-lang-semantic/src/expr/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2077,8 +2077,39 @@ fn maybe_compute_pattern_semantic(
})
}
ast::Pattern::Path(path) => {
// A path of length 1 is an identifier, which will result in a variable pattern.
// Currently, other paths are not supported (and not clear if ever will be).
let item_result = ctx.resolver.resolve_generic_path(
&mut Default::default(),
path,
NotFoundItemType::Identifier,
Some(&mut ctx.environment),
);
if let Ok(item) = item_result {
if let Some(generic_variant) =
try_extract_matches!(item, ResolvedGenericItem::Variant)
{
let (concrete_enum, _n_snapshots) =
extract_concrete_enum_from_pattern_and_validate(
ctx,
pattern_syntax,
ty,
generic_variant.enum_id,
)?;
let concrete_variant = ctx
.db
.concrete_enum_variant(concrete_enum, &generic_variant)
.map_err(|_| ctx.diagnostics.report(path, UnknownEnum))?;
return Ok(Pattern::EnumVariant(PatternEnumVariant {
variant: concrete_variant,
inner_pattern: None,
ty,
stable_ptr: path.stable_ptr().into(),
}));
}
}

// Paths with a single element are treated as identifiers, which will result in a
// variable pattern if no matching enum variant is found. If a matching enum
// variant exists, it is resolved to the corresponding concrete variant.
if path.elements(syntax_db).len() > 1 {
return Err(ctx.diagnostics.report(path, Unsupported));
}
Expand Down
123 changes: 123 additions & 0 deletions crates/cairo-lang-semantic/src/expr/semantic_test_data/match
Original file line number Diff line number Diff line change
Expand Up @@ -1037,3 +1037,126 @@ warning[E0001]: Unused variable. Consider ignoring by prefixing with `_`.
--> lib.cairo:7:15
MyEnum::A(x) | MyEnum::B((x, _)) => 1,
^

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

//! > Test match with imported variants.

//! > test_runner_name
test_expr_semantics(expect_diagnostics: false)

//! > module_code
enum MyEnum<T> {
A: u8,
B: (u8, felt252),
C: (T, u8),
}
use MyEnum::{A, B, C};

//! > function_body
let a: MyEnum<u8> = A(5);

//! > expr_code
match a {
A(x) | B((x, _)) => x,
C((x, y)) => x + y,
}

//! > expected_semantics
Match(
ExprMatch {
matched_expr: Var(
LocalVarId(test::a),
),
arms: [
MatchArm {
patterns: [
EnumVariant(
PatternEnumVariant {
variant: MyEnum::A,
inner_pattern: Some(
Variable(
x,
),
),
ty: test::MyEnum::<core::integer::u8>,
},
),
EnumVariant(
PatternEnumVariant {
variant: MyEnum::B,
inner_pattern: Some(
Tuple(
PatternTuple {
field_patterns: [
Variable(
x,
),
Otherwise(
PatternOtherwise {
ty: core::felt252,
},
),
],
ty: (core::integer::u8, core::felt252),
},
),
),
ty: test::MyEnum::<core::integer::u8>,
},
),
],
expression: Var(
LocalVarId(test::x),
),
},
MatchArm {
patterns: [
EnumVariant(
PatternEnumVariant {
variant: MyEnum::C,
inner_pattern: Some(
Tuple(
PatternTuple {
field_patterns: [
Variable(
x,
),
Variable(
y,
),
],
ty: (core::integer::u8, core::integer::u8),
},
),
),
ty: test::MyEnum::<core::integer::u8>,
},
),
],
expression: FunctionCall(
ExprFunctionCall {
function: core::integer::U8Add::add,
args: [
Value(
Var(
LocalVarId(test::x),
),
),
Value(
Var(
LocalVarId(test::y),
),
),
],
coupon_arg: None,
ty: core::integer::u8,
},
),
},
],
ty: core::integer::u8,
},
)

//! > expected_diagnostics
98 changes: 98 additions & 0 deletions crates/cairo-lang-semantic/src/expr/semantic_test_data/use
Original file line number Diff line number Diff line change
Expand Up @@ -1359,3 +1359,101 @@ FunctionCall(
)

//! > expected_diagnostics

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

//! > Test using a variant with a generic type.

//! > test_runner_name
test_expr_semantics(expect_diagnostics: false)

//! > module_code
enum myEnum<T> {
Variant: T,
}
use myEnum::Variant;

//! > function_body

//! > expr_code
Variant::<u32>(3)

//! > expected_semantics
EnumVariantCtor(
ExprEnumVariantCtor {
variant: myEnum::Variant,
value_expr: Literal(
ExprLiteral {
value: 3,
ty: core::integer::u32,
},
),
ty: test::myEnum::<core::integer::u32>,
},
)

//! > expected_diagnostics

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

//! > Test using a variant with a wrong generic type.

//! > test_runner_name
test_expr_semantics(expect_diagnostics: true)

//! > module_code
use Option::Some;

//! > function_body

//! > expr_code
Some::<i64>(3_u32)

//! > expected_semantics
Missing(
ExprMissing {
ty: <missing>,
},
)

//! > expected_diagnostics
error: Unexpected argument type. Expected: "core::integer::i64", found: "core::integer::u32".
--> lib.cairo:3:13
Some::<i64>(3_u32)
^^^^^

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

//! > Test using a variant within a module.

//! > test_runner_name
test_expr_semantics(expect_diagnostics: false)

//! > module_code
enum myEnum<T> {
Variant: T,
}
mod test {
use super::myEnum::Variant;
}

//! > function_body

//! > expr_code
test::Variant::<u32>(3)

//! > expected_semantics
EnumVariantCtor(
ExprEnumVariantCtor {
variant: myEnum::Variant,
value_expr: Literal(
ExprLiteral {
value: 3,
ty: core::integer::u32,
},
),
ty: test::myEnum::<core::integer::u32>,
},
)

//! > expected_diagnostics
41 changes: 36 additions & 5 deletions crates/cairo-lang-semantic/src/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut};

use cairo_lang_defs::ids::{
GenericKind, GenericParamId, GenericTypeId, ImplDefId, LanguageElementId, LookupItemId,
ModuleFileId, ModuleId, ModuleItemId, TraitId, TraitItemId,
ModuleFileId, ModuleId, ModuleItemId, TraitId, TraitItemId, VariantId,
};
use cairo_lang_diagnostics::Maybe;
use cairo_lang_filesystem::db::{CORELIB_CRATE_NAME, CrateSettings};
Expand Down Expand Up @@ -53,10 +53,10 @@ use crate::items::trt::{
};
use crate::items::{TraitOrImplContext, visibility};
use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter};
use crate::types::{ImplTypeId, are_coupons_enabled, resolve_type};
use crate::types::{ConcreteEnumLongId, ImplTypeId, are_coupons_enabled, resolve_type};
use crate::{
ConcreteFunction, ConcreteTypeId, ExprId, FunctionId, FunctionLongId, GenericArgumentId,
GenericParam, Member, Mutability, TypeId, TypeLongId,
ConcreteFunction, ConcreteTypeId, ConcreteVariant, ExprId, FunctionId, FunctionLongId,
GenericArgumentId, GenericParam, Member, Mutability, TypeId, TypeLongId,
};

#[cfg(test)]
Expand Down Expand Up @@ -1114,7 +1114,14 @@ impl<'db> Resolver<'db> {
)?)
.intern(self.db),
),
ResolvedGenericItem::Variant(_) => panic!("Variant is not a module item."),
ResolvedGenericItem::Variant(var) => {
ResolvedConcreteItem::Variant(self.specialize_variant(
diagnostics,
identifier.stable_ptr().untyped(),
var.id,
&generic_args_syntax.unwrap_or_default(),
)?)
}
ResolvedGenericItem::TraitFunction(_) => panic!("TraitFunction is not a module item."),
ResolvedGenericItem::Variable(_) => panic!("Variable is not a module item."),
})
Expand Down Expand Up @@ -1375,6 +1382,30 @@ impl<'db> Resolver<'db> {
Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
}

/// Specializes a variant.
fn specialize_variant(
&mut self,
diagnostics: &mut SemanticDiagnostics,
stable_ptr: SyntaxStablePtrId,
variant_id: VariantId,
generic_args: &[ast::GenericArg],
) -> Maybe<ConcreteVariant> {
let concrete_enum_id = ConcreteEnumLongId {
enum_id: variant_id.enum_id(self.db.upcast()),
generic_args: self.resolve_generic_args(
diagnostics,
&self.db.enum_generic_params(variant_id.enum_id(self.db.upcast()))?,
generic_args,
stable_ptr,
)?,
}
.intern(self.db);
self.db.concrete_enum_variant(
concrete_enum_id,
&self.db.variant_semantic(variant_id.enum_id(self.db.upcast()), variant_id)?,
)
}

/// Specializes a generic function.
pub fn specialize_function(
&mut self,
Expand Down

0 comments on commit c02c49d

Please sign in to comment.