@@ -238,22 +238,32 @@ pub fn const_folding(
238238 ctx. maybe_replace_inputs ( info. inputs_mut ( ) ) ;
239239 match info {
240240 MatchInfo :: Enum ( MatchEnumInfo { input, arms, .. } ) => {
241- if let Some ( VarInfo :: Const ( ConstValue :: Enum ( variant, value) ) ) =
242- ctx. var_info . get ( & input. var_id )
241+ if let Some ( (
242+ n_snapshots,
243+ VarInfo :: Const ( ConstValue :: Enum ( variant, value) ) ,
244+ ) ) = ctx. peel_snapshots ( input. var_id )
243245 {
244246 let arm = & arms[ variant. idx ] ;
245247 let value = value. as_ref ( ) . clone ( ) ;
246248 let output = arm. var_ids [ 0 ] ;
247249 if ctx. variables [ input. var_id ] . droppable . is_ok ( )
248250 && ctx. variables [ output] . copyable . is_ok ( )
251+ && ctx
252+ . try_generate_const_statements (
253+ & value,
254+ output,
255+ n_snapshots,
256+ & mut block. statements ,
257+ )
258+ . is_some ( )
249259 {
250- if let Some ( stmt ) = ctx . try_generate_const_statement ( & value , output )
251- {
252- block . statements . push ( stmt ) ;
253- block . end = BlockEnd :: Goto ( arm . block_id , Default :: default ( ) ) ;
254- }
260+ block . end = BlockEnd :: Goto ( arm . block_id , Default :: default ( ) ) ;
261+ }
262+ let mut info = VarInfo :: Const ( value ) ;
263+ for _ in 0 ..n_snapshots {
264+ info = VarInfo :: Snapshot ( Box :: new ( info ) ) ;
255265 }
256- ctx. var_info . insert ( output, VarInfo :: Const ( value ) ) ;
266+ ctx. var_info . insert ( output, info ) ;
257267 }
258268 }
259269 MatchInfo :: Value ( info) => {
@@ -633,20 +643,65 @@ impl ConstFoldingContext<'_> {
633643 self . propagate_const_and_get_statement ( BigInt :: zero ( ) , output, false )
634644 }
635645
636- /// Returns a statement that introduces the requested value into `output`, or None if fails.
637- fn try_generate_const_statement (
638- & self ,
646+ /// Addes statements that introduces the requested value into `output` and returns `Some(())`,
647+ /// or `None` if fails.
648+ fn try_generate_const_statements (
649+ & mut self ,
639650 value : & ConstValue ,
640651 output : VariableId ,
641- ) -> Option < Statement > {
642- if self . db . type_size_info ( self . variables [ output] . ty ) == Ok ( TypeSizeInformation :: Other ) {
643- Some ( Statement :: Const ( StatementConst { value : value. clone ( ) , output } ) )
644- } else if matches ! ( value, ConstValue :: Struct ( members, _) if members. is_empty( ) ) {
645- // Handling const empty structs - which are not supported in sierra-gen.
646- Some ( Statement :: StructConstruct ( StatementStructConstruct { inputs : vec ! [ ] , output } ) )
647- } else {
648- None
652+ n_snapshots : usize ,
653+ statements : & mut Vec < Statement > ,
654+ ) -> Option < ( ) > {
655+ let var = & self . variables [ output] ;
656+ let output_ty = var. ty ;
657+ let size_info = self . db . type_size_info ( output_ty) . ok ( ) ?;
658+ if size_info == TypeSizeInformation :: ZeroSized
659+ && !matches ! ( value, ConstValue :: Struct ( members, _) if members. is_empty( ) )
660+ {
661+ return None ;
649662 }
663+ let get_base_stmt = |var| {
664+ if size_info == TypeSizeInformation :: ZeroSized {
665+ Statement :: StructConstruct ( StatementStructConstruct { inputs : vec ! [ ] , output : var } )
666+ } else {
667+ Statement :: Const ( StatementConst { value : value. clone ( ) , output : var } )
668+ }
669+ } ;
670+ if n_snapshots == 0 {
671+ statements. push ( get_base_stmt ( output) ) ;
672+ return Some ( ( ) ) ;
673+ }
674+ let location = var. location ;
675+ let mut curr_ty = value. ty ( self . db ) . ok ( ) ?;
676+ let mut new_var = |ty| {
677+ self . variables . alloc ( Variable :: new ( self . db , ImplLookupContext :: default ( ) , ty, location) )
678+ } ;
679+ let mut curr_var = new_var ( curr_ty) ;
680+ statements. push ( get_base_stmt ( curr_var) ) ;
681+ for _ in 1 ..n_snapshots {
682+ let unused_orig = new_var ( curr_ty) ;
683+ let snapped_ty = TypeLongId :: Snapshot ( curr_ty) . intern ( self . db ) ;
684+ let snapped_var = new_var ( snapped_ty) ;
685+ statements. push ( Statement :: Snapshot ( StatementSnapshot {
686+ input : VarUsage { var_id : curr_var, location } ,
687+ outputs : [ unused_orig, snapped_var] ,
688+ } ) ) ;
689+ curr_ty = snapped_ty;
690+ curr_var = snapped_var;
691+ }
692+ let unused_orig = new_var ( curr_ty) ;
693+ statements. push ( Statement :: Snapshot ( StatementSnapshot {
694+ input : VarUsage { var_id : curr_var, location } ,
695+ outputs : [ unused_orig, output] ,
696+ } ) ) ;
697+ let final_ty = TypeLongId :: Snapshot ( curr_ty) . intern ( self . db ) ;
698+ assert ! (
699+ final_ty == output_ty,
700+ "{} != {}" ,
701+ final_ty. format( self . db) ,
702+ output_ty. format( self . db)
703+ ) ;
704+ Some ( ( ) )
650705 }
651706
652707 /// Handles the end of an extern block.
@@ -990,6 +1045,17 @@ impl ConstFoldingContext<'_> {
9901045 try_extract_matches ! ( self . var_info. get( & var_id) ?, VarInfo :: Const )
9911046 }
9921047
1048+ /// Returns the number of snapshots and the `VarInfo` wrapped by the snapshots.
1049+ fn peel_snapshots ( & self , var_id : VariableId ) -> Option < ( usize , & VarInfo ) > {
1050+ let mut n_snapshots = 0 ;
1051+ let mut curr = self . var_info . get ( & var_id) ?;
1052+ while let VarInfo :: Snapshot ( next) = curr {
1053+ n_snapshots += 1 ;
1054+ curr = next. as_ref ( ) ;
1055+ }
1056+ Some ( ( n_snapshots, curr) )
1057+ }
1058+
9931059 /// Return the const value as an int if it exists and is an integer, additionally, if it is of a
9941060 /// non-zero type.
9951061 fn as_int_ex ( & self , var_id : VariableId ) -> Option < ( & BigInt , bool ) > {
0 commit comments