Sitelet https://github.com/starkware-libs/cairo/commit/fa8c2432a10d5d7812efb778ccc80b09914c97b9
Skip to content

Commit fa8c243

Browse files
committed
bug fix(semantic): Support struct-update (..base) syntax in const expressions.
1 parent f241872 commit fa8c243

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

‎corelib/src/test/language_features/const_test.cairo‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,22 @@ fn test_const_generic_enum_return() {
203203
assert_eq!(RESULT, Either::Left(7));
204204
}
205205

206+
#[derive(Copy, Drop, PartialEq, Debug)]
207+
struct Point {
208+
x: felt252,
209+
y: felt252,
210+
z: felt252,
211+
}
212+
213+
#[test]
214+
fn test_const_struct_update() {
215+
const BASE: Point = Point { x: 1, y: 2, z: 3 };
216+
const UPDATED: Point = Point { y: 20, ..BASE };
217+
assert_eq!(UPDATED, Point { x: 1, y: 20, z: 3 });
218+
const FROM_UPDATED: Point = Point { x: 10, z: 30, ..UPDATED };
219+
assert_eq!(FROM_UPDATED, Point { x: 10, y: 20, z: 30 });
220+
}
221+
206222
#[test]
207223
fn test_const_casts_from_felt252() {
208224
const _U8_UNDER_RANGE: () = assert((-1_felt252).try_into() == None::<u8>, 'U8 under range');

‎crates/cairo-lang-semantic/src/items/constant.rs‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,13 @@ impl<'a, 'r, 'mt> ConstantEvaluateContext<'a, 'r, 'mt> {
589589
self.validate(*item);
590590
}
591591
}
592-
Expr::StructCtor(ExprStructCtor { members, base_struct: None, .. }) => {
592+
Expr::StructCtor(ExprStructCtor { members, base_struct, .. }) => {
593593
for (expr_id, _) in members {
594594
self.validate(*expr_id);
595595
}
596+
if let Some(base) = base_struct {
597+
self.validate(*base);
598+
}
596599
}
597600
Expr::EnumVariantCtor(expr) => self.validate(expr.value_expr),
598601
Expr::MemberAccess(expr) => self.validate(expr.expr),
@@ -729,27 +732,39 @@ impl<'a, 'r, 'mt> ConstantEvaluateContext<'a, 'r, 'mt> {
729732
.intern(db),
730733
Expr::StructCtor(ExprStructCtor {
731734
members,
732-
base_struct: None,
735+
base_struct,
733736
ty,
734737
concrete_struct_id,
735738
..
736739
}) => {
737740
let member_order =
738741
or_return!(db.concrete_struct_members(*concrete_struct_id).map_err(to_missing));
742+
let ty = or_return!(self.substitute(*ty).map_err(to_missing));
743+
let base_members = match base_struct {
744+
Some(base) => match self.evaluate(*base).long(db) {
745+
ConstValue::Struct(values, base_ty) if *base_ty == ty => {
746+
Some(values.as_slice())
747+
}
748+
_ => return to_missing(skip_diagnostic()),
749+
},
750+
None => None,
751+
};
739752
ConstValue::Struct(
740753
member_order
741754
.values()
742-
.map(|m| {
755+
.enumerate()
756+
.map(|(index, m)| {
743757
members
744758
.iter()
745759
.find(|(_, member_id)| m.id == *member_id)
746760
.map(|(expr_id, _)| self.evaluate(*expr_id))
761+
.or_else(|| Some(base_members?[index]))
747762
// Semantic validation already reported an error, suppress cascading
748763
// errors from const evaluation.
749764
.unwrap_or_else(|| to_missing(skip_diagnostic()))
750765
})
751766
.collect(),
752-
or_return!(self.substitute(*ty).map_err(to_missing)),
767+
ty,
753768
)
754769
.intern(db)
755770
}

0 commit comments

Comments
 (0)