77//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
88
99use rustc_macros:: extension;
10- use rustc_middle:: bug;
11- use rustc_middle:: ty:: { self , FnMutDelegate , GenericArgKind , TyCtxt , TypeFoldable } ;
10+ use rustc_middle:: ty:: {
11+ self , DelayedMap , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeSuperVisitable ,
12+ TypeVisitableExt , TypeVisitor ,
13+ } ;
14+ use rustc_type_ir:: TypeVisitable ;
1215
1316use crate :: infer:: canonical:: { Canonical , CanonicalVarValues } ;
1417
@@ -18,11 +21,15 @@ use crate::infer::canonical::{Canonical, CanonicalVarValues};
1821impl < ' tcx , V > Canonical < ' tcx , V > {
1922 /// Instantiate the wrapped value, replacing each canonical value
2023 /// with the value given in `var_values`.
21- fn instantiate ( & self , tcx : TyCtxt < ' tcx > , var_values : & CanonicalVarValues < ' tcx > ) -> V
24+ fn instantiate < const UWU : bool > (
25+ & self ,
26+ tcx : TyCtxt < ' tcx > ,
27+ var_values : & CanonicalVarValues < ' tcx > ,
28+ ) -> V
2229 where
2330 V : TypeFoldable < TyCtxt < ' tcx > > ,
2431 {
25- self . instantiate_projected ( tcx, var_values, |value| value. clone ( ) )
32+ self . instantiate_projected :: < _ , UWU > ( tcx, var_values, |value| value. clone ( ) )
2633 }
2734
2835 /// Allows one to apply a instantiation to some subset of
@@ -31,7 +38,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
3138 /// variables bound in `self` (usually this extracts from subset
3239 /// of `self`). Apply the instantiation `var_values` to this value
3340 /// V, replacing each of the canonical variables.
34- fn instantiate_projected < T > (
41+ fn instantiate_projected < T , const UWU : bool > (
3542 & self ,
3643 tcx : TyCtxt < ' tcx > ,
3744 var_values : & CanonicalVarValues < ' tcx > ,
@@ -42,14 +49,14 @@ impl<'tcx, V> Canonical<'tcx, V> {
4249 {
4350 assert_eq ! ( self . variables. len( ) , var_values. len( ) ) ;
4451 let value = projection_fn ( & self . value ) ;
45- instantiate_value ( tcx, var_values, value)
52+ instantiate_value_0 :: < _ , UWU > ( tcx, var_values, value)
4653 }
4754}
4855
4956/// Instantiate the values from `var_values` into `value`. `var_values`
5057/// must be values for the set of canonical variables that appear in
5158/// `value`.
52- pub ( super ) fn instantiate_value < ' tcx , T > (
59+ pub ( super ) fn instantiate_value_0 < ' tcx , T , const UWU : bool > (
5360 tcx : TyCtxt < ' tcx > ,
5461 var_values : & CanonicalVarValues < ' tcx > ,
5562 value : T ,
@@ -58,23 +65,160 @@ where
5865 T : TypeFoldable < TyCtxt < ' tcx > > ,
5966{
6067 if var_values. var_values . is_empty ( ) {
61- value
62- } else {
63- let delegate = FnMutDelegate {
64- regions : & mut |br : ty:: BoundRegion | match var_values[ br. var ] . kind ( ) {
65- GenericArgKind :: Lifetime ( l) => l,
66- r => bug ! ( "{:?} is a region but value is {:?}" , br, r) ,
67- } ,
68- types : & mut |bound_ty : ty:: BoundTy | match var_values[ bound_ty. var ] . kind ( ) {
69- GenericArgKind :: Type ( ty) => ty,
70- r => bug ! ( "{:?} is a type but value is {:?}" , bound_ty, r) ,
71- } ,
72- consts : & mut |bound_ct : ty:: BoundVar | match var_values[ bound_ct] . kind ( ) {
73- GenericArgKind :: Const ( ct) => ct,
74- c => bug ! ( "{:?} is a const but value is {:?}" , bound_ct, c) ,
75- } ,
76- } ;
77-
78- tcx. replace_escaping_bound_vars_uncached ( value, delegate)
68+ return value;
69+ }
70+
71+ value. fold_with ( & mut BoundVarReplacer :: < UWU > {
72+ tcx,
73+ current_index : ty:: INNERMOST ,
74+ var_values : var_values. var_values ,
75+ cache : Default :: default ( ) ,
76+ } )
77+ }
78+
79+ /// Replaces the escaping bound vars (late bound regions or bound types) in a type.
80+ struct BoundVarReplacer < ' tcx , const UWU : bool > {
81+ tcx : TyCtxt < ' tcx > ,
82+
83+ /// As with `RegionFolder`, represents the index of a binder *just outside*
84+ /// the ones we have visited.
85+ current_index : ty:: DebruijnIndex ,
86+
87+ var_values : ty:: GenericArgsRef < ' tcx > ,
88+
89+ /// This cache only tracks the `DebruijnIndex` and assumes that it does not matter
90+ /// for the delegate how often its methods get used.
91+ cache : DelayedMap < ( ty:: DebruijnIndex , Ty < ' tcx > ) , Ty < ' tcx > > ,
92+ }
93+
94+ impl < ' tcx , const UWU : bool > TypeFolder < TyCtxt < ' tcx > > for BoundVarReplacer < ' tcx , UWU > {
95+ fn cx ( & self ) -> TyCtxt < ' tcx > {
96+ self . tcx
97+ }
98+
99+ fn fold_binder < T : TypeFoldable < TyCtxt < ' tcx > > > (
100+ & mut self ,
101+ t : ty:: Binder < ' tcx , T > ,
102+ ) -> ty:: Binder < ' tcx , T > {
103+ self . current_index . shift_in ( 1 ) ;
104+ let t = t. super_fold_with ( self ) ;
105+ self . current_index . shift_out ( 1 ) ;
106+ t
107+ }
108+
109+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
110+ match * t. kind ( ) {
111+ ty:: Bound ( debruijn, bound_ty) if debruijn == self . current_index => {
112+ self . var_values [ bound_ty. var . as_usize ( ) ] . expect_ty ( )
113+ }
114+ _ => {
115+ if !t. has_vars_bound_at_or_above ( self . current_index ) {
116+ t
117+ } else if let Some ( & t) = self . cache . get ( & ( self . current_index , t) ) {
118+ t
119+ } else {
120+ let res = t. super_fold_with ( self ) ;
121+ assert ! ( self . cache. insert( ( self . current_index, t) , res) ) ;
122+ res
123+ }
124+ }
125+ }
126+ }
127+
128+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
129+ match r. kind ( ) {
130+ ty:: ReBound ( debruijn, br) if debruijn == self . current_index => {
131+ self . var_values [ br. var . as_usize ( ) ] . expect_region ( )
132+ }
133+ _ => r,
134+ }
135+ }
136+
137+ fn fold_const ( & mut self , ct : ty:: Const < ' tcx > ) -> ty:: Const < ' tcx > {
138+ match ct. kind ( ) {
139+ ty:: ConstKind :: Bound ( debruijn, bound_const) if debruijn == self . current_index => {
140+ self . var_values [ bound_const. as_usize ( ) ] . expect_const ( )
141+ }
142+ _ => ct. super_fold_with ( self ) ,
143+ }
144+ }
145+
146+ fn fold_predicate ( & mut self , p : ty:: Predicate < ' tcx > ) -> ty:: Predicate < ' tcx > {
147+ if p. has_vars_bound_at_or_above ( self . current_index ) { p. super_fold_with ( self ) } else { p }
148+ }
149+
150+ fn fold_clauses ( & mut self , c : ty:: Clauses < ' tcx > ) -> ty:: Clauses < ' tcx > {
151+ if c. has_vars_bound_at_or_above ( self . current_index ) {
152+ if self . current_index == ty:: INNERMOST {
153+ if UWU {
154+ let index = * self
155+ . tcx
156+ . highest_var_in_clauses_cache
157+ . lock ( )
158+ . entry ( c)
159+ . or_insert_with ( || highest_var_in_clauses ( c) ) ;
160+ let c_args = & self . var_values [ ..=index] ;
161+ if let Some ( c2) = self . tcx . clauses_cache . lock ( ) . get ( & ( c, c_args) ) {
162+ c2
163+ } else {
164+ let folded = c. super_fold_with ( self ) ;
165+ self . tcx . clauses_cache . lock ( ) . insert ( ( c, c_args) , folded) ;
166+ folded
167+ }
168+ } else {
169+ c. super_fold_with ( self )
170+ }
171+ } else {
172+ c. super_fold_with ( self )
173+ }
174+ } else {
175+ c
176+ }
177+ }
178+ }
179+
180+ fn highest_var_in_clauses < ' tcx > ( c : ty:: Clauses < ' tcx > ) -> usize {
181+ struct HighestVarInClauses {
182+ max_var : usize ,
183+ current_index : ty:: DebruijnIndex ,
184+ }
185+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for HighestVarInClauses {
186+ fn visit_binder < T : TypeFoldable < TyCtxt < ' tcx > > > (
187+ & mut self ,
188+ t : & ty:: Binder < ' tcx , T > ,
189+ ) -> Self :: Result {
190+ self . current_index . shift_in ( 1 ) ;
191+ let t = t. super_visit_with ( self ) ;
192+ self . current_index . shift_out ( 1 ) ;
193+ t
194+ }
195+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) {
196+ if let ty:: Bound ( debruijn, bound_ty) = * t. kind ( )
197+ && debruijn == self . current_index
198+ {
199+ self . max_var = self . max_var . max ( bound_ty. var . as_usize ( ) ) ;
200+ } else if t. has_vars_bound_at_or_above ( self . current_index ) {
201+ t. super_visit_with ( self ) ;
202+ }
203+ }
204+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) {
205+ if let ty:: ReBound ( debruijn, bound_region) = r. kind ( )
206+ && debruijn == self . current_index
207+ {
208+ self . max_var = self . max_var . max ( bound_region. var . as_usize ( ) ) ;
209+ }
210+ }
211+ fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) {
212+ if let ty:: ConstKind :: Bound ( debruijn, bound_const) = ct. kind ( )
213+ && debruijn == self . current_index
214+ {
215+ self . max_var = self . max_var . max ( bound_const. as_usize ( ) ) ;
216+ } else if ct. has_vars_bound_at_or_above ( self . current_index ) {
217+ ct. super_visit_with ( self ) ;
218+ }
219+ }
79220 }
221+ let mut visitor = HighestVarInClauses { max_var : 0 , current_index : ty:: INNERMOST } ;
222+ c. visit_with ( & mut visitor) ;
223+ visitor. max_var
80224}
0 commit comments