1
1
use crate :: errors:: AutoDerefReachedRecursionLimit ;
2
2
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
3
- use crate :: traits:: NormalizeExt ;
4
3
use crate :: traits:: { self , TraitEngine , TraitEngineExt } ;
5
4
use rustc_infer:: infer:: InferCtxt ;
6
5
use rustc_middle:: ty:: TypeVisitableExt ;
@@ -9,6 +8,7 @@ use rustc_session::Limit;
9
8
use rustc_span:: def_id:: LocalDefId ;
10
9
use rustc_span:: def_id:: LOCAL_CRATE ;
11
10
use rustc_span:: Span ;
11
+ use rustc_trait_selection:: traits:: StructurallyNormalizeExt ;
12
12
13
13
#[ derive( Copy , Clone , Debug ) ]
14
14
pub enum AutoderefKind {
@@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
66
66
}
67
67
68
68
// 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)
74
82
} 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
+ } ;
77
90
78
91
if new_ty. references_error ( ) {
79
92
return None ;
@@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
119
132
120
133
fn overloaded_deref_ty ( & mut self , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
121
134
debug ! ( "overloaded_deref_ty({:?})" , ty) ;
122
-
123
135
let tcx = self . infcx . tcx ;
124
136
125
137
// <ty as Deref>
126
138
let trait_ref = ty:: TraitRef :: new ( tcx, tcx. lang_items ( ) . deref_trait ( ) ?, [ ty] ) ;
127
-
128
139
let cause = traits:: ObligationCause :: misc ( self . span , self . body_id ) ;
129
-
130
140
let obligation = traits:: Obligation :: new (
131
141
tcx,
132
142
cause. clone ( ) ,
@@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
138
148
return None ;
139
149
}
140
150
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
142
169
. infcx
143
170
. 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 ) ;
149
184
if !errors. is_empty ( ) {
150
185
// This shouldn't happen, except for evaluate/fulfill mismatches,
151
186
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
152
187
// by design).
153
- debug ! ( "overloaded_deref_ty: encountered errors {:?} while fulfilling", errors ) ;
188
+ debug ! ( ?errors , " encountered errors while fulfilling") ;
154
189
return None ;
155
190
}
156
- let obligations = fulfillcx. pending_obligations ( ) ;
157
- debug ! ( "overloaded_deref_ty({:?}) = ({:?}, {:?})" , ty, normalized_ty, obligations) ;
158
- self . state . obligations . extend ( obligations) ;
159
191
160
- Some ( self . infcx . resolve_vars_if_possible ( normalized_ty) )
192
+ Some ( ( normalized_ty, fulfill_cx . pending_obligations ( ) ) )
161
193
}
162
194
163
195
/// Returns the final type we ended up with, which may be an inference
0 commit comments