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,
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 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> =
380 goal.with(self.cx(), goal.predicate.with_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_impl_candidates(goal, &mut candidates);
399 self.assemble_builtin_impl_candidates(goal, &mut candidates);
400 self.assemble_object_bound_candidates(goal, &mut candidates);
401 }
402 AssembleCandidatesFrom::EnvAndBounds => {}
403 }
404
405 candidates
406 }
407
408 pub(super) fn forced_ambiguity(
409 &mut self,
410 cause: MaybeCause,
411 ) -> Result<Candidate<I>, NoSolution> {
412 let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
418 let certainty = Certainty::Maybe(cause);
419 self.probe_trait_candidate(source)
420 .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
421 }
422
423 #[instrument(level = "trace", skip_all)]
424 fn assemble_impl_candidates<G: GoalKind<D>>(
425 &mut self,
426 goal: Goal<I, G>,
427 candidates: &mut Vec<Candidate<I>>,
428 ) {
429 let cx = self.cx();
430 cx.for_each_relevant_impl(
431 goal.predicate.trait_def_id(cx),
432 goal.predicate.self_ty(),
433 |impl_def_id| {
434 if cx.impl_is_default(impl_def_id) {
438 return;
439 }
440
441 match G::consider_impl_candidate(self, goal, impl_def_id) {
442 Ok(candidate) => candidates.push(candidate),
443 Err(NoSolution) => (),
444 }
445 },
446 );
447 }
448
449 #[instrument(level = "trace", skip_all)]
450 fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
451 &mut self,
452 goal: Goal<I, G>,
453 candidates: &mut Vec<Candidate<I>>,
454 ) {
455 let cx = self.cx();
456 let trait_def_id = goal.predicate.trait_def_id(cx);
457
458 let result = if let Err(guar) = goal.predicate.error_reported() {
466 G::consider_error_guaranteed_candidate(self, guar)
467 } else if cx.trait_is_auto(trait_def_id) {
468 G::consider_auto_trait_candidate(self, goal)
469 } else if cx.trait_is_alias(trait_def_id) {
470 G::consider_trait_alias_candidate(self, goal)
471 } else {
472 match cx.as_lang_item(trait_def_id) {
473 Some(TraitSolverLangItem::Sized) => {
474 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
475 }
476 Some(TraitSolverLangItem::MetaSized) => {
477 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
478 }
479 Some(TraitSolverLangItem::PointeeSized) => {
480 unreachable!("`PointeeSized` is removed during lowering");
481 }
482 Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
483 G::consider_builtin_copy_clone_candidate(self, goal)
484 }
485 Some(TraitSolverLangItem::Fn) => {
486 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
487 }
488 Some(TraitSolverLangItem::FnMut) => {
489 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
490 }
491 Some(TraitSolverLangItem::FnOnce) => {
492 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
493 }
494 Some(TraitSolverLangItem::AsyncFn) => {
495 G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
496 }
497 Some(TraitSolverLangItem::AsyncFnMut) => {
498 G::consider_builtin_async_fn_trait_candidates(
499 self,
500 goal,
501 ty::ClosureKind::FnMut,
502 )
503 }
504 Some(TraitSolverLangItem::AsyncFnOnce) => {
505 G::consider_builtin_async_fn_trait_candidates(
506 self,
507 goal,
508 ty::ClosureKind::FnOnce,
509 )
510 }
511 Some(TraitSolverLangItem::FnPtrTrait) => {
512 G::consider_builtin_fn_ptr_trait_candidate(self, goal)
513 }
514 Some(TraitSolverLangItem::AsyncFnKindHelper) => {
515 G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
516 }
517 Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
518 Some(TraitSolverLangItem::PointeeTrait) => {
519 G::consider_builtin_pointee_candidate(self, goal)
520 }
521 Some(TraitSolverLangItem::Future) => {
522 G::consider_builtin_future_candidate(self, goal)
523 }
524 Some(TraitSolverLangItem::Iterator) => {
525 G::consider_builtin_iterator_candidate(self, goal)
526 }
527 Some(TraitSolverLangItem::FusedIterator) => {
528 G::consider_builtin_fused_iterator_candidate(self, goal)
529 }
530 Some(TraitSolverLangItem::AsyncIterator) => {
531 G::consider_builtin_async_iterator_candidate(self, goal)
532 }
533 Some(TraitSolverLangItem::Coroutine) => {
534 G::consider_builtin_coroutine_candidate(self, goal)
535 }
536 Some(TraitSolverLangItem::DiscriminantKind) => {
537 G::consider_builtin_discriminant_kind_candidate(self, goal)
538 }
539 Some(TraitSolverLangItem::Destruct) => {
540 G::consider_builtin_destruct_candidate(self, goal)
541 }
542 Some(TraitSolverLangItem::TransmuteTrait) => {
543 G::consider_builtin_transmute_candidate(self, goal)
544 }
545 Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => {
546 G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
547 }
548 _ => Err(NoSolution),
549 }
550 };
551
552 candidates.extend(result);
553
554 if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
557 candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
558 }
559 }
560
561 #[instrument(level = "trace", skip_all)]
562 fn assemble_param_env_candidates<G: GoalKind<D>>(
563 &mut self,
564 goal: Goal<I, G>,
565 candidates: &mut Vec<Candidate<I>>,
566 ) {
567 for assumption in goal.param_env.caller_bounds().iter() {
568 candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
569 }
570 }
571
572 #[instrument(level = "trace", skip_all)]
573 fn assemble_alias_bound_candidates<G: GoalKind<D>>(
574 &mut self,
575 goal: Goal<I, G>,
576 candidates: &mut Vec<Candidate<I>>,
577 ) {
578 let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
579 ecx.assemble_alias_bound_candidates_recur(
580 goal.predicate.self_ty(),
581 goal,
582 candidates,
583 AliasBoundKind::SelfBounds,
584 );
585 });
586 }
587
588 fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
598 &mut self,
599 self_ty: I::Ty,
600 goal: Goal<I, G>,
601 candidates: &mut Vec<Candidate<I>>,
602 consider_self_bounds: AliasBoundKind,
603 ) {
604 let (kind, alias_ty) = match self_ty.kind() {
605 ty::Bool
606 | ty::Char
607 | ty::Int(_)
608 | ty::Uint(_)
609 | ty::Float(_)
610 | ty::Adt(_, _)
611 | ty::Foreign(_)
612 | ty::Str
613 | ty::Array(_, _)
614 | ty::Pat(_, _)
615 | ty::Slice(_)
616 | ty::RawPtr(_, _)
617 | ty::Ref(_, _, _)
618 | ty::FnDef(_, _)
619 | ty::FnPtr(..)
620 | ty::UnsafeBinder(_)
621 | ty::Dynamic(..)
622 | ty::Closure(..)
623 | ty::CoroutineClosure(..)
624 | ty::Coroutine(..)
625 | ty::CoroutineWitness(..)
626 | ty::Never
627 | ty::Tuple(_)
628 | ty::Param(_)
629 | ty::Placeholder(..)
630 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
631 | ty::Error(_) => return,
632 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
633 panic!("unexpected self type for `{goal:?}`")
634 }
635
636 ty::Infer(ty::TyVar(_)) => {
637 if let Ok(result) =
641 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
642 {
643 candidates.push(Candidate { source: CandidateSource::AliasBound, result });
644 }
645 return;
646 }
647
648 ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
649 ty::Alias(ty::Inherent | ty::Free, _) => {
650 self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
651 return;
652 }
653 };
654
655 match consider_self_bounds {
656 AliasBoundKind::SelfBounds => {
657 for assumption in self
658 .cx()
659 .item_self_bounds(alias_ty.def_id)
660 .iter_instantiated(self.cx(), alias_ty.args)
661 {
662 candidates.extend(G::probe_and_consider_implied_clause(
663 self,
664 CandidateSource::AliasBound,
665 goal,
666 assumption,
667 [],
668 ));
669 }
670 }
671 AliasBoundKind::NonSelfBounds => {
672 for assumption in self
673 .cx()
674 .item_non_self_bounds(alias_ty.def_id)
675 .iter_instantiated(self.cx(), alias_ty.args)
676 {
677 candidates.extend(G::probe_and_consider_implied_clause(
678 self,
679 CandidateSource::AliasBound,
680 goal,
681 assumption,
682 [],
683 ));
684 }
685 }
686 }
687
688 candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
689
690 if kind != ty::Projection {
691 return;
692 }
693
694 match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
696 Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
697 next_self_ty,
698 goal,
699 candidates,
700 AliasBoundKind::NonSelfBounds,
701 ),
702 Err(NoSolution) => {}
703 }
704 }
705
706 #[instrument(level = "trace", skip_all)]
707 fn assemble_object_bound_candidates<G: GoalKind<D>>(
708 &mut self,
709 goal: Goal<I, G>,
710 candidates: &mut Vec<Candidate<I>>,
711 ) {
712 let cx = self.cx();
713 if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) {
714 return;
715 }
716
717 let self_ty = goal.predicate.self_ty();
718 let bounds = match self_ty.kind() {
719 ty::Bool
720 | ty::Char
721 | ty::Int(_)
722 | ty::Uint(_)
723 | ty::Float(_)
724 | ty::Adt(_, _)
725 | ty::Foreign(_)
726 | ty::Str
727 | ty::Array(_, _)
728 | ty::Pat(_, _)
729 | ty::Slice(_)
730 | ty::RawPtr(_, _)
731 | ty::Ref(_, _, _)
732 | ty::FnDef(_, _)
733 | ty::FnPtr(..)
734 | ty::UnsafeBinder(_)
735 | ty::Alias(..)
736 | ty::Closure(..)
737 | ty::CoroutineClosure(..)
738 | ty::Coroutine(..)
739 | ty::CoroutineWitness(..)
740 | ty::Never
741 | ty::Tuple(_)
742 | ty::Param(_)
743 | ty::Placeholder(..)
744 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
745 | ty::Error(_) => return,
746 ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
747 | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
748 ty::Dynamic(bounds, ..) => bounds,
749 };
750
751 if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
753 return;
754 }
755
756 for bound in bounds.iter() {
760 match bound.skip_binder() {
761 ty::ExistentialPredicate::Trait(_) => {
762 }
764 ty::ExistentialPredicate::Projection(_)
765 | ty::ExistentialPredicate::AutoTrait(_) => {
766 candidates.extend(G::probe_and_consider_object_bound_candidate(
767 self,
768 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
769 goal,
770 bound.with_self_ty(cx, self_ty),
771 ));
772 }
773 }
774 }
775
776 if let Some(principal) = bounds.principal() {
780 let principal_trait_ref = principal.with_self_ty(cx, self_ty);
781 for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
782 candidates.extend(G::probe_and_consider_object_bound_candidate(
783 self,
784 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
785 goal,
786 assumption.upcast(cx),
787 ));
788 }
789 }
790 }
791
792 #[instrument(level = "trace", skip_all)]
799 fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
800 &mut self,
801 goal: Goal<I, G>,
802 ) -> Result<Candidate<I>, NoSolution> {
803 self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
804 let cx = ecx.cx();
805 let trait_ref = goal.predicate.trait_ref(cx);
806 if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
807 Err(NoSolution)
808 } else {
809 let predicate: I::Predicate = trait_ref.upcast(cx);
815 ecx.add_goals(
816 GoalSource::Misc,
817 elaborate::elaborate(cx, [predicate])
818 .skip(1)
819 .map(|predicate| goal.with(cx, predicate)),
820 );
821 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
822 }
823 })
824 }
825}
826
827pub(super) enum AllowInferenceConstraints {
828 Yes,
829 No,
830}
831
832impl<D, I> EvalCtxt<'_, D>
833where
834 D: SolverDelegate<Interner = I>,
835 I: Interner,
836{
837 pub(super) fn filter_specialized_impls(
841 &mut self,
842 allow_inference_constraints: AllowInferenceConstraints,
843 candidates: &mut Vec<Candidate<I>>,
844 ) {
845 match self.typing_mode() {
846 TypingMode::Coherence => return,
847 TypingMode::Analysis { .. }
848 | TypingMode::Borrowck { .. }
849 | TypingMode::PostBorrowckAnalysis { .. }
850 | TypingMode::PostAnalysis => {}
851 }
852
853 let mut i = 0;
854 'outer: while i < candidates.len() {
855 let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
856 i += 1;
857 continue;
858 };
859
860 for (j, c) in candidates.iter().enumerate() {
861 if i == j {
862 continue;
863 }
864
865 let CandidateSource::Impl(other_def_id) = c.source else {
866 continue;
867 };
868
869 if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
876 || has_only_region_constraints(c.result)
877 {
878 if self.cx().impl_specializes(other_def_id, victim_def_id) {
879 candidates.remove(i);
880 continue 'outer;
881 }
882 }
883 }
884
885 i += 1;
886 }
887 }
888
889 #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
920 pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
921 &mut self,
922 proven_via: Option<TraitGoalProvenVia>,
923 goal: Goal<I, G>,
924 inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
925 ) -> QueryResult<I> {
926 let Some(proven_via) = proven_via else {
927 return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
934 };
935
936 match proven_via {
937 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
938 let candidates_from_env_and_bounds: Vec<_> = self
942 .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
943
944 let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
947 .iter()
948 .any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
949 {
950 candidates_from_env_and_bounds
951 .into_iter()
952 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
953 .map(|c| c.result)
954 .collect()
955 } else {
956 candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
957 };
958
959 if considered_candidates.is_empty() {
962 if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
963 considered_candidates.push(response);
964 }
965 }
966
967 if let Some(response) = self.try_merge_responses(&considered_candidates) {
968 Ok(response)
969 } else {
970 self.flounder(&considered_candidates)
971 }
972 }
973 TraitGoalProvenVia::Misc => {
974 let mut candidates =
975 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
976
977 let candidates_from_env: Vec<_> = candidates
980 .iter()
981 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
982 .map(|c| c.result)
983 .collect();
984 if let Some(response) = self.try_merge_responses(&candidates_from_env) {
985 return Ok(response);
986 }
987
988 self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
994
995 let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
996 if let Some(response) = self.try_merge_responses(&responses) {
997 Ok(response)
998 } else {
999 self.flounder(&responses)
1000 }
1001 }
1002 }
1003 }
1004
1005 fn characterize_param_env_assumption(
1019 &mut self,
1020 param_env: I::ParamEnv,
1021 assumption: I::Clause,
1022 ) -> Result<CandidateSource<I>, NoSolution> {
1023 if assumption.has_bound_vars() {
1026 return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1027 }
1028
1029 match assumption.visit_with(&mut FindParamInClause {
1030 ecx: self,
1031 param_env,
1032 universes: vec![],
1033 }) {
1034 ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1035 ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1036 ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1037 }
1038 }
1039}
1040
1041struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
1042 ecx: &'a mut EvalCtxt<'b, D>,
1043 param_env: I::ParamEnv,
1044 universes: Vec<Option<ty::UniverseIndex>>,
1045}
1046
1047impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
1048where
1049 D: SolverDelegate<Interner = I>,
1050 I: Interner,
1051{
1052 type Result = ControlFlow<Result<(), NoSolution>>;
1053
1054 fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
1055 self.universes.push(None);
1056 t.super_visit_with(self)?;
1057 self.universes.pop();
1058 ControlFlow::Continue(())
1059 }
1060
1061 fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
1062 let ty = self.ecx.replace_bound_vars(ty, &mut self.universes);
1063 let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
1064 return ControlFlow::Break(Err(NoSolution));
1065 };
1066
1067 if let ty::Placeholder(p) = ty.kind() {
1068 if p.universe() == ty::UniverseIndex::ROOT {
1069 ControlFlow::Break(Ok(()))
1070 } else {
1071 ControlFlow::Continue(())
1072 }
1073 } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1074 ty.super_visit_with(self)
1075 } else {
1076 ControlFlow::Continue(())
1077 }
1078 }
1079
1080 fn visit_const(&mut self, ct: I::Const) -> Self::Result {
1081 let ct = self.ecx.replace_bound_vars(ct, &mut self.universes);
1082 let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
1083 return ControlFlow::Break(Err(NoSolution));
1084 };
1085
1086 if let ty::ConstKind::Placeholder(p) = ct.kind() {
1087 if p.universe() == ty::UniverseIndex::ROOT {
1088 ControlFlow::Break(Ok(()))
1089 } else {
1090 ControlFlow::Continue(())
1091 }
1092 } else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1093 ct.super_visit_with(self)
1094 } else {
1095 ControlFlow::Continue(())
1096 }
1097 }
1098
1099 fn visit_region(&mut self, r: I::Region) -> Self::Result {
1100 match self.ecx.eager_resolve_region(r).kind() {
1101 ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()),
1102 ty::RePlaceholder(p) => {
1103 if p.universe() == ty::UniverseIndex::ROOT {
1104 ControlFlow::Break(Ok(()))
1105 } else {
1106 ControlFlow::Continue(())
1107 }
1108 }
1109 ty::ReVar(_) => ControlFlow::Break(Ok(())),
1110 ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
1111 unreachable!("unexpected region in param-env clause")
1112 }
1113 }
1114 }
1115}