11use crate :: errors:: AutoDerefReachedRecursionLimit ;
22use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
3- use crate :: traits:: NormalizeExt ;
43use crate :: traits:: { self , TraitEngine , TraitEngineExt } ;
54use rustc_infer:: infer:: InferCtxt ;
65use rustc_middle:: ty:: TypeVisitableExt ;
@@ -9,6 +8,7 @@ use rustc_session::Limit;
98use rustc_span:: def_id:: LocalDefId ;
109use rustc_span:: def_id:: LOCAL_CRATE ;
1110use rustc_span:: Span ;
11+ use rustc_trait_selection:: traits:: StructurallyNormalizeExt ;
1212
1313#[ derive( Copy , Clone , Debug ) ]
1414pub enum AutoderefKind {
@@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
6666 }
6767
6868 // Otherwise, deref if type is derefable:
69- let ( kind, new_ty) =
70- if let Some ( mt) = self . state . cur_ty . builtin_deref ( self . include_raw_pointers ) {
71- ( AutoderefKind :: Builtin , mt. ty )
72- } else if let Some ( ty) = self . overloaded_deref_ty ( self . state . cur_ty ) {
73- ( AutoderefKind :: Overloaded , ty)
69+ let ( kind, new_ty) = if let Some ( ty:: TypeAndMut { ty, .. } ) =
70+ self . state . cur_ty . builtin_deref ( self . include_raw_pointers )
71+ {
72+ debug_assert_eq ! ( ty, self . infcx. resolve_vars_if_possible( ty) ) ;
73+ // NOTE: we may still need to normalize the built-in deref in case
74+ // we have some type like `&<Ty as Trait>::Assoc`, since users of
75+ // autoderef expect this type to have been structurally normalized.
76+ if self . infcx . tcx . trait_solver_next ( )
77+ && let ty:: Alias ( ty:: Projection , _) = ty. kind ( )
78+ {
79+ let ( normalized_ty, obligations) = self . structurally_normalize ( ty) ?;
80+ self . state . obligations . extend ( obligations) ;
81+ ( AutoderefKind :: Builtin , normalized_ty)
7482 } else {
75- return None ;
76- } ;
83+ ( AutoderefKind :: Builtin , ty)
84+ }
85+ } else if let Some ( ty) = self . overloaded_deref_ty ( self . state . cur_ty ) {
86+ ( AutoderefKind :: Overloaded , ty)
87+ } else {
88+ return None ;
89+ } ;
7790
7891 if new_ty. references_error ( ) {
7992 return None ;
@@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
119132
120133 fn overloaded_deref_ty ( & mut self , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
121134 debug ! ( "overloaded_deref_ty({:?})" , ty) ;
122-
123135 let tcx = self . infcx . tcx ;
124136
125137 // <ty as Deref>
126138 let trait_ref = ty:: TraitRef :: new ( tcx, tcx. lang_items ( ) . deref_trait ( ) ?, [ ty] ) ;
127-
128139 let cause = traits:: ObligationCause :: misc ( self . span , self . body_id ) ;
129-
130140 let obligation = traits:: Obligation :: new (
131141 tcx,
132142 cause. clone ( ) ,
@@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
138148 return None ;
139149 }
140150
141- let normalized_ty = self
151+ let ( normalized_ty, obligations) =
152+ self . structurally_normalize ( tcx. mk_projection ( tcx. lang_items ( ) . deref_target ( ) ?, [ ty] ) ) ?;
153+ debug ! ( "overloaded_deref_ty({:?}) = ({:?}, {:?})" , ty, normalized_ty, obligations) ;
154+ self . state . obligations . extend ( obligations) ;
155+
156+ Some ( self . infcx . resolve_vars_if_possible ( normalized_ty) )
157+ }
158+
159+ #[ instrument( level = "debug" , skip( self ) , ret) ]
160+ pub fn structurally_normalize (
161+ & self ,
162+ ty : Ty < ' tcx > ,
163+ ) -> Option < ( Ty < ' tcx > , Vec < traits:: PredicateObligation < ' tcx > > ) > {
164+ let tcx = self . infcx . tcx ;
165+ let mut fulfill_cx = <dyn TraitEngine < ' tcx > >:: new_in_snapshot ( tcx) ;
166+
167+ let cause = traits:: ObligationCause :: misc ( self . span , self . body_id ) ;
168+ let normalized_ty = match self
142169 . infcx
143170 . at ( & cause, self . param_env )
144- . normalize ( tcx. mk_projection ( tcx. lang_items ( ) . deref_target ( ) ?, trait_ref. substs ) ) ;
145- let mut fulfillcx = <dyn TraitEngine < ' tcx > >:: new_in_snapshot ( tcx) ;
146- let normalized_ty =
147- normalized_ty. into_value_registering_obligations ( self . infcx , & mut * fulfillcx) ;
148- let errors = fulfillcx. select_where_possible ( & self . infcx ) ;
171+ . structurally_normalize ( ty, & mut * fulfill_cx)
172+ {
173+ Ok ( normalized_ty) => normalized_ty,
174+ Err ( errors) => {
175+ // This shouldn't happen, except for evaluate/fulfill mismatches,
176+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
177+ // by design).
178+ debug ! ( ?errors, "encountered errors while fulfilling" ) ;
179+ return None ;
180+ }
181+ } ;
182+
183+ let errors = fulfill_cx. select_where_possible ( & self . infcx ) ;
149184 if !errors. is_empty ( ) {
150185 // This shouldn't happen, except for evaluate/fulfill mismatches,
151186 // but that's not a reason for an ICE (`predicate_may_hold` is conservative
152187 // by design).
153- debug ! ( "overloaded_deref_ty: encountered errors {:?} while fulfilling", errors ) ;
188+ debug ! ( ?errors , " encountered errors while fulfilling") ;
154189 return None ;
155190 }
156- let obligations = fulfillcx. pending_obligations ( ) ;
157- debug ! ( "overloaded_deref_ty({:?}) = ({:?}, {:?})" , ty, normalized_ty, obligations) ;
158- self . state . obligations . extend ( obligations) ;
159191
160- Some ( self . infcx . resolve_vars_if_possible ( normalized_ty) )
192+ Some ( ( normalized_ty, fulfill_cx . pending_obligations ( ) ) )
161193 }
162194
163195 /// Returns the final type we ended up with, which may be an inference
0 commit comments