@@ -12,112 +12,270 @@ use std::fmt::Debug;
12
12
///
13
13
/// It consists of both the `source`, which describes how that goal would be proven,
14
14
/// and the `result` when using the given `source`.
15
- ///
16
- /// For the list of possible candidates, please look at the documentation of
17
- /// [super::trait_goals::CandidateSource] and [super::project_goals::CandidateSource].
18
15
#[ derive( Debug , Clone ) ]
19
- pub ( super ) struct Candidate < ' tcx , G : GoalKind < ' tcx > > {
20
- pub ( super ) source : G :: CandidateSource ,
16
+ pub ( super ) struct Candidate < ' tcx > {
17
+ pub ( super ) source : CandidateSource ,
21
18
pub ( super ) result : CanonicalResponse < ' tcx > ,
22
19
}
23
20
24
- pub ( super ) trait GoalKind < ' tcx > : TypeFoldable < ' tcx > + Copy {
25
- type CandidateSource : Debug + Copy ;
21
+ /// Possible ways the given goal can be proven.
22
+ #[ derive( Debug , Clone , Copy ) ]
23
+ pub ( super ) enum CandidateSource {
24
+ /// A user written impl.
25
+ ///
26
+ /// ## Examples
27
+ ///
28
+ /// ```rust
29
+ /// fn main() {
30
+ /// let x: Vec<u32> = Vec::new();
31
+ /// // This uses the impl from the standard library to prove `Vec<T>: Clone`.
32
+ /// let y = x.clone();
33
+ /// }
34
+ /// ```
35
+ Impl ( DefId ) ,
36
+ /// A builtin impl generated by the compiler. When adding a new special
37
+ /// trait, try to use actual impls whenever possible. Builtin impls should
38
+ /// only be used in cases where the impl cannot be manually be written.
39
+ ///
40
+ /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
41
+ /// For a list of all traits with builtin impls, check out the
42
+ /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
43
+ BuiltinImpl ,
44
+ /// An assumption from the environment.
45
+ ///
46
+ /// More precicely we've used the `n-th` assumption in the `param_env`.
47
+ ///
48
+ /// ## Examples
49
+ ///
50
+ /// ```rust
51
+ /// fn is_clone<T: Clone>(x: T) -> (T, T) {
52
+ /// // This uses the assumption `T: Clone` from the `where`-bounds
53
+ /// // to prove `T: Clone`.
54
+ /// (x.clone(), x)
55
+ /// }
56
+ /// ```
57
+ ParamEnv ( usize ) ,
58
+ /// If the self type is an alias type, e.g. an opaque type or a projection,
59
+ /// we know the bounds on that alias to hold even without knowing its concrete
60
+ /// underlying type.
61
+ ///
62
+ /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
63
+ /// the self type.
64
+ ///
65
+ /// ## Examples
66
+ ///
67
+ /// ```rust
68
+ /// trait Trait {
69
+ /// type Assoc: Clone;
70
+ /// }
71
+ ///
72
+ /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
73
+ /// // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
74
+ /// // in the trait definition.
75
+ /// let _y = x.clone();
76
+ /// }
77
+ /// ```
78
+ AliasBound ( usize ) ,
79
+ }
26
80
81
+ pub ( super ) trait GoalKind < ' tcx > : TypeFoldable < ' tcx > + Copy {
27
82
fn self_ty ( self ) -> Ty < ' tcx > ;
28
83
29
84
fn with_self_ty ( self , tcx : TyCtxt < ' tcx > , self_ty : Ty < ' tcx > ) -> Self ;
30
85
31
86
fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId ;
32
87
33
88
fn consider_impl_candidate (
34
- acx : & mut AssemblyCtxt < ' _ , ' _ , ' tcx , Self > ,
89
+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
35
90
goal : Goal < ' tcx , Self > ,
36
91
impl_def_id : DefId ,
37
- ) ;
38
- }
92
+ ) -> Result < Certainty , NoSolution > ;
39
93
40
- /// An abstraction which correctly deals with the canonical results for candidates.
41
- ///
42
- /// It also deduplicates the behavior between trait and projection predicates.
43
- pub ( super ) struct AssemblyCtxt < ' a , ' b , ' tcx , G : GoalKind < ' tcx > > {
44
- pub ( super ) cx : & ' a mut EvalCtxt < ' b , ' tcx > ,
45
- candidates : Vec < Candidate < ' tcx , G > > ,
46
- }
94
+ fn consider_builtin_sized_candidate (
95
+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
96
+ goal : Goal < ' tcx , Self > ,
97
+ ) -> Result < Certainty , NoSolution > ;
47
98
48
- impl < ' a , ' b , ' tcx , G : GoalKind < ' tcx > > AssemblyCtxt < ' a , ' b , ' tcx , G > {
49
- pub ( super ) fn assemble_and_evaluate_candidates (
50
- cx : & ' a mut EvalCtxt < ' b , ' tcx > ,
99
+ fn consider_assumption (
100
+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
101
+ goal : Goal < ' tcx , Self > ,
102
+ assumption : ty:: Predicate < ' tcx > ,
103
+ ) -> Result < Certainty , NoSolution > ;
104
+ }
105
+ impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
106
+ pub ( super ) fn assemble_and_evaluate_candidates < G : GoalKind < ' tcx > > (
107
+ & mut self ,
51
108
goal : Goal < ' tcx , G > ,
52
- ) -> Vec < Candidate < ' tcx , G > > {
53
- let mut acx = AssemblyCtxt { cx , candidates : Vec :: new ( ) } ;
109
+ ) -> Vec < Candidate < ' tcx > > {
110
+ let mut candidates = Vec :: new ( ) ;
54
111
55
- acx . assemble_candidates_after_normalizing_self_ty ( goal) ;
112
+ self . assemble_candidates_after_normalizing_self_ty ( goal, & mut candidates ) ;
56
113
57
- acx . assemble_impl_candidates ( goal) ;
114
+ self . assemble_impl_candidates ( goal, & mut candidates ) ;
58
115
59
- acx. candidates
60
- }
116
+ self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
61
117
62
- pub ( super ) fn try_insert_candidate (
63
- & mut self ,
64
- source : G :: CandidateSource ,
65
- certainty : Certainty ,
66
- ) {
67
- match self . cx . make_canonical_response ( certainty) {
68
- Ok ( result) => self . candidates . push ( Candidate { source, result } ) ,
69
- Err ( NoSolution ) => debug ! ( ?source, ?certainty, "failed leakcheck" ) ,
70
- }
118
+ self . assemble_param_env_candidates ( goal, & mut candidates) ;
119
+
120
+ self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
121
+
122
+ candidates
71
123
}
72
124
73
125
/// If the self type of a goal is a projection, computing the relevant candidates is difficult.
74
126
///
75
127
/// To deal with this, we first try to normalize the self type and add the candidates for the normalized
76
128
/// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
77
129
/// this case as projections as self types add `
78
- fn assemble_candidates_after_normalizing_self_ty ( & mut self , goal : Goal < ' tcx , G > ) {
79
- let tcx = self . cx . tcx ( ) ;
80
- let infcx = self . cx . infcx ;
130
+ fn assemble_candidates_after_normalizing_self_ty < G : GoalKind < ' tcx > > (
131
+ & mut self ,
132
+ goal : Goal < ' tcx , G > ,
133
+ candidates : & mut Vec < Candidate < ' tcx > > ,
134
+ ) {
135
+ let tcx = self . tcx ( ) ;
81
136
// FIXME: We also have to normalize opaque types, not sure where to best fit that in.
82
137
let & ty:: Alias ( ty:: Projection , projection_ty) = goal. predicate . self_ty ( ) . kind ( ) else {
83
138
return
84
139
} ;
85
- infcx. probe ( |_| {
86
- let normalized_ty = infcx. next_ty_infer ( ) ;
140
+ self . infcx . probe ( |_| {
141
+ let normalized_ty = self . infcx . next_ty_infer ( ) ;
87
142
let normalizes_to_goal = goal. with (
88
143
tcx,
89
144
ty:: Binder :: dummy ( ty:: ProjectionPredicate {
90
145
projection_ty,
91
146
term : normalized_ty. into ( ) ,
92
147
} ) ,
93
148
) ;
94
- let normalization_certainty = match self . cx . evaluate_goal ( normalizes_to_goal) {
149
+ let normalization_certainty = match self . evaluate_goal ( normalizes_to_goal) {
95
150
Ok ( ( _, certainty) ) => certainty,
96
151
Err ( NoSolution ) => return ,
97
152
} ;
98
153
99
154
// NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
100
- // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items .
155
+ // This doesn't work as long as we use `CandidateSource` in winnowing.
101
156
let goal = goal. with ( tcx, goal. predicate . with_self_ty ( tcx, normalized_ty) ) ;
102
- let normalized_candidates =
103
- AssemblyCtxt :: assemble_and_evaluate_candidates ( self . cx , goal) ;
157
+ // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type
158
+ // could be normalized to yet another projection with different item bounds.
159
+ let normalized_candidates = self . assemble_and_evaluate_candidates ( goal) ;
104
160
for mut normalized_candidate in normalized_candidates {
105
161
normalized_candidate. result =
106
162
normalized_candidate. result . unchecked_map ( |mut response| {
163
+ // FIXME: This currently hides overflow in the normalization step of the self type
164
+ // which is probably wrong. Maybe `unify_and` should actually keep overflow as
165
+ // we treat it as non-fatal anyways.
107
166
response. certainty = response. certainty . unify_and ( normalization_certainty) ;
108
167
response
109
168
} ) ;
110
- self . candidates . push ( normalized_candidate) ;
169
+ candidates. push ( normalized_candidate) ;
111
170
}
112
171
} )
113
172
}
114
173
115
- fn assemble_impl_candidates ( & mut self , goal : Goal < ' tcx , G > ) {
116
- let tcx = self . cx . tcx ( ) ;
174
+ fn assemble_impl_candidates < G : GoalKind < ' tcx > > (
175
+ & mut self ,
176
+ goal : Goal < ' tcx , G > ,
177
+ candidates : & mut Vec < Candidate < ' tcx > > ,
178
+ ) {
179
+ let tcx = self . tcx ( ) ;
117
180
tcx. for_each_relevant_impl (
118
181
goal. predicate . trait_def_id ( tcx) ,
119
182
goal. predicate . self_ty ( ) ,
120
- |impl_def_id| G :: consider_impl_candidate ( self , goal, impl_def_id) ,
183
+ |impl_def_id| match G :: consider_impl_candidate ( self , goal, impl_def_id)
184
+ . and_then ( |certainty| self . make_canonical_response ( certainty) )
185
+ {
186
+ Ok ( result) => candidates
187
+ . push ( Candidate { source : CandidateSource :: Impl ( impl_def_id) , result } ) ,
188
+ Err ( NoSolution ) => ( ) ,
189
+ } ,
121
190
) ;
122
191
}
192
+
193
+ fn assemble_builtin_impl_candidates < G : GoalKind < ' tcx > > (
194
+ & mut self ,
195
+ goal : Goal < ' tcx , G > ,
196
+ candidates : & mut Vec < Candidate < ' tcx > > ,
197
+ ) {
198
+ let lang_items = self . tcx ( ) . lang_items ( ) ;
199
+ let trait_def_id = goal. predicate . trait_def_id ( self . tcx ( ) ) ;
200
+ let result = if lang_items. sized_trait ( ) == Some ( trait_def_id) {
201
+ G :: consider_builtin_sized_candidate ( self , goal)
202
+ } else {
203
+ Err ( NoSolution )
204
+ } ;
205
+
206
+ match result. and_then ( |certainty| self . make_canonical_response ( certainty) ) {
207
+ Ok ( result) => {
208
+ candidates. push ( Candidate { source : CandidateSource :: BuiltinImpl , result } )
209
+ }
210
+ Err ( NoSolution ) => ( ) ,
211
+ }
212
+ }
213
+
214
+ fn assemble_param_env_candidates < G : GoalKind < ' tcx > > (
215
+ & mut self ,
216
+ goal : Goal < ' tcx , G > ,
217
+ candidates : & mut Vec < Candidate < ' tcx > > ,
218
+ ) {
219
+ for ( i, assumption) in goal. param_env . caller_bounds ( ) . iter ( ) . enumerate ( ) {
220
+ match G :: consider_assumption ( self , goal, assumption)
221
+ . and_then ( |certainty| self . make_canonical_response ( certainty) )
222
+ {
223
+ Ok ( result) => {
224
+ candidates. push ( Candidate { source : CandidateSource :: ParamEnv ( i) , result } )
225
+ }
226
+ Err ( NoSolution ) => ( ) ,
227
+ }
228
+ }
229
+ }
230
+
231
+ fn assemble_alias_bound_candidates < G : GoalKind < ' tcx > > (
232
+ & mut self ,
233
+ goal : Goal < ' tcx , G > ,
234
+ candidates : & mut Vec < Candidate < ' tcx > > ,
235
+ ) {
236
+ let alias_ty = match goal. predicate . self_ty ( ) . kind ( ) {
237
+ ty:: Bool
238
+ | ty:: Char
239
+ | ty:: Int ( _)
240
+ | ty:: Uint ( _)
241
+ | ty:: Float ( _)
242
+ | ty:: Adt ( _, _)
243
+ | ty:: Foreign ( _)
244
+ | ty:: Str
245
+ | ty:: Array ( _, _)
246
+ | ty:: Slice ( _)
247
+ | ty:: RawPtr ( _)
248
+ | ty:: Ref ( _, _, _)
249
+ | ty:: FnDef ( _, _)
250
+ | ty:: FnPtr ( _)
251
+ | ty:: Dynamic ( ..)
252
+ | ty:: Closure ( ..)
253
+ | ty:: Generator ( ..)
254
+ | ty:: GeneratorWitness ( _)
255
+ | ty:: Never
256
+ | ty:: Tuple ( _)
257
+ | ty:: Param ( _)
258
+ | ty:: Placeholder ( ..)
259
+ | ty:: Infer ( _)
260
+ | ty:: Error ( _) => return ,
261
+ ty:: Bound ( ..) => bug ! ( "unexpected bound type: {goal:?}" ) ,
262
+ ty:: Alias ( _, alias_ty) => alias_ty,
263
+ } ;
264
+
265
+ for ( i, ( assumption, _) ) in self
266
+ . tcx ( )
267
+ . bound_explicit_item_bounds ( alias_ty. def_id )
268
+ . subst_iter_copied ( self . tcx ( ) , alias_ty. substs )
269
+ . enumerate ( )
270
+ {
271
+ match G :: consider_assumption ( self , goal, assumption)
272
+ . and_then ( |certainty| self . make_canonical_response ( certainty) )
273
+ {
274
+ Ok ( result) => {
275
+ candidates. push ( Candidate { source : CandidateSource :: AliasBound ( i) , result } )
276
+ }
277
+ Err ( NoSolution ) => ( ) ,
278
+ }
279
+ }
280
+ }
123
281
}
0 commit comments