]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/solve/assembly.rs
Rollup merge of #107248 - erikdesjardins:addrspace, r=oli-obk
[rust.git] / compiler / rustc_trait_selection / src / solve / assembly.rs
1 //! Code shared by trait and projection goals for candidate assembly.
2
3 use super::infcx_ext::InferCtxtExt;
4 use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
5 use rustc_hir::def_id::DefId;
6 use rustc_infer::traits::query::NoSolution;
7 use rustc_infer::traits::util::elaborate_predicates;
8 use rustc_middle::ty::TypeFoldable;
9 use rustc_middle::ty::{self, Ty, TyCtxt};
10 use std::fmt::Debug;
11
12 /// A candidate is a possible way to prove a goal.
13 ///
14 /// It consists of both the `source`, which describes how that goal would be proven,
15 /// and the `result` when using the given `source`.
16 #[derive(Debug, Clone)]
17 pub(super) struct Candidate<'tcx> {
18     pub(super) source: CandidateSource,
19     pub(super) result: CanonicalResponse<'tcx>,
20 }
21
22 /// Possible ways the given goal can be proven.
23 #[derive(Debug, Clone, Copy)]
24 pub(super) enum CandidateSource {
25     /// A user written impl.
26     ///
27     /// ## Examples
28     ///
29     /// ```rust
30     /// fn main() {
31     ///     let x: Vec<u32> = Vec::new();
32     ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
33     ///     let y = x.clone();
34     /// }
35     /// ```
36     Impl(DefId),
37     /// A builtin impl generated by the compiler. When adding a new special
38     /// trait, try to use actual impls whenever possible. Builtin impls should
39     /// only be used in cases where the impl cannot be manually be written.
40     ///
41     /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
42     /// For a list of all traits with builtin impls, check out the
43     /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
44     BuiltinImpl,
45     /// An assumption from the environment.
46     ///
47     /// More precicely we've used the `n-th` assumption in the `param_env`.
48     ///
49     /// ## Examples
50     ///
51     /// ```rust
52     /// fn is_clone<T: Clone>(x: T) -> (T, T) {
53     ///     // This uses the assumption `T: Clone` from the `where`-bounds
54     ///     // to prove `T: Clone`.
55     ///     (x.clone(), x)
56     /// }
57     /// ```
58     ParamEnv(usize),
59     /// If the self type is an alias type, e.g. an opaque type or a projection,
60     /// we know the bounds on that alias to hold even without knowing its concrete
61     /// underlying type.
62     ///
63     /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
64     /// the self type.
65     ///
66     /// ## Examples
67     ///
68     /// ```rust
69     /// trait Trait {
70     ///     type Assoc: Clone;
71     /// }
72     ///
73     /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
74     ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
75     ///     // in the trait definition.
76     ///     let _y = x.clone();
77     /// }
78     /// ```
79     AliasBound(usize),
80 }
81
82 pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
83     fn self_ty(self) -> Ty<'tcx>;
84
85     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
86
87     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
88
89     fn consider_impl_candidate(
90         ecx: &mut EvalCtxt<'_, 'tcx>,
91         goal: Goal<'tcx, Self>,
92         impl_def_id: DefId,
93     ) -> QueryResult<'tcx>;
94
95     fn consider_assumption(
96         ecx: &mut EvalCtxt<'_, 'tcx>,
97         goal: Goal<'tcx, Self>,
98         assumption: ty::Predicate<'tcx>,
99     ) -> QueryResult<'tcx>;
100
101     fn consider_auto_trait_candidate(
102         ecx: &mut EvalCtxt<'_, 'tcx>,
103         goal: Goal<'tcx, Self>,
104     ) -> QueryResult<'tcx>;
105
106     fn consider_trait_alias_candidate(
107         ecx: &mut EvalCtxt<'_, 'tcx>,
108         goal: Goal<'tcx, Self>,
109     ) -> QueryResult<'tcx>;
110
111     fn consider_builtin_sized_candidate(
112         ecx: &mut EvalCtxt<'_, 'tcx>,
113         goal: Goal<'tcx, Self>,
114     ) -> QueryResult<'tcx>;
115
116     fn consider_builtin_copy_clone_candidate(
117         ecx: &mut EvalCtxt<'_, 'tcx>,
118         goal: Goal<'tcx, Self>,
119     ) -> QueryResult<'tcx>;
120
121     fn consider_builtin_pointer_sized_candidate(
122         ecx: &mut EvalCtxt<'_, 'tcx>,
123         goal: Goal<'tcx, Self>,
124     ) -> QueryResult<'tcx>;
125
126     fn consider_builtin_fn_trait_candidates(
127         ecx: &mut EvalCtxt<'_, 'tcx>,
128         goal: Goal<'tcx, Self>,
129         kind: ty::ClosureKind,
130     ) -> QueryResult<'tcx>;
131
132     fn consider_builtin_tuple_candidate(
133         ecx: &mut EvalCtxt<'_, 'tcx>,
134         goal: Goal<'tcx, Self>,
135     ) -> QueryResult<'tcx>;
136
137     fn consider_builtin_pointee_candidate(
138         ecx: &mut EvalCtxt<'_, 'tcx>,
139         goal: Goal<'tcx, Self>,
140     ) -> QueryResult<'tcx>;
141 }
142
143 impl<'tcx> EvalCtxt<'_, 'tcx> {
144     pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
145         &mut self,
146         goal: Goal<'tcx, G>,
147     ) -> Vec<Candidate<'tcx>> {
148         debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal));
149
150         // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
151         // object bound, alias bound, etc. We are unable to determine this until we can at
152         // least structually resolve the type one layer.
153         if goal.predicate.self_ty().is_ty_var() {
154             return vec![Candidate {
155                 source: CandidateSource::BuiltinImpl,
156                 result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
157             }];
158         }
159
160         let mut candidates = Vec::new();
161
162         self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
163
164         self.assemble_impl_candidates(goal, &mut candidates);
165
166         self.assemble_builtin_impl_candidates(goal, &mut candidates);
167
168         self.assemble_param_env_candidates(goal, &mut candidates);
169
170         self.assemble_alias_bound_candidates(goal, &mut candidates);
171
172         self.assemble_object_bound_candidates(goal, &mut candidates);
173
174         candidates
175     }
176
177     /// If the self type of a goal is a projection, computing the relevant candidates is difficult.
178     ///
179     /// To deal with this, we first try to normalize the self type and add the candidates for the normalized
180     /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
181     /// this case as projections as self types add `
182     fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
183         &mut self,
184         goal: Goal<'tcx, G>,
185         candidates: &mut Vec<Candidate<'tcx>>,
186     ) {
187         let tcx = self.tcx();
188         // FIXME: We also have to normalize opaque types, not sure where to best fit that in.
189         let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
190             return
191         };
192         self.infcx.probe(|_| {
193             let normalized_ty = self.infcx.next_ty_infer();
194             let normalizes_to_goal = goal.with(
195                 tcx,
196                 ty::Binder::dummy(ty::ProjectionPredicate {
197                     projection_ty,
198                     term: normalized_ty.into(),
199                 }),
200             );
201             let normalization_certainty = match self.evaluate_goal(normalizes_to_goal) {
202                 Ok((_, certainty)) => certainty,
203                 Err(NoSolution) => return,
204             };
205             let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty);
206
207             // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
208             // This doesn't work as long as we use `CandidateSource` in winnowing.
209             let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
210             // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type
211             // could be normalized to yet another projection with different item bounds.
212             let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
213             for mut normalized_candidate in normalized_candidates {
214                 normalized_candidate.result =
215                     normalized_candidate.result.unchecked_map(|mut response| {
216                         // FIXME: This currently hides overflow in the normalization step of the self type
217                         // which is probably wrong. Maybe `unify_and` should actually keep overflow as
218                         // we treat it as non-fatal anyways.
219                         response.certainty = response.certainty.unify_and(normalization_certainty);
220                         response
221                     });
222                 candidates.push(normalized_candidate);
223             }
224         })
225     }
226
227     fn assemble_impl_candidates<G: GoalKind<'tcx>>(
228         &mut self,
229         goal: Goal<'tcx, G>,
230         candidates: &mut Vec<Candidate<'tcx>>,
231     ) {
232         let tcx = self.tcx();
233         tcx.for_each_relevant_impl(
234             goal.predicate.trait_def_id(tcx),
235             goal.predicate.self_ty(),
236             |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
237                 Ok(result) => candidates
238                     .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
239                 Err(NoSolution) => (),
240             },
241         );
242     }
243
244     fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
245         &mut self,
246         goal: Goal<'tcx, G>,
247         candidates: &mut Vec<Candidate<'tcx>>,
248     ) {
249         let lang_items = self.tcx().lang_items();
250         let trait_def_id = goal.predicate.trait_def_id(self.tcx());
251         let result = if self.tcx().trait_is_auto(trait_def_id) {
252             G::consider_auto_trait_candidate(self, goal)
253         } else if self.tcx().trait_is_alias(trait_def_id) {
254             G::consider_trait_alias_candidate(self, goal)
255         } else if lang_items.sized_trait() == Some(trait_def_id) {
256             G::consider_builtin_sized_candidate(self, goal)
257         } else if lang_items.copy_trait() == Some(trait_def_id)
258             || lang_items.clone_trait() == Some(trait_def_id)
259         {
260             G::consider_builtin_copy_clone_candidate(self, goal)
261         } else if lang_items.pointer_sized() == Some(trait_def_id) {
262             G::consider_builtin_pointer_sized_candidate(self, goal)
263         } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
264             G::consider_builtin_fn_trait_candidates(self, goal, kind)
265         } else if lang_items.tuple_trait() == Some(trait_def_id) {
266             G::consider_builtin_tuple_candidate(self, goal)
267         } else if lang_items.pointee_trait() == Some(trait_def_id) {
268             G::consider_builtin_pointee_candidate(self, goal)
269         } else {
270             Err(NoSolution)
271         };
272
273         match result {
274             Ok(result) => {
275                 candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
276             }
277             Err(NoSolution) => (),
278         }
279     }
280
281     fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
282         &mut self,
283         goal: Goal<'tcx, G>,
284         candidates: &mut Vec<Candidate<'tcx>>,
285     ) {
286         for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
287             match G::consider_assumption(self, goal, assumption) {
288                 Ok(result) => {
289                     candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
290                 }
291                 Err(NoSolution) => (),
292             }
293         }
294     }
295
296     fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
297         &mut self,
298         goal: Goal<'tcx, G>,
299         candidates: &mut Vec<Candidate<'tcx>>,
300     ) {
301         let alias_ty = match goal.predicate.self_ty().kind() {
302             ty::Bool
303             | ty::Char
304             | ty::Int(_)
305             | ty::Uint(_)
306             | ty::Float(_)
307             | ty::Adt(_, _)
308             | ty::Foreign(_)
309             | ty::Str
310             | ty::Array(_, _)
311             | ty::Slice(_)
312             | ty::RawPtr(_)
313             | ty::Ref(_, _, _)
314             | ty::FnDef(_, _)
315             | ty::FnPtr(_)
316             | ty::Dynamic(..)
317             | ty::Closure(..)
318             | ty::Generator(..)
319             | ty::GeneratorWitness(_)
320             | ty::Never
321             | ty::Tuple(_)
322             | ty::Param(_)
323             | ty::Placeholder(..)
324             | ty::Infer(_)
325             | ty::Error(_) => return,
326             ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
327             ty::Alias(_, alias_ty) => alias_ty,
328         };
329
330         for (i, (assumption, _)) in self
331             .tcx()
332             .bound_explicit_item_bounds(alias_ty.def_id)
333             .subst_iter_copied(self.tcx(), alias_ty.substs)
334             .enumerate()
335         {
336             match G::consider_assumption(self, goal, assumption) {
337                 Ok(result) => {
338                     candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
339                 }
340                 Err(NoSolution) => (),
341             }
342         }
343     }
344
345     fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
346         &mut self,
347         goal: Goal<'tcx, G>,
348         candidates: &mut Vec<Candidate<'tcx>>,
349     ) {
350         let self_ty = goal.predicate.self_ty();
351         let bounds = match *self_ty.kind() {
352             ty::Bool
353             | ty::Char
354             | ty::Int(_)
355             | ty::Uint(_)
356             | ty::Float(_)
357             | ty::Adt(_, _)
358             | ty::Foreign(_)
359             | ty::Str
360             | ty::Array(_, _)
361             | ty::Slice(_)
362             | ty::RawPtr(_)
363             | ty::Ref(_, _, _)
364             | ty::FnDef(_, _)
365             | ty::FnPtr(_)
366             | ty::Alias(..)
367             | ty::Closure(..)
368             | ty::Generator(..)
369             | ty::GeneratorWitness(_)
370             | ty::Never
371             | ty::Tuple(_)
372             | ty::Param(_)
373             | ty::Placeholder(..)
374             | ty::Infer(_)
375             | ty::Error(_) => return,
376             ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
377             ty::Dynamic(bounds, ..) => bounds,
378         };
379
380         let tcx = self.tcx();
381         for assumption in
382             elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
383         {
384             match G::consider_assumption(self, goal, assumption.predicate) {
385                 Ok(result) => {
386                     candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
387                 }
388                 Err(NoSolution) => (),
389             }
390         }
391     }
392 }