@@ -13,6 +13,7 @@ use rustc_middle::ty::flags::FlagComputation;
1313use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
1414use rustc_middle:: ty:: GenericArg ;
1515use rustc_middle:: ty:: { self , BoundVar , InferConst , List , Ty , TyCtxt , TypeFlags , TypeVisitableExt } ;
16+ use std:: borrow:: Cow ;
1617use std:: sync:: atomic:: Ordering ;
1718
1819use rustc_data_structures:: fx:: FxHashMap ;
@@ -148,6 +149,27 @@ impl<'tcx> InferCtxt<'tcx> {
148149 query_state,
149150 )
150151 }
152+
153+ pub fn canonicalize_query_keep_static_continue < U , V > (
154+ & self ,
155+ base : Canonical < ' tcx , U > ,
156+ value : V ,
157+ query_state : & mut Cow < ' _ , OriginalQueryValues < ' tcx > > ,
158+ ) -> Canonical < ' tcx , ( U , V ) >
159+ where
160+ V : TypeFoldable < TyCtxt < ' tcx > > ,
161+ {
162+ self . tcx . sess . perf_stats . queries_canonicalized . fetch_add ( 1 , Ordering :: Relaxed ) ;
163+
164+ Canonicalizer :: canonicalize_continue (
165+ base,
166+ value,
167+ self ,
168+ self . tcx ,
169+ & CanonicalizeFreeRegionsOtherThanStatic ,
170+ query_state,
171+ )
172+ }
151173}
152174
153175/// Controls how we canonicalize "free regions" that are not inference
@@ -616,6 +638,66 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
616638 Canonical { max_universe, variables : canonical_variables, value : out_value }
617639 }
618640
641+ fn canonicalize_continue < U , V > (
642+ base : Canonical < ' tcx , U > ,
643+ value : V ,
644+ infcx : & InferCtxt < ' tcx > ,
645+ tcx : TyCtxt < ' tcx > ,
646+ canonicalize_region_mode : & dyn CanonicalizeMode ,
647+ query_state : & mut Cow < ' _ , OriginalQueryValues < ' tcx > > ,
648+ ) -> Canonical < ' tcx , ( U , V ) >
649+ where
650+ V : TypeFoldable < TyCtxt < ' tcx > > ,
651+ {
652+ let needs_canonical_flags = if canonicalize_region_mode. any ( ) {
653+ TypeFlags :: HAS_INFER | TypeFlags :: HAS_PLACEHOLDER | TypeFlags :: HAS_FREE_REGIONS
654+ } else {
655+ TypeFlags :: HAS_INFER | TypeFlags :: HAS_PLACEHOLDER
656+ } ;
657+
658+ // Fast path: nothing that needs to be canonicalized.
659+ if !value. has_type_flags ( needs_canonical_flags) {
660+ return base. unchecked_map ( |b| ( b, value) ) ;
661+ }
662+
663+ let mut canonicalizer = Canonicalizer {
664+ infcx,
665+ tcx,
666+ canonicalize_mode : canonicalize_region_mode,
667+ needs_canonical_flags,
668+ variables : SmallVec :: from_slice ( base. variables ) ,
669+ query_state : query_state. to_mut ( ) ,
670+ indices : FxHashMap :: default ( ) ,
671+ binder_index : ty:: INNERMOST ,
672+ } ;
673+ if canonicalizer. query_state . var_values . spilled ( ) {
674+ canonicalizer. indices = canonicalizer
675+ . query_state
676+ . var_values
677+ . iter ( )
678+ . enumerate ( )
679+ . map ( |( i, & kind) | ( kind, BoundVar :: new ( i) ) )
680+ . collect ( ) ;
681+ }
682+ let out_value = value. fold_with ( & mut canonicalizer) ;
683+
684+ // Once we have canonicalized `out_value`, it should not
685+ // contain anything that ties it to this inference context
686+ // anymore.
687+ debug_assert ! ( !out_value. has_infer( ) && !out_value. has_placeholders( ) ) ;
688+
689+ let canonical_variables =
690+ tcx. mk_canonical_var_infos ( & canonicalizer. universe_canonicalized_variables ( ) ) ;
691+
692+ let max_universe = canonical_variables
693+ . iter ( )
694+ . map ( |cvar| cvar. universe ( ) )
695+ . max ( )
696+ . unwrap_or ( ty:: UniverseIndex :: ROOT ) ;
697+
698+ Canonical { max_universe, variables : canonical_variables, value : ( base. value , out_value) }
699+ }
700+
619701 /// Creates a canonical variable replacing `kind` from the input,
620702 /// or returns an existing variable if `kind` has already been
621703 /// seen. `kind` is expected to be an unbound variable (or
0 commit comments