]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/solve/trait_goals.rs
Test drop_tracking_mir before querying generator.
[rust.git] / compiler / rustc_trait_selection / src / solve / trait_goals.rs
1 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
2
3 use std::iter;
4
5 use super::assembly::{self, Candidate, CandidateSource};
6 use super::infcx_ext::InferCtxtExt;
7 use super::{Certainty, EvalCtxt, Goal, QueryResult};
8 use rustc_hir::def_id::DefId;
9 use rustc_infer::infer::InferCtxt;
10 use rustc_infer::traits::query::NoSolution;
11 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
12 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
13 use rustc_middle::ty::{TraitPredicate, TypeVisitable};
14 use rustc_span::DUMMY_SP;
15
16 pub mod structural_traits;
17
18 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
19     fn self_ty(self) -> Ty<'tcx> {
20         self.self_ty()
21     }
22
23     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
24         self.with_self_ty(tcx, self_ty)
25     }
26
27     fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId {
28         self.def_id()
29     }
30
31     fn consider_impl_candidate(
32         ecx: &mut EvalCtxt<'_, 'tcx>,
33         goal: Goal<'tcx, TraitPredicate<'tcx>>,
34         impl_def_id: DefId,
35     ) -> QueryResult<'tcx> {
36         let tcx = ecx.tcx();
37
38         let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
39         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
40         if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
41             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
42         {
43             return Err(NoSolution);
44         }
45
46         ecx.infcx.probe(|_| {
47             let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
48             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
49
50             let mut nested_goals =
51                 ecx.infcx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
52             let where_clause_bounds = tcx
53                 .predicates_of(impl_def_id)
54                 .instantiate(tcx, impl_substs)
55                 .predicates
56                 .into_iter()
57                 .map(|pred| goal.with(tcx, pred));
58             nested_goals.extend(where_clause_bounds);
59             ecx.evaluate_all_and_make_canonical_response(nested_goals)
60         })
61     }
62
63     fn consider_assumption(
64         ecx: &mut EvalCtxt<'_, 'tcx>,
65         goal: Goal<'tcx, Self>,
66         assumption: ty::Predicate<'tcx>,
67     ) -> QueryResult<'tcx> {
68         if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
69             && poly_trait_pred.def_id() == goal.predicate.def_id()
70         {
71             // FIXME: Constness and polarity
72             ecx.infcx.probe(|_| {
73                 let assumption_trait_pred =
74                     ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
75                 let nested_goals = ecx.infcx.eq(
76                     goal.param_env,
77                     goal.predicate.trait_ref,
78                     assumption_trait_pred.trait_ref,
79                 )?;
80                 ecx.evaluate_all_and_make_canonical_response(nested_goals)
81             })
82         } else {
83             Err(NoSolution)
84         }
85     }
86
87     fn consider_auto_trait_candidate(
88         ecx: &mut EvalCtxt<'_, 'tcx>,
89         goal: Goal<'tcx, Self>,
90     ) -> QueryResult<'tcx> {
91         ecx.probe_and_evaluate_goal_for_constituent_tys(
92             goal,
93             structural_traits::instantiate_constituent_tys_for_auto_trait,
94         )
95     }
96
97     fn consider_trait_alias_candidate(
98         ecx: &mut EvalCtxt<'_, 'tcx>,
99         goal: Goal<'tcx, Self>,
100     ) -> QueryResult<'tcx> {
101         let tcx = ecx.tcx();
102
103         ecx.infcx.probe(|_| {
104             let nested_obligations = tcx
105                 .predicates_of(goal.predicate.def_id())
106                 .instantiate(tcx, goal.predicate.trait_ref.substs);
107             ecx.evaluate_all_and_make_canonical_response(
108                 nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(),
109             )
110         })
111     }
112
113     fn consider_builtin_sized_candidate(
114         ecx: &mut EvalCtxt<'_, 'tcx>,
115         goal: Goal<'tcx, Self>,
116     ) -> QueryResult<'tcx> {
117         ecx.probe_and_evaluate_goal_for_constituent_tys(
118             goal,
119             structural_traits::instantiate_constituent_tys_for_sized_trait,
120         )
121     }
122
123     fn consider_builtin_copy_clone_candidate(
124         ecx: &mut EvalCtxt<'_, 'tcx>,
125         goal: Goal<'tcx, Self>,
126     ) -> QueryResult<'tcx> {
127         ecx.probe_and_evaluate_goal_for_constituent_tys(
128             goal,
129             structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
130         )
131     }
132
133     fn consider_builtin_pointer_sized_candidate(
134         ecx: &mut EvalCtxt<'_, 'tcx>,
135         goal: Goal<'tcx, Self>,
136     ) -> QueryResult<'tcx> {
137         if goal.predicate.self_ty().has_non_region_infer() {
138             return ecx.make_canonical_response(Certainty::AMBIGUOUS);
139         }
140
141         let tcx = ecx.tcx();
142         let self_ty = tcx.erase_regions(goal.predicate.self_ty());
143
144         if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty))
145             &&  let usize_layout = tcx.layout_of(ty::ParamEnv::empty().and(tcx.types.usize)).unwrap().layout
146             && layout.layout.size() == usize_layout.size()
147             && layout.layout.align().abi == usize_layout.align().abi
148         {
149             // FIXME: We could make this faster by making a no-constraints response
150             ecx.make_canonical_response(Certainty::Yes)
151         } else {
152             Err(NoSolution)
153         }
154     }
155
156     fn consider_builtin_fn_trait_candidates(
157         ecx: &mut EvalCtxt<'_, 'tcx>,
158         goal: Goal<'tcx, Self>,
159         goal_kind: ty::ClosureKind,
160     ) -> QueryResult<'tcx> {
161         if let Some(tupled_inputs_and_output) =
162             structural_traits::extract_tupled_inputs_and_output_from_callable(
163                 ecx.tcx(),
164                 goal.predicate.self_ty(),
165                 goal_kind,
166             )?
167         {
168             let pred = tupled_inputs_and_output
169                 .map_bound(|(inputs, _)| {
170                     ecx.tcx()
171                         .mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
172                 })
173                 .to_predicate(ecx.tcx());
174             Self::consider_assumption(ecx, goal, pred)
175         } else {
176             ecx.make_canonical_response(Certainty::AMBIGUOUS)
177         }
178     }
179
180     fn consider_builtin_tuple_candidate(
181         ecx: &mut EvalCtxt<'_, 'tcx>,
182         goal: Goal<'tcx, Self>,
183     ) -> QueryResult<'tcx> {
184         if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
185             ecx.make_canonical_response(Certainty::Yes)
186         } else {
187             Err(NoSolution)
188         }
189     }
190
191     fn consider_builtin_pointee_candidate(
192         ecx: &mut EvalCtxt<'_, 'tcx>,
193         _goal: Goal<'tcx, Self>,
194     ) -> QueryResult<'tcx> {
195         ecx.make_canonical_response(Certainty::Yes)
196     }
197
198     fn consider_builtin_future_candidate(
199         ecx: &mut EvalCtxt<'_, 'tcx>,
200         goal: Goal<'tcx, Self>,
201     ) -> QueryResult<'tcx> {
202         let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
203             return Err(NoSolution);
204         };
205
206         // Generators are not futures unless they come from `async` desugaring
207         let tcx = ecx.tcx();
208         if !tcx.generator_is_async(def_id) {
209             return Err(NoSolution);
210         }
211
212         // Async generator unconditionally implement `Future`
213         ecx.make_canonical_response(Certainty::Yes)
214     }
215
216     fn consider_builtin_generator_candidate(
217         ecx: &mut EvalCtxt<'_, 'tcx>,
218         goal: Goal<'tcx, Self>,
219     ) -> QueryResult<'tcx> {
220         let self_ty = goal.predicate.self_ty();
221         let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
222             return Err(NoSolution);
223         };
224
225         // `async`-desugared generators do not implement the generator trait
226         let tcx = ecx.tcx();
227         if tcx.generator_is_async(def_id) {
228             return Err(NoSolution);
229         }
230
231         let generator = substs.as_generator();
232         Self::consider_assumption(
233             ecx,
234             goal,
235             ty::Binder::dummy(
236                 tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
237             )
238             .to_predicate(tcx),
239         )
240     }
241 }
242
243 impl<'tcx> EvalCtxt<'_, 'tcx> {
244     /// Convenience function for traits that are structural, i.e. that only
245     /// have nested subgoals that only change the self type. Unlike other
246     /// evaluate-like helpers, this does a probe, so it doesn't need to be
247     /// wrapped in one.
248     fn probe_and_evaluate_goal_for_constituent_tys(
249         &mut self,
250         goal: Goal<'tcx, TraitPredicate<'tcx>>,
251         constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
252     ) -> QueryResult<'tcx> {
253         self.infcx.probe(|_| {
254             self.evaluate_all_and_make_canonical_response(
255                 constituent_tys(self.infcx, goal.predicate.self_ty())?
256                     .into_iter()
257                     .map(|ty| {
258                         goal.with(
259                             self.tcx(),
260                             ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
261                         )
262                     })
263                     .collect(),
264             )
265         })
266     }
267
268     pub(super) fn compute_trait_goal(
269         &mut self,
270         goal: Goal<'tcx, TraitPredicate<'tcx>>,
271     ) -> QueryResult<'tcx> {
272         let candidates = self.assemble_and_evaluate_candidates(goal);
273         self.merge_trait_candidates_discard_reservation_impls(candidates)
274     }
275
276     #[instrument(level = "debug", skip(self), ret)]
277     pub(super) fn merge_trait_candidates_discard_reservation_impls(
278         &mut self,
279         mut candidates: Vec<Candidate<'tcx>>,
280     ) -> QueryResult<'tcx> {
281         match candidates.len() {
282             0 => return Err(NoSolution),
283             1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
284             _ => {}
285         }
286
287         if candidates.len() > 1 {
288             let mut i = 0;
289             'outer: while i < candidates.len() {
290                 for j in (0..candidates.len()).filter(|&j| i != j) {
291                     if self.trait_candidate_should_be_dropped_in_favor_of(
292                         &candidates[i],
293                         &candidates[j],
294                     ) {
295                         debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
296                         candidates.swap_remove(i);
297                         continue 'outer;
298                     }
299                 }
300
301                 debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
302                 // If there are *STILL* multiple candidates, give up
303                 // and report ambiguity.
304                 i += 1;
305                 if i > 1 {
306                     debug!("multiple matches, ambig");
307                     // FIXME: return overflow if all candidates overflow, otherwise return ambiguity.
308                     unimplemented!();
309                 }
310             }
311         }
312
313         Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
314     }
315
316     fn trait_candidate_should_be_dropped_in_favor_of(
317         &self,
318         candidate: &Candidate<'tcx>,
319         other: &Candidate<'tcx>,
320     ) -> bool {
321         // FIXME: implement this
322         match (candidate.source, other.source) {
323             (CandidateSource::Impl(_), _)
324             | (CandidateSource::ParamEnv(_), _)
325             | (CandidateSource::AliasBound(_), _)
326             | (CandidateSource::BuiltinImpl, _) => unimplemented!(),
327         }
328     }
329
330     fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'tcx> {
331         if let CandidateSource::Impl(def_id) = candidate.source {
332             if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
333                 debug!("Selected reservation impl");
334                 // FIXME: reduce candidate to ambiguous
335                 // FIXME: replace `var_values` with identity, yeet external constraints.
336                 unimplemented!()
337             }
338         }
339
340         candidate
341     }
342 }