@@ -16,8 +16,7 @@ use cairo_lang_sierra::{
1616 starknet:: StarknetTypeConcrete ,
1717 utils:: Range ,
1818 } ,
19- ids:: { ConcreteTypeId , UserTypeId } ,
20- program:: GenericArg ,
19+ ids:: ConcreteTypeId ,
2120 program_registry:: ProgramRegistry ,
2221} ;
2322use melior:: {
@@ -28,7 +27,7 @@ use melior::{
2827} ;
2928use num_bigint:: { BigInt , Sign } ;
3029use num_traits:: { Bounded , One } ;
31- use std:: { alloc:: Layout , error:: Error , ops:: Deref , sync :: OnceLock } ;
30+ use std:: { alloc:: Layout , error:: Error , ops:: Deref } ;
3231
3332pub mod array;
3433mod bitwise;
@@ -956,31 +955,25 @@ impl TypeBuilder for CoreTypeConcrete {
956955 _metadata : & mut MetadataStorage ,
957956 _self_ty : & ConcreteTypeId ,
958957 ) -> Result < Value < ' ctx , ' this > , Self :: Error > {
959- static BOOL_USER_TYPE_ID : OnceLock < UserTypeId > = OnceLock :: new ( ) ;
960- let bool_user_type_id =
961- BOOL_USER_TYPE_ID . get_or_init ( || UserTypeId :: from_string ( "core::bool" ) ) ;
962-
963958 Ok ( match self {
964- Self :: Enum ( info) => match & info. info . long_id . generic_args [ 0 ] {
965- GenericArg :: UserType ( id) if id == bool_user_type_id => {
966- let tag = entry. const_int ( context, location, 0 , 1 ) ?;
967-
968- let value = entry. append_op_result ( llvm:: undef (
969- llvm:: r#type:: r#struct (
970- context,
971- & [
972- IntegerType :: new ( context, 1 ) . into ( ) ,
973- llvm:: r#type:: array ( IntegerType :: new ( context, 8 ) . into ( ) , 0 ) ,
974- ] ,
975- false ,
976- ) ,
977- location,
978- ) ) ?;
979-
980- entry. insert_value ( context, location, value, tag, 0 ) ?
981- }
982- _ => native_panic ! ( "unsupported dict value type" ) ,
983- } ,
959+ Self :: Enum ( _) => {
960+ // Sierra validates that only enums with two or less values are allowed, and that they are zero size.
961+ let tag = entry. const_int ( context, location, 0 , 1 ) ?;
962+
963+ let value = entry. append_op_result ( llvm:: undef (
964+ llvm:: r#type:: r#struct (
965+ context,
966+ & [
967+ IntegerType :: new ( context, 1 ) . into ( ) ,
968+ llvm:: r#type:: array ( IntegerType :: new ( context, 8 ) . into ( ) , 0 ) ,
969+ ] ,
970+ false ,
971+ ) ,
972+ location,
973+ ) ) ?;
974+
975+ entry. insert_value ( context, location, value, tag, 0 ) ?
976+ }
984977 Self :: Felt252 ( _) => entry. const_int ( context, location, 0 , 252 ) ?,
985978 Self :: Nullable ( _) => {
986979 entry. append_op_result ( llvm:: zero ( llvm:: r#type:: pointer ( context, 0 ) , location) ) ?
@@ -1028,11 +1021,19 @@ impl<T> Deref for WithSelf<'_, T> {
10281021#[ cfg( test) ]
10291022mod test {
10301023 use super :: TypeBuilder ;
1031- use crate :: utils:: testing:: load_program;
1024+ use crate :: {
1025+ context:: initialize_mlir, libfuncs:: LibfuncHelper , load_cairo, metadata:: MetadataStorage ,
1026+ utils:: testing:: load_program,
1027+ } ;
10321028 use cairo_lang_sierra:: {
1033- extensions:: core:: { CoreLibfunc , CoreType } ,
1029+ extensions:: core:: { CoreLibfunc , CoreType , CoreTypeConcrete } ,
10341030 program_registry:: ProgramRegistry ,
10351031 } ;
1032+ use melior:: {
1033+ dialect:: llvm,
1034+ ir:: { r#type:: IntegerType , Block , Location , Module , Region , ValueLike } ,
1035+ } ;
1036+ use std:: cell:: Cell ;
10361037
10371038 #[ test]
10381039 fn ensure_padded_layouts ( ) {
@@ -1045,4 +1046,83 @@ mod test {
10451046 assert_eq ! ( layout, layout. pad_to_align( ) ) ;
10461047 }
10471048 }
1049+
1050+ /// `build_default` produces the value used when a missing `Felt252Dict` key is accessed.
1051+ /// The Sierra spec allows any enum with two zero-sized-payload variants
1052+ /// as a dict value type (e.g. `Option<()>`, `Result<(), ()>`, or any user-defined unit enum).
1053+ #[ test]
1054+ fn build_default_two_variant_unit_enum ( ) {
1055+ // A user-defined enum with two unit (zero-sized) variants, just like `bool`.
1056+ let ( _, program) = load_cairo ! {
1057+ #[ derive( Drop ) ]
1058+ enum Color {
1059+ Red ,
1060+ Green ,
1061+ }
1062+
1063+ fn run_test( ) -> Color {
1064+ Color :: Red
1065+ }
1066+ } ;
1067+ let registry = ProgramRegistry :: < CoreType , CoreLibfunc > :: new ( & program) . unwrap ( ) ;
1068+
1069+ // Find the user-defined enum with two zero-sized-payload variants (`Color`).
1070+ let ( self_ty, enum_ty) = program
1071+ . type_declarations
1072+ . iter ( )
1073+ . map ( |decl| ( & decl. id , registry. get_type ( & decl. id ) . unwrap ( ) ) )
1074+ . find ( |( _, ty) | {
1075+ matches ! ( ty, CoreTypeConcrete :: Enum ( info)
1076+ if info. variants. len( ) == 2
1077+ && info
1078+ . variants
1079+ . iter( )
1080+ . all( |v| registry. get_type( v) . unwrap( ) . is_zst( & registry) . unwrap( ) ) )
1081+ } )
1082+ . expect ( "the program must declare a two-variant unit enum" ) ;
1083+
1084+ let context = initialize_mlir ( ) ;
1085+ let location = Location :: unknown ( & context) ;
1086+ let module = Module :: new ( location) ;
1087+
1088+ let region = Region :: new ( ) ;
1089+ let block = region. append_block ( Block :: new ( & [ ] ) ) ;
1090+ let blocks_arena = bumpalo:: Bump :: new ( ) ;
1091+ let mut metadata = MetadataStorage :: new ( ) ;
1092+ let helper = LibfuncHelper {
1093+ module : & module,
1094+ init_block : & block,
1095+ region : & region,
1096+ blocks_arena : & blocks_arena,
1097+ last_block : Cell :: new ( & block) ,
1098+ branches : Vec :: new ( ) ,
1099+ results : Vec :: new ( ) ,
1100+
1101+ #[ cfg( feature = "with-libfunc-profiling" ) ]
1102+ profiler : None ,
1103+ } ;
1104+
1105+ let value = enum_ty
1106+ . build_default (
1107+ & context,
1108+ & registry,
1109+ & block,
1110+ location,
1111+ & helper,
1112+ & mut metadata,
1113+ self_ty,
1114+ )
1115+ . expect ( "build_default must not panic for a two-variant unit enum" ) ;
1116+
1117+ // The default value matches the enum's `{ i1, [0 x i8] }` representation, with tag 0.
1118+ let expected_ty = llvm:: r#type:: r#struct (
1119+ & context,
1120+ & [
1121+ IntegerType :: new ( & context, 1 ) . into ( ) ,
1122+ llvm:: r#type:: array ( IntegerType :: new ( & context, 8 ) . into ( ) , 0 ) ,
1123+ ] ,
1124+ false ,
1125+ ) ;
1126+ assert_eq ! ( value. r#type( ) , expected_ty) ;
1127+ }
10481128}
0 commit comments