@@ -70,14 +70,13 @@ pub fn analyze_ap_changes<'db>(
7070
7171 let mut ctx = analysis. analyzer ;
7272 let peeled_used_after_revoke: OrderedHashSet < _ > =
73- ctx. used_after_revoke . iter ( ) . map ( |var| ctx. peel_aliases ( var) ) . copied ( ) . collect ( ) ;
73+ ctx. used_after_revoke . iter ( ) . map ( |var| ctx. peel_aliases ( var) . variable_id ) . collect ( ) ;
7474 // Any used after revoke variable that might be revoked should be a local.
7575 let locals: OrderedHashSet < VariableId > = ctx
7676 . used_after_revoke
7777 . iter ( )
7878 . filter ( |var| ctx. might_be_revoked ( & peeled_used_after_revoke, var) )
79- . map ( |var| ctx. peel_aliases ( var) )
80- . cloned ( )
79+ . map ( |var| ctx. peel_aliases ( var) . variable_id )
8180 . collect ( ) ;
8281 let mut need_ap_alignment = OrderedHashSet :: default ( ) ;
8382 if !root_info. known_ap_change {
@@ -115,6 +114,11 @@ struct CalledBlockInfo {
115114 introduced_vars : Vec < VariableId > ,
116115}
117116
117+ struct VarSource {
118+ variable_id : VariableId ,
119+ allow_const : bool ,
120+ }
121+
118122/// Context for the find_local_variables logic.
119123struct FindLocalsContext < ' db , ' a > {
120124 db : & ' db dyn Database ,
@@ -127,9 +131,9 @@ struct FindLocalsContext<'db, 'a> {
127131 constants : UnorderedHashSet < VariableId > ,
128132 /// A mapping of variables which are the same in the context of finding locals.
129133 /// I.e. if `aliases[var_id]` is local than var_id is also local.
130- aliases : UnorderedHashMap < VariableId , VariableId > ,
134+ aliases : UnorderedHashMap < VariableId , VarSource > ,
131135 /// A mapping from partial param variables to the containing variable.
132- partial_param_parents : UnorderedHashMap < VariableId , VariableId > ,
136+ partial_param_parents : UnorderedHashMap < VariableId , VarSource > ,
133137}
134138
135139pub type LoweredDemand = Demand < VariableId , ( ) > ;
@@ -241,11 +245,13 @@ struct BranchInfo {
241245
242246impl < ' db , ' a > FindLocalsContext < ' db , ' a > {
243247 /// Given a variable that might be an alias follow aliases until we get the original variable.
244- pub fn peel_aliases ( & ' a self , mut var : & ' a VariableId ) -> & ' a VariableId {
248+ pub fn peel_aliases ( & ' a self , mut var : & ' a VariableId ) -> VarSource {
249+ let mut allow_const = true ;
245250 while let Some ( alias) = self . aliases . get ( var) {
246- var = alias;
251+ var = & alias. variable_id ;
252+ allow_const &= alias. allow_const ;
247253 }
248- var
254+ VarSource { variable_id : * var, allow_const }
249255 }
250256
251257 /// Return true if the variable might be revoked by ap changes.
@@ -258,19 +264,28 @@ impl<'db, 'a> FindLocalsContext<'db, 'a> {
258264 peeled_used_after_revoke : & OrderedHashSet < VariableId > ,
259265 var : & VariableId ,
260266 ) -> bool {
261- if self . constants . contains ( var) {
267+ let mut peeled = self . peel_aliases ( var) ;
268+ if self . constants . contains ( & peeled. variable_id ) {
262269 return false ;
263270 }
264- let mut peeled = self . peel_aliases ( var) ;
265- if self . non_ap_based . contains ( peeled) {
271+ if self . non_ap_based . contains ( & peeled. variable_id ) {
266272 return false ;
267273 }
268274 // In the case of partial params, we check if one of its ancestors is a local variable, or
269275 // will be used after the revoke, and thus will be used as a local variable. If that
270276 // is the case, then 'var' can not be revoked.
271- while let Some ( parent) = self . partial_param_parents . get ( peeled) {
272- peeled = self . peel_aliases ( parent) ;
273- if self . non_ap_based . contains ( peeled) || peeled_used_after_revoke. contains ( peeled) {
277+
278+ let mut allow_const = peeled. allow_const ;
279+ while let Some ( parent) = self . partial_param_parents . get ( & peeled. variable_id ) {
280+ allow_const &= parent. allow_const ;
281+ peeled = self . peel_aliases ( & parent. variable_id ) ;
282+ allow_const &= peeled. allow_const ;
283+ if self . non_ap_based . contains ( & peeled. variable_id ) {
284+ return false ;
285+ }
286+ // If the variable parent-peel chain ends in a const, but the allow_const flag is false (i.e. the chain went through a libfunc that doesn't allow consts),
287+ // then the variable can be revoked as the saved const will be ap based.
288+ if peeled_used_after_revoke. contains ( & peeled. variable_id ) && ( !self . constants . contains ( & peeled. variable_id ) || allow_const) {
274289 return false ;
275290 }
276291 }
@@ -309,10 +324,10 @@ impl<'db, 'a> FindLocalsContext<'db, 'a> {
309324 for ( var, output_info) in zip_eq ( output_vars. iter ( ) , var_output_infos. iter ( ) ) {
310325 match output_info. ref_info {
311326 OutputVarReferenceInfo :: SameAsParam { param_idx } => {
312- self . aliases . insert ( * var, input_vars[ param_idx] . var_id ) ;
327+ self . aliases . insert ( * var, VarSource { variable_id : input_vars[ param_idx] . var_id , allow_const : _params_signatures [ param_idx ] . allow_const } ) ;
313328 }
314329 OutputVarReferenceInfo :: PartialParam { param_idx } => {
315- self . partial_param_parents . insert ( * var, input_vars[ param_idx] . var_id ) ;
330+ self . partial_param_parents . insert ( * var, VarSource { variable_id : input_vars[ param_idx] . var_id , allow_const : _params_signatures [ param_idx ] . allow_const } ) ;
316331 }
317332 OutputVarReferenceInfo :: Deferred ( DeferredOutputKind :: Const )
318333 | OutputVarReferenceInfo :: NewLocalVar
@@ -387,12 +402,12 @@ impl<'db, 'a> FindLocalsContext<'db, 'a> {
387402 )
388403 }
389404 lowering:: Statement :: Snapshot ( statement_snapshot) => {
390- self . aliases . insert ( statement_snapshot. original ( ) , statement_snapshot. input . var_id ) ;
391- self . aliases . insert ( statement_snapshot. snapshot ( ) , statement_snapshot. input . var_id ) ;
405+ self . aliases . insert ( statement_snapshot. original ( ) , VarSource { variable_id : statement_snapshot. input . var_id , allow_const : true } ) ;
406+ self . aliases . insert ( statement_snapshot. snapshot ( ) , VarSource { variable_id : statement_snapshot. input . var_id , allow_const : true } ) ;
392407 BranchInfo { known_ap_change : true }
393408 }
394409 lowering:: Statement :: Desnap ( statement_desnap) => {
395- self . aliases . insert ( statement_desnap. output , statement_desnap. input . var_id ) ;
410+ self . aliases . insert ( statement_desnap. output , VarSource { variable_id : statement_desnap. input . var_id , allow_const : true } ) ;
396411 BranchInfo { known_ap_change : true }
397412 }
398413 } ;
0 commit comments