1 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
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
;
15 impl<'tcx
> assembly
::GoalKind
<'tcx
> for TraitPredicate
<'tcx
> {
16 fn self_ty(self) -> Ty
<'tcx
> {
20 fn trait_ref(self, _
: TyCtxt
<'tcx
>) -> ty
::TraitRef
<'tcx
> {
24 fn with_self_ty(self, tcx
: TyCtxt
<'tcx
>, self_ty
: Ty
<'tcx
>) -> Self {
25 self.with_self_ty(tcx
, self_ty
)
28 fn trait_def_id(self, _
: TyCtxt
<'tcx
>) -> DefId
{
32 fn consider_impl_candidate(
33 ecx
: &mut EvalCtxt
<'_
, 'tcx
>,
34 goal
: Goal
<'tcx
, TraitPredicate
<'tcx
>>,
36 ) -> QueryResult
<'tcx
> {
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
,
45 return Err(NoSolution
);
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
),
58 ty
::ImplPolarity
::Reservation
=> match ecx
.solver_mode() {
59 SolverMode
::Normal
=> return Err(NoSolution
),
60 SolverMode
::Coherence
=> Certainty
::AMBIGUOUS
,
65 let impl_substs
= ecx
.fresh_substs_for_item(impl_def_id
);
66 let impl_trait_ref
= impl_trait_ref
.subst(tcx
, impl_substs
);
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
)
74 .map(|pred
| goal
.with(tcx
, pred
));
75 ecx
.add_goals(where_clause_bounds
);
77 ecx
.evaluate_added_goals_and_make_canonical_response(maximal_certainty
)
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()
90 // FIXME: Constness and polarity
92 let assumption_trait_pred
=
93 ecx
.instantiate_binder_with_infer(poly_trait_pred
);
96 goal
.predicate
.trait_ref
,
97 assumption_trait_pred
.trait_ref
,
99 ecx
.add_goals(requirements
);
100 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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()
115 // FIXME: Constness and polarity
117 let assumption_trait_pred
=
118 ecx
.instantiate_binder_with_infer(poly_trait_pred
);
121 goal
.predicate
.trait_ref
,
122 assumption_trait_pred
.trait_ref
,
126 let ty
::Dynamic(bounds
, _
, _
) = *goal
.predicate
.self_ty().kind() else {
127 bug
!("expected object type in `consider_object_bound_candidate`");
130 structural_traits
::predicates_for_object_candidate(
133 goal
.predicate
.trait_ref
,
137 .map(|pred
| goal
.with(tcx
, pred
)),
139 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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
) {
154 ecx
.probe_and_evaluate_goal_for_constituent_tys(
156 structural_traits
::instantiate_constituent_tys_for_auto_trait
,
160 fn consider_trait_alias_candidate(
161 ecx
: &mut EvalCtxt
<'_
, 'tcx
>,
162 goal
: Goal
<'tcx
, Self>,
163 ) -> QueryResult
<'tcx
> {
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
)
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(
181 structural_traits
::instantiate_constituent_tys_for_sized_trait
,
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(
191 structural_traits
::instantiate_constituent_tys_for_copy_clone_trait
,
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
);
204 let self_ty
= tcx
.erase_regions(goal
.predicate
.self_ty());
206 if let Ok(layout
) = tcx
.layout_of(goal
.param_env
.and(self_ty
))
207 && layout
.layout
.is_pointer_like(&tcx
.data_layout
)
209 // FIXME: We could make this faster by making a no-constraints response
210 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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
)
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
> {
233 let tupled_inputs_and_output
=
234 match structural_traits
::extract_tupled_inputs_and_output_from_callable(
236 goal
.predicate
.self_ty(),
242 .evaluate_added_goals_and_make_canonical_response(Certainty
::AMBIGUOUS
);
245 let output_is_sized_pred
= tupled_inputs_and_output
246 .map_bound(|(_
, output
)| tcx
.at(DUMMY_SP
).mk_trait_ref(LangItem
::Sized
, [output
]));
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
])
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
)])
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
)
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
)
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
);
284 // Generators are not futures unless they come from `async` desugaring
286 if !tcx
.generator_is_async(def_id
) {
287 return Err(NoSolution
);
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
)
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
);
305 // `async`-desugared generators do not implement the generator trait
307 if tcx
.generator_is_async(def_id
) {
308 return Err(NoSolution
);
311 let generator
= substs
.as_generator();
312 Self::consider_implied_clause(
316 tcx
.mk_trait_ref(goal
.predicate
.def_id(), [self_ty
, generator
.resume_ty()]),
319 // Technically, we need to check that the generator types are Sized,
320 // but that's already proven by the generator being WF.
325 fn consider_builtin_unsize_candidate(
326 ecx
: &mut EvalCtxt
<'_
, 'tcx
>,
327 goal
: Goal
<'tcx
, Self>,
328 ) -> QueryResult
<'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
);
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.
344 // `T` -> `dyn Trait` unsizing
345 (_
, &ty
::Dynamic(data
, region
, ty
::Dyn
)) => {
346 // Can only unsize to an object-safe type
349 .map_or(false, |def_id
| !tcx
.check_is_object_safe(def_id
))
351 return Err(NoSolution
);
354 let Some(sized_def_id
) = tcx
.lang_items().sized_trait() else {
355 return Err(NoSolution
);
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)
360 data
.iter().map(|pred
| goal
.with(tcx
, pred
.with_self_ty(tcx
, a_ty
))),
362 // The type must be Sized to be unsized.
364 goal
.with(tcx
, ty
::Binder
::dummy(tcx
.mk_trait_ref(sized_def_id
, [a_ty
]))),
366 // The type must outlive the lifetime of the `dyn` we're unsizing into.
368 goal
.with(tcx
, ty
::Binder
::dummy(ty
::OutlivesPredicate(a_ty
, region
))),
370 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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
)
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() =>
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
);
389 let tail_field
= a_def
394 .expect("expected unsized ADT to have a tail field");
395 let tail_field_ty
= tcx
.type_of(tail_field
.did
);
397 let a_tail_ty
= tail_field_ty
.subst(tcx
, a_substs
);
398 let b_tail_ty
= tail_field_ty
.subst(tcx
, b_substs
);
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.
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 }
407 let unsized_a_ty
= tcx
.mk_adt(a_def
, new_a_substs
);
409 // Finally, we require that `TailA: Unsize<TailB>` for the tail field
411 ecx
.eq(goal
.param_env
, unsized_a_ty
, b_ty
)?
;
412 ecx
.add_goal(goal
.with(
415 tcx
.mk_trait_ref(goal
.predicate
.def_id(), [a_tail_ty
, b_tail_ty
]),
418 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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() =>
424 let (a_last_ty
, a_rest_tys
) = a_tys
.split_last().unwrap();
425 let b_last_ty
= b_tys
.last().unwrap();
427 // Substitute just the tail field of B., and require that they're equal.
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
)?
;
432 // Similar to ADTs, require that the rest of the fields are equal.
433 ecx
.add_goal(goal
.with(
436 tcx
.mk_trait_ref(goal
.predicate
.def_id(), [*a_last_ty
, *b_last_ty
]),
439 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
441 _
=> Err(NoSolution
),
446 fn consider_builtin_dyn_upcast_candidates(
447 ecx
: &mut EvalCtxt
<'_
, 'tcx
>,
448 goal
: Goal
<'tcx
, Self>,
449 ) -> Vec
<CanonicalResponse
<'tcx
>> {
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 {
457 let ty
::Dynamic(b_data
, b_region
, ty
::Dyn
) = *b_ty
.kind() else {
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
{
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
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(_
))
482 .map(ty
::ExistentialPredicate
::AutoTrait
)
483 .map(ty
::Binder
::dummy
),
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
);
488 // We also require that A's lifetime outlives B's lifetime.
489 ecx
.eq(goal
.param_env
, new_a_ty
, b_ty
)?
;
491 goal
.with(tcx
, ty
::Binder
::dummy(ty
::OutlivesPredicate(a_region
, b_region
))),
493 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
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
);
504 } else if let Some(a_principal
) = a_data
.principal()
505 && let Some(b_principal
) = b_data
.principal()
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() {
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
);
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
)
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
)
539 // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver
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
);
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
);
557 let Some(assume
) = rustc_transmute
::Assume
::from_const(
562 return Err(NoSolution
);
565 let certainty
= ecx
.is_transmutable(
566 rustc_transmute
::Types { dst: substs.type_at(0), src: substs.type_at(1) }
,
570 ecx
.evaluate_added_goals_and_make_canonical_response(certainty
)
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(
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
))
594 // These types cannot be structurally decomposed into constitutent
595 // types, and therefore have no built-in auto impl.
599 | ty
::Alias(ty
::Projection
, ..)
600 | ty
::Placeholder(..) => Some(Err(NoSolution
)),
602 ty
::Infer(_
) | ty
::Bound(_
, _
) => bug
!("unexpected type `{self_ty}`"),
604 // Generators have one special built-in candidate, `Unpin`, which
605 // takes precedence over the structural auto trait candidate being
607 ty
::Generator(_
, _
, movability
)
608 if Some(goal
.predicate
.def_id()) == self.tcx().lang_items().unpin_trait() =>
611 Movability
::Static
=> Some(Err(NoSolution
)),
612 Movability
::Movable
=> {
613 Some(self.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
))
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.
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.
639 | ty
::Generator(_
, _
, _
)
640 | ty
::GeneratorWitness(_
)
641 | ty
::GeneratorWitnessMIR(_
, _
)
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
,
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
));
662 ty
::Error(_
) => None
,
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
670 fn probe_and_evaluate_goal_for_constituent_tys(
672 goal
: Goal
<'tcx
, TraitPredicate
<'tcx
>>,
673 constituent_tys
: impl Fn(&EvalCtxt
<'_
, 'tcx
>, Ty
<'tcx
>) -> Result
<Vec
<Ty
<'tcx
>>, NoSolution
>,
674 ) -> QueryResult
<'tcx
> {
677 constituent_tys(ecx
, goal
.predicate
.self_ty())?
682 ty
::Binder
::dummy(goal
.predicate
.with_self_ty(ecx
.tcx(), ty
)),
685 .collect
::<Vec
<_
>>(),
687 ecx
.evaluate_added_goals_and_make_canonical_response(Certainty
::Yes
)
691 #[instrument(level = "debug", skip(self))]
692 pub(super) fn compute_trait_goal(
694 goal
: Goal
<'tcx
, TraitPredicate
<'tcx
>>,
695 ) -> QueryResult
<'tcx
> {
696 let candidates
= self.assemble_and_evaluate_candidates(goal
);
697 self.merge_candidates(candidates
)