]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_trait_selection/src/solve/trait_goals.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / solve / trait_goals.rs
1 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
2
3 use super::assembly::{self, structural_traits};
4 use super::{EvalCtxt, SolverMode};
5 use rustc_hir::def_id::DefId;
6 use rustc_hir::{LangItem, Movability};
7 use rustc_infer::traits::query::NoSolution;
8 use rustc_infer::traits::util::supertraits;
9 use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
10 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
11 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
12 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
13 use rustc_span::DUMMY_SP;
14
15 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
16 fn self_ty(self) -> Ty<'tcx> {
17 self.self_ty()
18 }
19
20 fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
21 self.trait_ref
22 }
23
24 fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
25 self.with_self_ty(tcx, self_ty)
26 }
27
28 fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId {
29 self.def_id()
30 }
31
32 fn consider_impl_candidate(
33 ecx: &mut EvalCtxt<'_, 'tcx>,
34 goal: Goal<'tcx, TraitPredicate<'tcx>>,
35 impl_def_id: DefId,
36 ) -> QueryResult<'tcx> {
37 let tcx = ecx.tcx();
38
39 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
40 let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
41 if !drcx.substs_refs_may_unify(
42 goal.predicate.trait_ref.substs,
43 impl_trait_ref.skip_binder().substs,
44 ) {
45 return Err(NoSolution);
46 }
47
48 let impl_polarity = tcx.impl_polarity(impl_def_id);
49 // An upper bound of the certainty of this goal, used to lower the certainty
50 // of reservation impl to ambiguous during coherence.
51 let maximal_certainty = match impl_polarity {
52 ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => {
53 match impl_polarity == goal.predicate.polarity {
54 true => Certainty::Yes,
55 false => return Err(NoSolution),
56 }
57 }
58 ty::ImplPolarity::Reservation => match ecx.solver_mode() {
59 SolverMode::Normal => return Err(NoSolution),
60 SolverMode::Coherence => Certainty::AMBIGUOUS,
61 },
62 };
63
64 ecx.probe(|ecx| {
65 let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
66 let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
67
68 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
69 let where_clause_bounds = tcx
70 .predicates_of(impl_def_id)
71 .instantiate(tcx, impl_substs)
72 .predicates
73 .into_iter()
74 .map(|pred| goal.with(tcx, pred));
75 ecx.add_goals(where_clause_bounds);
76
77 ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
78 })
79 }
80
81 fn consider_implied_clause(
82 ecx: &mut EvalCtxt<'_, 'tcx>,
83 goal: Goal<'tcx, Self>,
84 assumption: ty::Predicate<'tcx>,
85 requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
86 ) -> QueryResult<'tcx> {
87 if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
88 && poly_trait_pred.def_id() == goal.predicate.def_id()
89 {
90 // FIXME: Constness and polarity
91 ecx.probe(|ecx| {
92 let assumption_trait_pred =
93 ecx.instantiate_binder_with_infer(poly_trait_pred);
94 ecx.eq(
95 goal.param_env,
96 goal.predicate.trait_ref,
97 assumption_trait_pred.trait_ref,
98 )?;
99 ecx.add_goals(requirements);
100 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
101 })
102 } else {
103 Err(NoSolution)
104 }
105 }
106
107 fn consider_object_bound_candidate(
108 ecx: &mut EvalCtxt<'_, 'tcx>,
109 goal: Goal<'tcx, Self>,
110 assumption: ty::Predicate<'tcx>,
111 ) -> QueryResult<'tcx> {
112 if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
113 && poly_trait_pred.def_id() == goal.predicate.def_id()
114 {
115 // FIXME: Constness and polarity
116 ecx.probe(|ecx| {
117 let assumption_trait_pred =
118 ecx.instantiate_binder_with_infer(poly_trait_pred);
119 ecx.eq(
120 goal.param_env,
121 goal.predicate.trait_ref,
122 assumption_trait_pred.trait_ref,
123 )?;
124
125 let tcx = ecx.tcx();
126 let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
127 bug!("expected object type in `consider_object_bound_candidate`");
128 };
129 ecx.add_goals(
130 structural_traits::predicates_for_object_candidate(
131 &ecx,
132 goal.param_env,
133 goal.predicate.trait_ref,
134 bounds,
135 )
136 .into_iter()
137 .map(|pred| goal.with(tcx, pred)),
138 );
139 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
140 })
141 } else {
142 Err(NoSolution)
143 }
144 }
145
146 fn consider_auto_trait_candidate(
147 ecx: &mut EvalCtxt<'_, 'tcx>,
148 goal: Goal<'tcx, Self>,
149 ) -> QueryResult<'tcx> {
150 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
151 return result;
152 }
153
154 ecx.probe_and_evaluate_goal_for_constituent_tys(
155 goal,
156 structural_traits::instantiate_constituent_tys_for_auto_trait,
157 )
158 }
159
160 fn consider_trait_alias_candidate(
161 ecx: &mut EvalCtxt<'_, 'tcx>,
162 goal: Goal<'tcx, Self>,
163 ) -> QueryResult<'tcx> {
164 let tcx = ecx.tcx();
165
166 ecx.probe(|ecx| {
167 let nested_obligations = tcx
168 .predicates_of(goal.predicate.def_id())
169 .instantiate(tcx, goal.predicate.trait_ref.substs);
170 ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
171 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
172 })
173 }
174
175 fn consider_builtin_sized_candidate(
176 ecx: &mut EvalCtxt<'_, 'tcx>,
177 goal: Goal<'tcx, Self>,
178 ) -> QueryResult<'tcx> {
179 ecx.probe_and_evaluate_goal_for_constituent_tys(
180 goal,
181 structural_traits::instantiate_constituent_tys_for_sized_trait,
182 )
183 }
184
185 fn consider_builtin_copy_clone_candidate(
186 ecx: &mut EvalCtxt<'_, 'tcx>,
187 goal: Goal<'tcx, Self>,
188 ) -> QueryResult<'tcx> {
189 ecx.probe_and_evaluate_goal_for_constituent_tys(
190 goal,
191 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
192 )
193 }
194
195 fn consider_builtin_pointer_like_candidate(
196 ecx: &mut EvalCtxt<'_, 'tcx>,
197 goal: Goal<'tcx, Self>,
198 ) -> QueryResult<'tcx> {
199 if goal.predicate.self_ty().has_non_region_infer() {
200 return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
201 }
202
203 let tcx = ecx.tcx();
204 let self_ty = tcx.erase_regions(goal.predicate.self_ty());
205
206 if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty))
207 && layout.layout.is_pointer_like(&tcx.data_layout)
208 {
209 // FIXME: We could make this faster by making a no-constraints response
210 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
211 } else {
212 Err(NoSolution)
213 }
214 }
215
216 fn consider_builtin_fn_ptr_trait_candidate(
217 ecx: &mut EvalCtxt<'_, 'tcx>,
218 goal: Goal<'tcx, Self>,
219 ) -> QueryResult<'tcx> {
220 if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
221 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
222 } else {
223 Err(NoSolution)
224 }
225 }
226
227 fn consider_builtin_fn_trait_candidates(
228 ecx: &mut EvalCtxt<'_, 'tcx>,
229 goal: Goal<'tcx, Self>,
230 goal_kind: ty::ClosureKind,
231 ) -> QueryResult<'tcx> {
232 let tcx = ecx.tcx();
233 let tupled_inputs_and_output =
234 match structural_traits::extract_tupled_inputs_and_output_from_callable(
235 tcx,
236 goal.predicate.self_ty(),
237 goal_kind,
238 )? {
239 Some(a) => a,
240 None => {
241 return ecx
242 .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
243 }
244 };
245 let output_is_sized_pred = tupled_inputs_and_output
246 .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
247
248 let pred = tupled_inputs_and_output
249 .map_bound(|(inputs, _)| {
250 tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
251 })
252 .to_predicate(tcx);
253 // A built-in `Fn` impl only holds if the output is sized.
254 // (FIXME: technically we only need to check this if the type is a fn ptr...)
255 Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
256 }
257
258 fn consider_builtin_tuple_candidate(
259 ecx: &mut EvalCtxt<'_, 'tcx>,
260 goal: Goal<'tcx, Self>,
261 ) -> QueryResult<'tcx> {
262 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
263 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
264 } else {
265 Err(NoSolution)
266 }
267 }
268
269 fn consider_builtin_pointee_candidate(
270 ecx: &mut EvalCtxt<'_, 'tcx>,
271 _goal: Goal<'tcx, Self>,
272 ) -> QueryResult<'tcx> {
273 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
274 }
275
276 fn consider_builtin_future_candidate(
277 ecx: &mut EvalCtxt<'_, 'tcx>,
278 goal: Goal<'tcx, Self>,
279 ) -> QueryResult<'tcx> {
280 let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
281 return Err(NoSolution);
282 };
283
284 // Generators are not futures unless they come from `async` desugaring
285 let tcx = ecx.tcx();
286 if !tcx.generator_is_async(def_id) {
287 return Err(NoSolution);
288 }
289
290 // Async generator unconditionally implement `Future`
291 // Technically, we need to check that the future output type is Sized,
292 // but that's already proven by the generator being WF.
293 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
294 }
295
296 fn consider_builtin_generator_candidate(
297 ecx: &mut EvalCtxt<'_, 'tcx>,
298 goal: Goal<'tcx, Self>,
299 ) -> QueryResult<'tcx> {
300 let self_ty = goal.predicate.self_ty();
301 let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
302 return Err(NoSolution);
303 };
304
305 // `async`-desugared generators do not implement the generator trait
306 let tcx = ecx.tcx();
307 if tcx.generator_is_async(def_id) {
308 return Err(NoSolution);
309 }
310
311 let generator = substs.as_generator();
312 Self::consider_implied_clause(
313 ecx,
314 goal,
315 ty::Binder::dummy(
316 tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
317 )
318 .to_predicate(tcx),
319 // Technically, we need to check that the generator types are Sized,
320 // but that's already proven by the generator being WF.
321 [],
322 )
323 }
324
325 fn consider_builtin_unsize_candidate(
326 ecx: &mut EvalCtxt<'_, 'tcx>,
327 goal: Goal<'tcx, Self>,
328 ) -> QueryResult<'tcx> {
329 let tcx = ecx.tcx();
330 let a_ty = goal.predicate.self_ty();
331 let b_ty = goal.predicate.trait_ref.substs.type_at(1);
332 if b_ty.is_ty_var() {
333 return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
334 }
335 ecx.probe(|ecx| {
336 match (a_ty.kind(), b_ty.kind()) {
337 // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
338 (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
339 // Dyn upcasting is handled separately, since due to upcasting,
340 // when there are two supertraits that differ by substs, we
341 // may return more than one query response.
342 Err(NoSolution)
343 }
344 // `T` -> `dyn Trait` unsizing
345 (_, &ty::Dynamic(data, region, ty::Dyn)) => {
346 // Can only unsize to an object-safe type
347 if data
348 .principal_def_id()
349 .map_or(false, |def_id| !tcx.check_is_object_safe(def_id))
350 {
351 return Err(NoSolution);
352 }
353
354 let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
355 return Err(NoSolution);
356 };
357 // Check that the type implements all of the predicates of the def-id.
358 // (i.e. the principal, all of the associated types match, and any auto traits)
359 ecx.add_goals(
360 data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
361 );
362 // The type must be Sized to be unsized.
363 ecx.add_goal(
364 goal.with(tcx, ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty]))),
365 );
366 // The type must outlive the lifetime of the `dyn` we're unsizing into.
367 ecx.add_goal(
368 goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
369 );
370 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
371 }
372 // `[T; n]` -> `[T]` unsizing
373 (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
374 // We just require that the element type stays the same
375 ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
376 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
377 }
378 // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
379 (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
380 if a_def.is_struct() && a_def.did() == b_def.did() =>
381 {
382 let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
383 // We must be unsizing some type parameters. This also implies
384 // that the struct has a tail field.
385 if unsizing_params.is_empty() {
386 return Err(NoSolution);
387 }
388
389 let tail_field = a_def
390 .non_enum_variant()
391 .fields
392 .raw
393 .last()
394 .expect("expected unsized ADT to have a tail field");
395 let tail_field_ty = tcx.type_of(tail_field.did);
396
397 let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
398 let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
399
400 // Substitute just the unsizing params from B into A. The type after
401 // this substitution must be equal to B. This is so we don't unsize
402 // unrelated type parameters.
403 let new_a_substs =
404 tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
405 if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
406 }));
407 let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
408
409 // Finally, we require that `TailA: Unsize<TailB>` for the tail field
410 // types.
411 ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
412 ecx.add_goal(goal.with(
413 tcx,
414 ty::Binder::dummy(
415 tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
416 ),
417 ));
418 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
419 }
420 // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
421 (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
422 if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
423 {
424 let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
425 let b_last_ty = b_tys.last().unwrap();
426
427 // Substitute just the tail field of B., and require that they're equal.
428 let unsized_a_ty =
429 tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
430 ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
431
432 // Similar to ADTs, require that the rest of the fields are equal.
433 ecx.add_goal(goal.with(
434 tcx,
435 ty::Binder::dummy(
436 tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
437 ),
438 ));
439 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
440 }
441 _ => Err(NoSolution),
442 }
443 })
444 }
445
446 fn consider_builtin_dyn_upcast_candidates(
447 ecx: &mut EvalCtxt<'_, 'tcx>,
448 goal: Goal<'tcx, Self>,
449 ) -> Vec<CanonicalResponse<'tcx>> {
450 let tcx = ecx.tcx();
451
452 let a_ty = goal.predicate.self_ty();
453 let b_ty = goal.predicate.trait_ref.substs.type_at(1);
454 let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
455 return vec![];
456 };
457 let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
458 return vec![];
459 };
460
461 // All of a's auto traits need to be in b's auto traits.
462 let auto_traits_compatible =
463 b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
464 if !auto_traits_compatible {
465 return vec![];
466 }
467
468 let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
469 ecx.probe(|ecx| -> Result<_, NoSolution> {
470 // Require that all of the trait predicates from A match B, except for
471 // the auto traits. We do this by constructing a new A type with B's
472 // auto traits, and equating these types.
473 let new_a_data = principal
474 .into_iter()
475 .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
476 .chain(a_data.iter().filter(|a| {
477 matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
478 }))
479 .chain(
480 b_data
481 .auto_traits()
482 .map(ty::ExistentialPredicate::AutoTrait)
483 .map(ty::Binder::dummy),
484 );
485 let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
486 let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
487
488 // We also require that A's lifetime outlives B's lifetime.
489 ecx.eq(goal.param_env, new_a_ty, b_ty)?;
490 ecx.add_goal(
491 goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))),
492 );
493 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
494 })
495 };
496
497 let mut responses = vec![];
498 // If the principal def ids match (or are both none), then we're not doing
499 // trait upcasting. We're just removing auto traits (or shortening the lifetime).
500 if a_data.principal_def_id() == b_data.principal_def_id() {
501 if let Ok(response) = unsize_dyn_to_principal(a_data.principal()) {
502 responses.push(response);
503 }
504 } else if let Some(a_principal) = a_data.principal()
505 && let Some(b_principal) = b_data.principal()
506 {
507 for super_trait_ref in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)) {
508 if super_trait_ref.def_id() != b_principal.def_id() {
509 continue;
510 }
511 let erased_trait_ref = super_trait_ref
512 .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
513 if let Ok(response) = unsize_dyn_to_principal(Some(erased_trait_ref)) {
514 responses.push(response);
515 }
516 }
517 }
518
519 responses
520 }
521
522 fn consider_builtin_discriminant_kind_candidate(
523 ecx: &mut EvalCtxt<'_, 'tcx>,
524 _goal: Goal<'tcx, Self>,
525 ) -> QueryResult<'tcx> {
526 // `DiscriminantKind` is automatically implemented for every type.
527 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
528 }
529
530 fn consider_builtin_destruct_candidate(
531 ecx: &mut EvalCtxt<'_, 'tcx>,
532 goal: Goal<'tcx, Self>,
533 ) -> QueryResult<'tcx> {
534 if !goal.param_env.is_const() {
535 // `Destruct` is automatically implemented for every type in
536 // non-const environments.
537 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
538 } else {
539 // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver
540 Err(NoSolution)
541 }
542 }
543
544 fn consider_builtin_transmute_candidate(
545 ecx: &mut EvalCtxt<'_, 'tcx>,
546 goal: Goal<'tcx, Self>,
547 ) -> QueryResult<'tcx> {
548 // `rustc_transmute` does not have support for type or const params
549 if goal.has_non_region_placeholders() {
550 return Err(NoSolution);
551 }
552
553 // Erase regions because we compute layouts in `rustc_transmute`,
554 // which will ICE for region vars.
555 let substs = ecx.tcx().erase_regions(goal.predicate.trait_ref.substs);
556
557 let Some(assume) = rustc_transmute::Assume::from_const(
558 ecx.tcx(),
559 goal.param_env,
560 substs.const_at(3),
561 ) else {
562 return Err(NoSolution);
563 };
564
565 let certainty = ecx.is_transmutable(
566 rustc_transmute::Types { dst: substs.type_at(0), src: substs.type_at(1) },
567 substs.type_at(2),
568 assume,
569 )?;
570 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
571 }
572 }
573
574 impl<'tcx> EvalCtxt<'_, 'tcx> {
575 // Return `Some` if there is an impl (built-in or user provided) that may
576 // hold for the self type of the goal, which for coherence and soundness
577 // purposes must disqualify the built-in auto impl assembled by considering
578 // the type's constituent types.
579 fn disqualify_auto_trait_candidate_due_to_possible_impl(
580 &mut self,
581 goal: Goal<'tcx, TraitPredicate<'tcx>>,
582 ) -> Option<QueryResult<'tcx>> {
583 let self_ty = goal.predicate.self_ty();
584 match *self_ty.kind() {
585 // Stall int and float vars until they are resolved to a concrete
586 // numerical type. That's because the check for impls below treats
587 // int vars as matching any impl. Even if we filtered such impls,
588 // we probably don't want to treat an `impl !AutoTrait for i32` as
589 // disqualifying the built-in auto impl for `i64: AutoTrait` either.
590 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
591 Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS))
592 }
593
594 // These types cannot be structurally decomposed into constitutent
595 // types, and therefore have no built-in auto impl.
596 ty::Dynamic(..)
597 | ty::Param(..)
598 | ty::Foreign(..)
599 | ty::Alias(ty::Projection, ..)
600 | ty::Placeholder(..) => Some(Err(NoSolution)),
601
602 ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
603
604 // Generators have one special built-in candidate, `Unpin`, which
605 // takes precedence over the structural auto trait candidate being
606 // assembled.
607 ty::Generator(_, _, movability)
608 if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() =>
609 {
610 match movability {
611 Movability::Static => Some(Err(NoSolution)),
612 Movability::Movable => {
613 Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
614 }
615 }
616 }
617
618 // For rigid types, any possible implementation that could apply to
619 // the type (even if after unification and processing nested goals
620 // it does not hold) will disqualify the built-in auto impl.
621 //
622 // This differs from the current stable behavior and fixes #84857.
623 // Due to breakage found via crater, we currently instead lint
624 // patterns which can be used to exploit this unsoundness on stable,
625 // see #93367 for more details.
626 ty::Bool
627 | ty::Char
628 | ty::Int(_)
629 | ty::Uint(_)
630 | ty::Float(_)
631 | ty::Str
632 | ty::Array(_, _)
633 | ty::Slice(_)
634 | ty::RawPtr(_)
635 | ty::Ref(_, _, _)
636 | ty::FnDef(_, _)
637 | ty::FnPtr(_)
638 | ty::Closure(_, _)
639 | ty::Generator(_, _, _)
640 | ty::GeneratorWitness(_)
641 | ty::GeneratorWitnessMIR(_, _)
642 | ty::Never
643 | ty::Tuple(_)
644 | ty::Adt(_, _)
645 // FIXME: Handling opaques here is kinda sus. Especially because we
646 // simplify them to PlaceholderSimplifiedType.
647 | ty::Alias(ty::Opaque, _) => {
648 if let Some(def_id) = self.tcx().find_map_relevant_impl(
649 goal.predicate.def_id(),
650 goal.predicate.self_ty(),
651 TreatProjections::NextSolverLookup,
652 Some,
653 ) {
654 debug!(?def_id, ?goal, "disqualified auto-trait implementation");
655 // No need to actually consider the candidate here,
656 // since we do that in `consider_impl_candidate`.
657 return Some(Err(NoSolution));
658 } else {
659 None
660 }
661 }
662 ty::Error(_) => None,
663 }
664 }
665
666 /// Convenience function for traits that are structural, i.e. that only
667 /// have nested subgoals that only change the self type. Unlike other
668 /// evaluate-like helpers, this does a probe, so it doesn't need to be
669 /// wrapped in one.
670 fn probe_and_evaluate_goal_for_constituent_tys(
671 &mut self,
672 goal: Goal<'tcx, TraitPredicate<'tcx>>,
673 constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
674 ) -> QueryResult<'tcx> {
675 self.probe(|ecx| {
676 ecx.add_goals(
677 constituent_tys(ecx, goal.predicate.self_ty())?
678 .into_iter()
679 .map(|ty| {
680 goal.with(
681 ecx.tcx(),
682 ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
683 )
684 })
685 .collect::<Vec<_>>(),
686 );
687 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
688 })
689 }
690
691 #[instrument(level = "debug", skip(self))]
692 pub(super) fn compute_trait_goal(
693 &mut self,
694 goal: Goal<'tcx, TraitPredicate<'tcx>>,
695 ) -> QueryResult<'tcx> {
696 let candidates = self.assemble_and_evaluate_candidates(goal);
697 self.merge_candidates(candidates)
698 }
699 }