1pub(super) mod structural_traits;
4
5use std::cell::Cell;
6use std::ops::ControlFlow;
7
8use derive_where::derive_where;
9use rustc_type_ir::inherent::*;
10use rustc_type_ir::lang_items::TraitSolverLangItem;
11use rustc_type_ir::solve::SizedTraitKind;
12use rustc_type_ir::{
13 self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
14 TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate,
15};
16use tracing::{debug, instrument};
17
18use super::trait_goals::TraitGoalProvenVia;
19use super::{has_only_region_constraints, inspect};
20use crate::delegate::SolverDelegate;
21use crate::solve::inspect::ProbeKind;
22use crate::solve::{
23 BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
24 MaybeCause, NoSolution, ParamEnvSource, QueryResult, has_no_inference_or_external_constraints,
25};
26
27enum AliasBoundKind {
28 SelfBounds,
29 NonSelfBounds,
30}
31
32#[derive_where(Clone, Debug; I: Interner)]
37pub(super) struct Candidate<I: Interner> {
38 pub(super) source: CandidateSource<I>,
39 pub(super) result: CanonicalResponse<I>,
40}
41
42pub(super) trait GoalKind<D, I = <D as SolverDelegate>::Interner>:
44 TypeFoldable<I> + Copy + Eq + std::fmt::Display
45where
46 D: SolverDelegate<Interner = I>,
47 I: Interner,
48{
49 fn self_ty(self) -> I::Ty;
50
51 fn trait_ref(self, cx: I) -> ty::TraitRef<I>;
52
53 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self;
54
55 fn trait_def_id(self, cx: I) -> I::DefId;
56
57 fn probe_and_consider_implied_clause(
61 ecx: &mut EvalCtxt<'_, D>,
62 parent_source: CandidateSource<I>,
63 goal: Goal<I, Self>,
64 assumption: I::Clause,
65 requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>,
66 ) -> Result<Candidate<I>, NoSolution> {
67 Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
68 for (nested_source, goal) in requirements {
69 ecx.add_goal(nested_source, goal);
70 }
71 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
72 })
73 }
74
75 fn probe_and_consider_object_bound_candidate(
79 ecx: &mut EvalCtxt<'_, D>,
80 source: CandidateSource<I>,
81 goal: Goal<I, Self>,
82 assumption: I::Clause,
83 ) -> Result<Candidate<I>, NoSolution> {
84 Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
85 let cx = ecx.cx();
86 let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
87 panic!("expected object type in `probe_and_consider_object_bound_candidate`");
88 };
89 match structural_traits::predicates_for_object_candidate(
90 ecx,
91 goal.param_env,
92 goal.predicate.trait_ref(cx),
93 bounds,
94 ) {
95 Ok(requirements) => {
96 ecx.add_goals(GoalSource::ImplWhereBound, requirements);
97 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
98 }
99 Err(_) => {
100 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
101 }
102 }
103 })
104 }
105
106 fn consider_additional_alias_assumptions(
110 ecx: &mut EvalCtxt<'_, D>,
111 goal: Goal<I, Self>,
112 alias_ty: ty::AliasTy<I>,
113 ) -> Vec<Candidate<I>>;
114
115 fn probe_and_consider_param_env_candidate(
116 ecx: &mut EvalCtxt<'_, D>,
117 goal: Goal<I, Self>,
118 assumption: I::Clause,
119 ) -> Result<Candidate<I>, NoSolution> {
120 Self::fast_reject_assumption(ecx, goal, assumption)?;
121
122 let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
129 ecx.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
130 source: source.get(),
131 result: *result,
132 })
133 .enter(|ecx| {
134 Self::match_assumption(ecx, goal, assumption, |ecx| {
135 ecx.try_evaluate_added_goals()?;
136 source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
137 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
138 })
139 })
140 .map(|result| Candidate { source: source.get(), result })
141 }
142
143 fn probe_and_match_goal_against_assumption(
148 ecx: &mut EvalCtxt<'_, D>,
149 source: CandidateSource<I>,
150 goal: Goal<I, Self>,
151 assumption: I::Clause,
152 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
153 ) -> Result<Candidate<I>, NoSolution> {
154 Self::fast_reject_assumption(ecx, goal, assumption)?;
155
156 ecx.probe_trait_candidate(source)
157 .enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
158 }
159
160 fn fast_reject_assumption(
163 ecx: &mut EvalCtxt<'_, D>,
164 goal: Goal<I, Self>,
165 assumption: I::Clause,
166 ) -> Result<(), NoSolution>;
167
168 fn match_assumption(
170 ecx: &mut EvalCtxt<'_, D>,
171 goal: Goal<I, Self>,
172 assumption: I::Clause,
173 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
174 ) -> QueryResult<I>;
175
176 fn consider_impl_candidate(
177 ecx: &mut EvalCtxt<'_, D>,
178 goal: Goal<I, Self>,
179 impl_def_id: I::DefId,
180 ) -> Result<Candidate<I>, NoSolution>;
181
182 fn consider_error_guaranteed_candidate(
189 ecx: &mut EvalCtxt<'_, D>,
190 guar: I::ErrorGuaranteed,
191 ) -> Result<Candidate<I>, NoSolution>;
192
193 fn consider_auto_trait_candidate(
198 ecx: &mut EvalCtxt<'_, D>,
199 goal: Goal<I, Self>,
200 ) -> Result<Candidate<I>, NoSolution>;
201
202 fn consider_trait_alias_candidate(
204 ecx: &mut EvalCtxt<'_, D>,
205 goal: Goal<I, Self>,
206 ) -> Result<Candidate<I>, NoSolution>;
207
208 fn consider_builtin_sizedness_candidates(
214 ecx: &mut EvalCtxt<'_, D>,
215 goal: Goal<I, Self>,
216 sizedness: SizedTraitKind,
217 ) -> Result<Candidate<I>, NoSolution>;
218
219 fn consider_builtin_copy_clone_candidate(
224 ecx: &mut EvalCtxt<'_, D>,
225 goal: Goal<I, Self>,
226 ) -> Result<Candidate<I>, NoSolution>;
227
228 fn consider_builtin_fn_ptr_trait_candidate(
230 ecx: &mut EvalCtxt<'_, D>,
231 goal: Goal<I, Self>,
232 ) -> Result<Candidate<I>, NoSolution>;
233
234 fn consider_builtin_fn_trait_candidates(
237 ecx: &mut EvalCtxt<'_, D>,
238 goal: Goal<I, Self>,
239 kind: ty::ClosureKind,
240 ) -> Result<Candidate<I>, NoSolution>;
241
242 fn consider_builtin_async_fn_trait_candidates(
245 ecx: &mut EvalCtxt<'_, D>,
246 goal: Goal<I, Self>,
247 kind: ty::ClosureKind,
248 ) -> Result<Candidate<I>, NoSolution>;
249
250 fn consider_builtin_async_fn_kind_helper_candidate(
254 ecx: &mut EvalCtxt<'_, D>,
255 goal: Goal<I, Self>,
256 ) -> Result<Candidate<I>, NoSolution>;
257
258 fn consider_builtin_tuple_candidate(
260 ecx: &mut EvalCtxt<'_, D>,
261 goal: Goal<I, Self>,
262 ) -> Result<Candidate<I>, NoSolution>;
263
264 fn consider_builtin_pointee_candidate(
270 ecx: &mut EvalCtxt<'_, D>,
271 goal: Goal<I, Self>,
272 ) -> Result<Candidate<I>, NoSolution>;
273
274 fn consider_builtin_future_candidate(
278 ecx: &mut EvalCtxt<'_, D>,
279 goal: Goal<I, Self>,
280 ) -> Result<Candidate<I>, NoSolution>;
281
282 fn consider_builtin_iterator_candidate(
286 ecx: &mut EvalCtxt<'_, D>,
287 goal: Goal<I, Self>,
288 ) -> Result<Candidate<I>, NoSolution>;
289
290 fn consider_builtin_fused_iterator_candidate(
293 ecx: &mut EvalCtxt<'_, D>,
294 goal: Goal<I, Self>,
295 ) -> Result<Candidate<I>, NoSolution>;
296
297 fn consider_builtin_async_iterator_candidate(
298 ecx: &mut EvalCtxt<'_, D>,
299 goal: Goal<I, Self>,
300 ) -> Result<Candidate<I>, NoSolution>;
301
302 fn consider_builtin_coroutine_candidate(
306 ecx: &mut EvalCtxt<'_, D>,
307 goal: Goal<I, Self>,
308 ) -> Result<Candidate<I>, NoSolution>;
309
310 fn consider_builtin_discriminant_kind_candidate(
311 ecx: &mut EvalCtxt<'_, D>,
312 goal: Goal<I, Self>,
313 ) -> Result<Candidate<I>, NoSolution>;
314
315 fn consider_builtin_destruct_candidate(
316 ecx: &mut EvalCtxt<'_, D>,
317 goal: Goal<I, Self>,
318 ) -> Result<Candidate<I>, NoSolution>;
319
320 fn consider_builtin_transmute_candidate(
321 ecx: &mut EvalCtxt<'_, D>,
322 goal: Goal<I, Self>,
323 ) -> Result<Candidate<I>, NoSolution>;
324
325 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
326 ecx: &mut EvalCtxt<'_, D>,
327 goal: Goal<I, Self>,
328 ) -> Result<Candidate<I>, NoSolution>;
329
330 fn consider_structural_builtin_unsize_candidates(
338 ecx: &mut EvalCtxt<'_, D>,
339 goal: Goal<I, Self>,
340 ) -> Vec<Candidate<I>>;
341}
342
343pub(super) enum AssembleCandidatesFrom {
351 All,
352 EnvAndBounds,
356}
357
358impl<D, I> EvalCtxt<'_, D>
359where
360 D: SolverDelegate<Interner = I>,
361 I: Interner,
362{
363 pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
364 &mut self,
365 goal: Goal<I, G>,
366 assemble_from: AssembleCandidatesFrom,
367 ) -> Vec<Candidate<I>> {
368 let Ok(normalized_self_ty) =
369 self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
370 else {
371 return vec![];
372 };
373
374 if normalized_self_ty.is_ty_var() {
375 debug!("self type has been normalized to infer");
376 return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
377 }
378
379 let goal: Goal<I, G> = goal
380 .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
381 let goal = self.resolve_vars_if_possible(goal);
384
385 let mut candidates = vec![];
386
387 if let TypingMode::Coherence = self.typing_mode()
388 && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
389 {
390 return vec![candidate];
391 }
392
393 self.assemble_alias_bound_candidates(goal, &mut candidates);
394 self.assemble_param_env_candidates(goal, &mut candidates);
395
396 match assemble_from {
397 AssembleCandidatesFrom::All => {
398 self.assemble_builtin_impl_candidates(goal, &mut candidates);
399 if TypingMode::Coherence == self.typing_mode()
411 || !candidates.iter().any(|c| {
412 matches!(
413 c.source,
414 CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
415 | CandidateSource::AliasBound
416 ) && has_no_inference_or_external_constraints(c.result)
417 })
418 {
419 self.assemble_impl_candidates(goal, &mut candidates);
420 self.assemble_object_bound_candidates(goal, &mut candidates);
421 }
422 }
423 AssembleCandidatesFrom::EnvAndBounds => {}
424 }
425
426 candidates
427 }
428
429 pub(super) fn forced_ambiguity(
430 &mut self,
431 cause: MaybeCause,
432 ) -> Result<Candidate<I>, NoSolution> {
433 let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
439 let certainty = Certainty::Maybe(cause);
440 self.probe_trait_candidate(source)
441 .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
442 }
443
444 #[instrument(level = "trace", skip_all)]
445 fn assemble_impl_candidates<G: GoalKind<D>>(
446 &mut self,
447 goal: Goal<I, G>,
448 candidates: &mut Vec<Candidate<I>>,
449 ) {
450 let cx = self.cx();
451 cx.for_each_relevant_impl(
452 goal.predicate.trait_def_id(cx),
453 goal.predicate.self_ty(),
454 |impl_def_id| {
455 if cx.impl_is_default(impl_def_id) {
459 return;
460 }
461
462 match G::consider_impl_candidate(self, goal, impl_def_id) {
463 Ok(candidate) => candidates.push(candidate),
464 Err(NoSolution) => (),
465 }
466 },
467 );
468 }
469
470 #[instrument(level = "trace", skip_all)]
471 fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
472 &mut self,
473 goal: Goal<I, G>,
474 candidates: &mut Vec<Candidate<I>>,
475 ) {
476 let cx = self.cx();
477 let trait_def_id = goal.predicate.trait_def_id(cx);
478
479 let result = if let Err(guar) = goal.predicate.error_reported() {
487 G::consider_error_guaranteed_candidate(self, guar)
488 } else if cx.trait_is_auto(trait_def_id) {
489 G::consider_auto_trait_candidate(self, goal)
490 } else if cx.trait_is_alias(trait_def_id) {
491 G::consider_trait_alias_candidate(self, goal)
492 } else {
493 match cx.as_lang_item(trait_def_id) {
494 Some(TraitSolverLangItem::Sized) => {
495 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
496 }
497 Some(TraitSolverLangItem::MetaSized) => {
498 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
499 }
500 Some(TraitSolverLangItem::PointeeSized) => {
501 unreachable!("`PointeeSized` is removed during lowering");
502 }
503 Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
504 G::consider_builtin_copy_clone_candidate(self, goal)
505 }
506 Some(TraitSolverLangItem::Fn) => {
507 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
508 }
509 Some(TraitSolverLangItem::FnMut) => {
510 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
511 }
512 Some(TraitSolverLangItem::FnOnce) => {
513 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
514 }
515 Some(TraitSolverLangItem::AsyncFn) => {
516 G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
517 }
518 Some(TraitSolverLangItem::AsyncFnMut) => {
519 G::consider_builtin_async_fn_trait_candidates(
520 self,
521 goal,
522 ty::ClosureKind::FnMut,
523 )
524 }
525 Some(TraitSolverLangItem::AsyncFnOnce) => {
526 G::consider_builtin_async_fn_trait_candidates(
527 self,
528 goal,
529 ty::ClosureKind::FnOnce,
530 )
531 }
532 Some(TraitSolverLangItem::FnPtrTrait) => {
533 G::consider_builtin_fn_ptr_trait_candidate(self, goal)
534 }
535 Some(TraitSolverLangItem::AsyncFnKindHelper) => {
536 G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
537 }
538 Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
539 Some(TraitSolverLangItem::PointeeTrait) => {
540 G::consider_builtin_pointee_candidate(self, goal)
541 }
542 Some(TraitSolverLangItem::Future) => {
543 G::consider_builtin_future_candidate(self, goal)
544 }
545 Some(TraitSolverLangItem::Iterator) => {
546 G::consider_builtin_iterator_candidate(self, goal)
547 }
548 Some(TraitSolverLangItem::FusedIterator) => {
549 G::consider_builtin_fused_iterator_candidate(self, goal)
550 }
551 Some(TraitSolverLangItem::AsyncIterator) => {
552 G::consider_builtin_async_iterator_candidate(self, goal)
553 }
554 Some(TraitSolverLangItem::Coroutine) => {
555 G::consider_builtin_coroutine_candidate(self, goal)
556 }
557 Some(TraitSolverLangItem::DiscriminantKind) => {
558 G::consider_builtin_discriminant_kind_candidate(self, goal)
559 }
560 Some(TraitSolverLangItem::Destruct) => {
561 G::consider_builtin_destruct_candidate(self, goal)
562 }
563 Some(TraitSolverLangItem::TransmuteTrait) => {
564 G::consider_builtin_transmute_candidate(self, goal)
565 }
566 Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => {
567 G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
568 }
569 _ => Err(NoSolution),
570 }
571 };
572
573 candidates.extend(result);
574
575 if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
578 candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
579 }
580 }
581
582 #[instrument(level = "trace", skip_all)]
583 fn assemble_param_env_candidates<G: GoalKind<D>>(
584 &mut self,
585 goal: Goal<I, G>,
586 candidates: &mut Vec<Candidate<I>>,
587 ) {
588 for assumption in goal.param_env.caller_bounds().iter() {
589 candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
590 }
591 }
592
593 #[instrument(level = "trace", skip_all)]
594 fn assemble_alias_bound_candidates<G: GoalKind<D>>(
595 &mut self,
596 goal: Goal<I, G>,
597 candidates: &mut Vec<Candidate<I>>,
598 ) {
599 let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
600 ecx.assemble_alias_bound_candidates_recur(
601 goal.predicate.self_ty(),
602 goal,
603 candidates,
604 AliasBoundKind::SelfBounds,
605 );
606 });
607 }
608
609 fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
619 &mut self,
620 self_ty: I::Ty,
621 goal: Goal<I, G>,
622 candidates: &mut Vec<Candidate<I>>,
623 consider_self_bounds: AliasBoundKind,
624 ) {
625 let (kind, alias_ty) = match self_ty.kind() {
626 ty::Bool
627 | ty::Char
628 | ty::Int(_)
629 | ty::Uint(_)
630 | ty::Float(_)
631 | ty::Adt(_, _)
632 | ty::Foreign(_)
633 | ty::Str
634 | ty::Array(_, _)
635 | ty::Pat(_, _)
636 | ty::Slice(_)
637 | ty::RawPtr(_, _)
638 | ty::Ref(_, _, _)
639 | ty::FnDef(_, _)
640 | ty::FnPtr(..)
641 | ty::UnsafeBinder(_)
642 | ty::Dynamic(..)
643 | ty::Closure(..)
644 | ty::CoroutineClosure(..)
645 | ty::Coroutine(..)
646 | ty::CoroutineWitness(..)
647 | ty::Never
648 | ty::Tuple(_)
649 | ty::Param(_)
650 | ty::Placeholder(..)
651 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
652 | ty::Error(_) => return,
653 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
654 panic!("unexpected self type for `{goal:?}`")
655 }
656
657 ty::Infer(ty::TyVar(_)) => {
658 if let Ok(result) =
662 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
663 {
664 candidates.push(Candidate { source: CandidateSource::AliasBound, result });
665 }
666 return;
667 }
668
669 ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
670 ty::Alias(ty::Inherent | ty::Free, _) => {
671 self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
672 return;
673 }
674 };
675
676 match consider_self_bounds {
677 AliasBoundKind::SelfBounds => {
678 for assumption in self
679 .cx()
680 .item_self_bounds(alias_ty.def_id)
681 .iter_instantiated(self.cx(), alias_ty.args)
682 {
683 candidates.extend(G::probe_and_consider_implied_clause(
684 self,
685 CandidateSource::AliasBound,
686 goal,
687 assumption,
688 [],
689 ));
690 }
691 }
692 AliasBoundKind::NonSelfBounds => {
693 for assumption in self
694 .cx()
695 .item_non_self_bounds(alias_ty.def_id)
696 .iter_instantiated(self.cx(), alias_ty.args)
697 {
698 candidates.extend(G::probe_and_consider_implied_clause(
699 self,
700 CandidateSource::AliasBound,
701 goal,
702 assumption,
703 [],
704 ));
705 }
706 }
707 }
708
709 candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
710
711 if kind != ty::Projection {
712 return;
713 }
714
715 match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
717 Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
718 next_self_ty,
719 goal,
720 candidates,
721 AliasBoundKind::NonSelfBounds,
722 ),
723 Err(NoSolution) => {}
724 }
725 }
726
727 #[instrument(level = "trace", skip_all)]
728 fn assemble_object_bound_candidates<G: GoalKind<D>>(
729 &mut self,
730 goal: Goal<I, G>,
731 candidates: &mut Vec<Candidate<I>>,
732 ) {
733 let cx = self.cx();
734 if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) {
735 return;
736 }
737
738 let self_ty = goal.predicate.self_ty();
739 let bounds = match self_ty.kind() {
740 ty::Bool
741 | ty::Char
742 | ty::Int(_)
743 | ty::Uint(_)
744 | ty::Float(_)
745 | ty::Adt(_, _)
746 | ty::Foreign(_)
747 | ty::Str
748 | ty::Array(_, _)
749 | ty::Pat(_, _)
750 | ty::Slice(_)
751 | ty::RawPtr(_, _)
752 | ty::Ref(_, _, _)
753 | ty::FnDef(_, _)
754 | ty::FnPtr(..)
755 | ty::UnsafeBinder(_)
756 | ty::Alias(..)
757 | ty::Closure(..)
758 | ty::CoroutineClosure(..)
759 | ty::Coroutine(..)
760 | ty::CoroutineWitness(..)
761 | ty::Never
762 | ty::Tuple(_)
763 | ty::Param(_)
764 | ty::Placeholder(..)
765 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
766 | ty::Error(_) => return,
767 ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
768 | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
769 ty::Dynamic(bounds, ..) => bounds,
770 };
771
772 if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
774 return;
775 }
776
777 for bound in bounds.iter() {
781 match bound.skip_binder() {
782 ty::ExistentialPredicate::Trait(_) => {
783 }
785 ty::ExistentialPredicate::Projection(_)
786 | ty::ExistentialPredicate::AutoTrait(_) => {
787 candidates.extend(G::probe_and_consider_object_bound_candidate(
788 self,
789 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
790 goal,
791 bound.with_self_ty(cx, self_ty),
792 ));
793 }
794 }
795 }
796
797 if let Some(principal) = bounds.principal() {
801 let principal_trait_ref = principal.with_self_ty(cx, self_ty);
802 for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
803 candidates.extend(G::probe_and_consider_object_bound_candidate(
804 self,
805 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
806 goal,
807 assumption.upcast(cx),
808 ));
809 }
810 }
811 }
812
813 #[instrument(level = "trace", skip_all)]
820 fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
821 &mut self,
822 goal: Goal<I, G>,
823 ) -> Result<Candidate<I>, NoSolution> {
824 self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
825 let cx = ecx.cx();
826 let trait_ref = goal.predicate.trait_ref(cx);
827 if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
828 Err(NoSolution)
829 } else {
830 let predicate: I::Predicate = trait_ref.upcast(cx);
836 ecx.add_goals(
837 GoalSource::Misc,
838 elaborate::elaborate(cx, [predicate])
839 .skip(1)
840 .map(|predicate| goal.with(cx, predicate)),
841 );
842 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
843 }
844 })
845 }
846}
847
848pub(super) enum AllowInferenceConstraints {
849 Yes,
850 No,
851}
852
853impl<D, I> EvalCtxt<'_, D>
854where
855 D: SolverDelegate<Interner = I>,
856 I: Interner,
857{
858 pub(super) fn filter_specialized_impls(
862 &mut self,
863 allow_inference_constraints: AllowInferenceConstraints,
864 candidates: &mut Vec<Candidate<I>>,
865 ) {
866 match self.typing_mode() {
867 TypingMode::Coherence => return,
868 TypingMode::Analysis { .. }
869 | TypingMode::Borrowck { .. }
870 | TypingMode::PostBorrowckAnalysis { .. }
871 | TypingMode::PostAnalysis => {}
872 }
873
874 let mut i = 0;
875 'outer: while i < candidates.len() {
876 let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
877 i += 1;
878 continue;
879 };
880
881 for (j, c) in candidates.iter().enumerate() {
882 if i == j {
883 continue;
884 }
885
886 let CandidateSource::Impl(other_def_id) = c.source else {
887 continue;
888 };
889
890 if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
897 || has_only_region_constraints(c.result)
898 {
899 if self.cx().impl_specializes(other_def_id, victim_def_id) {
900 candidates.remove(i);
901 continue 'outer;
902 }
903 }
904 }
905
906 i += 1;
907 }
908 }
909
910 #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
941 pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
942 &mut self,
943 proven_via: Option<TraitGoalProvenVia>,
944 goal: Goal<I, G>,
945 inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
946 ) -> QueryResult<I> {
947 let Some(proven_via) = proven_via else {
948 return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
955 };
956
957 match proven_via {
958 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
959 let mut candidates: Vec<_> = self
963 .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
964
965 if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
968 candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
969 } else if candidates.is_empty() {
970 return inject_normalize_to_rigid_candidate(self);
973 }
974
975 if let Some(response) = self.try_merge_candidates(&candidates) {
976 Ok(response)
977 } else {
978 self.flounder(&candidates)
979 }
980 }
981 TraitGoalProvenVia::Misc => {
982 let mut candidates =
983 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
984
985 let candidates_from_env: Vec<_> = candidates
988 .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
989 .collect();
990 if let Some(response) = self.try_merge_candidates(&candidates_from_env) {
991 return Ok(response);
992 }
993
994 self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
1000 if let Some(response) = self.try_merge_candidates(&candidates) {
1001 Ok(response)
1002 } else {
1003 self.flounder(&candidates)
1004 }
1005 }
1006 }
1007 }
1008
1009 fn characterize_param_env_assumption(
1023 &mut self,
1024 param_env: I::ParamEnv,
1025 assumption: I::Clause,
1026 ) -> Result<CandidateSource<I>, NoSolution> {
1027 if assumption.has_bound_vars() {
1030 return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1031 }
1032
1033 match assumption.visit_with(&mut FindParamInClause {
1034 ecx: self,
1035 param_env,
1036 universes: vec![],
1037 }) {
1038 ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1039 ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1040 ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1041 }
1042 }
1043}
1044
1045struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
1046 ecx: &'a mut EvalCtxt<'b, D>,
1047 param_env: I::ParamEnv,
1048 universes: Vec<Option<ty::UniverseIndex>>,
1049}
1050
1051impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
1052where
1053 D: SolverDelegate<Interner = I>,
1054 I: Interner,
1055{
1056 type Result = ControlFlow<Result<(), NoSolution>>;
1057
1058 fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
1059 self.universes.push(None);
1060 t.super_visit_with(self)?;
1061 self.universes.pop();
1062 ControlFlow::Continue(())
1063 }
1064
1065 fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
1066 let ty = self.ecx.replace_bound_vars(ty, &mut self.universes);
1067 let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
1068 return ControlFlow::Break(Err(NoSolution));
1069 };
1070
1071 if let ty::Placeholder(p) = ty.kind() {
1072 if p.universe() == ty::UniverseIndex::ROOT {
1073 ControlFlow::Break(Ok(()))
1074 } else {
1075 ControlFlow::Continue(())
1076 }
1077 } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1078 ty.super_visit_with(self)
1079 } else {
1080 ControlFlow::Continue(())
1081 }
1082 }
1083
1084 fn visit_const(&mut self, ct: I::Const) -> Self::Result {
1085 let ct = self.ecx.replace_bound_vars(ct, &mut self.universes);
1086 let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
1087 return ControlFlow::Break(Err(NoSolution));
1088 };
1089
1090 if let ty::ConstKind::Placeholder(p) = ct.kind() {
1091 if p.universe() == ty::UniverseIndex::ROOT {
1092 ControlFlow::Break(Ok(()))
1093 } else {
1094 ControlFlow::Continue(())
1095 }
1096 } else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1097 ct.super_visit_with(self)
1098 } else {
1099 ControlFlow::Continue(())
1100 }
1101 }
1102
1103 fn visit_region(&mut self, r: I::Region) -> Self::Result {
1104 match self.ecx.eager_resolve_region(r).kind() {
1105 ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()),
1106 ty::RePlaceholder(p) => {
1107 if p.universe() == ty::UniverseIndex::ROOT {
1108 ControlFlow::Break(Ok(()))
1109 } else {
1110 ControlFlow::Continue(())
1111 }
1112 }
1113 ty::ReVar(_) => ControlFlow::Break(Ok(())),
1114 ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
1115 unreachable!("unexpected region in param-env clause")
1116 }
1117 }
1118 }
1119}