@@ -13,11 +13,11 @@ use triomphe::Arc;
1313use crate :: {
1414 TraitEnvironment ,
1515 db:: HirDatabase ,
16- infer:: unify :: InferenceTable ,
16+ infer:: InferenceContext ,
1717 next_solver:: {
18- Canonical , TraitRef , Ty , TyKind ,
18+ Canonical , DbInterner , ParamEnv , TraitRef , Ty , TyKind , TypingMode ,
1919 infer:: {
20- InferOk ,
20+ DbInternerInferExt , InferCtxt ,
2121 traits:: { Obligation , ObligationCause , PredicateObligations } ,
2222 } ,
2323 obligation_ctxt:: ObligationCtxt ,
@@ -38,14 +38,15 @@ pub fn autoderef<'db>(
3838 env : Arc < TraitEnvironment < ' db > > ,
3939 ty : Canonical < ' db , Ty < ' db > > ,
4040) -> impl Iterator < Item = Ty < ' db > > + use < ' db > {
41- let mut table = InferenceTable :: new ( db, env, None ) ;
42- let ty = table. instantiate_canonical ( ty) ;
43- let mut autoderef = Autoderef :: new_no_tracking ( & mut table, ty) ;
41+ let interner = DbInterner :: new_with ( db, Some ( env. krate ) , env. block ) ;
42+ let infcx = interner. infer_ctxt ( ) . build ( TypingMode :: PostAnalysis ) ;
43+ let ( ty, _) = infcx. instantiate_canonical ( & ty) ;
44+ let autoderef = Autoderef :: new ( & infcx, & env, ty) ;
4445 let mut v = Vec :: new ( ) ;
45- while let Some ( ( ty, _steps) ) = autoderef. next ( ) {
46+ for ( ty, _steps) in autoderef {
4647 // `ty` may contain unresolved inference variables. Since there's no chance they would be
4748 // resolved, just replace with fallback type.
48- let resolved = autoderef . table . resolve_completely ( ty) ;
49+ let resolved = infcx . resolve_vars_if_possible ( ty) . replace_infer_with_error ( interner ) ;
4950
5051 // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
5152 // would revisit some already visited types. Stop here to avoid duplication.
@@ -105,13 +106,48 @@ struct AutoderefTraits {
105106 trait_target : TypeAliasId ,
106107}
107108
109+ // We use a trait here and a generic implementation unfortunately, because sometimes (specifically
110+ // in place_op.rs), you need to have mutable access to the `InferenceContext` while the `Autoderef`
111+ // borrows it.
112+ pub ( crate ) trait AutoderefCtx < ' db > {
113+ fn infcx ( & self ) -> & InferCtxt < ' db > ;
114+ fn env ( & self ) -> & TraitEnvironment < ' db > ;
115+ }
116+
117+ pub ( crate ) struct DefaultAutoderefCtx < ' a , ' db > {
118+ infcx : & ' a InferCtxt < ' db > ,
119+ env : & ' a TraitEnvironment < ' db > ,
120+ }
121+ impl < ' db > AutoderefCtx < ' db > for DefaultAutoderefCtx < ' _ , ' db > {
122+ #[ inline]
123+ fn infcx ( & self ) -> & InferCtxt < ' db > {
124+ self . infcx
125+ }
126+ #[ inline]
127+ fn env ( & self ) -> & TraitEnvironment < ' db > {
128+ self . env
129+ }
130+ }
131+
132+ pub ( crate ) struct InferenceContextAutoderefCtx < ' a , ' b , ' db > ( & ' a mut InferenceContext < ' b , ' db > ) ;
133+ impl < ' db > AutoderefCtx < ' db > for InferenceContextAutoderefCtx < ' _ , ' _ , ' db > {
134+ #[ inline]
135+ fn infcx ( & self ) -> & InferCtxt < ' db > {
136+ & self . 0 . table . infer_ctxt
137+ }
138+ #[ inline]
139+ fn env ( & self ) -> & TraitEnvironment < ' db > {
140+ & self . 0 . table . trait_env
141+ }
142+ }
143+
108144/// Recursively dereference a type, considering both built-in
109145/// dereferences (`*`) and the `Deref` trait.
110146/// Although called `Autoderef` it can be configured to use the
111147/// `Receiver` trait instead of the `Deref` trait.
112- pub ( crate ) struct Autoderef < ' a , ' db , Steps = Vec < ( Ty < ' db > , AutoderefKind ) > > {
148+ pub ( crate ) struct GeneralAutoderef < ' db , Ctx , Steps = Vec < ( Ty < ' db > , AutoderefKind ) > > {
113149 // Meta infos:
114- pub ( crate ) table : & ' a mut InferenceTable < ' db > ,
150+ ctx : Ctx ,
115151 traits : Option < AutoderefTraits > ,
116152
117153 // Current state:
@@ -122,7 +158,16 @@ pub(crate) struct Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> {
122158 use_receiver_trait : bool ,
123159}
124160
125- impl < ' a , ' db , Steps : TrackAutoderefSteps < ' db > > Iterator for Autoderef < ' a , ' db , Steps > {
161+ pub ( crate ) type Autoderef < ' a , ' db , Steps = Vec < ( Ty < ' db > , AutoderefKind ) > > =
162+ GeneralAutoderef < ' db , DefaultAutoderefCtx < ' a , ' db > , Steps > ;
163+ pub ( crate ) type InferenceContextAutoderef < ' a , ' b , ' db , Steps = Vec < ( Ty < ' db > , AutoderefKind ) > > =
164+ GeneralAutoderef < ' db , InferenceContextAutoderefCtx < ' a , ' b , ' db > , Steps > ;
165+
166+ impl < ' db , Ctx , Steps > Iterator for GeneralAutoderef < ' db , Ctx , Steps >
167+ where
168+ Ctx : AutoderefCtx < ' db > ,
169+ Steps : TrackAutoderefSteps < ' db > ,
170+ {
126171 type Item = ( Ty < ' db > , usize ) ;
127172
128173 fn next ( & mut self ) -> Option < Self :: Item > {
@@ -148,26 +193,26 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, S
148193 // be better to skip this clause and use the Overloaded case only, since &T
149194 // and &mut T implement Receiver. But built-in derefs apply equally to Receiver
150195 // and Deref, and this has benefits for const and the emitted MIR.
151- let ( kind, new_ty) = if let Some ( ty) =
152- self . state . cur_ty . builtin_deref ( self . table . db , self . include_raw_pointers )
153- {
154- debug_assert_eq ! ( ty, self . table. infer_ctxt. resolve_vars_if_possible( ty) ) ;
155- // NOTE: we may still need to normalize the built-in deref in case
156- // we have some type like `&<Ty as Trait>::Assoc`, since users of
157- // autoderef expect this type to have been structurally normalized.
158- if let TyKind :: Alias ( ..) = ty. kind ( ) {
159- let ( normalized_ty, obligations) = structurally_normalize_ty ( self . table , ty) ?;
160- self . state . obligations . extend ( obligations) ;
161- ( AutoderefKind :: Builtin , normalized_ty)
196+ let ( kind, new_ty) =
197+ if let Some ( ty) = self . state . cur_ty . builtin_deref ( self . include_raw_pointers ) {
198+ debug_assert_eq ! ( ty, self . infcx( ) . resolve_vars_if_possible( ty) ) ;
199+ // NOTE: we may still need to normalize the built-in deref in case
200+ // we have some type like `&<Ty as Trait>::Assoc`, since users of
201+ // autoderef expect this type to have been structurally normalized.
202+ if let TyKind :: Alias ( ..) = ty. kind ( ) {
203+ let ( normalized_ty, obligations) =
204+ structurally_normalize_ty ( self . infcx ( ) , self . env ( ) . env , ty) ?;
205+ self . state . obligations . extend ( obligations) ;
206+ ( AutoderefKind :: Builtin , normalized_ty)
207+ } else {
208+ ( AutoderefKind :: Builtin , ty)
209+ }
210+ } else if let Some ( ty) = self . overloaded_deref_ty ( self . state . cur_ty ) {
211+ // The overloaded deref check already normalizes the pointee type.
212+ ( AutoderefKind :: Overloaded , ty)
162213 } else {
163- ( AutoderefKind :: Builtin , ty)
164- }
165- } else if let Some ( ty) = self . overloaded_deref_ty ( self . state . cur_ty ) {
166- // The overloaded deref check already normalizes the pointee type.
167- ( AutoderefKind :: Overloaded , ty)
168- } else {
169- return None ;
170- } ;
214+ return None ;
215+ } ;
171216
172217 self . state . steps . push ( self . state . cur_ty , kind) ;
173218 debug ! (
@@ -183,34 +228,84 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, S
183228}
184229
185230impl < ' a , ' db > Autoderef < ' a , ' db > {
186- pub ( crate ) fn new ( table : & ' a mut InferenceTable < ' db > , base_ty : Ty < ' db > ) -> Self {
187- Self :: new_impl ( table, base_ty)
231+ #[ inline]
232+ pub ( crate ) fn new_with_tracking (
233+ infcx : & ' a InferCtxt < ' db > ,
234+ env : & ' a TraitEnvironment < ' db > ,
235+ base_ty : Ty < ' db > ,
236+ ) -> Self {
237+ Self :: new_impl ( DefaultAutoderefCtx { infcx, env } , base_ty)
238+ }
239+ }
240+
241+ impl < ' a , ' b , ' db > InferenceContextAutoderef < ' a , ' b , ' db > {
242+ #[ inline]
243+ pub ( crate ) fn new_from_inference_context (
244+ ctx : & ' a mut InferenceContext < ' b , ' db > ,
245+ base_ty : Ty < ' db > ,
246+ ) -> Self {
247+ Self :: new_impl ( InferenceContextAutoderefCtx ( ctx) , base_ty)
248+ }
249+
250+ #[ inline]
251+ pub ( crate ) fn ctx ( & mut self ) -> & mut InferenceContext < ' b , ' db > {
252+ self . ctx . 0
188253 }
189254}
190255
191256impl < ' a , ' db > Autoderef < ' a , ' db , usize > {
192- pub ( crate ) fn new_no_tracking ( table : & ' a mut InferenceTable < ' db > , base_ty : Ty < ' db > ) -> Self {
193- Self :: new_impl ( table, base_ty)
257+ #[ inline]
258+ pub ( crate ) fn new (
259+ infcx : & ' a InferCtxt < ' db > ,
260+ env : & ' a TraitEnvironment < ' db > ,
261+ base_ty : Ty < ' db > ,
262+ ) -> Self {
263+ Self :: new_impl ( DefaultAutoderefCtx { infcx, env } , base_ty)
194264 }
195265}
196266
197- impl < ' a , ' db , Steps : TrackAutoderefSteps < ' db > > Autoderef < ' a , ' db , Steps > {
198- fn new_impl ( table : & ' a mut InferenceTable < ' db > , base_ty : Ty < ' db > ) -> Self {
199- Autoderef {
267+ impl < ' db , Ctx , Steps > GeneralAutoderef < ' db , Ctx , Steps >
268+ where
269+ Ctx : AutoderefCtx < ' db > ,
270+ Steps : TrackAutoderefSteps < ' db > ,
271+ {
272+ #[ inline]
273+ fn new_impl ( ctx : Ctx , base_ty : Ty < ' db > ) -> Self {
274+ GeneralAutoderef {
200275 state : AutoderefSnapshot {
201276 steps : Steps :: default ( ) ,
202- cur_ty : table . infer_ctxt . resolve_vars_if_possible ( base_ty) ,
277+ cur_ty : ctx . infcx ( ) . resolve_vars_if_possible ( base_ty) ,
203278 obligations : PredicateObligations :: new ( ) ,
204279 at_start : true ,
205280 reached_recursion_limit : false ,
206281 } ,
207- table ,
282+ ctx ,
208283 traits : None ,
209284 include_raw_pointers : false ,
210285 use_receiver_trait : false ,
211286 }
212287 }
213288
289+ #[ inline]
290+ fn infcx ( & self ) -> & InferCtxt < ' db > {
291+ self . ctx . infcx ( )
292+ }
293+
294+ #[ inline]
295+ fn env ( & self ) -> & TraitEnvironment < ' db > {
296+ self . ctx . env ( )
297+ }
298+
299+ #[ inline]
300+ fn interner ( & self ) -> DbInterner < ' db > {
301+ self . infcx ( ) . interner
302+ }
303+
304+ #[ inline]
305+ fn db ( & self ) -> & ' db dyn HirDatabase {
306+ self . interner ( ) . db
307+ }
308+
214309 fn autoderef_traits ( & mut self ) -> Option < AutoderefTraits > {
215310 match & mut self . traits {
216311 Some ( it) => Some ( * it) ,
@@ -219,25 +314,23 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
219314 ( || {
220315 Some ( AutoderefTraits {
221316 trait_ : LangItem :: Receiver
222- . resolve_trait ( self . table . db , self . table . trait_env . krate ) ?,
317+ . resolve_trait ( self . db ( ) , self . env ( ) . krate ) ?,
223318 trait_target : LangItem :: ReceiverTarget
224- . resolve_type_alias ( self . table . db , self . table . trait_env . krate ) ?,
319+ . resolve_type_alias ( self . db ( ) , self . env ( ) . krate ) ?,
225320 } )
226321 } ) ( )
227322 . or_else ( || {
228323 Some ( AutoderefTraits {
229- trait_ : LangItem :: Deref
230- . resolve_trait ( self . table . db , self . table . trait_env . krate ) ?,
324+ trait_ : LangItem :: Deref . resolve_trait ( self . db ( ) , self . env ( ) . krate ) ?,
231325 trait_target : LangItem :: DerefTarget
232- . resolve_type_alias ( self . table . db , self . table . trait_env . krate ) ?,
326+ . resolve_type_alias ( self . db ( ) , self . env ( ) . krate ) ?,
233327 } )
234328 } ) ?
235329 } else {
236330 AutoderefTraits {
237- trait_ : LangItem :: Deref
238- . resolve_trait ( self . table . db , self . table . trait_env . krate ) ?,
331+ trait_ : LangItem :: Deref . resolve_trait ( self . db ( ) , self . env ( ) . krate ) ?,
239332 trait_target : LangItem :: DerefTarget
240- . resolve_type_alias ( self . table . db , self . table . trait_env . krate ) ?,
333+ . resolve_type_alias ( self . db ( ) , self . env ( ) . krate ) ?,
241334 }
242335 } ;
243336 Some ( * self . traits . insert ( traits) )
@@ -247,31 +340,32 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
247340
248341 fn overloaded_deref_ty ( & mut self , ty : Ty < ' db > ) -> Option < Ty < ' db > > {
249342 debug ! ( "overloaded_deref_ty({:?})" , ty) ;
250- let interner = self . table . interner ( ) ;
343+ let interner = self . interner ( ) ;
251344
252345 // <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
253346 let AutoderefTraits { trait_, trait_target } = self . autoderef_traits ( ) ?;
254347
255348 let trait_ref = TraitRef :: new ( interner, trait_. into ( ) , [ ty] ) ;
256349 let obligation =
257- Obligation :: new ( interner, ObligationCause :: new ( ) , self . table . trait_env . env , trait_ref) ;
350+ Obligation :: new ( interner, ObligationCause :: new ( ) , self . env ( ) . env , trait_ref) ;
258351 // We detect whether the self type implements `Deref` before trying to
259352 // structurally normalize. We use `predicate_may_hold_opaque_types_jank`
260353 // to support not-yet-defined opaque types. It will succeed for `impl Deref`
261354 // but fail for `impl OtherTrait`.
262- if !self . table . infer_ctxt . predicate_may_hold_opaque_types_jank ( & obligation) {
355+ if !self . infcx ( ) . predicate_may_hold_opaque_types_jank ( & obligation) {
263356 debug ! ( "overloaded_deref_ty: cannot match obligation" ) ;
264357 return None ;
265358 }
266359
267360 let ( normalized_ty, obligations) = structurally_normalize_ty (
268- self . table ,
361+ self . infcx ( ) ,
362+ self . env ( ) . env ,
269363 Ty :: new_projection ( interner, trait_target. into ( ) , [ ty] ) ,
270364 ) ?;
271365 debug ! ( "overloaded_deref_ty({:?}) = ({:?}, {:?})" , ty, normalized_ty, obligations) ;
272366 self . state . obligations . extend ( obligations) ;
273367
274- Some ( self . table . infer_ctxt . resolve_vars_if_possible ( normalized_ty) )
368+ Some ( self . infcx ( ) . resolve_vars_if_possible ( normalized_ty) )
275369 }
276370
277371 /// Returns the final type we ended up with, which may be an unresolved
@@ -292,7 +386,6 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
292386 & self . state . steps
293387 }
294388
295- #[ expect( dead_code) ]
296389 pub ( crate ) fn reached_recursion_limit ( & self ) -> bool {
297390 self . state . reached_recursion_limit
298391 }
@@ -316,12 +409,12 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
316409}
317410
318411fn structurally_normalize_ty < ' db > (
319- table : & InferenceTable < ' db > ,
412+ infcx : & InferCtxt < ' db > ,
413+ param_env : ParamEnv < ' db > ,
320414 ty : Ty < ' db > ,
321415) -> Option < ( Ty < ' db > , PredicateObligations < ' db > ) > {
322- let mut ocx = ObligationCtxt :: new ( & table. infer_ctxt ) ;
323- let Ok ( normalized_ty) =
324- ocx. structurally_normalize_ty ( & ObligationCause :: misc ( ) , table. trait_env . env , ty)
416+ let mut ocx = ObligationCtxt :: new ( infcx) ;
417+ let Ok ( normalized_ty) = ocx. structurally_normalize_ty ( & ObligationCause :: misc ( ) , param_env, ty)
325418 else {
326419 // We shouldn't have errors here in the old solver, except for
327420 // evaluate/fulfill mismatches, but that's not a reason for an ICE.
@@ -334,17 +427,3 @@ fn structurally_normalize_ty<'db>(
334427
335428 Some ( ( normalized_ty, ocx. into_pending_obligations ( ) ) )
336429}
337-
338- pub ( crate ) fn overloaded_deref_ty < ' db > (
339- table : & InferenceTable < ' db > ,
340- ty : Ty < ' db > ,
341- ) -> Option < InferOk < ' db , Ty < ' db > > > {
342- let interner = table. interner ( ) ;
343-
344- let trait_target = LangItem :: DerefTarget . resolve_type_alias ( table. db , table. trait_env . krate ) ?;
345-
346- let ( normalized_ty, obligations) =
347- structurally_normalize_ty ( table, Ty :: new_projection ( interner, trait_target. into ( ) , [ ty] ) ) ?;
348-
349- Some ( InferOk { value : normalized_ty, obligations } )
350- }
0 commit comments