From 3574eae6405bcbe0119dd6b26c60fbddc40dfdc9 Mon Sep 17 00:00:00 2001 From: Ori Ziv Date: Sun, 26 Apr 2026 14:02:53 +0300 Subject: [PATCH] feat(semantic): support tuple member access via v.0 syntax (#7608) --- crates/cairo-lang-lowering/src/lower/mod.rs | 50 ++++-- .../cairo-lang-semantic/src/expr/compute.rs | 161 +++++++++--------- .../cairo-lang-semantic/src/expr/inference.rs | 4 +- .../cairo-lang-semantic/src/expr/objects.rs | 4 +- .../src/expr/semantic_test_data/repr_ptr | 18 +- .../src/expr/semantic_test_data/structure | 45 +++-- .../src/expr/semantic_test_data/tuple | 66 +++++++ .../src/expr/test_data/structure | 7 +- .../cairo-lang-semantic/src/items/constant.rs | 26 ++- .../src/items/structure.rs | 4 +- .../src/items/visibility.rs | 2 +- .../cairo-lang-semantic/src/substitution.rs | 2 + 12 files changed, 256 insertions(+), 133 deletions(-) diff --git a/crates/cairo-lang-lowering/src/lower/mod.rs b/crates/cairo-lang-lowering/src/lower/mod.rs index 15cfd39ebfa..0c46a04c9c1 100644 --- a/crates/cairo-lang-lowering/src/lower/mod.rs +++ b/crates/cairo-lang-lowering/src/lower/mod.rs @@ -15,8 +15,9 @@ use cairo_lang_semantic::items::functions::{ FunctionsSemantic, GenericFunctionId, ImplGenericFunctionId, }; use cairo_lang_semantic::items::imp::ImplLongId; -use cairo_lang_semantic::items::structure::StructSemantic; +use cairo_lang_semantic::items::structure::{StructSemantic, TypeMemberKind}; use cairo_lang_semantic::items::trt::TraitSemantic; +use cairo_lang_semantic::types::peel_snapshots; use cairo_lang_semantic::usage::MemberPath; use cairo_lang_semantic::{ ConcreteFunction, ConcreteTraitLongId, ExprVar, LocalVariable, VarId, corelib, @@ -1808,23 +1809,42 @@ fn lower_expr_member_access<'db>( )); } let location = ctx.get_location(expr.stable_ptr.untyped()); - let members = ctx - .db - .concrete_struct_members(expr.concrete_struct_id) - .map_err(LoweringFlowError::Failed)?; - let member_idx = - members.iter().position(|(_, member)| member.id == expr.member).ok_or_else(|| { - LoweringFlowError::Failed( - ctx.diagnostics.report(expr.stable_ptr.untyped(), UnexpectedError), - ) - })?; + let container_ty = ctx.function_body.arenas.exprs[expr.expr].ty(); + let (_, container_long_ty) = peel_snapshots(ctx.db, container_ty); + let (member_tys, member_idx) = match &expr.type_member.kind { + TypeMemberKind::StructMember(member_id) => { + let semantic::ConcreteTypeId::Struct(concrete_struct_id) = + extract_matches!(container_long_ty, TypeLongId::Concrete) + else { + unreachable!("Container must be a struct for StructMember access") + }; + let members = ctx + .db + .concrete_struct_members(concrete_struct_id) + .map_err(LoweringFlowError::Failed)?; + let member_idx = + members.iter().position(|(_, m)| m.id == *member_id).ok_or_else(|| { + LoweringFlowError::Failed( + ctx.diagnostics.report(expr.stable_ptr.untyped(), UnexpectedError), + ) + })?; + let member_tys = members + .iter() + .map(|(_, m)| wrap_in_snapshots(ctx.db, m.ty, expr.n_snapshots)) + .collect(); + (member_tys, member_idx) + } + TypeMemberKind::TupleElement(idx) => { + let tys = extract_matches!(container_long_ty, TypeLongId::Tuple); + let member_tys = + tys.iter().map(|&ty| wrap_in_snapshots(ctx.db, ty, expr.n_snapshots)).collect(); + (member_tys, *idx) + } + }; Ok(LoweredExpr::AtVariable( generators::StructMemberAccess { input: lower_expr_to_var_usage(ctx, builder, expr.expr)?, - member_tys: members - .iter() - .map(|(_, member)| wrap_in_snapshots(ctx.db, member.ty, expr.n_snapshots)) - .collect(), + member_tys, member_idx, location, } diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index 0a4556270fb..ca0e5ae3361 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -3760,23 +3760,6 @@ fn try_extract_identifier_from_path<'a>( } } -/// Given an expression syntax, if it's an identifier, returns it. Otherwise, returns the proper -/// error. -fn expr_as_identifier<'db>( - ctx: &mut ComputationContext<'db, '_>, - path: &ast::ExprPath<'db>, - db: &'db dyn Database, -) -> Maybe> { - let segments_var = path.segments(db); - let mut segments = segments_var.elements(db); - if segments.len() == 1 { - Ok(segments.next().unwrap().identifier(db)) - } else { - Err(ctx.diagnostics.report(path.stable_ptr(db), InvalidMemberExpression)) - } -} - -// TODO(spapini): Consider moving some checks here to the responsibility of the parser. /// Computes the semantic expression for a dot expression. fn dot_expr<'db>( ctx: &mut ComputationContext<'db, '_>, @@ -3784,11 +3767,41 @@ fn dot_expr<'db>( rhs_syntax: ast::Expr<'db>, stable_ptr: ast::ExprPtr<'db>, ) -> Maybe> { - // Find MemberId. - match rhs_syntax { - ast::Expr::Path(expr) => member_access_expr(ctx, lexpr, expr, stable_ptr), - ast::Expr::FunctionCall(expr) => method_call_expr(ctx, lexpr, expr, stable_ptr), - _ => Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(ctx.db), InvalidMemberExpression)), + if let Some(member_name) = match rhs_syntax { + ast::Expr::FunctionCall(expr) => return method_call_expr(ctx, lexpr, expr, stable_ptr), + ast::Expr::Path(ref expr) => path_as_identifier(ctx.db, &expr), + ast::Expr::Literal(ref literal) => literal_as_identifier(ctx.db, &literal), + _ => None, + } { + member_access_expr_by_name( + ctx, + lexpr, + member_name, + rhs_syntax.stable_ptr(ctx.db).untyped(), + stable_ptr, + ) + } else { + Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(ctx.db), InvalidMemberExpression)) + } +} + +/// Given a path syntax, return it as an identifier if possible, otherwise, return None. +fn path_as_identifier<'db>( + db: &'db dyn Database, + path: &ast::ExprPath<'db>, +) -> Option> { + Some(path.segments(db).elements(db).exactly_one().ok()?.identifier(db)) +} + +/// Given a literal syntax, return it as an identifier if possible, otherwise, return None. +fn literal_as_identifier<'db>( + db: &'db dyn Database, + literal: &ast::TerminalLiteralNumber<'db>, +) -> Option> { + if let (value, None) = literal.numeric_value_and_suffix(db)? { + Some(SmolStrId::from(db, value.to_usize()?.to_string())) + } else { + None } } @@ -3933,19 +3946,16 @@ fn method_call_expr<'db>( expr_function_call(ctx, function_id, named_args, expr.stable_ptr(db), stable_ptr) } -/// Computes the semantic model of a member access expression (e.g. "expr.member"). -fn member_access_expr<'db>( +/// Computes the semantic model of a member access expression for a given member name. +fn member_access_expr_by_name<'db>( ctx: &mut ComputationContext<'db, '_>, lexpr: ExprAndId<'db>, - rhs_syntax: ast::ExprPath<'db>, + member_name: SmolStrId<'db>, + name_stable_ptr: SyntaxStablePtrId<'db>, stable_ptr: ast::ExprPtr<'db>, ) -> Maybe> { let db = ctx.db; - - // Find MemberId. - let member_name = expr_as_identifier(ctx, &rhs_syntax, db)?; - let (n_snapshots, long_ty) = - finalized_snapshot_peeled_ty(ctx, lexpr.ty(), rhs_syntax.stable_ptr(db))?; + let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, lexpr.ty(), name_stable_ptr)?; match &long_ty { TypeLongId::Concrete(_) | TypeLongId::Tuple(_) | TypeLongId::FixedSizeArray { .. } => { @@ -3953,35 +3963,29 @@ fn member_access_expr<'db>( get_enriched_type_member_access(ctx, lexpr.clone(), stable_ptr, member_name)? else { return Err(ctx.diagnostics.report( - rhs_syntax.stable_ptr(db), + name_stable_ptr, NoSuchTypeMember { ty: long_ty.intern(ctx.db), member_name }, )); }; - // TODO(#7608): handle TypeMemberKind::TupleElement here. - let TypeMemberKind::StructMember(member_id) = type_member.kind else { - return Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported)); - }; - let member = semantic::Member { - id: member_id, - ty: type_member.ty, - visibility: type_member.visibility, - }; - check_struct_member_is_visible( - ctx, - &member, - rhs_syntax.stable_ptr(db).untyped(), - member_name, - ); - let member_path = match &long_ty { - TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) - if n_snapshots == 0 && deref_functions.is_empty() => - { + if let TypeMemberKind::StructMember(member_id) = type_member.kind { + let member = semantic::Member { + id: member_id, + ty: type_member.ty, + visibility: type_member.visibility, + }; + check_struct_member_is_visible(ctx, &member, name_stable_ptr, member_name); + } + let member_path = match (&type_member.kind, &long_ty) { + ( + TypeMemberKind::StructMember(member_id), + TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)), + ) if n_snapshots == 0 && deref_functions.is_empty() => { lexpr.as_member_path().map(|parent| ExprVarMemberPath::Member { parent: Box::new(parent), - member_id: member.id, + member_id: *member_id, stable_ptr, concrete_struct_id: *concrete_struct_id, - ty: member.ty, + ty: type_member.ty, }) } _ => None, @@ -4000,19 +4004,12 @@ fn member_access_expr<'db>( derefed_expr = ExprAndId { expr: cur_expr.clone(), id: ctx.arenas.exprs.alloc(cur_expr) }; } - let (n_snapshots, long_ty) = - finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), rhs_syntax.stable_ptr(db))?; - let derefed_expr_concrete_struct_id = match long_ty { - TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) => { - concrete_struct_id - } - _ => unreachable!(), - }; - let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots); + let (n_snapshots, _) = + finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), name_stable_ptr)?; + let ty = wrap_in_snapshots(ctx.db, type_member.ty, n_snapshots); let mut final_expr = Expr::MemberAccess(ExprMemberAccess { expr: derefed_expr.id, - concrete_struct_id: derefed_expr_concrete_struct_id, - member: member.id, + type_member, ty, member_path, n_snapshots, @@ -4031,20 +4028,15 @@ fn member_access_expr<'db>( Ok(final_expr) } - TypeLongId::Snapshot(_) => { - // TODO(spapini): Handle snapshot members. - Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported)) - } - TypeLongId::Closure(_) => { - Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported)) - } + TypeLongId::Snapshot(_) => Err(ctx.diagnostics.report(name_stable_ptr, Unsupported)), + TypeLongId::Closure(_) => Err(ctx.diagnostics.report(name_stable_ptr, Unsupported)), TypeLongId::Var(_) => Err(ctx.diagnostics.report( - rhs_syntax.stable_ptr(db), + name_stable_ptr, InternalInferenceError(InferenceError::TypeNotInferred(long_ty.intern(ctx.db))), )), TypeLongId::ImplType(_) | TypeLongId::GenericParameter(_) | TypeLongId::Coupon(_) => { Err(ctx.diagnostics.report( - rhs_syntax.stable_ptr(db), + name_stable_ptr, TypeHasNoMembers { ty: long_ty.intern(ctx.db), member_name }, )) } @@ -4090,18 +4082,19 @@ fn get_enriched_type_member_access<'db>( } Entry::Vacant(_) => { let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, stable_ptr)?; - let members = if let Some(type_members_map) = ctx.db.type_members(long_ty.intern(ctx.db))? { - if let Some(type_member) = type_members_map.get(&accessed_member_name) { - // Found direct member access - so directly returning it. - return Ok(Some(EnrichedTypeMemberAccess { - type_member: type_member.clone(), - deref_functions: vec![], - })); - } - type_members_map.iter().map(|(k, v)| (*k, (v.clone(), 0))).collect() - } else { - Default::default() - }; + let members = + if let Some(type_members_map) = ctx.db.type_members(long_ty.intern(ctx.db))? { + if let Some(type_member) = type_members_map.get(&accessed_member_name) { + // Found direct member access - so directly returning it. + return Ok(Some(EnrichedTypeMemberAccess { + type_member: type_member.clone(), + deref_functions: vec![], + })); + } + type_members_map.iter().map(|(k, v)| (*k, (v.clone(), 0))).collect() + } else { + Default::default() + }; EnrichedMembers { members, diff --git a/crates/cairo-lang-semantic/src/expr/inference.rs b/crates/cairo-lang-semantic/src/expr/inference.rs index 1ce21bd3204..0926e066fa8 100644 --- a/crates/cairo-lang-semantic/src/expr/inference.rs +++ b/crates/cairo-lang-semantic/src/expr/inference.rs @@ -58,8 +58,8 @@ use crate::{ ConcreteEnumId, ConcreteExternTypeId, ConcreteFunction, ConcreteImplId, ConcreteImplLongId, ConcreteStructId, ConcreteTraitId, ConcreteTraitLongId, ConcreteTypeId, ConcreteVariant, FunctionId, FunctionLongId, GenericArgumentId, GenericParam, LocalVariable, MatchArmSelector, - Member, Parameter, SemanticObject, Signature, TypeId, TypeLongId, ValueSelectorArm, - add_basic_rewrites, add_expr_rewrites, add_rewrite, semantic_object_for_id, + Member, Parameter, SemanticObject, Signature, TypeId, TypeLongId, TypeMember, TypeMemberKind, + ValueSelectorArm, add_basic_rewrites, add_expr_rewrites, add_rewrite, semantic_object_for_id, }; pub mod canonic; diff --git a/crates/cairo-lang-semantic/src/expr/objects.rs b/crates/cairo-lang-semantic/src/expr/objects.rs index 33509e2c5af..0d1c45394b0 100644 --- a/crates/cairo-lang-semantic/src/expr/objects.rs +++ b/crates/cairo-lang-semantic/src/expr/objects.rs @@ -10,6 +10,7 @@ use salsa::Database; use super::fmt::ExprFormatter; use crate::items::constant::ConstValueId; +use crate::items::structure::TypeMember; use crate::{ConcreteStructId, FunctionId, TypeId, semantic}; /// Defines an arena id type and its behavior for usage in an arena. @@ -526,8 +527,7 @@ pub struct ExprStringLiteral<'db> { #[debug_db(ExprFormatter<'db>)] pub struct ExprMemberAccess<'db> { pub expr: semantic::ExprId, - pub concrete_struct_id: ConcreteStructId<'db>, - pub member: MemberId<'db>, + pub type_member: TypeMember<'db>, pub ty: semantic::TypeId<'db>, #[hide_field_debug_with_db] pub member_path: Option>, diff --git a/crates/cairo-lang-semantic/src/expr/semantic_test_data/repr_ptr b/crates/cairo-lang-semantic/src/expr/semantic_test_data/repr_ptr index 4754f29d00b..ff419848e1a 100644 --- a/crates/cairo-lang-semantic/src/expr/semantic_test_data/repr_ptr +++ b/crates/cairo-lang-semantic/src/expr/semantic_test_data/repr_ptr @@ -537,13 +537,23 @@ FunctionCall( expr: Var( LocalVarId(test::p), ), - concrete_struct_id: test::PPoint, - member: MemberId(test::PPoint::point), + type_member: TypeMember { + ty: test::Point, + visibility: Private, + kind: StructMember( + MemberId(test::PPoint::point), + ), + }, ty: test::Point, }, ), - concrete_struct_id: test::Point, - member: MemberId(test::Point::x), + type_member: TypeMember { + ty: core::integer::u32, + visibility: Private, + kind: StructMember( + MemberId(test::Point::x), + ), + }, ty: core::integer::u32, }, ), diff --git a/crates/cairo-lang-semantic/src/expr/semantic_test_data/structure b/crates/cairo-lang-semantic/src/expr/semantic_test_data/structure index 56b5fde0238..5a2a8e2d30d 100644 --- a/crates/cairo-lang-semantic/src/expr/semantic_test_data/structure +++ b/crates/cairo-lang-semantic/src/expr/semantic_test_data/structure @@ -39,8 +39,13 @@ Block( expr: Var( LocalVarId(test::a), ), - concrete_struct_id: test::A, - member: MemberId(test::A::a), + type_member: TypeMember { + ty: (core::felt252,), + visibility: Private, + kind: StructMember( + MemberId(test::A::a), + ), + }, ty: (core::felt252,), }, ), @@ -53,8 +58,13 @@ Block( expr: Var( LocalVarId(test::a), ), - concrete_struct_id: test::A, - member: MemberId(test::A::b), + type_member: TypeMember { + ty: core::felt252, + visibility: Private, + kind: StructMember( + MemberId(test::A::b), + ), + }, ty: core::felt252, }, ), @@ -67,8 +77,13 @@ Block( expr: Var( LocalVarId(test::a), ), - concrete_struct_id: test::A, - member: MemberId(test::A::c), + type_member: TypeMember { + ty: test::B, + visibility: Private, + kind: StructMember( + MemberId(test::A::c), + ), + }, ty: test::B, }, ), @@ -83,13 +98,23 @@ Block( expr: Var( LocalVarId(test::a), ), - concrete_struct_id: test::A, - member: MemberId(test::A::c), + type_member: TypeMember { + ty: test::B, + visibility: Private, + kind: StructMember( + MemberId(test::A::c), + ), + }, ty: test::B, }, ), - concrete_struct_id: test::B, - member: MemberId(test::B::a), + type_member: TypeMember { + ty: core::felt252, + visibility: Private, + kind: StructMember( + MemberId(test::B::a), + ), + }, ty: core::felt252, }, ), diff --git a/crates/cairo-lang-semantic/src/expr/semantic_test_data/tuple b/crates/cairo-lang-semantic/src/expr/semantic_test_data/tuple index 1b0bc35cef6..6e6904d6644 100644 --- a/crates/cairo-lang-semantic/src/expr/semantic_test_data/tuple +++ b/crates/cairo-lang-semantic/src/expr/semantic_test_data/tuple @@ -62,3 +62,69 @@ Tuple( ) //! > expected_diagnostics + +//! > ========================================================================== + +//! > Test tuple member access + +//! > test_runner_name +test_expr_semantics(expect_diagnostics: false) + +//! > function_body +let t = (1_u32, 2_u64); + +//! > expr_code +{ + t.0; + t.1; +} + +//! > expected_semantics +Block( + ExprBlock { + statements: [ + Expr( + StatementExpr { + expr: MemberAccess( + ExprMemberAccess { + expr: Var( + LocalVarId(test::t), + ), + type_member: TypeMember { + ty: core::integer::u32, + visibility: Public, + kind: TupleElement( + 0, + ), + }, + ty: core::integer::u32, + }, + ), + }, + ), + Expr( + StatementExpr { + expr: MemberAccess( + ExprMemberAccess { + expr: Var( + LocalVarId(test::t), + ), + type_member: TypeMember { + ty: core::integer::u64, + visibility: Public, + kind: TupleElement( + 1, + ), + }, + ty: core::integer::u64, + }, + ), + }, + ), + ], + tail: None, + ty: (), + }, +) + +//! > expected_diagnostics diff --git a/crates/cairo-lang-semantic/src/expr/test_data/structure b/crates/cairo-lang-semantic/src/expr/test_data/structure index dec9f4a01be..d20aff234ce 100644 --- a/crates/cairo-lang-semantic/src/expr/test_data/structure +++ b/crates/cairo-lang-semantic/src/expr/test_data/structure @@ -87,16 +87,11 @@ error[E2085]: Invalid member expression. a.a::b; ^^^^ -error[E2085]: Invalid member expression. +error[E0007]: Type "test::A" has no member "4" --> lib.cairo:9:7 a.4.4; ^ -error[E2085]: Invalid member expression. - --> lib.cairo:9:9 - a.4.4; - ^ - error[E0007]: Type "core::felt252" has no member "a" --> lib.cairo:10:15 5_felt252.a; diff --git a/crates/cairo-lang-semantic/src/items/constant.rs b/crates/cairo-lang-semantic/src/items/constant.rs index 288a8694f5d..39d563e3aa5 100644 --- a/crates/cairo-lang-semantic/src/items/constant.rs +++ b/crates/cairo-lang-semantic/src/items/constant.rs @@ -43,11 +43,11 @@ use crate::items::free_function::FreeFunctionSemantic; use crate::items::function_with_body::FunctionWithBodySemantic; use crate::items::generics::GenericParamSemantic; use crate::items::imp::ImplSemantic; -use crate::items::structure::StructSemantic; +use crate::items::structure::{StructSemantic, TypeMemberKind}; use crate::items::trt::TraitSemantic; use crate::resolve::{Resolver, ResolverData}; use crate::substitution::{GenericSubstitution, SemanticRewriter}; -use crate::types::resolve_type; +use crate::types::{peel_snapshots, resolve_type}; use crate::{ Arenas, ConcreteFunction, ConcreteTypeId, ConcreteVariant, Condition, Expr, ExprBlock, ExprConstant, ExprFunctionCall, ExprFunctionCallArg, ExprId, ExprMemberAccess, ExprStructCtor, @@ -1162,11 +1162,23 @@ impl<'a, 'r, 'mt> ConstantEvaluateContext<'a, 'r, 'mt> { // A semantic diagnostic should have been reported. return Err(skip_diagnostic()); }; - let members = self.db.concrete_struct_members(expr.concrete_struct_id)?; - let Some(member_idx) = members.iter().position(|(_, member)| member.id == expr.member) - else { - // A semantic diagnostic should have been reported. - return Err(skip_diagnostic()); + let member_idx = match &expr.type_member.kind { + TypeMemberKind::StructMember(member_id) => { + let container_ty = self.arenas.exprs[expr.expr].ty(); + let (_, container_long_ty) = peel_snapshots(self.db, container_ty); + let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = + container_long_ty + else { + return Err(skip_diagnostic()); + }; + let members = self.db.concrete_struct_members(concrete_struct_id)?; + let Some(idx) = members.iter().position(|(_, m)| m.id == *member_id) else { + // A semantic diagnostic should have been reported. + return Err(skip_diagnostic()); + }; + idx + } + TypeMemberKind::TupleElement(idx) => *idx, }; Ok(values[member_idx]) } diff --git a/crates/cairo-lang-semantic/src/items/structure.rs b/crates/cairo-lang-semantic/src/items/structure.rs index e132852ff6b..46ba7f900a9 100644 --- a/crates/cairo-lang-semantic/src/items/structure.rs +++ b/crates/cairo-lang-semantic/src/items/structure.rs @@ -123,7 +123,7 @@ pub struct Member<'db> { /// A member or element of a type, abstracting over named struct members and positional tuple /// elements, enabling unified member access across both. -#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)] #[debug_db(dyn Database)] pub struct TypeMember<'db> { pub ty: TypeId<'db>, @@ -133,7 +133,7 @@ pub struct TypeMember<'db> { } /// Distinguishes between named struct members and positional tuple elements. -#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)] #[debug_db(dyn Database)] pub enum TypeMemberKind<'db> { /// A named struct member, identified by its `MemberId`. diff --git a/crates/cairo-lang-semantic/src/items/visibility.rs b/crates/cairo-lang-semantic/src/items/visibility.rs index 6ed36c2157f..52826943ada 100644 --- a/crates/cairo-lang-semantic/src/items/visibility.rs +++ b/crates/cairo-lang-semantic/src/items/visibility.rs @@ -6,7 +6,7 @@ use salsa::Database; use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder}; /// Visibility of an item. -#[derive(Copy, Clone, Debug, PartialEq, Eq, salsa::Update)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, salsa::Update)] pub enum Visibility { Public, PublicInCrate, diff --git a/crates/cairo-lang-semantic/src/substitution.rs b/crates/cairo-lang-semantic/src/substitution.rs index d6b7b81c49b..c8418371972 100644 --- a/crates/cairo-lang-semantic/src/substitution.rs +++ b/crates/cairo-lang-semantic/src/substitution.rs @@ -462,6 +462,8 @@ macro_rules! add_expr_rewrites { $crate::prune_single!(__regular_helper, PatternMissing, $($exclude)*); $crate::prune_single!(__regular_helper, LocalVariable, $($exclude)*); $crate::prune_single!(__regular_helper, Member, $($exclude)*); + $crate::prune_single!(__regular_helper, TypeMember, $($exclude)*); + $crate::prune_single!(__regular_helper, TypeMemberKind, $($exclude)*); }; }