@@ -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,31 @@ 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
287+ // (i.e. the chain went through a libfunc that doesn't allow consts),
288+ // then the variable can be revoked as the saved const will be ap based.
289+ if peeled_used_after_revoke. contains ( & peeled. variable_id )
290+ && ( !self . constants . contains ( & peeled. variable_id ) || allow_const)
291+ {
274292 return false ;
275293 }
276294 }
@@ -309,10 +327,22 @@ impl<'db, 'a> FindLocalsContext<'db, 'a> {
309327 for ( var, output_info) in zip_eq ( output_vars. iter ( ) , var_output_infos. iter ( ) ) {
310328 match output_info. ref_info {
311329 OutputVarReferenceInfo :: SameAsParam { param_idx } => {
312- self . aliases . insert ( * var, input_vars[ param_idx] . var_id ) ;
330+ self . aliases . insert (
331+ * var,
332+ VarSource {
333+ variable_id : input_vars[ param_idx] . var_id ,
334+ allow_const : _params_signatures[ param_idx] . allow_const ,
335+ } ,
336+ ) ;
313337 }
314338 OutputVarReferenceInfo :: PartialParam { param_idx } => {
315- self . partial_param_parents . insert ( * var, input_vars[ param_idx] . var_id ) ;
339+ self . partial_param_parents . insert (
340+ * var,
341+ VarSource {
342+ variable_id : input_vars[ param_idx] . var_id ,
343+ allow_const : _params_signatures[ param_idx] . allow_const ,
344+ } ,
345+ ) ;
316346 }
317347 OutputVarReferenceInfo :: Deferred ( DeferredOutputKind :: Const )
318348 | OutputVarReferenceInfo :: NewLocalVar
@@ -387,12 +417,21 @@ impl<'db, 'a> FindLocalsContext<'db, 'a> {
387417 )
388418 }
389419 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 ) ;
420+ self . aliases . insert (
421+ statement_snapshot. original ( ) ,
422+ VarSource { variable_id : statement_snapshot. input . var_id , allow_const : true } ,
423+ ) ;
424+ self . aliases . insert (
425+ statement_snapshot. snapshot ( ) ,
426+ VarSource { variable_id : statement_snapshot. input . var_id , allow_const : true } ,
427+ ) ;
392428 BranchInfo { known_ap_change : true }
393429 }
394430 lowering:: Statement :: Desnap ( statement_desnap) => {
395- self . aliases . insert ( statement_desnap. output , statement_desnap. input . var_id ) ;
431+ self . aliases . insert (
432+ statement_desnap. output ,
433+ VarSource { variable_id : statement_desnap. input . var_id , allow_const : true } ,
434+ ) ;
396435 BranchInfo { known_ap_change : true }
397436 }
398437 } ;
0 commit comments