Skip to content

Commit 41506df

Browse files
committed
feat(syntax,semantic,lowering): support tuple struct syntax (struct Foo(T1, T2))
1 parent 5e73005 commit 41506df

19 files changed

Lines changed: 1159 additions & 399 deletions

File tree

crates/cairo-lang-defs/src/db.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,13 +1395,15 @@ fn validate_attributes<'db>(
13951395
}
13961396
}
13971397
ast::ModuleItem::Struct(item) => {
1398-
validate_attributes_element_list(
1399-
db,
1400-
allowed_attributes,
1401-
&extra_allowed_attributes,
1402-
item.members(db).elements(db),
1403-
plugin_diagnostics,
1404-
);
1398+
if let ast::StructBody::Braces(body) = item.body(db) {
1399+
validate_attributes_element_list(
1400+
db,
1401+
allowed_attributes,
1402+
&extra_allowed_attributes,
1403+
body.members(db).elements(db),
1404+
plugin_diagnostics,
1405+
);
1406+
}
14051407
}
14061408
ast::ModuleItem::Enum(item) => {
14071409
validate_attributes_element_list(

crates/cairo-lang-defs/src/ids.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,8 @@ define_named_language_element_id!(MemberId, MemberLongId, ast::Member<'db>);
992992
impl<'db> MemberId<'db> {
993993
pub fn struct_id(&self, db: &'db dyn Database) -> StructId<'db> {
994994
let MemberLongId(module_id, ptr) = self.long(db).clone();
995-
let struct_ptr = ast::ItemStructPtr(ptr.untyped().nth_parent(db, 2));
995+
// Member -> MemberList -> StructBodyBraces -> ItemStruct (3 levels up).
996+
let struct_ptr = ast::ItemStructPtr(ptr.untyped().nth_parent(db, 3));
996997
StructLongId(module_id, struct_ptr).intern(db)
997998
}
998999
}

crates/cairo-lang-lowering/src/lower/mod.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,12 +1834,30 @@ fn lower_expr_member_access<'db>(
18341834
.collect();
18351835
(member_tys, member_idx)
18361836
}
1837-
TypeMemberKind::TupleElement(idx) => {
1838-
let tys = extract_matches!(container_long_ty, TypeLongId::Tuple);
1839-
let member_tys =
1840-
tys.iter().map(|&ty| wrap_in_snapshots(ctx.db, ty, expr.n_snapshots)).collect();
1841-
(member_tys, *idx)
1842-
}
1837+
TypeMemberKind::TupleElement(idx) => match container_long_ty {
1838+
TypeLongId::Tuple(tys) => {
1839+
let member_tys =
1840+
tys.iter().map(|&ty| wrap_in_snapshots(ctx.db, ty, expr.n_snapshots)).collect();
1841+
(member_tys, *idx)
1842+
}
1843+
TypeLongId::Concrete(semantic::ConcreteTypeId::Struct(concrete_struct_id)) => {
1844+
let positional_tys = ctx
1845+
.db
1846+
.concrete_struct_positional_types(concrete_struct_id)
1847+
.map_err(LoweringFlowError::Failed)?
1848+
.ok_or_else(|| {
1849+
LoweringFlowError::Failed(
1850+
ctx.diagnostics.report(expr.stable_ptr.untyped(), UnexpectedError),
1851+
)
1852+
})?;
1853+
let member_tys = positional_tys
1854+
.iter()
1855+
.map(|&(ty, _)| wrap_in_snapshots(ctx.db, ty, expr.n_snapshots))
1856+
.collect();
1857+
(member_tys, *idx)
1858+
}
1859+
_ => unreachable!("TupleElement access on unexpected container type"),
1860+
},
18431861
};
18441862
Ok(LoweredExpr::AtVariable(
18451863
generators::StructMemberAccess {

crates/cairo-lang-parser/src/parser.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,8 @@ impl<'a, 'mt> Parser<'a, 'mt> {
486486
}
487487

488488
/// Assumes the current token is Struct.
489-
/// Expected pattern: `struct<Identifier>{<ParamList>}`
489+
/// Expected pattern: `struct<Identifier>{<MemberList>}` or
490+
/// `struct<Identifier>(<StructArgMemberList>)`.
490491
fn expect_item_struct(
491492
&mut self,
492493
attributes: AttributeListGreen<'a>,
@@ -495,22 +496,52 @@ impl<'a, 'mt> Parser<'a, 'mt> {
495496
let struct_kw = self.take::<TerminalStruct<'_>>();
496497
let name = self.parse_identifier();
497498
let generic_params = self.parse_optional_generic_params();
498-
let lbrace = self.parse_token::<TerminalLBrace<'_>>();
499-
let members = self.parse_member_list();
500-
let rbrace = self.parse_token::<TerminalRBrace<'_>>();
499+
let body = if self.peek().kind == SyntaxKind::TerminalLParen {
500+
let lparen = self.take::<TerminalLParen<'_>>();
501+
let members = self.parse_struct_arg_member_list();
502+
let rparen = self.parse_token::<TerminalRParen<'_>>();
503+
StructBodyParens::new_green(self.db, lparen, members, rparen).into()
504+
} else {
505+
let lbrace = self.parse_token::<TerminalLBrace<'_>>();
506+
let members = self.parse_member_list();
507+
let rbrace = self.parse_token::<TerminalRBrace<'_>>();
508+
StructBodyBraces::new_green(self.db, lbrace, members, rbrace).into()
509+
};
501510
ItemStruct::new_green(
502511
self.db,
503512
attributes,
504513
visibility,
505514
struct_kw,
506515
name,
507516
generic_params,
508-
lbrace,
509-
members,
510-
rbrace,
517+
body,
511518
)
512519
}
513520

521+
/// Returns a GreenId of a node with kind StructArgMemberList.
522+
fn parse_struct_arg_member_list(&mut self) -> StructArgMemberListGreen<'a> {
523+
StructArgMemberList::new_green(
524+
self.db,
525+
&self.parse_separated_list::<
526+
StructArgMember<'_>,
527+
TerminalComma<'_>,
528+
StructArgMemberListElementOrSeparatorGreen<'_>,
529+
>(
530+
Self::try_parse_struct_arg_member,
531+
is_of_kind!(rparen, block, lbrace, rbrace, module_item_kw),
532+
"type",
533+
),
534+
)
535+
}
536+
537+
/// Returns a GreenId of a node with kind StructArgMember, or TryParseFailure if a positional
538+
/// struct member can't be parsed.
539+
fn try_parse_struct_arg_member(&mut self) -> TryParseResult<StructArgMemberGreen<'a>> {
540+
let visibility = self.parse_visibility();
541+
let ty = self.try_parse_type_expr()?;
542+
Ok(StructArgMember::new_green(self.db, visibility, ty))
543+
}
544+
514545
/// Assumes the current token is Enum.
515546
/// Expected pattern: `enum<Identifier>{<ParamList>}`
516547
fn expect_item_enum(

0 commit comments

Comments
 (0)