@@ -12,112 +12,270 @@ use std::fmt::Debug;
1212///
1313/// It consists of both the `source`, which describes how that goal would be proven,
1414/// 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].
1815#[ 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 ,
2118 pub ( super ) result : CanonicalResponse < ' tcx > ,
2219}
2320
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+ }
2680
81+ pub ( super ) trait GoalKind < ' tcx > : TypeFoldable < ' tcx > + Copy {
2782 fn self_ty ( self ) -> Ty < ' tcx > ;
2883
2984 fn with_self_ty ( self , tcx : TyCtxt < ' tcx > , self_ty : Ty < ' tcx > ) -> Self ;
3085
3186 fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId ;
3287
3388 fn consider_impl_candidate (
34- acx : & mut AssemblyCtxt < ' _ , ' _ , ' tcx , Self > ,
89+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
3590 goal : Goal < ' tcx , Self > ,
3691 impl_def_id : DefId ,
37- ) ;
38- }
92+ ) -> Result < Certainty , NoSolution > ;
3993
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 > ;
4798
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 ,
51108 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 ( ) ;
54111
55- acx . assemble_candidates_after_normalizing_self_ty ( goal) ;
112+ self . assemble_candidates_after_normalizing_self_ty ( goal, & mut candidates ) ;
56113
57- acx . assemble_impl_candidates ( goal) ;
114+ self . assemble_impl_candidates ( goal, & mut candidates ) ;
58115
59- acx. candidates
60- }
116+ self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
61117
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
71123 }
72124
73125 /// If the self type of a goal is a projection, computing the relevant candidates is difficult.
74126 ///
75127 /// To deal with this, we first try to normalize the self type and add the candidates for the normalized
76128 /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
77129 /// 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 ( ) ;
81136 // FIXME: We also have to normalize opaque types, not sure where to best fit that in.
82137 let & ty:: Alias ( ty:: Projection , projection_ty) = goal. predicate . self_ty ( ) . kind ( ) else {
83138 return
84139 } ;
85- infcx. probe ( |_| {
86- let normalized_ty = infcx. next_ty_infer ( ) ;
140+ self . infcx . probe ( |_| {
141+ let normalized_ty = self . infcx . next_ty_infer ( ) ;
87142 let normalizes_to_goal = goal. with (
88143 tcx,
89144 ty:: Binder :: dummy ( ty:: ProjectionPredicate {
90145 projection_ty,
91146 term : normalized_ty. into ( ) ,
92147 } ) ,
93148 ) ;
94- let normalization_certainty = match self . cx . evaluate_goal ( normalizes_to_goal) {
149+ let normalization_certainty = match self . evaluate_goal ( normalizes_to_goal) {
95150 Ok ( ( _, certainty) ) => certainty,
96151 Err ( NoSolution ) => return ,
97152 } ;
98153
99154 // 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.
101156 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) ;
104160 for mut normalized_candidate in normalized_candidates {
105161 normalized_candidate. result =
106162 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.
107166 response. certainty = response. certainty . unify_and ( normalization_certainty) ;
108167 response
109168 } ) ;
110- self . candidates . push ( normalized_candidate) ;
169+ candidates. push ( normalized_candidate) ;
111170 }
112171 } )
113172 }
114173
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 ( ) ;
117180 tcx. for_each_relevant_impl (
118181 goal. predicate . trait_def_id ( tcx) ,
119182 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+ } ,
121190 ) ;
122191 }
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+ }
123281}
0 commit comments