]>
Commit | Line | Data |
---|---|---|
353b0b11 | 1 | use crate::traits::specialization_graph; |
9c376795 | 2 | |
353b0b11 FG |
3 | use super::assembly::{self, structural_traits}; |
4 | use super::EvalCtxt; | |
9c376795 FG |
5 | use rustc_errors::ErrorGuaranteed; |
6 | use rustc_hir::def::DefKind; | |
7 | use rustc_hir::def_id::DefId; | |
9ffffee4 | 8 | use rustc_hir::LangItem; |
9c376795 FG |
9 | use rustc_infer::traits::query::NoSolution; |
10 | use rustc_infer::traits::specialization_graph::LeafDef; | |
11 | use rustc_infer::traits::Reveal; | |
353b0b11 | 12 | use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; |
9c376795 | 13 | use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; |
9ffffee4 | 14 | use rustc_middle::ty::ProjectionPredicate; |
9c376795 | 15 | use rustc_middle::ty::{self, Ty, TyCtxt}; |
9ffffee4 FG |
16 | use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; |
17 | use rustc_span::{sym, DUMMY_SP}; | |
9c376795 FG |
18 | |
19 | impl<'tcx> EvalCtxt<'_, 'tcx> { | |
353b0b11 | 20 | #[instrument(level = "debug", skip(self), ret)] |
9c376795 FG |
21 | pub(super) fn compute_projection_goal( |
22 | &mut self, | |
23 | goal: Goal<'tcx, ProjectionPredicate<'tcx>>, | |
24 | ) -> QueryResult<'tcx> { | |
25 | // To only compute normalization once for each projection we only | |
26 | // normalize if the expected term is an unconstrained inference variable. | |
27 | // | |
9ffffee4 FG |
28 | // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal |
29 | // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for | |
9c376795 FG |
30 | // `U` and equate it with `u32`. This means that we don't need a separate |
31 | // projection cache in the solver. | |
32 | if self.term_is_fully_unconstrained(goal) { | |
33 | let candidates = self.assemble_and_evaluate_candidates(goal); | |
353b0b11 | 34 | self.merge_candidates(candidates) |
9c376795 | 35 | } else { |
353b0b11 FG |
36 | self.set_normalizes_to_hack_goal(goal); |
37 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
9c376795 FG |
38 | } |
39 | } | |
9c376795 FG |
40 | } |
41 | ||
42 | impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { | |
43 | fn self_ty(self) -> Ty<'tcx> { | |
44 | self.self_ty() | |
45 | } | |
46 | ||
353b0b11 FG |
47 | fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { |
48 | self.projection_ty.trait_ref(tcx) | |
49 | } | |
50 | ||
9c376795 FG |
51 | fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { |
52 | self.with_self_ty(tcx, self_ty) | |
53 | } | |
54 | ||
55 | fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { | |
56 | self.trait_def_id(tcx) | |
57 | } | |
58 | ||
9ffffee4 FG |
59 | fn consider_implied_clause( |
60 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
61 | goal: Goal<'tcx, Self>, | |
62 | assumption: ty::Predicate<'tcx>, | |
63 | requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, | |
64 | ) -> QueryResult<'tcx> { | |
65 | if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() | |
66 | && poly_projection_pred.projection_def_id() == goal.predicate.def_id() | |
67 | { | |
68 | ecx.probe(|ecx| { | |
69 | let assumption_projection_pred = | |
70 | ecx.instantiate_binder_with_infer(poly_projection_pred); | |
353b0b11 | 71 | ecx.eq( |
9ffffee4 FG |
72 | goal.param_env, |
73 | goal.predicate.projection_ty, | |
74 | assumption_projection_pred.projection_ty, | |
75 | )?; | |
353b0b11 FG |
76 | ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; |
77 | ecx.add_goals(requirements); | |
78 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
9ffffee4 FG |
79 | }) |
80 | } else { | |
81 | Err(NoSolution) | |
82 | } | |
83 | } | |
84 | ||
85 | fn consider_object_bound_candidate( | |
86 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
87 | goal: Goal<'tcx, Self>, | |
88 | assumption: ty::Predicate<'tcx>, | |
89 | ) -> QueryResult<'tcx> { | |
90 | if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() | |
91 | && poly_projection_pred.projection_def_id() == goal.predicate.def_id() | |
92 | { | |
93 | ecx.probe(|ecx| { | |
353b0b11 FG |
94 | let tcx = ecx.tcx(); |
95 | ||
9ffffee4 FG |
96 | let assumption_projection_pred = |
97 | ecx.instantiate_binder_with_infer(poly_projection_pred); | |
353b0b11 | 98 | ecx.eq( |
9ffffee4 FG |
99 | goal.param_env, |
100 | goal.predicate.projection_ty, | |
101 | assumption_projection_pred.projection_ty, | |
102 | )?; | |
103 | ||
9ffffee4 FG |
104 | let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { |
105 | bug!("expected object type in `consider_object_bound_candidate`"); | |
106 | }; | |
353b0b11 | 107 | ecx.add_goals( |
9ffffee4 | 108 | structural_traits::predicates_for_object_candidate( |
353b0b11 | 109 | &ecx, |
9ffffee4 FG |
110 | goal.param_env, |
111 | goal.predicate.projection_ty.trait_ref(tcx), | |
112 | bounds, | |
113 | ) | |
114 | .into_iter() | |
115 | .map(|pred| goal.with(tcx, pred)), | |
116 | ); | |
353b0b11 FG |
117 | ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; |
118 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
9ffffee4 FG |
119 | }) |
120 | } else { | |
121 | Err(NoSolution) | |
122 | } | |
123 | } | |
124 | ||
9c376795 FG |
125 | fn consider_impl_candidate( |
126 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
127 | goal: Goal<'tcx, ProjectionPredicate<'tcx>>, | |
128 | impl_def_id: DefId, | |
129 | ) -> QueryResult<'tcx> { | |
130 | let tcx = ecx.tcx(); | |
131 | ||
132 | let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); | |
133 | let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); | |
353b0b11 FG |
134 | let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; |
135 | if !drcx.substs_refs_may_unify(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) { | |
9c376795 FG |
136 | return Err(NoSolution); |
137 | } | |
138 | ||
9ffffee4 FG |
139 | ecx.probe(|ecx| { |
140 | let impl_substs = ecx.fresh_substs_for_item(impl_def_id); | |
9c376795 FG |
141 | let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); |
142 | ||
353b0b11 FG |
143 | ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; |
144 | ||
9c376795 FG |
145 | let where_clause_bounds = tcx |
146 | .predicates_of(impl_def_id) | |
147 | .instantiate(tcx, impl_substs) | |
148 | .predicates | |
149 | .into_iter() | |
150 | .map(|pred| goal.with(tcx, pred)); | |
353b0b11 | 151 | ecx.add_goals(where_clause_bounds); |
9c376795 FG |
152 | |
153 | // In case the associated item is hidden due to specialization, we have to | |
154 | // return ambiguity this would otherwise be incomplete, resulting in | |
155 | // unsoundness during coherence (#105782). | |
156 | let Some(assoc_def) = fetch_eligible_assoc_item_def( | |
353b0b11 | 157 | ecx, |
9c376795 FG |
158 | goal.param_env, |
159 | goal_trait_ref, | |
160 | goal.predicate.def_id(), | |
161 | impl_def_id | |
162 | )? else { | |
353b0b11 | 163 | return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); |
9c376795 FG |
164 | }; |
165 | ||
166 | if !assoc_def.item.defaultness(tcx).has_value() { | |
167 | tcx.sess.delay_span_bug( | |
168 | tcx.def_span(assoc_def.item.def_id), | |
169 | "missing value for assoc item in impl", | |
170 | ); | |
171 | } | |
172 | ||
173 | // Getting the right substitutions here is complex, e.g. given: | |
174 | // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` | |
175 | // - the applicable impl `impl<T> Trait<i32> for Vec<T>` | |
176 | // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>` | |
177 | // | |
178 | // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]` | |
179 | // to `[u32, u64]`. | |
180 | // | |
181 | // And then map these substs to the substs of the defining impl of `Assoc`, going | |
182 | // from `[u32, u64]` to `[u32, i32, u64]`. | |
183 | let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( | |
184 | tcx, | |
185 | goal_trait_ref.def_id, | |
186 | impl_substs, | |
187 | ); | |
353b0b11 | 188 | let substs = ecx.translate_substs( |
9c376795 FG |
189 | goal.param_env, |
190 | impl_def_id, | |
191 | impl_substs_with_gat, | |
192 | assoc_def.defining_node, | |
193 | ); | |
194 | ||
195 | // Finally we construct the actual value of the associated type. | |
196 | let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst); | |
9ffffee4 | 197 | let ty = tcx.type_of(assoc_def.item.def_id); |
9c376795 FG |
198 | let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { |
199 | let identity_substs = | |
200 | ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id); | |
201 | let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id); | |
202 | let kind = | |
203 | ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs)); | |
204 | ty.map_bound(|ty| tcx.mk_const(kind, ty).into()) | |
205 | } else { | |
206 | ty.map_bound(|ty| ty.into()) | |
207 | }; | |
208 | ||
353b0b11 FG |
209 | ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?; |
210 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
9c376795 FG |
211 | }) |
212 | } | |
213 | ||
9c376795 FG |
214 | fn consider_auto_trait_candidate( |
215 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
216 | goal: Goal<'tcx, Self>, | |
217 | ) -> QueryResult<'tcx> { | |
218 | bug!("auto traits do not have associated types: {:?}", goal); | |
219 | } | |
220 | ||
221 | fn consider_trait_alias_candidate( | |
222 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
223 | goal: Goal<'tcx, Self>, | |
224 | ) -> QueryResult<'tcx> { | |
225 | bug!("trait aliases do not have associated types: {:?}", goal); | |
226 | } | |
227 | ||
228 | fn consider_builtin_sized_candidate( | |
229 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
230 | goal: Goal<'tcx, Self>, | |
231 | ) -> QueryResult<'tcx> { | |
232 | bug!("`Sized` does not have an associated type: {:?}", goal); | |
233 | } | |
234 | ||
235 | fn consider_builtin_copy_clone_candidate( | |
236 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
237 | goal: Goal<'tcx, Self>, | |
238 | ) -> QueryResult<'tcx> { | |
239 | bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); | |
240 | } | |
241 | ||
9ffffee4 | 242 | fn consider_builtin_pointer_like_candidate( |
9c376795 FG |
243 | _ecx: &mut EvalCtxt<'_, 'tcx>, |
244 | goal: Goal<'tcx, Self>, | |
245 | ) -> QueryResult<'tcx> { | |
9ffffee4 | 246 | bug!("`PointerLike` does not have an associated type: {:?}", goal); |
9c376795 FG |
247 | } |
248 | ||
353b0b11 FG |
249 | fn consider_builtin_fn_ptr_trait_candidate( |
250 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
251 | goal: Goal<'tcx, Self>, | |
252 | ) -> QueryResult<'tcx> { | |
253 | bug!("`FnPtr` does not have an associated type: {:?}", goal); | |
254 | } | |
255 | ||
9c376795 FG |
256 | fn consider_builtin_fn_trait_candidates( |
257 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
258 | goal: Goal<'tcx, Self>, | |
259 | goal_kind: ty::ClosureKind, | |
260 | ) -> QueryResult<'tcx> { | |
9ffffee4 | 261 | let tcx = ecx.tcx(); |
353b0b11 FG |
262 | let tupled_inputs_and_output = |
263 | match structural_traits::extract_tupled_inputs_and_output_from_callable( | |
264 | tcx, | |
265 | goal.predicate.self_ty(), | |
266 | goal_kind, | |
267 | )? { | |
268 | Some(tupled_inputs_and_output) => tupled_inputs_and_output, | |
269 | None => { | |
270 | return ecx | |
271 | .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); | |
272 | } | |
273 | }; | |
9ffffee4 FG |
274 | let output_is_sized_pred = tupled_inputs_and_output |
275 | .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); | |
276 | ||
277 | let pred = tupled_inputs_and_output | |
278 | .map_bound(|(inputs, output)| ty::ProjectionPredicate { | |
279 | projection_ty: tcx | |
280 | .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), | |
281 | term: output.into(), | |
282 | }) | |
283 | .to_predicate(tcx); | |
284 | // A built-in `Fn` impl only holds if the output is sized. | |
285 | // (FIXME: technically we only need to check this if the type is a fn ptr...) | |
286 | Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) | |
9c376795 FG |
287 | } |
288 | ||
289 | fn consider_builtin_tuple_candidate( | |
290 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
291 | goal: Goal<'tcx, Self>, | |
292 | ) -> QueryResult<'tcx> { | |
293 | bug!("`Tuple` does not have an associated type: {:?}", goal); | |
294 | } | |
9ffffee4 FG |
295 | |
296 | fn consider_builtin_pointee_candidate( | |
297 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
298 | goal: Goal<'tcx, Self>, | |
299 | ) -> QueryResult<'tcx> { | |
300 | let tcx = ecx.tcx(); | |
301 | ecx.probe(|ecx| { | |
302 | let metadata_ty = match goal.predicate.self_ty().kind() { | |
303 | ty::Bool | |
304 | | ty::Char | |
305 | | ty::Int(..) | |
306 | | ty::Uint(..) | |
307 | | ty::Float(..) | |
308 | | ty::Array(..) | |
309 | | ty::RawPtr(..) | |
310 | | ty::Ref(..) | |
311 | | ty::FnDef(..) | |
312 | | ty::FnPtr(..) | |
313 | | ty::Closure(..) | |
314 | | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | |
315 | | ty::Generator(..) | |
316 | | ty::GeneratorWitness(..) | |
317 | | ty::GeneratorWitnessMIR(..) | |
318 | | ty::Never | |
319 | | ty::Foreign(..) => tcx.types.unit, | |
320 | ||
321 | ty::Error(e) => tcx.ty_error(*e), | |
322 | ||
323 | ty::Str | ty::Slice(_) => tcx.types.usize, | |
324 | ||
325 | ty::Dynamic(_, _, _) => { | |
326 | let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); | |
327 | tcx.type_of(dyn_metadata) | |
328 | .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) | |
329 | } | |
330 | ||
331 | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { | |
332 | // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. | |
333 | let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref( | |
334 | LangItem::Sized, | |
335 | [ty::GenericArg::from(goal.predicate.self_ty())], | |
336 | )); | |
353b0b11 FG |
337 | ecx.add_goal(goal.with(tcx, sized_predicate)); |
338 | tcx.types.unit | |
9ffffee4 FG |
339 | } |
340 | ||
341 | ty::Adt(def, substs) if def.is_struct() => { | |
353b0b11 | 342 | match def.non_enum_variant().fields.raw.last() { |
9ffffee4 FG |
343 | None => tcx.types.unit, |
344 | Some(field_def) => { | |
345 | let self_ty = field_def.ty(tcx, substs); | |
353b0b11 | 346 | ecx.add_goal(goal.with( |
9ffffee4 FG |
347 | tcx, |
348 | ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), | |
353b0b11 FG |
349 | )); |
350 | return ecx | |
351 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
9ffffee4 FG |
352 | } |
353 | } | |
354 | } | |
355 | ty::Adt(_, _) => tcx.types.unit, | |
356 | ||
357 | ty::Tuple(elements) => match elements.last() { | |
358 | None => tcx.types.unit, | |
359 | Some(&self_ty) => { | |
353b0b11 | 360 | ecx.add_goal(goal.with( |
9ffffee4 FG |
361 | tcx, |
362 | ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), | |
353b0b11 FG |
363 | )); |
364 | return ecx | |
365 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
9ffffee4 FG |
366 | } |
367 | }, | |
368 | ||
369 | ty::Infer( | |
370 | ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), | |
371 | ) | |
372 | | ty::Bound(..) => bug!( | |
373 | "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", | |
374 | goal.predicate.self_ty() | |
375 | ), | |
376 | }; | |
377 | ||
353b0b11 FG |
378 | ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?; |
379 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
9ffffee4 FG |
380 | }) |
381 | } | |
382 | ||
383 | fn consider_builtin_future_candidate( | |
384 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
385 | goal: Goal<'tcx, Self>, | |
386 | ) -> QueryResult<'tcx> { | |
387 | let self_ty = goal.predicate.self_ty(); | |
388 | let ty::Generator(def_id, substs, _) = *self_ty.kind() else { | |
389 | return Err(NoSolution); | |
390 | }; | |
391 | ||
392 | // Generators are not futures unless they come from `async` desugaring | |
393 | let tcx = ecx.tcx(); | |
394 | if !tcx.generator_is_async(def_id) { | |
395 | return Err(NoSolution); | |
396 | } | |
397 | ||
398 | let term = substs.as_generator().return_ty().into(); | |
399 | ||
400 | Self::consider_implied_clause( | |
401 | ecx, | |
402 | goal, | |
403 | ty::Binder::dummy(ty::ProjectionPredicate { | |
404 | projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]), | |
405 | term, | |
406 | }) | |
407 | .to_predicate(tcx), | |
408 | // Technically, we need to check that the future type is Sized, | |
409 | // but that's already proven by the generator being WF. | |
410 | [], | |
411 | ) | |
412 | } | |
413 | ||
414 | fn consider_builtin_generator_candidate( | |
415 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
416 | goal: Goal<'tcx, Self>, | |
417 | ) -> QueryResult<'tcx> { | |
418 | let self_ty = goal.predicate.self_ty(); | |
419 | let ty::Generator(def_id, substs, _) = *self_ty.kind() else { | |
420 | return Err(NoSolution); | |
421 | }; | |
422 | ||
423 | // `async`-desugared generators do not implement the generator trait | |
424 | let tcx = ecx.tcx(); | |
425 | if tcx.generator_is_async(def_id) { | |
426 | return Err(NoSolution); | |
427 | } | |
428 | ||
429 | let generator = substs.as_generator(); | |
430 | ||
431 | let name = tcx.associated_item(goal.predicate.def_id()).name; | |
432 | let term = if name == sym::Return { | |
433 | generator.return_ty().into() | |
434 | } else if name == sym::Yield { | |
435 | generator.yield_ty().into() | |
436 | } else { | |
437 | bug!("unexpected associated item `<{self_ty} as Generator>::{name}`") | |
438 | }; | |
439 | ||
440 | Self::consider_implied_clause( | |
441 | ecx, | |
442 | goal, | |
443 | ty::Binder::dummy(ty::ProjectionPredicate { | |
444 | projection_ty: ecx | |
445 | .tcx() | |
446 | .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), | |
447 | term, | |
448 | }) | |
449 | .to_predicate(tcx), | |
450 | // Technically, we need to check that the future type is Sized, | |
451 | // but that's already proven by the generator being WF. | |
452 | [], | |
453 | ) | |
454 | } | |
455 | ||
456 | fn consider_builtin_unsize_candidate( | |
457 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
458 | goal: Goal<'tcx, Self>, | |
459 | ) -> QueryResult<'tcx> { | |
460 | bug!("`Unsize` does not have an associated type: {:?}", goal); | |
461 | } | |
462 | ||
463 | fn consider_builtin_dyn_upcast_candidates( | |
464 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
465 | goal: Goal<'tcx, Self>, | |
353b0b11 | 466 | ) -> Vec<CanonicalResponse<'tcx>> { |
9ffffee4 FG |
467 | bug!("`Unsize` does not have an associated type: {:?}", goal); |
468 | } | |
469 | ||
470 | fn consider_builtin_discriminant_kind_candidate( | |
471 | ecx: &mut EvalCtxt<'_, 'tcx>, | |
472 | goal: Goal<'tcx, Self>, | |
473 | ) -> QueryResult<'tcx> { | |
353b0b11 FG |
474 | let self_ty = goal.predicate.self_ty(); |
475 | let discriminant_ty = match *self_ty.kind() { | |
476 | ty::Bool | |
477 | | ty::Char | |
478 | | ty::Int(..) | |
479 | | ty::Uint(..) | |
480 | | ty::Float(..) | |
481 | | ty::Array(..) | |
482 | | ty::RawPtr(..) | |
483 | | ty::Ref(..) | |
484 | | ty::FnDef(..) | |
485 | | ty::FnPtr(..) | |
486 | | ty::Closure(..) | |
487 | | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | |
488 | | ty::Generator(..) | |
489 | | ty::GeneratorWitness(..) | |
490 | | ty::GeneratorWitnessMIR(..) | |
491 | | ty::Never | |
492 | | ty::Foreign(..) | |
493 | | ty::Adt(_, _) | |
494 | | ty::Str | |
495 | | ty::Slice(_) | |
496 | | ty::Dynamic(_, _, _) | |
497 | | ty::Tuple(_) | |
498 | | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()), | |
499 | ||
500 | // We do not call `Ty::discriminant_ty` on alias, param, or placeholder | |
501 | // types, which return `<self_ty as DiscriminantKind>::Discriminant` | |
502 | // (or ICE in the case of placeholders). Projecting a type to itself | |
503 | // is never really productive. | |
504 | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { | |
505 | return Err(NoSolution); | |
506 | } | |
507 | ||
508 | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | |
509 | | ty::Bound(..) => bug!( | |
510 | "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`", | |
511 | goal.predicate.self_ty() | |
512 | ), | |
513 | }; | |
514 | ||
515 | ecx.probe(|ecx| { | |
516 | ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())?; | |
517 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
518 | }) | |
519 | } | |
520 | ||
521 | fn consider_builtin_destruct_candidate( | |
522 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
523 | goal: Goal<'tcx, Self>, | |
524 | ) -> QueryResult<'tcx> { | |
525 | bug!("`Destruct` does not have an associated type: {:?}", goal); | |
526 | } | |
527 | ||
528 | fn consider_builtin_transmute_candidate( | |
529 | _ecx: &mut EvalCtxt<'_, 'tcx>, | |
530 | goal: Goal<'tcx, Self>, | |
531 | ) -> QueryResult<'tcx> { | |
532 | bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) | |
9ffffee4 | 533 | } |
9c376795 FG |
534 | } |
535 | ||
536 | /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. | |
537 | /// | |
538 | /// FIXME: We should merge these 3 implementations as it's likely that they otherwise | |
539 | /// diverge. | |
353b0b11 | 540 | #[instrument(level = "debug", skip(ecx, param_env), ret)] |
9c376795 | 541 | fn fetch_eligible_assoc_item_def<'tcx>( |
353b0b11 | 542 | ecx: &EvalCtxt<'_, 'tcx>, |
9c376795 FG |
543 | param_env: ty::ParamEnv<'tcx>, |
544 | goal_trait_ref: ty::TraitRef<'tcx>, | |
545 | trait_assoc_def_id: DefId, | |
546 | impl_def_id: DefId, | |
547 | ) -> Result<Option<LeafDef>, NoSolution> { | |
353b0b11 | 548 | let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id) |
9c376795 FG |
549 | .map_err(|ErrorGuaranteed { .. }| NoSolution)?; |
550 | ||
551 | let eligible = if node_item.is_final() { | |
552 | // Non-specializable items are always projectable. | |
553 | true | |
554 | } else { | |
555 | // Only reveal a specializable default if we're past type-checking | |
556 | // and the obligation is monomorphic, otherwise passes such as | |
557 | // transmute checking and polymorphic MIR optimizations could | |
558 | // get a result which isn't correct for all monomorphizations. | |
559 | if param_env.reveal() == Reveal::All { | |
353b0b11 | 560 | let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref); |
9c376795 FG |
561 | !poly_trait_ref.still_further_specializable() |
562 | } else { | |
563 | debug!(?node_item.item.def_id, "not eligible due to default"); | |
564 | false | |
565 | } | |
566 | }; | |
567 | ||
568 | if eligible { Ok(Some(node_item)) } else { Ok(None) } | |
569 | } |