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::SolverTraitLangItem;
11use rustc_type_ir::search_graph::CandidateHeadUsages;
12use rustc_type_ir::solve::SizedTraitKind;
13use rustc_type_ir::{
14 self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
15 TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
16 elaborate,
17};
18use tracing::{debug, instrument};
19
20use super::trait_goals::TraitGoalProvenVia;
21use super::{has_only_region_constraints, inspect};
22use crate::delegate::SolverDelegate;
23use crate::solve::inspect::ProbeKind;
24use crate::solve::{
25 BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
26 MaybeCause, NoSolution, OpaqueTypesJank, ParamEnvSource, QueryResult,
27 has_no_inference_or_external_constraints,
28};
29
30enum AliasBoundKind {
31 SelfBounds,
32 NonSelfBounds,
33}
34
35#[derive_where(Debug; I: Interner)]
40pub(super) struct Candidate<I: Interner> {
41 pub(super) source: CandidateSource<I>,
42 pub(super) result: CanonicalResponse<I>,
43 pub(super) head_usages: CandidateHeadUsages,
44}
45
46pub(super) trait GoalKind<D, I = <D as SolverDelegate>::Interner>:
48 TypeFoldable<I> + Copy + Eq + std::fmt::Display
49where
50 D: SolverDelegate<Interner = I>,
51 I: Interner,
52{
53 fn self_ty(self) -> I::Ty;
54
55 fn trait_ref(self, cx: I) -> ty::TraitRef<I>;
56
57 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self;
58
59 fn trait_def_id(self, cx: I) -> I::TraitId;
60
61 fn probe_and_consider_implied_clause(
65 ecx: &mut EvalCtxt<'_, D>,
66 parent_source: CandidateSource<I>,
67 goal: Goal<I, Self>,
68 assumption: I::Clause,
69 requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>,
70 ) -> Result<Candidate<I>, NoSolution> {
71 Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
72 for (nested_source, goal) in requirements {
73 ecx.add_goal(nested_source, goal);
74 }
75 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
76 })
77 }
78
79 fn probe_and_consider_object_bound_candidate(
83 ecx: &mut EvalCtxt<'_, D>,
84 source: CandidateSource<I>,
85 goal: Goal<I, Self>,
86 assumption: I::Clause,
87 ) -> Result<Candidate<I>, NoSolution> {
88 Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
89 let cx = ecx.cx();
90 let ty::Dynamic(bounds, _) = goal.predicate.self_ty().kind() else {
91 panic!("expected object type in `probe_and_consider_object_bound_candidate`");
92 };
93 match structural_traits::predicates_for_object_candidate(
94 ecx,
95 goal.param_env,
96 goal.predicate.trait_ref(cx),
97 bounds,
98 ) {
99 Ok(requirements) => {
100 ecx.add_goals(GoalSource::ImplWhereBound, requirements);
101 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
102 }
103 Err(_) => {
104 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
105 }
106 }
107 })
108 }
109
110 fn consider_additional_alias_assumptions(
114 ecx: &mut EvalCtxt<'_, D>,
115 goal: Goal<I, Self>,
116 alias_ty: ty::AliasTy<I>,
117 ) -> Vec<Candidate<I>>;
118
119 fn probe_and_consider_param_env_candidate(
120 ecx: &mut EvalCtxt<'_, D>,
121 goal: Goal<I, Self>,
122 assumption: I::Clause,
123 ) -> Result<Candidate<I>, CandidateHeadUsages> {
124 match Self::fast_reject_assumption(ecx, goal, assumption) {
125 Ok(()) => {}
126 Err(NoSolution) => return Err(CandidateHeadUsages::default()),
127 }
128
129 let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
136 let (result, head_usages) = ecx
137 .probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
138 source: source.get(),
139 result: *result,
140 })
141 .enter_single_candidate(|ecx| {
142 Self::match_assumption(ecx, goal, assumption, |ecx| {
143 ecx.try_evaluate_added_goals()?;
144 source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
145 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
146 })
147 });
148
149 match result {
150 Ok(result) => Ok(Candidate { source: source.get(), result, head_usages }),
151 Err(NoSolution) => Err(head_usages),
152 }
153 }
154
155 fn probe_and_match_goal_against_assumption(
160 ecx: &mut EvalCtxt<'_, D>,
161 source: CandidateSource<I>,
162 goal: Goal<I, Self>,
163 assumption: I::Clause,
164 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
165 ) -> Result<Candidate<I>, NoSolution> {
166 Self::fast_reject_assumption(ecx, goal, assumption)?;
167
168 ecx.probe_trait_candidate(source)
169 .enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
170 }
171
172 fn fast_reject_assumption(
175 ecx: &mut EvalCtxt<'_, D>,
176 goal: Goal<I, Self>,
177 assumption: I::Clause,
178 ) -> Result<(), NoSolution>;
179
180 fn match_assumption(
182 ecx: &mut EvalCtxt<'_, D>,
183 goal: Goal<I, Self>,
184 assumption: I::Clause,
185 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
186 ) -> QueryResult<I>;
187
188 fn consider_impl_candidate(
189 ecx: &mut EvalCtxt<'_, D>,
190 goal: Goal<I, Self>,
191 impl_def_id: I::ImplId,
192 then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
193 ) -> Result<Candidate<I>, NoSolution>;
194
195 fn consider_error_guaranteed_candidate(
202 ecx: &mut EvalCtxt<'_, D>,
203 guar: I::ErrorGuaranteed,
204 ) -> Result<Candidate<I>, NoSolution>;
205
206 fn consider_auto_trait_candidate(
211 ecx: &mut EvalCtxt<'_, D>,
212 goal: Goal<I, Self>,
213 ) -> Result<Candidate<I>, NoSolution>;
214
215 fn consider_trait_alias_candidate(
217 ecx: &mut EvalCtxt<'_, D>,
218 goal: Goal<I, Self>,
219 ) -> Result<Candidate<I>, NoSolution>;
220
221 fn consider_builtin_sizedness_candidates(
227 ecx: &mut EvalCtxt<'_, D>,
228 goal: Goal<I, Self>,
229 sizedness: SizedTraitKind,
230 ) -> Result<Candidate<I>, NoSolution>;
231
232 fn consider_builtin_copy_clone_candidate(
237 ecx: &mut EvalCtxt<'_, D>,
238 goal: Goal<I, Self>,
239 ) -> Result<Candidate<I>, NoSolution>;
240
241 fn consider_builtin_fn_ptr_trait_candidate(
243 ecx: &mut EvalCtxt<'_, D>,
244 goal: Goal<I, Self>,
245 ) -> Result<Candidate<I>, NoSolution>;
246
247 fn consider_builtin_fn_trait_candidates(
250 ecx: &mut EvalCtxt<'_, D>,
251 goal: Goal<I, Self>,
252 kind: ty::ClosureKind,
253 ) -> Result<Candidate<I>, NoSolution>;
254
255 fn consider_builtin_async_fn_trait_candidates(
258 ecx: &mut EvalCtxt<'_, D>,
259 goal: Goal<I, Self>,
260 kind: ty::ClosureKind,
261 ) -> Result<Candidate<I>, NoSolution>;
262
263 fn consider_builtin_async_fn_kind_helper_candidate(
267 ecx: &mut EvalCtxt<'_, D>,
268 goal: Goal<I, Self>,
269 ) -> Result<Candidate<I>, NoSolution>;
270
271 fn consider_builtin_tuple_candidate(
273 ecx: &mut EvalCtxt<'_, D>,
274 goal: Goal<I, Self>,
275 ) -> Result<Candidate<I>, NoSolution>;
276
277 fn consider_builtin_pointee_candidate(
283 ecx: &mut EvalCtxt<'_, D>,
284 goal: Goal<I, Self>,
285 ) -> Result<Candidate<I>, NoSolution>;
286
287 fn consider_builtin_future_candidate(
291 ecx: &mut EvalCtxt<'_, D>,
292 goal: Goal<I, Self>,
293 ) -> Result<Candidate<I>, NoSolution>;
294
295 fn consider_builtin_iterator_candidate(
299 ecx: &mut EvalCtxt<'_, D>,
300 goal: Goal<I, Self>,
301 ) -> Result<Candidate<I>, NoSolution>;
302
303 fn consider_builtin_fused_iterator_candidate(
306 ecx: &mut EvalCtxt<'_, D>,
307 goal: Goal<I, Self>,
308 ) -> Result<Candidate<I>, NoSolution>;
309
310 fn consider_builtin_async_iterator_candidate(
311 ecx: &mut EvalCtxt<'_, D>,
312 goal: Goal<I, Self>,
313 ) -> Result<Candidate<I>, NoSolution>;
314
315 fn consider_builtin_coroutine_candidate(
319 ecx: &mut EvalCtxt<'_, D>,
320 goal: Goal<I, Self>,
321 ) -> Result<Candidate<I>, NoSolution>;
322
323 fn consider_builtin_discriminant_kind_candidate(
324 ecx: &mut EvalCtxt<'_, D>,
325 goal: Goal<I, Self>,
326 ) -> Result<Candidate<I>, NoSolution>;
327
328 fn consider_builtin_destruct_candidate(
329 ecx: &mut EvalCtxt<'_, D>,
330 goal: Goal<I, Self>,
331 ) -> Result<Candidate<I>, NoSolution>;
332
333 fn consider_builtin_transmute_candidate(
334 ecx: &mut EvalCtxt<'_, D>,
335 goal: Goal<I, Self>,
336 ) -> Result<Candidate<I>, NoSolution>;
337
338 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
339 ecx: &mut EvalCtxt<'_, D>,
340 goal: Goal<I, Self>,
341 ) -> Result<Candidate<I>, NoSolution>;
342
343 fn consider_structural_builtin_unsize_candidates(
351 ecx: &mut EvalCtxt<'_, D>,
352 goal: Goal<I, Self>,
353 ) -> Vec<Candidate<I>>;
354}
355
356pub(super) enum AssembleCandidatesFrom {
364 All,
365 EnvAndBounds,
369}
370
371impl AssembleCandidatesFrom {
372 fn should_assemble_impl_candidates(&self) -> bool {
373 match self {
374 AssembleCandidatesFrom::All => true,
375 AssembleCandidatesFrom::EnvAndBounds => false,
376 }
377 }
378}
379
380#[derive(Debug)]
389pub(super) struct FailedCandidateInfo {
390 pub param_env_head_usages: CandidateHeadUsages,
391}
392
393impl<D, I> EvalCtxt<'_, D>
394where
395 D: SolverDelegate<Interner = I>,
396 I: Interner,
397{
398 pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
399 &mut self,
400 goal: Goal<I, G>,
401 assemble_from: AssembleCandidatesFrom,
402 ) -> (Vec<Candidate<I>>, FailedCandidateInfo) {
403 let mut candidates = vec![];
404 let mut failed_candidate_info =
405 FailedCandidateInfo { param_env_head_usages: CandidateHeadUsages::default() };
406 let Ok(normalized_self_ty) =
407 self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
408 else {
409 return (candidates, failed_candidate_info);
410 };
411
412 let goal: Goal<I, G> = goal
413 .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
414
415 if normalized_self_ty.is_ty_var() {
416 debug!("self type has been normalized to infer");
417 self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates);
418 return (candidates, failed_candidate_info);
419 }
420
421 let goal = self.resolve_vars_if_possible(goal);
424
425 if let TypingMode::Coherence = self.typing_mode()
426 && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
427 {
428 candidates.push(candidate);
429 return (candidates, failed_candidate_info);
430 }
431
432 self.assemble_alias_bound_candidates(goal, &mut candidates);
433 self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info);
434
435 match assemble_from {
436 AssembleCandidatesFrom::All => {
437 self.assemble_builtin_impl_candidates(goal, &mut candidates);
438 if TypingMode::Coherence == self.typing_mode()
450 || !candidates.iter().any(|c| {
451 matches!(
452 c.source,
453 CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
454 | CandidateSource::AliasBound
455 ) && has_no_inference_or_external_constraints(c.result)
456 })
457 {
458 self.assemble_impl_candidates(goal, &mut candidates);
459 self.assemble_object_bound_candidates(goal, &mut candidates);
460 }
461 }
462 AssembleCandidatesFrom::EnvAndBounds => {}
463 }
464
465 (candidates, failed_candidate_info)
466 }
467
468 pub(super) fn forced_ambiguity(
469 &mut self,
470 cause: MaybeCause,
471 ) -> Result<Candidate<I>, NoSolution> {
472 let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
481 let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
482 self.probe_trait_candidate(source)
483 .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
484 }
485
486 #[instrument(level = "trace", skip_all)]
487 fn assemble_impl_candidates<G: GoalKind<D>>(
488 &mut self,
489 goal: Goal<I, G>,
490 candidates: &mut Vec<Candidate<I>>,
491 ) {
492 let cx = self.cx();
493 cx.for_each_relevant_impl(
494 goal.predicate.trait_def_id(cx),
495 goal.predicate.self_ty(),
496 |impl_def_id| {
497 if cx.impl_is_default(impl_def_id) {
501 return;
502 }
503 match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
504 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
505 }) {
506 Ok(candidate) => candidates.push(candidate),
507 Err(NoSolution) => (),
508 }
509 },
510 );
511 }
512
513 #[instrument(level = "trace", skip_all)]
514 fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
515 &mut self,
516 goal: Goal<I, G>,
517 candidates: &mut Vec<Candidate<I>>,
518 ) {
519 let cx = self.cx();
520 let trait_def_id = goal.predicate.trait_def_id(cx);
521
522 let result = if let Err(guar) = goal.predicate.error_reported() {
530 G::consider_error_guaranteed_candidate(self, guar)
531 } else if cx.trait_is_auto(trait_def_id) {
532 G::consider_auto_trait_candidate(self, goal)
533 } else if cx.trait_is_alias(trait_def_id) {
534 G::consider_trait_alias_candidate(self, goal)
535 } else {
536 match cx.as_trait_lang_item(trait_def_id) {
537 Some(SolverTraitLangItem::Sized) => {
538 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
539 }
540 Some(SolverTraitLangItem::MetaSized) => {
541 G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
542 }
543 Some(SolverTraitLangItem::PointeeSized) => {
544 unreachable!("`PointeeSized` is removed during lowering");
545 }
546 Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => {
547 G::consider_builtin_copy_clone_candidate(self, goal)
548 }
549 Some(SolverTraitLangItem::Fn) => {
550 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
551 }
552 Some(SolverTraitLangItem::FnMut) => {
553 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
554 }
555 Some(SolverTraitLangItem::FnOnce) => {
556 G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
557 }
558 Some(SolverTraitLangItem::AsyncFn) => {
559 G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
560 }
561 Some(SolverTraitLangItem::AsyncFnMut) => {
562 G::consider_builtin_async_fn_trait_candidates(
563 self,
564 goal,
565 ty::ClosureKind::FnMut,
566 )
567 }
568 Some(SolverTraitLangItem::AsyncFnOnce) => {
569 G::consider_builtin_async_fn_trait_candidates(
570 self,
571 goal,
572 ty::ClosureKind::FnOnce,
573 )
574 }
575 Some(SolverTraitLangItem::FnPtrTrait) => {
576 G::consider_builtin_fn_ptr_trait_candidate(self, goal)
577 }
578 Some(SolverTraitLangItem::AsyncFnKindHelper) => {
579 G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
580 }
581 Some(SolverTraitLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
582 Some(SolverTraitLangItem::PointeeTrait) => {
583 G::consider_builtin_pointee_candidate(self, goal)
584 }
585 Some(SolverTraitLangItem::Future) => {
586 G::consider_builtin_future_candidate(self, goal)
587 }
588 Some(SolverTraitLangItem::Iterator) => {
589 G::consider_builtin_iterator_candidate(self, goal)
590 }
591 Some(SolverTraitLangItem::FusedIterator) => {
592 G::consider_builtin_fused_iterator_candidate(self, goal)
593 }
594 Some(SolverTraitLangItem::AsyncIterator) => {
595 G::consider_builtin_async_iterator_candidate(self, goal)
596 }
597 Some(SolverTraitLangItem::Coroutine) => {
598 G::consider_builtin_coroutine_candidate(self, goal)
599 }
600 Some(SolverTraitLangItem::DiscriminantKind) => {
601 G::consider_builtin_discriminant_kind_candidate(self, goal)
602 }
603 Some(SolverTraitLangItem::Destruct) => {
604 G::consider_builtin_destruct_candidate(self, goal)
605 }
606 Some(SolverTraitLangItem::TransmuteTrait) => {
607 G::consider_builtin_transmute_candidate(self, goal)
608 }
609 Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => {
610 G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
611 }
612 _ => Err(NoSolution),
613 }
614 };
615
616 candidates.extend(result);
617
618 if cx.is_trait_lang_item(trait_def_id, SolverTraitLangItem::Unsize) {
621 candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
622 }
623 }
624
625 #[instrument(level = "trace", skip_all)]
626 fn assemble_param_env_candidates<G: GoalKind<D>>(
627 &mut self,
628 goal: Goal<I, G>,
629 candidates: &mut Vec<Candidate<I>>,
630 failed_candidate_info: &mut FailedCandidateInfo,
631 ) {
632 for assumption in goal.param_env.caller_bounds().iter() {
633 match G::probe_and_consider_param_env_candidate(self, goal, assumption) {
634 Ok(candidate) => candidates.push(candidate),
635 Err(head_usages) => {
636 failed_candidate_info.param_env_head_usages.merge_usages(head_usages)
637 }
638 }
639 }
640 }
641
642 #[instrument(level = "trace", skip_all)]
643 fn assemble_alias_bound_candidates<G: GoalKind<D>>(
644 &mut self,
645 goal: Goal<I, G>,
646 candidates: &mut Vec<Candidate<I>>,
647 ) {
648 let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
649 ecx.assemble_alias_bound_candidates_recur(
650 goal.predicate.self_ty(),
651 goal,
652 candidates,
653 AliasBoundKind::SelfBounds,
654 );
655 });
656 }
657
658 fn assemble_alias_bound_candidates_recur<G: GoalKind<D>>(
668 &mut self,
669 self_ty: I::Ty,
670 goal: Goal<I, G>,
671 candidates: &mut Vec<Candidate<I>>,
672 consider_self_bounds: AliasBoundKind,
673 ) {
674 let (kind, alias_ty) = match self_ty.kind() {
675 ty::Bool
676 | ty::Char
677 | ty::Int(_)
678 | ty::Uint(_)
679 | ty::Float(_)
680 | ty::Adt(_, _)
681 | ty::Foreign(_)
682 | ty::Str
683 | ty::Array(_, _)
684 | ty::Pat(_, _)
685 | ty::Slice(_)
686 | ty::RawPtr(_, _)
687 | ty::Ref(_, _, _)
688 | ty::FnDef(_, _)
689 | ty::FnPtr(..)
690 | ty::UnsafeBinder(_)
691 | ty::Dynamic(..)
692 | ty::Closure(..)
693 | ty::CoroutineClosure(..)
694 | ty::Coroutine(..)
695 | ty::CoroutineWitness(..)
696 | ty::Never
697 | ty::Tuple(_)
698 | ty::Param(_)
699 | ty::Placeholder(..)
700 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
701 | ty::Error(_) => return,
702 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
703 panic!("unexpected self type for `{goal:?}`")
704 }
705
706 ty::Infer(ty::TyVar(_)) => {
707 if let Ok(result) =
711 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
712 {
713 candidates.push(Candidate {
714 source: CandidateSource::AliasBound,
715 result,
716 head_usages: CandidateHeadUsages::default(),
717 });
718 }
719 return;
720 }
721
722 ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
723 ty::Alias(ty::Inherent | ty::Free, _) => {
724 self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
725 return;
726 }
727 };
728
729 match consider_self_bounds {
730 AliasBoundKind::SelfBounds => {
731 for assumption in self
732 .cx()
733 .item_self_bounds(alias_ty.def_id)
734 .iter_instantiated(self.cx(), alias_ty.args)
735 {
736 candidates.extend(G::probe_and_consider_implied_clause(
737 self,
738 CandidateSource::AliasBound,
739 goal,
740 assumption,
741 [],
742 ));
743 }
744 }
745 AliasBoundKind::NonSelfBounds => {
746 for assumption in self
747 .cx()
748 .item_non_self_bounds(alias_ty.def_id)
749 .iter_instantiated(self.cx(), alias_ty.args)
750 {
751 candidates.extend(G::probe_and_consider_implied_clause(
752 self,
753 CandidateSource::AliasBound,
754 goal,
755 assumption,
756 [],
757 ));
758 }
759 }
760 }
761
762 candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
763
764 if kind != ty::Projection {
765 return;
766 }
767
768 match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
770 Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
771 next_self_ty,
772 goal,
773 candidates,
774 AliasBoundKind::NonSelfBounds,
775 ),
776 Err(NoSolution) => {}
777 }
778 }
779
780 #[instrument(level = "trace", skip_all)]
781 fn assemble_object_bound_candidates<G: GoalKind<D>>(
782 &mut self,
783 goal: Goal<I, G>,
784 candidates: &mut Vec<Candidate<I>>,
785 ) {
786 let cx = self.cx();
787 if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) {
788 return;
789 }
790
791 let self_ty = goal.predicate.self_ty();
792 let bounds = match self_ty.kind() {
793 ty::Bool
794 | ty::Char
795 | ty::Int(_)
796 | ty::Uint(_)
797 | ty::Float(_)
798 | ty::Adt(_, _)
799 | ty::Foreign(_)
800 | ty::Str
801 | ty::Array(_, _)
802 | ty::Pat(_, _)
803 | ty::Slice(_)
804 | ty::RawPtr(_, _)
805 | ty::Ref(_, _, _)
806 | ty::FnDef(_, _)
807 | ty::FnPtr(..)
808 | ty::UnsafeBinder(_)
809 | ty::Alias(..)
810 | ty::Closure(..)
811 | ty::CoroutineClosure(..)
812 | ty::Coroutine(..)
813 | ty::CoroutineWitness(..)
814 | ty::Never
815 | ty::Tuple(_)
816 | ty::Param(_)
817 | ty::Placeholder(..)
818 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
819 | ty::Error(_) => return,
820 ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
821 | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
822 ty::Dynamic(bounds, ..) => bounds,
823 };
824
825 if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
827 return;
828 }
829
830 for bound in bounds.iter() {
834 match bound.skip_binder() {
835 ty::ExistentialPredicate::Trait(_) => {
836 }
838 ty::ExistentialPredicate::Projection(_)
839 | ty::ExistentialPredicate::AutoTrait(_) => {
840 candidates.extend(G::probe_and_consider_object_bound_candidate(
841 self,
842 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
843 goal,
844 bound.with_self_ty(cx, self_ty),
845 ));
846 }
847 }
848 }
849
850 if let Some(principal) = bounds.principal() {
854 let principal_trait_ref = principal.with_self_ty(cx, self_ty);
855 for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
856 candidates.extend(G::probe_and_consider_object_bound_candidate(
857 self,
858 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
859 goal,
860 assumption.upcast(cx),
861 ));
862 }
863 }
864 }
865
866 #[instrument(level = "trace", skip_all)]
873 fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
874 &mut self,
875 goal: Goal<I, G>,
876 ) -> Result<Candidate<I>, NoSolution> {
877 self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
878 let cx = ecx.cx();
879 let trait_ref = goal.predicate.trait_ref(cx);
880 if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
881 Err(NoSolution)
882 } else {
883 let predicate: I::Predicate = trait_ref.upcast(cx);
889 ecx.add_goals(
890 GoalSource::Misc,
891 elaborate::elaborate(cx, [predicate])
892 .skip(1)
893 .map(|predicate| goal.with(cx, predicate)),
894 );
895 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
896 }
897 })
898 }
899}
900
901pub(super) enum AllowInferenceConstraints {
902 Yes,
903 No,
904}
905
906impl<D, I> EvalCtxt<'_, D>
907where
908 D: SolverDelegate<Interner = I>,
909 I: Interner,
910{
911 pub(super) fn filter_specialized_impls(
915 &mut self,
916 allow_inference_constraints: AllowInferenceConstraints,
917 candidates: &mut Vec<Candidate<I>>,
918 ) {
919 match self.typing_mode() {
920 TypingMode::Coherence => return,
921 TypingMode::Analysis { .. }
922 | TypingMode::Borrowck { .. }
923 | TypingMode::PostBorrowckAnalysis { .. }
924 | TypingMode::PostAnalysis => {}
925 }
926
927 let mut i = 0;
928 'outer: while i < candidates.len() {
929 let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
930 i += 1;
931 continue;
932 };
933
934 for (j, c) in candidates.iter().enumerate() {
935 if i == j {
936 continue;
937 }
938
939 let CandidateSource::Impl(other_def_id) = c.source else {
940 continue;
941 };
942
943 if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
950 || has_only_region_constraints(c.result)
951 {
952 if self.cx().impl_specializes(other_def_id, victim_def_id) {
953 candidates.remove(i);
954 continue 'outer;
955 }
956 }
957 }
958
959 i += 1;
960 }
961 }
962
963 fn try_assemble_bounds_via_registered_opaques<G: GoalKind<D>>(
975 &mut self,
976 goal: Goal<I, G>,
977 assemble_from: AssembleCandidatesFrom,
978 candidates: &mut Vec<Candidate<I>>,
979 ) {
980 let self_ty = goal.predicate.self_ty();
981 let opaque_types = match self.typing_mode() {
983 TypingMode::Analysis { .. } => self.opaques_with_sub_unified_hidden_type(self_ty),
984 TypingMode::Coherence
985 | TypingMode::Borrowck { .. }
986 | TypingMode::PostBorrowckAnalysis { .. }
987 | TypingMode::PostAnalysis => vec![],
988 };
989
990 if opaque_types.is_empty() {
991 candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
992 return;
993 }
994
995 for &alias_ty in &opaque_types {
996 debug!("self ty is sub unified with {alias_ty:?}");
997
998 struct ReplaceOpaque<I: Interner> {
999 cx: I,
1000 alias_ty: ty::AliasTy<I>,
1001 self_ty: I::Ty,
1002 }
1003 impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> {
1004 fn cx(&self) -> I {
1005 self.cx
1006 }
1007 fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1008 if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
1009 if alias_ty == self.alias_ty {
1010 return self.self_ty;
1011 }
1012 }
1013 ty.super_fold_with(self)
1014 }
1015 }
1016
1017 for item_bound in self
1025 .cx()
1026 .item_self_bounds(alias_ty.def_id)
1027 .iter_instantiated(self.cx(), alias_ty.args)
1028 {
1029 let assumption =
1030 item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
1031 candidates.extend(G::probe_and_match_goal_against_assumption(
1032 self,
1033 CandidateSource::AliasBound,
1034 goal,
1035 assumption,
1036 |ecx| {
1037 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
1040 },
1041 ));
1042 }
1043 }
1044
1045 if assemble_from.should_assemble_impl_candidates() {
1050 let cx = self.cx();
1051 cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
1052 if cx.impl_is_default(impl_def_id) {
1056 return;
1057 }
1058
1059 match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
1060 if ecx.shallow_resolve(self_ty).is_ty_var() {
1061 let certainty = certainty.and(Certainty::AMBIGUOUS);
1063 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
1064 } else {
1065 Err(NoSolution)
1071 }
1072 }) {
1073 Ok(candidate) => candidates.push(candidate),
1074 Err(NoSolution) => (),
1075 }
1076 });
1077 }
1078
1079 if candidates.is_empty() {
1080 let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
1081 let certainty = Certainty::Maybe {
1082 cause: MaybeCause::Ambiguity,
1083 opaque_types_jank: OpaqueTypesJank::ErrorIfRigidSelfTy,
1084 };
1085 candidates
1086 .extend(self.probe_trait_candidate(source).enter(|this| {
1087 this.evaluate_added_goals_and_make_canonical_response(certainty)
1088 }));
1089 }
1090 }
1091
1092 #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
1123 pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
1124 &mut self,
1125 proven_via: Option<TraitGoalProvenVia>,
1126 goal: Goal<I, G>,
1127 inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
1128 ) -> QueryResult<I> {
1129 let Some(proven_via) = proven_via else {
1130 return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
1137 };
1138
1139 match proven_via {
1140 TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
1141 let (mut candidates, _) = self
1145 .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
1146
1147 if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
1150 candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
1151 } else if candidates.is_empty() {
1152 return inject_normalize_to_rigid_candidate(self);
1155 }
1156
1157 if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1158 Ok(response)
1159 } else {
1160 self.flounder(&candidates)
1161 }
1162 }
1163 TraitGoalProvenVia::Misc => {
1164 let (mut candidates, _) =
1165 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1166
1167 if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
1170 candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
1171 }
1172
1173 self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
1179 if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1180 Ok(response)
1181 } else {
1182 self.flounder(&candidates)
1183 }
1184 }
1185 }
1186 }
1187
1188 fn characterize_param_env_assumption(
1202 &mut self,
1203 param_env: I::ParamEnv,
1204 assumption: I::Clause,
1205 ) -> Result<CandidateSource<I>, NoSolution> {
1206 if assumption.has_bound_vars() {
1209 return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1210 }
1211
1212 match assumption.visit_with(&mut FindParamInClause {
1213 ecx: self,
1214 param_env,
1215 universes: vec![],
1216 }) {
1217 ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1218 ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1219 ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1220 }
1221 }
1222}
1223
1224struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
1225 ecx: &'a mut EvalCtxt<'b, D>,
1226 param_env: I::ParamEnv,
1227 universes: Vec<Option<ty::UniverseIndex>>,
1228}
1229
1230impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
1231where
1232 D: SolverDelegate<Interner = I>,
1233 I: Interner,
1234{
1235 type Result = ControlFlow<Result<(), NoSolution>>;
1236
1237 fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
1238 self.universes.push(None);
1239 t.super_visit_with(self)?;
1240 self.universes.pop();
1241 ControlFlow::Continue(())
1242 }
1243
1244 fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
1245 let ty = self.ecx.replace_bound_vars(ty, &mut self.universes);
1246 let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
1247 return ControlFlow::Break(Err(NoSolution));
1248 };
1249
1250 if let ty::Placeholder(p) = ty.kind() {
1251 if p.universe() == ty::UniverseIndex::ROOT {
1252 ControlFlow::Break(Ok(()))
1253 } else {
1254 ControlFlow::Continue(())
1255 }
1256 } else if ty.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1257 ty.super_visit_with(self)
1258 } else {
1259 ControlFlow::Continue(())
1260 }
1261 }
1262
1263 fn visit_const(&mut self, ct: I::Const) -> Self::Result {
1264 let ct = self.ecx.replace_bound_vars(ct, &mut self.universes);
1265 let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
1266 return ControlFlow::Break(Err(NoSolution));
1267 };
1268
1269 if let ty::ConstKind::Placeholder(p) = ct.kind() {
1270 if p.universe() == ty::UniverseIndex::ROOT {
1271 ControlFlow::Break(Ok(()))
1272 } else {
1273 ControlFlow::Continue(())
1274 }
1275 } else if ct.has_type_flags(TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_RE_INFER) {
1276 ct.super_visit_with(self)
1277 } else {
1278 ControlFlow::Continue(())
1279 }
1280 }
1281
1282 fn visit_region(&mut self, r: I::Region) -> Self::Result {
1283 match self.ecx.eager_resolve_region(r).kind() {
1284 ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()),
1285 ty::RePlaceholder(p) => {
1286 if p.universe() == ty::UniverseIndex::ROOT {
1287 ControlFlow::Break(Ok(()))
1288 } else {
1289 ControlFlow::Continue(())
1290 }
1291 }
1292 ty::ReVar(_) => ControlFlow::Break(Ok(())),
1293 ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
1294 unreachable!("unexpected region in param-env clause")
1295 }
1296 }
1297 }
1298}