1use rustc_type_ir::data_structures::IndexSet;
4use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::TraitSolverLangItem;
7use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
8use rustc_type_ir::{
9 self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
10 Upcast as _, elaborate,
11};
12use tracing::{debug, instrument, trace};
13
14use crate::delegate::SolverDelegate;
15use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16use crate::solve::assembly::{
17 self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate, FailedCandidateInfo,
18};
19use crate::solve::inspect::ProbeKind;
20use crate::solve::{
21 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
22 MergeCandidateInfo, NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
23};
24
25impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
26where
27 D: SolverDelegate<Interner = I>,
28 I: Interner,
29{
30 fn self_ty(self) -> I::Ty {
31 self.self_ty()
32 }
33
34 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
35 self.trait_ref
36 }
37
38 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
39 self.with_replaced_self_ty(cx, self_ty)
40 }
41
42 fn trait_def_id(self, _: I) -> I::DefId {
43 self.def_id()
44 }
45
46 fn consider_additional_alias_assumptions(
47 _ecx: &mut EvalCtxt<'_, D>,
48 _goal: Goal<I, Self>,
49 _alias_ty: ty::AliasTy<I>,
50 ) -> Vec<Candidate<I>> {
51 vec![]
52 }
53
54 fn consider_impl_candidate(
55 ecx: &mut EvalCtxt<'_, D>,
56 goal: Goal<I, TraitPredicate<I>>,
57 impl_def_id: I::DefId,
58 ) -> Result<Candidate<I>, NoSolution> {
59 let cx = ecx.cx();
60
61 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
62 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
63 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
64 {
65 return Err(NoSolution);
66 }
67
68 let impl_polarity = cx.impl_polarity(impl_def_id);
71 let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
72 (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
75 TypingMode::Coherence => Certainty::AMBIGUOUS,
76 TypingMode::Analysis { .. }
77 | TypingMode::Borrowck { .. }
78 | TypingMode::PostBorrowckAnalysis { .. }
79 | TypingMode::PostAnalysis => return Err(NoSolution),
80 },
81
82 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
84 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
85
86 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
88 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
89 return Err(NoSolution);
90 }
91 };
92
93 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
94 let impl_args = ecx.fresh_args_for_item(impl_def_id);
95 ecx.record_impl_args(impl_args);
96 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
97
98 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
99 let where_clause_bounds = cx
100 .predicates_of(impl_def_id)
101 .iter_instantiated(cx, impl_args)
102 .map(|pred| goal.with(cx, pred));
103 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
104
105 ecx.add_goals(
109 GoalSource::Misc,
110 cx.impl_super_outlives(impl_def_id)
111 .iter_instantiated(cx, impl_args)
112 .map(|pred| goal.with(cx, pred)),
113 );
114
115 ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
116 })
117 }
118
119 fn consider_error_guaranteed_candidate(
120 ecx: &mut EvalCtxt<'_, D>,
121 _guar: I::ErrorGuaranteed,
122 ) -> Result<Candidate<I>, NoSolution> {
123 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
124 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
125 }
126
127 fn fast_reject_assumption(
128 ecx: &mut EvalCtxt<'_, D>,
129 goal: Goal<I, Self>,
130 assumption: I::Clause,
131 ) -> Result<(), NoSolution> {
132 fn trait_def_id_matches<I: Interner>(
133 cx: I,
134 clause_def_id: I::DefId,
135 goal_def_id: I::DefId,
136 ) -> bool {
137 clause_def_id == goal_def_id
138 || (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
143 && cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized))
144 }
145
146 if let Some(trait_clause) = assumption.as_trait_clause()
147 && trait_clause.polarity() == goal.predicate.polarity
148 && trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id())
149 && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
150 goal.predicate.trait_ref.args,
151 trait_clause.skip_binder().trait_ref.args,
152 )
153 {
154 return Ok(());
155 } else {
156 Err(NoSolution)
157 }
158 }
159
160 fn match_assumption(
161 ecx: &mut EvalCtxt<'_, D>,
162 goal: Goal<I, Self>,
163 assumption: I::Clause,
164 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
165 ) -> QueryResult<I> {
166 let trait_clause = assumption.as_trait_clause().unwrap();
167
168 if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
172 && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
173 {
174 let meta_sized_clause =
175 trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
176 return Self::match_assumption(ecx, goal, meta_sized_clause, then);
177 }
178
179 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
180 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
181
182 then(ecx)
183 }
184
185 fn consider_auto_trait_candidate(
186 ecx: &mut EvalCtxt<'_, D>,
187 goal: Goal<I, Self>,
188 ) -> Result<Candidate<I>, NoSolution> {
189 let cx = ecx.cx();
190 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
191 return Err(NoSolution);
192 }
193
194 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
195 return result;
196 }
197
198 if cx.trait_is_unsafe(goal.predicate.def_id())
201 && goal.predicate.self_ty().has_unsafe_fields()
202 {
203 return Err(NoSolution);
204 }
205
206 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
222 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
223 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
224 if item_bound
225 .as_trait_clause()
226 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
227 {
228 return Err(NoSolution);
229 }
230 }
231 }
232
233 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
235 return cand;
236 }
237
238 ecx.probe_and_evaluate_goal_for_constituent_tys(
239 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
240 goal,
241 structural_traits::instantiate_constituent_tys_for_auto_trait,
242 )
243 }
244
245 fn consider_trait_alias_candidate(
246 ecx: &mut EvalCtxt<'_, D>,
247 goal: Goal<I, Self>,
248 ) -> Result<Candidate<I>, NoSolution> {
249 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
250 return Err(NoSolution);
251 }
252
253 let cx = ecx.cx();
254
255 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
256 let nested_obligations = cx
257 .predicates_of(goal.predicate.def_id())
258 .iter_instantiated(cx, goal.predicate.trait_ref.args)
259 .map(|p| goal.with(cx, p));
260 ecx.add_goals(GoalSource::Misc, nested_obligations);
266 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
267 })
268 }
269
270 fn consider_builtin_sizedness_candidates(
271 ecx: &mut EvalCtxt<'_, D>,
272 goal: Goal<I, Self>,
273 sizedness: SizedTraitKind,
274 ) -> Result<Candidate<I>, NoSolution> {
275 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
276 return Err(NoSolution);
277 }
278
279 ecx.probe_and_evaluate_goal_for_constituent_tys(
280 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
281 goal,
282 |ecx, ty| {
283 structural_traits::instantiate_constituent_tys_for_sizedness_trait(
284 ecx, sizedness, ty,
285 )
286 },
287 )
288 }
289
290 fn consider_builtin_copy_clone_candidate(
291 ecx: &mut EvalCtxt<'_, D>,
292 goal: Goal<I, Self>,
293 ) -> Result<Candidate<I>, NoSolution> {
294 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
295 return Err(NoSolution);
296 }
297
298 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
300 return cand;
301 }
302
303 ecx.probe_and_evaluate_goal_for_constituent_tys(
304 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
305 goal,
306 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
307 )
308 }
309
310 fn consider_builtin_fn_ptr_trait_candidate(
311 ecx: &mut EvalCtxt<'_, D>,
312 goal: Goal<I, Self>,
313 ) -> Result<Candidate<I>, NoSolution> {
314 let self_ty = goal.predicate.self_ty();
315 match goal.predicate.polarity {
316 ty::PredicatePolarity::Positive => {
318 if self_ty.is_fn_ptr() {
319 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
320 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
321 })
322 } else {
323 Err(NoSolution)
324 }
325 }
326 ty::PredicatePolarity::Negative => {
328 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
331 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
332 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
333 })
334 } else {
335 Err(NoSolution)
336 }
337 }
338 }
339 }
340
341 fn consider_builtin_fn_trait_candidates(
342 ecx: &mut EvalCtxt<'_, D>,
343 goal: Goal<I, Self>,
344 goal_kind: ty::ClosureKind,
345 ) -> Result<Candidate<I>, NoSolution> {
346 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
347 return Err(NoSolution);
348 }
349
350 let cx = ecx.cx();
351 let tupled_inputs_and_output =
352 match structural_traits::extract_tupled_inputs_and_output_from_callable(
353 cx,
354 goal.predicate.self_ty(),
355 goal_kind,
356 )? {
357 Some(a) => a,
358 None => {
359 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
360 }
361 };
362
363 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
366 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
367 });
368
369 let pred = tupled_inputs_and_output
370 .map_bound(|(inputs, _)| {
371 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
372 })
373 .upcast(cx);
374 Self::probe_and_consider_implied_clause(
375 ecx,
376 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
377 goal,
378 pred,
379 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
380 )
381 }
382
383 fn consider_builtin_async_fn_trait_candidates(
384 ecx: &mut EvalCtxt<'_, D>,
385 goal: Goal<I, Self>,
386 goal_kind: ty::ClosureKind,
387 ) -> Result<Candidate<I>, NoSolution> {
388 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
389 return Err(NoSolution);
390 }
391
392 let cx = ecx.cx();
393 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
394 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
395 cx,
396 goal.predicate.self_ty(),
397 goal_kind,
398 Region::new_static(cx),
400 )?;
401
402 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
405 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
406 ty::TraitRef::new(
407 cx,
408 cx.require_lang_item(TraitSolverLangItem::Sized),
409 [output_coroutine_ty],
410 )
411 },
412 );
413
414 let pred = tupled_inputs_and_output_and_coroutine
415 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
416 ty::TraitRef::new(
417 cx,
418 goal.predicate.def_id(),
419 [goal.predicate.self_ty(), tupled_inputs_ty],
420 )
421 })
422 .upcast(cx);
423 Self::probe_and_consider_implied_clause(
424 ecx,
425 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
426 goal,
427 pred,
428 [goal.with(cx, output_is_sized_pred)]
429 .into_iter()
430 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
431 .map(|goal| (GoalSource::ImplWhereBound, goal)),
432 )
433 }
434
435 fn consider_builtin_async_fn_kind_helper_candidate(
436 ecx: &mut EvalCtxt<'_, D>,
437 goal: Goal<I, Self>,
438 ) -> Result<Candidate<I>, NoSolution> {
439 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
440 panic!();
441 };
442
443 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
444 return Err(NoSolution);
446 };
447 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
448 if closure_kind.extends(goal_kind) {
449 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
450 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
451 } else {
452 Err(NoSolution)
453 }
454 }
455
456 fn consider_builtin_tuple_candidate(
463 ecx: &mut EvalCtxt<'_, D>,
464 goal: Goal<I, Self>,
465 ) -> Result<Candidate<I>, NoSolution> {
466 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
467 return Err(NoSolution);
468 }
469
470 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
471 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
472 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
473 } else {
474 Err(NoSolution)
475 }
476 }
477
478 fn consider_builtin_pointee_candidate(
479 ecx: &mut EvalCtxt<'_, D>,
480 goal: Goal<I, Self>,
481 ) -> Result<Candidate<I>, NoSolution> {
482 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
483 return Err(NoSolution);
484 }
485
486 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
487 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
488 }
489
490 fn consider_builtin_future_candidate(
491 ecx: &mut EvalCtxt<'_, D>,
492 goal: Goal<I, Self>,
493 ) -> Result<Candidate<I>, NoSolution> {
494 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
495 return Err(NoSolution);
496 }
497
498 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
499 return Err(NoSolution);
500 };
501
502 let cx = ecx.cx();
504 if !cx.coroutine_is_async(def_id) {
505 return Err(NoSolution);
506 }
507
508 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
512 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
513 }
514
515 fn consider_builtin_iterator_candidate(
516 ecx: &mut EvalCtxt<'_, D>,
517 goal: Goal<I, Self>,
518 ) -> Result<Candidate<I>, NoSolution> {
519 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
520 return Err(NoSolution);
521 }
522
523 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
524 return Err(NoSolution);
525 };
526
527 let cx = ecx.cx();
529 if !cx.coroutine_is_gen(def_id) {
530 return Err(NoSolution);
531 }
532
533 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
537 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
538 }
539
540 fn consider_builtin_fused_iterator_candidate(
541 ecx: &mut EvalCtxt<'_, D>,
542 goal: Goal<I, Self>,
543 ) -> Result<Candidate<I>, NoSolution> {
544 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
545 return Err(NoSolution);
546 }
547
548 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
549 return Err(NoSolution);
550 };
551
552 let cx = ecx.cx();
554 if !cx.coroutine_is_gen(def_id) {
555 return Err(NoSolution);
556 }
557
558 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
560 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
561 }
562
563 fn consider_builtin_async_iterator_candidate(
564 ecx: &mut EvalCtxt<'_, D>,
565 goal: Goal<I, Self>,
566 ) -> Result<Candidate<I>, NoSolution> {
567 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
568 return Err(NoSolution);
569 }
570
571 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
572 return Err(NoSolution);
573 };
574
575 let cx = ecx.cx();
577 if !cx.coroutine_is_async_gen(def_id) {
578 return Err(NoSolution);
579 }
580
581 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
585 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
586 }
587
588 fn consider_builtin_coroutine_candidate(
589 ecx: &mut EvalCtxt<'_, D>,
590 goal: Goal<I, Self>,
591 ) -> Result<Candidate<I>, NoSolution> {
592 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
593 return Err(NoSolution);
594 }
595
596 let self_ty = goal.predicate.self_ty();
597 let ty::Coroutine(def_id, args) = self_ty.kind() else {
598 return Err(NoSolution);
599 };
600
601 let cx = ecx.cx();
603 if !cx.is_general_coroutine(def_id) {
604 return Err(NoSolution);
605 }
606
607 let coroutine = args.as_coroutine();
608 Self::probe_and_consider_implied_clause(
609 ecx,
610 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
611 goal,
612 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
613 .upcast(cx),
614 [],
617 )
618 }
619
620 fn consider_builtin_discriminant_kind_candidate(
621 ecx: &mut EvalCtxt<'_, D>,
622 goal: Goal<I, Self>,
623 ) -> Result<Candidate<I>, NoSolution> {
624 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
625 return Err(NoSolution);
626 }
627
628 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
630 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
631 }
632
633 fn consider_builtin_destruct_candidate(
634 ecx: &mut EvalCtxt<'_, D>,
635 goal: Goal<I, Self>,
636 ) -> Result<Candidate<I>, NoSolution> {
637 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
638 return Err(NoSolution);
639 }
640
641 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
644 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
645 }
646
647 fn consider_builtin_transmute_candidate(
648 ecx: &mut EvalCtxt<'_, D>,
649 goal: Goal<I, Self>,
650 ) -> Result<Candidate<I>, NoSolution> {
651 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
652 return Err(NoSolution);
653 }
654
655 if goal.has_non_region_placeholders() {
657 return Err(NoSolution);
658 }
659
660 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
661 let assume = ecx.structurally_normalize_const(
662 goal.param_env,
663 goal.predicate.trait_ref.args.const_at(2),
664 )?;
665
666 let certainty = ecx.is_transmutable(
667 goal.predicate.trait_ref.args.type_at(0),
668 goal.predicate.trait_ref.args.type_at(1),
669 assume,
670 )?;
671 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
672 })
673 }
674
675 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
685 ecx: &mut EvalCtxt<'_, D>,
686 goal: Goal<I, Self>,
687 ) -> Result<Candidate<I>, NoSolution> {
688 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
689 return Err(NoSolution);
690 }
691
692 let cx = ecx.cx();
693 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
694 let ty = goal.predicate.self_ty();
695 match ty.kind() {
696 ty::Ref(..) => {}
698 ty::Adt(def, _) if def.is_manually_drop() => {}
700 ty::Tuple(tys) => {
703 ecx.add_goals(
704 GoalSource::ImplWhereBound,
705 tys.iter().map(|elem_ty| {
706 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
707 }),
708 );
709 }
710 ty::Array(elem_ty, _) => {
711 ecx.add_goal(
712 GoalSource::ImplWhereBound,
713 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
714 );
715 }
716
717 ty::FnDef(..)
721 | ty::FnPtr(..)
722 | ty::Error(_)
723 | ty::Uint(_)
724 | ty::Int(_)
725 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
726 | ty::Bool
727 | ty::Float(_)
728 | ty::Char
729 | ty::RawPtr(..)
730 | ty::Never
731 | ty::Pat(..)
732 | ty::Dynamic(..)
733 | ty::Str
734 | ty::Slice(_)
735 | ty::Foreign(..)
736 | ty::Adt(..)
737 | ty::Alias(..)
738 | ty::Param(_)
739 | ty::Placeholder(..)
740 | ty::Closure(..)
741 | ty::CoroutineClosure(..)
742 | ty::Coroutine(..)
743 | ty::UnsafeBinder(_)
744 | ty::CoroutineWitness(..) => {
745 ecx.add_goal(
746 GoalSource::ImplWhereBound,
747 goal.with(
748 cx,
749 ty::TraitRef::new(
750 cx,
751 cx.require_lang_item(TraitSolverLangItem::Copy),
752 [ty],
753 ),
754 ),
755 );
756 }
757
758 ty::Bound(..)
759 | ty::Infer(
760 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
761 ) => {
762 panic!("unexpected type `{ty:?}`")
763 }
764 }
765
766 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
767 })
768 }
769
770 fn consider_structural_builtin_unsize_candidates(
778 ecx: &mut EvalCtxt<'_, D>,
779 goal: Goal<I, Self>,
780 ) -> Vec<Candidate<I>> {
781 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
782 return vec![];
783 }
784
785 let result_to_single = |result| match result {
786 Ok(resp) => vec![resp],
787 Err(NoSolution) => vec![],
788 };
789
790 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
791 let a_ty = goal.predicate.self_ty();
792 let Ok(b_ty) = ecx.structurally_normalize_ty(
795 goal.param_env,
796 goal.predicate.trait_ref.args.type_at(1),
797 ) else {
798 return vec![];
799 };
800
801 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
802 match (a_ty.kind(), b_ty.kind()) {
803 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
804
805 (_, ty::Infer(ty::TyVar(..))) => {
806 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
807 }
808
809 (
811 ty::Dynamic(a_data, a_region, ty::Dyn),
812 ty::Dynamic(b_data, b_region, ty::Dyn),
813 ) => ecx.consider_builtin_dyn_upcast_candidates(
814 goal, a_data, a_region, b_data, b_region,
815 ),
816
817 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
819 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
820 ),
821
822 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
824 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
825 }
826
827 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
829 if a_def.is_struct() && a_def == b_def =>
830 {
831 result_to_single(
832 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
833 )
834 }
835
836 _ => vec![],
837 }
838 })
839 }
840}
841
842#[inline(always)]
848fn trait_predicate_with_def_id<I: Interner>(
849 cx: I,
850 clause: ty::Binder<I, ty::TraitPredicate<I>>,
851 did: I::DefId,
852) -> I::Clause {
853 clause
854 .map_bound(|c| TraitPredicate {
855 trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
856 polarity: c.polarity,
857 })
858 .upcast(cx)
859}
860
861impl<D, I> EvalCtxt<'_, D>
862where
863 D: SolverDelegate<Interner = I>,
864 I: Interner,
865{
866 fn consider_builtin_dyn_upcast_candidates(
876 &mut self,
877 goal: Goal<I, (I::Ty, I::Ty)>,
878 a_data: I::BoundExistentialPredicates,
879 a_region: I::Region,
880 b_data: I::BoundExistentialPredicates,
881 b_region: I::Region,
882 ) -> Vec<Candidate<I>> {
883 let cx = self.cx();
884 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
885
886 let mut responses = vec![];
887 let b_principal_def_id = b_data.principal_def_id();
890 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
891 responses.extend(self.consider_builtin_upcast_to_principal(
892 goal,
893 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
894 a_data,
895 a_region,
896 b_data,
897 b_region,
898 a_data.principal(),
899 ));
900 } else if let Some(a_principal) = a_data.principal() {
901 for (idx, new_a_principal) in
902 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
903 .enumerate()
904 .skip(1)
905 {
906 responses.extend(self.consider_builtin_upcast_to_principal(
907 goal,
908 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
909 a_data,
910 a_region,
911 b_data,
912 b_region,
913 Some(new_a_principal.map_bound(|trait_ref| {
914 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
915 })),
916 ));
917 }
918 }
919
920 responses
921 }
922
923 fn consider_builtin_unsize_to_dyn_candidate(
924 &mut self,
925 goal: Goal<I, (I::Ty, I::Ty)>,
926 b_data: I::BoundExistentialPredicates,
927 b_region: I::Region,
928 ) -> Result<Candidate<I>, NoSolution> {
929 let cx = self.cx();
930 let Goal { predicate: (a_ty, _), .. } = goal;
931
932 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
934 return Err(NoSolution);
935 }
936
937 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
938 ecx.add_goals(
941 GoalSource::ImplWhereBound,
942 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
943 );
944
945 ecx.add_goal(
947 GoalSource::ImplWhereBound,
948 goal.with(
949 cx,
950 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
951 ),
952 );
953
954 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
956 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
957 })
958 }
959
960 fn consider_builtin_upcast_to_principal(
961 &mut self,
962 goal: Goal<I, (I::Ty, I::Ty)>,
963 source: CandidateSource<I>,
964 a_data: I::BoundExistentialPredicates,
965 a_region: I::Region,
966 b_data: I::BoundExistentialPredicates,
967 b_region: I::Region,
968 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
969 ) -> Result<Candidate<I>, NoSolution> {
970 let param_env = goal.param_env;
971
972 let a_auto_traits: IndexSet<I::DefId> = a_data
976 .auto_traits()
977 .into_iter()
978 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
979 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
980 .filter(|def_id| self.cx().trait_is_auto(*def_id))
981 }))
982 .collect();
983
984 let projection_may_match =
989 |ecx: &mut EvalCtxt<'_, D>,
990 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
991 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
992 source_projection.item_def_id() == target_projection.item_def_id()
993 && ecx
994 .probe(|_| ProbeKind::ProjectionCompatibility)
995 .enter(|ecx| -> Result<_, NoSolution> {
996 ecx.enter_forall(target_projection, |ecx, target_projection| {
997 let source_projection =
998 ecx.instantiate_binder_with_infer(source_projection);
999 ecx.eq(param_env, source_projection, target_projection)?;
1000 ecx.try_evaluate_added_goals()
1001 })
1002 })
1003 .is_ok()
1004 };
1005
1006 self.probe_trait_candidate(source).enter(|ecx| {
1007 for bound in b_data.iter() {
1008 match bound.skip_binder() {
1009 ty::ExistentialPredicate::Trait(target_principal) => {
1012 let source_principal = upcast_principal.unwrap();
1013 let target_principal = bound.rebind(target_principal);
1014 ecx.enter_forall(target_principal, |ecx, target_principal| {
1015 let source_principal =
1016 ecx.instantiate_binder_with_infer(source_principal);
1017 ecx.eq(param_env, source_principal, target_principal)?;
1018 ecx.try_evaluate_added_goals()
1019 })?;
1020 }
1021 ty::ExistentialPredicate::Projection(target_projection) => {
1027 let target_projection = bound.rebind(target_projection);
1028 let mut matching_projections =
1029 a_data.projection_bounds().into_iter().filter(|source_projection| {
1030 projection_may_match(ecx, *source_projection, target_projection)
1031 });
1032 let Some(source_projection) = matching_projections.next() else {
1033 return Err(NoSolution);
1034 };
1035 if matching_projections.next().is_some() {
1036 return ecx.evaluate_added_goals_and_make_canonical_response(
1037 Certainty::AMBIGUOUS,
1038 );
1039 }
1040 ecx.enter_forall(target_projection, |ecx, target_projection| {
1041 let source_projection =
1042 ecx.instantiate_binder_with_infer(source_projection);
1043 ecx.eq(param_env, source_projection, target_projection)?;
1044 ecx.try_evaluate_added_goals()
1045 })?;
1046 }
1047 ty::ExistentialPredicate::AutoTrait(def_id) => {
1049 if !a_auto_traits.contains(&def_id) {
1050 return Err(NoSolution);
1051 }
1052 }
1053 }
1054 }
1055
1056 ecx.add_goal(
1058 GoalSource::ImplWhereBound,
1059 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1060 );
1061
1062 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1063 })
1064 }
1065
1066 fn consider_builtin_array_unsize(
1075 &mut self,
1076 goal: Goal<I, (I::Ty, I::Ty)>,
1077 a_elem_ty: I::Ty,
1078 b_elem_ty: I::Ty,
1079 ) -> Result<Candidate<I>, NoSolution> {
1080 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1081 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1082 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1083 }
1084
1085 fn consider_builtin_struct_unsize(
1099 &mut self,
1100 goal: Goal<I, (I::Ty, I::Ty)>,
1101 def: I::AdtDef,
1102 a_args: I::GenericArgs,
1103 b_args: I::GenericArgs,
1104 ) -> Result<Candidate<I>, NoSolution> {
1105 let cx = self.cx();
1106 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1107
1108 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1109 if unsizing_params.is_empty() {
1112 return Err(NoSolution);
1113 }
1114
1115 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1116
1117 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1118 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1119
1120 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1124 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1125 }));
1126 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1127
1128 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1131 self.add_goal(
1132 GoalSource::ImplWhereBound,
1133 goal.with(
1134 cx,
1135 ty::TraitRef::new(
1136 cx,
1137 cx.require_lang_item(TraitSolverLangItem::Unsize),
1138 [a_tail_ty, b_tail_ty],
1139 ),
1140 ),
1141 );
1142 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1143 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1144 }
1145
1146 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1151 &mut self,
1152 goal: Goal<I, TraitPredicate<I>>,
1153 ) -> Option<Result<Candidate<I>, NoSolution>> {
1154 let self_ty = goal.predicate.self_ty();
1155 let check_impls = || {
1156 let mut disqualifying_impl = None;
1157 self.cx().for_each_relevant_impl(
1158 goal.predicate.def_id(),
1159 goal.predicate.self_ty(),
1160 |impl_def_id| {
1161 disqualifying_impl = Some(impl_def_id);
1162 },
1163 );
1164 if let Some(def_id) = disqualifying_impl {
1165 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1166 return Some(Err(NoSolution));
1169 } else {
1170 None
1171 }
1172 };
1173
1174 match self_ty.kind() {
1175 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1181 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1182 }
1183
1184 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1187
1188 ty::Dynamic(..)
1191 | ty::Param(..)
1192 | ty::Foreign(..)
1193 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1194 | ty::Placeholder(..) => Some(Err(NoSolution)),
1195
1196 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1197
1198 ty::Coroutine(def_id, _)
1202 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1203 {
1204 match self.cx().coroutine_movability(def_id) {
1205 Movability::Static => Some(Err(NoSolution)),
1206 Movability::Movable => Some(
1207 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1208 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1209 }),
1210 ),
1211 }
1212 }
1213
1214 ty::Alias(..) => None,
1219
1220 ty::Bool
1227 | ty::Char
1228 | ty::Int(_)
1229 | ty::Uint(_)
1230 | ty::Float(_)
1231 | ty::Str
1232 | ty::Array(_, _)
1233 | ty::Pat(_, _)
1234 | ty::Slice(_)
1235 | ty::RawPtr(_, _)
1236 | ty::Ref(_, _, _)
1237 | ty::FnDef(_, _)
1238 | ty::FnPtr(..)
1239 | ty::Closure(..)
1240 | ty::CoroutineClosure(..)
1241 | ty::Coroutine(_, _)
1242 | ty::CoroutineWitness(..)
1243 | ty::Never
1244 | ty::Tuple(_)
1245 | ty::Adt(_, _)
1246 | ty::UnsafeBinder(_) => check_impls(),
1247 ty::Error(_) => None,
1248 }
1249 }
1250
1251 fn probe_and_evaluate_goal_for_constituent_tys(
1256 &mut self,
1257 source: CandidateSource<I>,
1258 goal: Goal<I, TraitPredicate<I>>,
1259 constituent_tys: impl Fn(
1260 &EvalCtxt<'_, D>,
1261 I::Ty,
1262 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1263 ) -> Result<Candidate<I>, NoSolution> {
1264 self.probe_trait_candidate(source).enter(|ecx| {
1265 let goals =
1266 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1267 tys.into_iter()
1268 .map(|ty| {
1269 goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty))
1270 })
1271 .collect::<Vec<_>>()
1272 });
1273 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1274 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1275 })
1276 }
1277}
1278
1279#[derive(Debug, Clone, Copy)]
1290pub(super) enum TraitGoalProvenVia {
1291 Misc,
1297 ParamEnv,
1298 AliasBound,
1299}
1300
1301impl<D, I> EvalCtxt<'_, D>
1302where
1303 D: SolverDelegate<Interner = I>,
1304 I: Interner,
1305{
1306 pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1319 match self.typing_mode() {
1320 TypingMode::Coherence => return,
1321 TypingMode::Analysis { .. }
1322 | TypingMode::Borrowck { .. }
1323 | TypingMode::PostBorrowckAnalysis { .. }
1324 | TypingMode::PostAnalysis => {}
1325 }
1326
1327 if candidates
1328 .iter()
1329 .find(|c| {
1330 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1331 })
1332 .is_some_and(|c| has_only_region_constraints(c.result))
1333 {
1334 candidates.retain(|c| {
1335 if matches!(c.source, CandidateSource::Impl(_)) {
1336 debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1337 false
1338 } else {
1339 true
1340 }
1341 });
1342 }
1343 }
1344
1345 #[instrument(level = "debug", skip(self), ret)]
1346 pub(super) fn merge_trait_candidates(
1347 &mut self,
1348 mut candidates: Vec<Candidate<I>>,
1349 failed_candidate_info: FailedCandidateInfo,
1350 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1351 if let TypingMode::Coherence = self.typing_mode() {
1352 return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1353 Ok((response, Some(TraitGoalProvenVia::Misc)))
1354 } else {
1355 self.flounder(&candidates).map(|r| (r, None))
1356 };
1357 }
1358
1359 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1364 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1365 });
1366 if let Some(candidate) = trivial_builtin_impls.next() {
1367 assert!(trivial_builtin_impls.next().is_none());
1370 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1371 }
1372
1373 let has_non_global_where_bounds = candidates
1376 .iter()
1377 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1378 if has_non_global_where_bounds {
1379 let where_bounds: Vec<_> = candidates
1380 .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
1381 .collect();
1382 if let Some((response, info)) = self.try_merge_candidates(&where_bounds) {
1383 match info {
1384 MergeCandidateInfo::AlwaysApplicable(i) => {
1400 for (j, c) in where_bounds.into_iter().enumerate() {
1401 if i != j {
1402 self.ignore_candidate_head_usages(c.head_usages)
1403 }
1404 }
1405 self.ignore_candidate_head_usages(
1409 failed_candidate_info.param_env_head_usages,
1410 );
1411 }
1412 MergeCandidateInfo::EqualResponse => {}
1413 }
1414 return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
1415 } else {
1416 return Ok((self.bail_with_ambiguity(&where_bounds), None));
1417 };
1418 }
1419
1420 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1421 let alias_bounds: Vec<_> = candidates
1422 .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
1423 .collect();
1424 return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1425 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1426 } else {
1427 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1428 };
1429 }
1430
1431 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1432 self.unsound_prefer_builtin_dyn_impl(&mut candidates);
1433
1434 let proven_via = if candidates
1439 .iter()
1440 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1441 {
1442 TraitGoalProvenVia::ParamEnv
1443 } else {
1444 candidates
1445 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1446 TraitGoalProvenVia::Misc
1447 };
1448
1449 if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1450 Ok((response, Some(proven_via)))
1451 } else {
1452 self.flounder(&candidates).map(|r| (r, None))
1453 }
1454 }
1455
1456 #[instrument(level = "trace", skip(self))]
1457 pub(super) fn compute_trait_goal(
1458 &mut self,
1459 goal: Goal<I, TraitPredicate<I>>,
1460 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1461 let (candidates, failed_candidate_info) =
1462 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1463 self.merge_trait_candidates(candidates, failed_candidate_info)
1464 }
1465
1466 fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> {
1467 if let ty::Coroutine(def_id, _) = self_ty.kind() {
1468 match self.typing_mode() {
1469 TypingMode::Analysis {
1470 defining_opaque_types_and_generators: stalled_generators,
1471 } => {
1472 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1473 {
1474 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1475 }
1476 }
1477 TypingMode::Coherence
1478 | TypingMode::PostAnalysis
1479 | TypingMode::Borrowck { defining_opaque_types: _ }
1480 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1481 }
1482 }
1483
1484 None
1485 }
1486}