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, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _,
14 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,
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_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 source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
136 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
137 })
138 })
139 .map(|result| Candidate { source: source.get(), result })
140 }
141
142 fn probe_and_match_goal_against_assumption(
147 ecx: &mut EvalCtxt<'_, D>,
148 source: CandidateSource<I>,
149 goal: Goal<I, Self>,
150 assumption: I::Clause,
151 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
152 ) -> Result<Candidate<I>, NoSolution> {
153 Self::fast_reject_assumption(ecx, goal, assumption)?;
154
155 ecx.probe_trait_candidate(source)
156 .enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
157 }
158
159 fn fast_reject_assumption(
162 ecx: &mut EvalCtxt<'_, D>,
163 goal: Goal<I, Self>,
164 assumption: I::Clause,
165 ) -> Result<(), NoSolution>;
166
167 fn match_assumption(
169 ecx: &mut EvalCtxt<'_, D>,
170 goal: Goal<I, Self>,
171 assumption: I::Clause,
172 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
173 ) -> QueryResult<I>;
174
175 fn consider_impl_candidate(
176 ecx: &mut EvalCtxt<'_, D>,
177 goal: Goal<I, Self>,
178 impl_def_id: I::DefId,
179 ) -> Result<Candidate<I>, NoSolution>;
180
181 fn consider_error_guaranteed_candidate(
188 ecx: &mut EvalCtxt<'_, D>,
189 guar: I::ErrorGuaranteed,
190 ) -> Result<Candidate<I>, NoSolution>;
191
192 fn consider_auto_trait_candidate(
197 ecx: &mut EvalCtxt<'_, D>,
198 goal: Goal<I, Self>,
199 ) -> Result<Candidate<I>, NoSolution>;
200
201 fn consider_trait_alias_candidate(
203 ecx: &mut EvalCtxt<'_, D>,
204 goal: Goal<I, Self>,
205 ) -> Result<Candidate<I>, NoSolution>;
206
207 fn consider_builtin_sizedness_candidates(
213 ecx: &mut EvalCtxt<'_, D>,
214 goal: Goal<I, Self>,
215 sizedness: SizedTraitKind,
216 ) -> Result<Candidate<I>, NoSolution>;
217
218 fn consider_builtin_copy_clone_candidate(
223 ecx: &mut EvalCtxt<'_, D>,
224 goal: Goal<I, Self>,
225 ) -> Result<Candidate<I>, NoSolution>;
226
227 fn consider_builtin_fn_ptr_trait_candidate(
229 ecx: &mut EvalCtxt<'_, D>,
230 goal: Goal<I, Self>,
231 ) -> Result<Candidate<I>, NoSolution>;
232
233 fn consider_builtin_fn_trait_candidates(
236 ecx: &mut EvalCtxt<'_, D>,
237 goal: Goal<I, Self>,
238 kind: ty::ClosureKind,
239 ) -> Result<Candidate<I>, NoSolution>;
240
241 fn consider_builtin_async_fn_trait_candidates(
244 ecx: &mut EvalCtxt<'_, D>,
245 goal: Goal<I, Self>,
246 kind: ty::ClosureKind,
247 ) -> Result<Candidate<I>, NoSolution>;
248
249 fn consider_builtin_async_fn_kind_helper_candidate(
253 ecx: &mut EvalCtxt<'_, D>,
254 goal: Goal<I, Self>,
255 ) -> Result<Candidate<I>, NoSolution>;
256
257 fn consider_builtin_tuple_candidate(
259 ecx: &mut EvalCtxt<'_, D>,
260 goal: Goal<I, Self>,
261 ) -> Result<Candidate<I>, NoSolution>;
262
263 fn consider_builtin_pointee_candidate(
269 ecx: &mut EvalCtxt<'_, D>,
270 goal: Goal<I, Self>,
271 ) -> Result<Candidate<I>, NoSolution>;
272
273 fn consider_builtin_future_candidate(
277 ecx: &mut EvalCtxt<'_, D>,
278 goal: Goal<I, Self>,
279 ) -> Result<Candidate<I>, NoSolution>;
280
281 fn consider_builtin_iterator_candidate(
285 ecx: &mut EvalCtxt<'_, D>,
286 goal: Goal<I, Self>,
287 ) -> Result<Candidate<I>, NoSolution>;
288
289 fn consider_builtin_fused_iterator_candidate(
292 ecx: &mut EvalCtxt<'_, D>,
293 goal: Goal<I, Self>,
294 ) -> Result<Candidate<I>, NoSolution>;
295
296 fn consider_builtin_async_iterator_candidate(
297 ecx: &mut EvalCtxt<'_, D>,
298 goal: Goal<I, Self>,
299 ) -> Result<Candidate<I>, NoSolution>;
300
301 fn consider_builtin_coroutine_candidate(
305 ecx: &mut EvalCtxt<'_, D>,
306 goal: Goal<I, Self>,
307 ) -> Result<Candidate<I>, NoSolution>;
308
309 fn consider_builtin_discriminant_kind_candidate(
310 ecx: &mut EvalCtxt<'_, D>,
311 goal: Goal<I, Self>,
312 ) -> Result<Candidate<I>, NoSolution>;
313
314 fn consider_builtin_destruct_candidate(
315 ecx: &mut EvalCtxt<'_, D>,
316 goal: Goal<I, Self>,
317 ) -> Result<Candidate<I>, NoSolution>;
318
319 fn consider_builtin_transmute_candidate(
320 ecx: &mut EvalCtxt<'_, D>,
321 goal: Goal<I, Self>,
322 ) -> Result<Candidate<I>, NoSolution>;
323
324 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
325 ecx: &mut EvalCtxt<'_, D>,
326 goal: Goal<I, Self>,
327 ) -> Result<Candidate<I>, NoSolution>;
328
329 fn consider_structural_builtin_unsize_candidates(
337 ecx: &mut EvalCtxt<'_, D>,
338 goal: Goal<I, Self>,
339 ) -> Vec<Candidate<I>>;
340}
341
342pub(super) enum AssembleCandidatesFrom {
350 All,
351 EnvAndBounds,
355}
356
357impl<D, I> EvalCtxt<'_, D>
358where
359 D: SolverDelegate<Interner = I>,
360 I: Interner,
361{
362 pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
363 &mut self,
364 goal: Goal<I, G>,
365 assemble_from: AssembleCandidatesFrom,
366 ) -> Vec<Candidate<I>> {
367 let Ok(normalized_self_ty) =
368 self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
369 else {
370 return vec![];
371 };
372
373 if normalized_self_ty.is_ty_var() {
374 debug!("self type has been normalized to infer");
375 return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
376 }
377
378 let goal: Goal<I, G> =
379 goal.with(self.cx(), goal.predicate.with_self_ty(self.cx(), normalized_self_ty));
380 let goal = self.resolve_vars_if_possible(goal);
383
384 let mut candidates = vec![];
385
386 if let TypingMode::Coherence = self.typing_mode() {
387 if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
388 return vec![candidate];
389 }
390 }
391
392 self.assemble_alias_bound_candidates(goal, &mut candidates);
393 self.assemble_param_env_candidates(goal, &mut candidates);
394
395 match assemble_from {
396 AssembleCandidatesFrom::All => {
397 self.assemble_impl_candidates(goal, &mut candidates);
398 self.assemble_builtin_impl_candidates(goal, &mut candidates);
399 self.assemble_object_bound_candidates(goal, &mut candidates);
400 }
401 AssembleCandidatesFrom::EnvAndBounds => {}
402 }
403
404 candidates
405 }
406
407 pub(super) fn forced_ambiguity(
408 &mut self,
409 cause: MaybeCause,
410 ) -> Result<Candidate<I>, NoSolution> {
411 let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
417 let certainty = Certainty::Maybe(cause);
418 self.probe_trait_candidate(source)
419 .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
420 }
421
422 #[instrument(level = "trace", skip_all)]
423 fn assemble_impl_candidates<G: GoalKind<D>>(
424 &mut self,
425 goal: Goal<I, G>,
426 candidates: &mut Vec<Candidate<I>>,
427 ) {
428 let cx = self.cx();
429 cx.for_each_relevant_impl(
430 goal.predicate.trait_def_id(cx),
431 goal.predicate.self_ty(),
432 |impl_def_id| {
433 if cx.impl_is_default(impl_def_id) {
437 return;
438 }
439
440 match G::consider_impl_candidate(self, goal, impl_def_id) {
441 Ok(candidate) => candidates.push(candidate),
442 Err(NoSolution) => (),
443 }
444 },
445 );
446 }
447
448 #[instrument(level = "trace", skip_all)]
449 fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
450 &mut self,
451 goal: Goal<I, G>,
452 candidates: &mut Vec<Candidate<I>>,
453 ) {
454 let cx = self.cx();
455 let trait_def_id = goal.predicate.trait_def_id(cx);
456
457 let result = if let Err(guar) = goal.predicate.error_reported() {
465 G::consider_error_guaranteed_candidate(self, guar)
466 } else if cx.trait_is_auto(trait_def_id) {
467 G::consider_auto_trait_candidate(self, goal)
468 } else if cx.trait_is_alias(trait_def_id) {
469 G::consider_trait_alias_candidate(self, goal)
470 } else {
471 match cx.as_lang_item(trait_def_id) {
472 Some(TraitSolverLangItem::Sized) => {
473 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
474 }
475 Some(TraitSolverLangItem::MetaSized) => {
476 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
477 }
478 Some(TraitSolverLangItem::PointeeSized) => {
479 unreachable!("`PointeeSized` is removed during lowering");
480 }
481 Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
482 G::consider_builtin_copy_clone_candidate(self, goal)
483 }
484 Some(TraitSolverLangItem::Fn) => {
485 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
486 }
487 Some(TraitSolverLangItem::FnMut) => {
488 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
489 }
490 Some(TraitSolverLangItem::FnOnce) => {
491 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
492 }
493 Some(TraitSolverLangItem::AsyncFn) => {
494 G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
495 }
496 Some(TraitSolverLangItem::AsyncFnMut) => {
497 G::consider_builtin_async_fn_trait_candidates(
498 self,
499 goal,
500 ty::ClosureKind::FnMut,
501 )
502 }
503 Some(TraitSolverLangItem::AsyncFnOnce) => {
504 G::consider_builtin_async_fn_trait_candidates(
505 self,
506 goal,
507 ty::ClosureKind::FnOnce,
508 )
509 }
510 Some(TraitSolverLangItem::FnPtrTrait) => {
511 G::consider_builtin_fn_ptr_trait_candidate(self, goal)
512 }
513 Some(TraitSolverLangItem::AsyncFnKindHelper) => {
514 G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
515 }
516 Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
517 Some(TraitSolverLangItem::PointeeTrait) => {
518 G::consider_builtin_pointee_candidate(self, goal)
519 }
520 Some(TraitSolverLangItem::Future) => {
521 G::consider_builtin_future_candidate(self, goal)
522 }
523 Some(TraitSolverLangItem::Iterator) => {
524 G::consider_builtin_iterator_candidate(self, goal)
525 }
526 Some(TraitSolverLangItem::FusedIterator) => {
527 G::consider_builtin_fused_iterator_candidate(self, goal)
528 }
529 Some(TraitSolverLangItem::AsyncIterator) => {
530 G::consider_builtin_async_iterator_candidate(self, goal)
531 }
532 Some(TraitSolverLangItem::Coroutine) => {
533 G::consider_builtin_coroutine_candidate(self, goal)
534 }
535 Some(TraitSolverLangItem::DiscriminantKind) => {
536 G::consider_builtin_discriminant_kind_candidate(self, goal)
537 }
538 Some(TraitSolverLangItem::Destruct) => {
539 G::consider_builtin_destruct_candidate(self, goal)
540 }
541 Some(TraitSolverLangItem::TransmuteTrait) => {
542 G::consider_builtin_transmute_candidate(self, goal)
543 }
544 Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => {
545 G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
546 }
547 _ => Err(NoSolution),
548 }
549 };
550
551 candidates.extend(result);
552
553 if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
556 candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
557 }
558 }
559
560 #[instrument(level = "trace", skip_all)]
561 fn assemble_param_env_candidates<G: GoalKind<D>>(
562 &mut self,
563 goal: Goal<I, G>,
564 candidates: &mut Vec<Candidate<I>>,
565 ) {
566 for assumption in goal.param_env.caller_bounds().iter() {
567 candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
568 }
569 }
570
571 #[instrument(level = "trace", skip_all)]
572 fn assemble_alias_bound_candidates<G: GoalKind<D>>(
573 &mut self,
574 goal: Goal<I, G>,
575 candidates: &mut Vec<Candidate<I>>,
576 ) {
577 let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
578 ecx.assemble_alias_bound_candidates_recur(
579 goal.predicate.self_ty(),
580 goal,
581 candidates,
582 AliasBoundKind::SelfBounds,
583 );
584 });
585 }
586
587 fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
597 &mut self,
598 self_ty: I::Ty,
599 goal: Goal<I, G>,
600 candidates: &mut Vec<Candidate<I>>,
601 consider_self_bounds: AliasBoundKind,
602 ) {
603 let (kind, alias_ty) = match self_ty.kind() {
604 ty::Bool
605 | ty::Char
606 | ty::Int(_)
607 | ty::Uint(_)
608 | ty::Float(_)
609 | ty::Adt(_, _)
610 | ty::Foreign(_)
611 | ty::Str
612 | ty::Array(_, _)
613 | ty::Pat(_, _)
614 | ty::Slice(_)
615 | ty::RawPtr(_, _)
616 | ty::Ref(_, _, _)
617 | ty::FnDef(_, _)
618 | ty::FnPtr(..)
619 | ty::UnsafeBinder(_)
620 | ty::Dynamic(..)
621 | ty::Closure(..)
622 | ty::CoroutineClosure(..)
623 | ty::Coroutine(..)
624 | ty::CoroutineWitness(..)
625 | ty::Never
626 | ty::Tuple(_)
627 | ty::Param(_)
628 | ty::Placeholder(..)
629 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
630 | ty::Error(_) => return,
631 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
632 panic!("unexpected self type for `{goal:?}`")
633 }
634
635 ty::Infer(ty::TyVar(_)) => {
636 if let Ok(result) =
640 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
641 {
642 candidates.push(Candidate { source: CandidateSource::AliasBound, result });
643 }
644 return;
645 }
646
647 ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
648 ty::Alias(ty::Inherent | ty::Free, _) => {
649 self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
650 return;
651 }
652 };
653
654 match consider_self_bounds {
655 AliasBoundKind::SelfBounds => {
656 for assumption in self
657 .cx()
658 .item_self_bounds(alias_ty.def_id)
659 .iter_instantiated(self.cx(), alias_ty.args)
660 {
661 candidates.extend(G::probe_and_consider_implied_clause(
662 self,
663 CandidateSource::AliasBound,
664 goal,
665 assumption,
666 [],
667 ));
668 }
669 }
670 AliasBoundKind::NonSelfBounds => {
671 for assumption in self
672 .cx()
673 .item_non_self_bounds(alias_ty.def_id)
674 .iter_instantiated(self.cx(), alias_ty.args)
675 {
676 candidates.extend(G::probe_and_consider_implied_clause(
677 self,
678 CandidateSource::AliasBound,
679 goal,
680 assumption,
681 [],
682 ));
683 }
684 }
685 }
686
687 candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
688
689 if kind != ty::Projection {
690 return;
691 }
692
693 match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
695 Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
696 next_self_ty,
697 goal,
698 candidates,
699 AliasBoundKind::NonSelfBounds,
700 ),
701 Err(NoSolution) => {}
702 }
703 }
704
705 #[instrument(level = "trace", skip_all)]
706 fn assemble_object_bound_candidates<G: GoalKind<D>>(
707 &mut self,
708 goal: Goal<I, G>,
709 candidates: &mut Vec<Candidate<I>>,
710 ) {
711 let cx = self.cx();
712 if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) {
713 return;
714 }
715
716 let self_ty = goal.predicate.self_ty();
717 let bounds = match self_ty.kind() {
718 ty::Bool
719 | ty::Char
720 | ty::Int(_)
721 | ty::Uint(_)
722 | ty::Float(_)
723 | ty::Adt(_, _)
724 | ty::Foreign(_)
725 | ty::Str
726 | ty::Array(_, _)
727 | ty::Pat(_, _)
728 | ty::Slice(_)
729 | ty::RawPtr(_, _)
730 | ty::Ref(_, _, _)
731 | ty::FnDef(_, _)
732 | ty::FnPtr(..)
733 | ty::UnsafeBinder(_)
734 | ty::Alias(..)
735 | ty::Closure(..)
736 | ty::CoroutineClosure(..)
737 | ty::Coroutine(..)
738 | ty::CoroutineWitness(..)
739 | ty::Never
740 | ty::Tuple(_)
741 | ty::Param(_)
742 | ty::Placeholder(..)
743 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
744 | ty::Error(_) => return,
745 ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
746 | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
747 ty::Dynamic(bounds, ..) => bounds,
748 };
749
750 if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
752 return;
753 }
754
755 for bound in bounds.iter() {
759 match bound.skip_binder() {
760 ty::ExistentialPredicate::Trait(_) => {
761 }
763 ty::ExistentialPredicate::Projection(_)
764 | ty::ExistentialPredicate::AutoTrait(_) => {
765 candidates.extend(G::probe_and_consider_object_bound_candidate(
766 self,
767 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
768 goal,
769 bound.with_self_ty(cx, self_ty),
770 ));
771 }
772 }
773 }
774
775 if let Some(principal) = bounds.principal() {
779 let principal_trait_ref = principal.with_self_ty(cx, self_ty);
780 for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
781 candidates.extend(G::probe_and_consider_object_bound_candidate(
782 self,
783 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
784 goal,
785 assumption.upcast(cx),
786 ));
787 }
788 }
789 }
790
791 #[instrument(level = "trace", skip_all)]
798 fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
799 &mut self,
800 goal: Goal<I, G>,
801 ) -> Result<Candidate<I>, NoSolution> {
802 self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
803 let cx = ecx.cx();
804 let trait_ref = goal.predicate.trait_ref(cx);
805 if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
806 Err(NoSolution)
807 } else {
808 let predicate: I::Predicate = trait_ref.upcast(cx);
814 ecx.add_goals(
815 GoalSource::Misc,
816 elaborate::elaborate(cx, [predicate])
817 .skip(1)
818 .map(|predicate| goal.with(cx, predicate)),
819 );
820 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
821 }
822 })
823 }
824}
825
826pub(super) enum AllowInferenceConstraints {
827 Yes,
828 No,
829}
830
831impl<D, I> EvalCtxt<'_, D>
832where
833 D: SolverDelegate<Interner = I>,
834 I: Interner,
835{
836 pub(super) fn filter_specialized_impls(
840 &mut self,
841 allow_inference_constraints: AllowInferenceConstraints,
842 candidates: &mut Vec<Candidate<I>>,
843 ) {
844 match self.typing_mode() {
845 TypingMode::Coherence => return,
846 TypingMode::Analysis { .. }
847 | TypingMode::Borrowck { .. }
848 | TypingMode::PostBorrowckAnalysis { .. }
849 | TypingMode::PostAnalysis => {}
850 }
851
852 let mut i = 0;
853 'outer: while i < candidates.len() {
854 let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
855 i += 1;
856 continue;
857 };
858
859 for (j, c) in candidates.iter().enumerate() {
860 if i == j {
861 continue;
862 }
863
864 let CandidateSource::Impl(other_def_id) = c.source else {
865 continue;
866 };
867
868 if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
875 || has_only_region_constraints(c.result)
876 {
877 if self.cx().impl_specializes(other_def_id, victim_def_id) {
878 candidates.remove(i);
879 continue 'outer;
880 }
881 }
882 }
883
884 i += 1;
885 }
886 }
887
888 #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
919 pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
920 &mut self,
921 proven_via: Option<TraitGoalProvenVia>,
922 goal: Goal<I, G>,
923 inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
924 ) -> QueryResult<I> {
925 let Some(proven_via) = proven_via else {
926 return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
933 };
934
935 match proven_via {
936 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
937 let candidates_from_env_and_bounds: Vec<_> = self
941 .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
942
943 let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
946 .iter()
947 .any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
948 {
949 candidates_from_env_and_bounds
950 .into_iter()
951 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
952 .map(|c| c.result)
953 .collect()
954 } else {
955 candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
956 };
957
958 if considered_candidates.is_empty() {
961 if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
962 considered_candidates.push(response);
963 }
964 }
965
966 if let Some(response) = self.try_merge_responses(&considered_candidates) {
967 Ok(response)
968 } else {
969 self.flounder(&considered_candidates)
970 }
971 }
972 TraitGoalProvenVia::Misc => {
973 let mut candidates =
974 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
975
976 let candidates_from_env: Vec<_> = candidates
979 .iter()
980 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
981 .map(|c| c.result)
982 .collect();
983 if let Some(response) = self.try_merge_responses(&candidates_from_env) {
984 return Ok(response);
985 }
986
987 self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
993
994 let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
995 if let Some(response) = self.try_merge_responses(&responses) {
996 Ok(response)
997 } else {
998 self.flounder(&responses)
999 }
1000 }
1001 }
1002 }
1003
1004 fn characterize_param_env_assumption(
1018 &mut self,
1019 param_env: I::ParamEnv,
1020 assumption: I::Clause,
1021 ) -> Result<CandidateSource<I>, NoSolution> {
1022 if assumption.has_bound_vars() {
1025 return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1026 }
1027
1028 match assumption.visit_with(&mut FindParamInClause {
1029 ecx: self,
1030 param_env,
1031 universes: vec![],
1032 }) {
1033 ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1034 ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1035 ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1036 }
1037 }
1038}
1039
1040struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
1041 ecx: &'a mut EvalCtxt<'b, D>,
1042 param_env: I::ParamEnv,
1043 universes: Vec<Option<ty::UniverseIndex>>,
1044}
1045
1046impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
1047where
1048 D: SolverDelegate<Interner = I>,
1049 I: Interner,
1050{
1051 type Result = ControlFlow<Result<(), NoSolution>>;
1052
1053 fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
1054 self.universes.push(None);
1055 t.super_visit_with(self)?;
1056 self.universes.pop();
1057 ControlFlow::Continue(())
1058 }
1059
1060 fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
1061 let ty = self.ecx.replace_bound_vars(ty, &mut self.universes);
1062 let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
1063 return ControlFlow::Break(Err(NoSolution));
1064 };
1065
1066 if let ty::Placeholder(p) = ty.kind() {
1067 if p.universe() == ty::UniverseIndex::ROOT {
1068 ControlFlow::Break(Ok(()))
1069 } else {
1070 ControlFlow::Continue(())
1071 }
1072 } else {
1073 ty.super_visit_with(self)
1074 }
1075 }
1076
1077 fn visit_const(&mut self, ct: I::Const) -> Self::Result {
1078 let ct = self.ecx.replace_bound_vars(ct, &mut self.universes);
1079 let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
1080 return ControlFlow::Break(Err(NoSolution));
1081 };
1082
1083 if let ty::ConstKind::Placeholder(p) = ct.kind() {
1084 if p.universe() == ty::UniverseIndex::ROOT {
1085 ControlFlow::Break(Ok(()))
1086 } else {
1087 ControlFlow::Continue(())
1088 }
1089 } else {
1090 ct.super_visit_with(self)
1091 }
1092 }
1093
1094 fn visit_region(&mut self, r: I::Region) -> Self::Result {
1095 match self.ecx.eager_resolve_region(r).kind() {
1096 ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()),
1097 ty::RePlaceholder(p) => {
1098 if p.universe() == ty::UniverseIndex::ROOT {
1099 ControlFlow::Break(Ok(()))
1100 } else {
1101 ControlFlow::Continue(())
1102 }
1103 }
1104 ty::ReVar(_) => ControlFlow::Break(Ok(())),
1105 ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
1106 unreachable!("unexpected region in param-env clause")
1107 }
1108 }
1109 }
1110}