1use rustc_type_ir::data_structures::IndexSet;
4use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::SolverTraitLangItem;
7use rustc_type_ir::solve::{
8 AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, SizedTraitKind,
9};
10use rustc_type_ir::{
11 self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
12 TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
13};
14use tracing::{debug, instrument, trace};
15
16use crate::delegate::SolverDelegate;
17use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
18use crate::solve::assembly::{
19 self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate, FailedCandidateInfo,
20};
21use crate::solve::inspect::ProbeKind;
22use crate::solve::{
23 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
24 MergeCandidateInfo, NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
25};
26
27impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
28where
29 D: SolverDelegate<Interner = I>,
30 I: Interner,
31{
32 fn self_ty(self) -> I::Ty {
33 self.self_ty()
34 }
35
36 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
37 self.trait_ref
38 }
39
40 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
41 self.with_replaced_self_ty(cx, self_ty)
42 }
43
44 fn trait_def_id(self, _: I) -> I::TraitId {
45 self.def_id()
46 }
47
48 fn consider_additional_alias_assumptions(
49 _ecx: &mut EvalCtxt<'_, D>,
50 _goal: Goal<I, Self>,
51 _alias_ty: ty::AliasTy<I>,
52 ) -> Vec<Candidate<I>> {
53 vec![]
54 }
55
56 fn consider_impl_candidate(
57 ecx: &mut EvalCtxt<'_, D>,
58 goal: Goal<I, TraitPredicate<I>>,
59 impl_def_id: I::ImplId,
60 then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
61 ) -> Result<Candidate<I>, NoSolution> {
62 let cx = ecx.cx();
63
64 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
65 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
66 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
67 {
68 return Err(NoSolution);
69 }
70
71 let impl_polarity = cx.impl_polarity(impl_def_id);
74 let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
75 (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
78 TypingMode::Coherence => Certainty::AMBIGUOUS,
79 TypingMode::Analysis { .. }
80 | TypingMode::Borrowck { .. }
81 | TypingMode::PostBorrowckAnalysis { .. }
82 | TypingMode::PostAnalysis => return Err(NoSolution),
83 },
84
85 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
87 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
88
89 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
91 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
92 return Err(NoSolution);
93 }
94 };
95
96 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
97 let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
98 ecx.record_impl_args(impl_args);
99 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
100
101 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
102 let where_clause_bounds = cx
103 .predicates_of(impl_def_id.into())
104 .iter_instantiated(cx, impl_args)
105 .map(|pred| goal.with(cx, pred));
106 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
107
108 ecx.add_goals(
112 GoalSource::Misc,
113 cx.impl_super_outlives(impl_def_id)
114 .iter_instantiated(cx, impl_args)
115 .map(|pred| goal.with(cx, pred)),
116 );
117
118 then(ecx, maximal_certainty)
119 })
120 }
121
122 fn consider_error_guaranteed_candidate(
123 ecx: &mut EvalCtxt<'_, D>,
124 _guar: I::ErrorGuaranteed,
125 ) -> Result<Candidate<I>, NoSolution> {
126 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
127 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
128 }
129
130 fn fast_reject_assumption(
131 ecx: &mut EvalCtxt<'_, D>,
132 goal: Goal<I, Self>,
133 assumption: I::Clause,
134 ) -> Result<(), NoSolution> {
135 fn trait_def_id_matches<I: Interner>(
136 cx: I,
137 clause_def_id: I::TraitId,
138 goal_def_id: I::TraitId,
139 polarity: PredicatePolarity,
140 ) -> bool {
141 clause_def_id == goal_def_id
142 || (polarity == PredicatePolarity::Positive
147 && cx.is_trait_lang_item(clause_def_id, SolverTraitLangItem::Sized)
148 && cx.is_trait_lang_item(goal_def_id, SolverTraitLangItem::MetaSized))
149 }
150
151 if let Some(trait_clause) = assumption.as_trait_clause()
152 && trait_clause.polarity() == goal.predicate.polarity
153 && trait_def_id_matches(
154 ecx.cx(),
155 trait_clause.def_id(),
156 goal.predicate.def_id(),
157 goal.predicate.polarity,
158 )
159 && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
160 goal.predicate.trait_ref.args,
161 trait_clause.skip_binder().trait_ref.args,
162 )
163 {
164 return Ok(());
165 } else {
166 Err(NoSolution)
167 }
168 }
169
170 fn match_assumption(
171 ecx: &mut EvalCtxt<'_, D>,
172 goal: Goal<I, Self>,
173 assumption: I::Clause,
174 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
175 ) -> QueryResult<I> {
176 let trait_clause = assumption.as_trait_clause().unwrap();
177
178 if ecx.cx().is_trait_lang_item(goal.predicate.def_id(), SolverTraitLangItem::MetaSized)
184 && ecx.cx().is_trait_lang_item(trait_clause.def_id(), SolverTraitLangItem::Sized)
185 {
186 let meta_sized_clause =
187 trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
188 return Self::match_assumption(ecx, goal, meta_sized_clause, then);
189 }
190
191 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
192 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
193
194 then(ecx)
195 }
196
197 fn consider_auto_trait_candidate(
198 ecx: &mut EvalCtxt<'_, D>,
199 goal: Goal<I, Self>,
200 ) -> Result<Candidate<I>, NoSolution> {
201 let cx = ecx.cx();
202 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
203 return Err(NoSolution);
204 }
205
206 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
207 return result;
208 }
209
210 if cx.trait_is_unsafe(goal.predicate.def_id())
213 && goal.predicate.self_ty().has_unsafe_fields()
214 {
215 return Err(NoSolution);
216 }
217
218 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
234 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
235 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
236 if item_bound
237 .as_trait_clause()
238 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
239 {
240 return Err(NoSolution);
241 }
242 }
243 }
244
245 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
247 return cand;
248 }
249
250 ecx.probe_and_evaluate_goal_for_constituent_tys(
251 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
252 goal,
253 structural_traits::instantiate_constituent_tys_for_auto_trait,
254 )
255 }
256
257 fn consider_trait_alias_candidate(
258 ecx: &mut EvalCtxt<'_, D>,
259 goal: Goal<I, Self>,
260 ) -> Result<Candidate<I>, NoSolution> {
261 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
262 return Err(NoSolution);
263 }
264
265 let cx = ecx.cx();
266
267 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
268 let nested_obligations = cx
269 .predicates_of(goal.predicate.def_id().into())
270 .iter_instantiated(cx, goal.predicate.trait_ref.args)
271 .map(|p| goal.with(cx, p));
272 ecx.add_goals(GoalSource::Misc, nested_obligations);
278 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
279 })
280 }
281
282 fn consider_builtin_sizedness_candidates(
283 ecx: &mut EvalCtxt<'_, D>,
284 goal: Goal<I, Self>,
285 sizedness: SizedTraitKind,
286 ) -> Result<Candidate<I>, NoSolution> {
287 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
288 return Err(NoSolution);
289 }
290
291 ecx.probe_and_evaluate_goal_for_constituent_tys(
292 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
293 goal,
294 |ecx, ty| {
295 structural_traits::instantiate_constituent_tys_for_sizedness_trait(
296 ecx, sizedness, ty,
297 )
298 },
299 )
300 }
301
302 fn consider_builtin_copy_clone_candidate(
303 ecx: &mut EvalCtxt<'_, D>,
304 goal: Goal<I, Self>,
305 ) -> Result<Candidate<I>, NoSolution> {
306 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
307 return Err(NoSolution);
308 }
309
310 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
312 return cand;
313 }
314
315 ecx.probe_and_evaluate_goal_for_constituent_tys(
316 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
317 goal,
318 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
319 )
320 }
321
322 fn consider_builtin_fn_ptr_trait_candidate(
323 ecx: &mut EvalCtxt<'_, D>,
324 goal: Goal<I, Self>,
325 ) -> Result<Candidate<I>, NoSolution> {
326 let self_ty = goal.predicate.self_ty();
327 match goal.predicate.polarity {
328 ty::PredicatePolarity::Positive => {
330 if self_ty.is_fn_ptr() {
331 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
332 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
333 })
334 } else {
335 Err(NoSolution)
336 }
337 }
338 ty::PredicatePolarity::Negative => {
340 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
343 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
344 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
345 })
346 } else {
347 Err(NoSolution)
348 }
349 }
350 }
351 }
352
353 fn consider_builtin_fn_trait_candidates(
354 ecx: &mut EvalCtxt<'_, D>,
355 goal: Goal<I, Self>,
356 goal_kind: ty::ClosureKind,
357 ) -> Result<Candidate<I>, NoSolution> {
358 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
359 return Err(NoSolution);
360 }
361
362 let cx = ecx.cx();
363 let tupled_inputs_and_output =
364 match structural_traits::extract_tupled_inputs_and_output_from_callable(
365 cx,
366 goal.predicate.self_ty(),
367 goal_kind,
368 )? {
369 Some(a) => a,
370 None => {
371 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
372 }
373 };
374 let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);
375
376 let output_is_sized_pred =
379 ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
380
381 let pred =
382 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
383 .upcast(cx);
384 Self::probe_and_consider_implied_clause(
385 ecx,
386 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
387 goal,
388 pred,
389 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
390 )
391 }
392
393 fn consider_builtin_async_fn_trait_candidates(
394 ecx: &mut EvalCtxt<'_, D>,
395 goal: Goal<I, Self>,
396 goal_kind: ty::ClosureKind,
397 ) -> Result<Candidate<I>, NoSolution> {
398 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
399 return Err(NoSolution);
400 }
401
402 let cx = ecx.cx();
403 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
404 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
405 cx,
406 goal.predicate.self_ty(),
407 goal_kind,
408 Region::new_static(cx),
410 )?;
411 let AsyncCallableRelevantTypes {
412 tupled_inputs_ty,
413 output_coroutine_ty,
414 coroutine_return_ty: _,
415 } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine);
416
417 let output_is_sized_pred = ty::TraitRef::new(
420 cx,
421 cx.require_trait_lang_item(SolverTraitLangItem::Sized),
422 [output_coroutine_ty],
423 );
424
425 let pred = ty::TraitRef::new(
426 cx,
427 goal.predicate.def_id(),
428 [goal.predicate.self_ty(), tupled_inputs_ty],
429 )
430 .upcast(cx);
431 Self::probe_and_consider_implied_clause(
432 ecx,
433 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
434 goal,
435 pred,
436 [goal.with(cx, output_is_sized_pred)]
437 .into_iter()
438 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
439 .map(|goal| (GoalSource::ImplWhereBound, goal)),
440 )
441 }
442
443 fn consider_builtin_async_fn_kind_helper_candidate(
444 ecx: &mut EvalCtxt<'_, D>,
445 goal: Goal<I, Self>,
446 ) -> Result<Candidate<I>, NoSolution> {
447 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
448 panic!();
449 };
450
451 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
452 return Err(NoSolution);
454 };
455 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
456 if closure_kind.extends(goal_kind) {
457 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
458 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
459 } else {
460 Err(NoSolution)
461 }
462 }
463
464 fn consider_builtin_tuple_candidate(
471 ecx: &mut EvalCtxt<'_, D>,
472 goal: Goal<I, Self>,
473 ) -> Result<Candidate<I>, NoSolution> {
474 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
475 return Err(NoSolution);
476 }
477
478 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
479 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
480 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
481 } else {
482 Err(NoSolution)
483 }
484 }
485
486 fn consider_builtin_pointee_candidate(
487 ecx: &mut EvalCtxt<'_, D>,
488 goal: Goal<I, Self>,
489 ) -> Result<Candidate<I>, NoSolution> {
490 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
491 return Err(NoSolution);
492 }
493
494 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
495 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
496 }
497
498 fn consider_builtin_future_candidate(
499 ecx: &mut EvalCtxt<'_, D>,
500 goal: Goal<I, Self>,
501 ) -> Result<Candidate<I>, NoSolution> {
502 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
503 return Err(NoSolution);
504 }
505
506 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
507 return Err(NoSolution);
508 };
509
510 let cx = ecx.cx();
512 if !cx.coroutine_is_async(def_id) {
513 return Err(NoSolution);
514 }
515
516 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
520 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
521 }
522
523 fn consider_builtin_iterator_candidate(
524 ecx: &mut EvalCtxt<'_, D>,
525 goal: Goal<I, Self>,
526 ) -> Result<Candidate<I>, NoSolution> {
527 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
528 return Err(NoSolution);
529 }
530
531 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
532 return Err(NoSolution);
533 };
534
535 let cx = ecx.cx();
537 if !cx.coroutine_is_gen(def_id) {
538 return Err(NoSolution);
539 }
540
541 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
545 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
546 }
547
548 fn consider_builtin_fused_iterator_candidate(
549 ecx: &mut EvalCtxt<'_, D>,
550 goal: Goal<I, Self>,
551 ) -> Result<Candidate<I>, NoSolution> {
552 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
553 return Err(NoSolution);
554 }
555
556 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
557 return Err(NoSolution);
558 };
559
560 let cx = ecx.cx();
562 if !cx.coroutine_is_gen(def_id) {
563 return Err(NoSolution);
564 }
565
566 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
568 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
569 }
570
571 fn consider_builtin_async_iterator_candidate(
572 ecx: &mut EvalCtxt<'_, D>,
573 goal: Goal<I, Self>,
574 ) -> Result<Candidate<I>, NoSolution> {
575 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
576 return Err(NoSolution);
577 }
578
579 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
580 return Err(NoSolution);
581 };
582
583 let cx = ecx.cx();
585 if !cx.coroutine_is_async_gen(def_id) {
586 return Err(NoSolution);
587 }
588
589 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
593 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
594 }
595
596 fn consider_builtin_coroutine_candidate(
597 ecx: &mut EvalCtxt<'_, D>,
598 goal: Goal<I, Self>,
599 ) -> Result<Candidate<I>, NoSolution> {
600 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
601 return Err(NoSolution);
602 }
603
604 let self_ty = goal.predicate.self_ty();
605 let ty::Coroutine(def_id, args) = self_ty.kind() else {
606 return Err(NoSolution);
607 };
608
609 let cx = ecx.cx();
611 if !cx.is_general_coroutine(def_id) {
612 return Err(NoSolution);
613 }
614
615 let coroutine = args.as_coroutine();
616 Self::probe_and_consider_implied_clause(
617 ecx,
618 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
619 goal,
620 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
621 .upcast(cx),
622 [],
625 )
626 }
627
628 fn consider_builtin_discriminant_kind_candidate(
629 ecx: &mut EvalCtxt<'_, D>,
630 goal: Goal<I, Self>,
631 ) -> Result<Candidate<I>, NoSolution> {
632 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
633 return Err(NoSolution);
634 }
635
636 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
638 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
639 }
640
641 fn consider_builtin_destruct_candidate(
642 ecx: &mut EvalCtxt<'_, D>,
643 goal: Goal<I, Self>,
644 ) -> Result<Candidate<I>, NoSolution> {
645 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
646 return Err(NoSolution);
647 }
648
649 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
652 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
653 }
654
655 fn consider_builtin_transmute_candidate(
656 ecx: &mut EvalCtxt<'_, D>,
657 goal: Goal<I, Self>,
658 ) -> Result<Candidate<I>, NoSolution> {
659 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
660 return Err(NoSolution);
661 }
662
663 if goal.has_non_region_placeholders() {
665 return Err(NoSolution);
666 }
667
668 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
669 let assume = ecx.structurally_normalize_const(
670 goal.param_env,
671 goal.predicate.trait_ref.args.const_at(2),
672 )?;
673
674 let certainty = ecx.is_transmutable(
675 goal.predicate.trait_ref.args.type_at(0),
676 goal.predicate.trait_ref.args.type_at(1),
677 assume,
678 )?;
679 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
680 })
681 }
682
683 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
693 ecx: &mut EvalCtxt<'_, D>,
694 goal: Goal<I, Self>,
695 ) -> Result<Candidate<I>, NoSolution> {
696 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
697 return Err(NoSolution);
698 }
699
700 let cx = ecx.cx();
701 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
702 let ty = goal.predicate.self_ty();
703 match ty.kind() {
704 ty::Ref(..) => {}
706 ty::Adt(def, _) if def.is_manually_drop() => {}
708 ty::Tuple(tys) => {
711 ecx.add_goals(
712 GoalSource::ImplWhereBound,
713 tys.iter().map(|elem_ty| {
714 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
715 }),
716 );
717 }
718 ty::Array(elem_ty, _) => {
719 ecx.add_goal(
720 GoalSource::ImplWhereBound,
721 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
722 );
723 }
724
725 ty::FnDef(..)
729 | ty::FnPtr(..)
730 | ty::Error(_)
731 | ty::Uint(_)
732 | ty::Int(_)
733 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
734 | ty::Bool
735 | ty::Float(_)
736 | ty::Char
737 | ty::RawPtr(..)
738 | ty::Never
739 | ty::Pat(..)
740 | ty::Dynamic(..)
741 | ty::Str
742 | ty::Slice(_)
743 | ty::Foreign(..)
744 | ty::Adt(..)
745 | ty::Alias(..)
746 | ty::Param(_)
747 | ty::Placeholder(..)
748 | ty::Closure(..)
749 | ty::CoroutineClosure(..)
750 | ty::Coroutine(..)
751 | ty::UnsafeBinder(_)
752 | ty::CoroutineWitness(..) => {
753 ecx.add_goal(
754 GoalSource::ImplWhereBound,
755 goal.with(
756 cx,
757 ty::TraitRef::new(
758 cx,
759 cx.require_trait_lang_item(SolverTraitLangItem::Copy),
760 [ty],
761 ),
762 ),
763 );
764 }
765
766 ty::Bound(..)
767 | ty::Infer(
768 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
769 ) => {
770 panic!("unexpected type `{ty:?}`")
771 }
772 }
773
774 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
775 })
776 }
777
778 fn consider_structural_builtin_unsize_candidates(
786 ecx: &mut EvalCtxt<'_, D>,
787 goal: Goal<I, Self>,
788 ) -> Vec<Candidate<I>> {
789 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
790 return vec![];
791 }
792
793 let result_to_single = |result| match result {
794 Ok(resp) => vec![resp],
795 Err(NoSolution) => vec![],
796 };
797
798 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
799 let a_ty = goal.predicate.self_ty();
800 let Ok(b_ty) = ecx.structurally_normalize_ty(
803 goal.param_env,
804 goal.predicate.trait_ref.args.type_at(1),
805 ) else {
806 return vec![];
807 };
808
809 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
810 match (a_ty.kind(), b_ty.kind()) {
811 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
812
813 (_, ty::Infer(ty::TyVar(..))) => {
814 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
815 }
816
817 (ty::Dynamic(a_data, a_region), ty::Dynamic(b_data, b_region)) => ecx
819 .consider_builtin_dyn_upcast_candidates(
820 goal, a_data, a_region, b_data, b_region,
821 ),
822
823 (_, ty::Dynamic(b_region, b_data)) => result_to_single(
825 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
826 ),
827
828 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
830 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
831 }
832
833 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
835 if a_def.is_struct() && a_def == b_def =>
836 {
837 result_to_single(
838 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
839 )
840 }
841
842 _ => vec![],
843 }
844 })
845 }
846}
847
848#[inline(always)]
854fn trait_predicate_with_def_id<I: Interner>(
855 cx: I,
856 clause: ty::Binder<I, ty::TraitPredicate<I>>,
857 did: I::TraitId,
858) -> I::Clause {
859 clause
860 .map_bound(|c| TraitPredicate {
861 trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
862 polarity: c.polarity,
863 })
864 .upcast(cx)
865}
866
867impl<D, I> EvalCtxt<'_, D>
868where
869 D: SolverDelegate<Interner = I>,
870 I: Interner,
871{
872 fn consider_builtin_dyn_upcast_candidates(
882 &mut self,
883 goal: Goal<I, (I::Ty, I::Ty)>,
884 a_data: I::BoundExistentialPredicates,
885 a_region: I::Region,
886 b_data: I::BoundExistentialPredicates,
887 b_region: I::Region,
888 ) -> Vec<Candidate<I>> {
889 let cx = self.cx();
890 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
891
892 let mut responses = vec![];
893 let b_principal_def_id = b_data.principal_def_id();
896 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
897 responses.extend(self.consider_builtin_upcast_to_principal(
898 goal,
899 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
900 a_data,
901 a_region,
902 b_data,
903 b_region,
904 a_data.principal(),
905 ));
906 } else if let Some(a_principal) = a_data.principal() {
907 for (idx, new_a_principal) in
908 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
909 .enumerate()
910 .skip(1)
911 {
912 responses.extend(self.consider_builtin_upcast_to_principal(
913 goal,
914 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
915 a_data,
916 a_region,
917 b_data,
918 b_region,
919 Some(new_a_principal.map_bound(|trait_ref| {
920 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
921 })),
922 ));
923 }
924 }
925
926 responses
927 }
928
929 fn consider_builtin_unsize_to_dyn_candidate(
930 &mut self,
931 goal: Goal<I, (I::Ty, I::Ty)>,
932 b_data: I::BoundExistentialPredicates,
933 b_region: I::Region,
934 ) -> Result<Candidate<I>, NoSolution> {
935 let cx = self.cx();
936 let Goal { predicate: (a_ty, _), .. } = goal;
937
938 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
940 return Err(NoSolution);
941 }
942
943 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
944 ecx.add_goals(
947 GoalSource::ImplWhereBound,
948 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
949 );
950
951 ecx.add_goal(
953 GoalSource::ImplWhereBound,
954 goal.with(
955 cx,
956 ty::TraitRef::new(
957 cx,
958 cx.require_trait_lang_item(SolverTraitLangItem::Sized),
959 [a_ty],
960 ),
961 ),
962 );
963
964 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
966 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
967 })
968 }
969
970 fn consider_builtin_upcast_to_principal(
971 &mut self,
972 goal: Goal<I, (I::Ty, I::Ty)>,
973 source: CandidateSource<I>,
974 a_data: I::BoundExistentialPredicates,
975 a_region: I::Region,
976 b_data: I::BoundExistentialPredicates,
977 b_region: I::Region,
978 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
979 ) -> Result<Candidate<I>, NoSolution> {
980 let param_env = goal.param_env;
981
982 let a_auto_traits: IndexSet<I::TraitId> = a_data
986 .auto_traits()
987 .into_iter()
988 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
989 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
990 .filter(|def_id| self.cx().trait_is_auto(*def_id))
991 }))
992 .collect();
993
994 let projection_may_match =
999 |ecx: &mut EvalCtxt<'_, D>,
1000 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
1001 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
1002 source_projection.item_def_id() == target_projection.item_def_id()
1003 && ecx
1004 .probe(|_| ProbeKind::ProjectionCompatibility)
1005 .enter(|ecx| -> Result<_, NoSolution> {
1006 ecx.enter_forall(target_projection, |ecx, target_projection| {
1007 let source_projection =
1008 ecx.instantiate_binder_with_infer(source_projection);
1009 ecx.eq(param_env, source_projection, target_projection)?;
1010 ecx.try_evaluate_added_goals()
1011 })
1012 })
1013 .is_ok()
1014 };
1015
1016 self.probe_trait_candidate(source).enter(|ecx| {
1017 for bound in b_data.iter() {
1018 match bound.skip_binder() {
1019 ty::ExistentialPredicate::Trait(target_principal) => {
1022 let source_principal = upcast_principal.unwrap();
1023 let target_principal = bound.rebind(target_principal);
1024 ecx.enter_forall(target_principal, |ecx, target_principal| {
1025 let source_principal =
1026 ecx.instantiate_binder_with_infer(source_principal);
1027 ecx.eq(param_env, source_principal, target_principal)?;
1028 ecx.try_evaluate_added_goals()
1029 })?;
1030 }
1031 ty::ExistentialPredicate::Projection(target_projection) => {
1037 let target_projection = bound.rebind(target_projection);
1038 let mut matching_projections =
1039 a_data.projection_bounds().into_iter().filter(|source_projection| {
1040 projection_may_match(ecx, *source_projection, target_projection)
1041 });
1042 let Some(source_projection) = matching_projections.next() else {
1043 return Err(NoSolution);
1044 };
1045 if matching_projections.next().is_some() {
1046 return ecx.evaluate_added_goals_and_make_canonical_response(
1047 Certainty::AMBIGUOUS,
1048 );
1049 }
1050 ecx.enter_forall(target_projection, |ecx, target_projection| {
1051 let source_projection =
1052 ecx.instantiate_binder_with_infer(source_projection);
1053 ecx.eq(param_env, source_projection, target_projection)?;
1054 ecx.try_evaluate_added_goals()
1055 })?;
1056 }
1057 ty::ExistentialPredicate::AutoTrait(def_id) => {
1059 if !a_auto_traits.contains(&def_id) {
1060 return Err(NoSolution);
1061 }
1062 }
1063 }
1064 }
1065
1066 ecx.add_goal(
1068 GoalSource::ImplWhereBound,
1069 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1070 );
1071
1072 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1073 })
1074 }
1075
1076 fn consider_builtin_array_unsize(
1085 &mut self,
1086 goal: Goal<I, (I::Ty, I::Ty)>,
1087 a_elem_ty: I::Ty,
1088 b_elem_ty: I::Ty,
1089 ) -> Result<Candidate<I>, NoSolution> {
1090 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1091 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1092 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1093 }
1094
1095 fn consider_builtin_struct_unsize(
1109 &mut self,
1110 goal: Goal<I, (I::Ty, I::Ty)>,
1111 def: I::AdtDef,
1112 a_args: I::GenericArgs,
1113 b_args: I::GenericArgs,
1114 ) -> Result<Candidate<I>, NoSolution> {
1115 let cx = self.cx();
1116 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1117
1118 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1119 if unsizing_params.is_empty() {
1122 return Err(NoSolution);
1123 }
1124
1125 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1126
1127 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1128 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1129
1130 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1134 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1135 }));
1136 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1137
1138 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1141 self.add_goal(
1142 GoalSource::ImplWhereBound,
1143 goal.with(
1144 cx,
1145 ty::TraitRef::new(
1146 cx,
1147 cx.require_trait_lang_item(SolverTraitLangItem::Unsize),
1148 [a_tail_ty, b_tail_ty],
1149 ),
1150 ),
1151 );
1152 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1153 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1154 }
1155
1156 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1161 &mut self,
1162 goal: Goal<I, TraitPredicate<I>>,
1163 ) -> Option<Result<Candidate<I>, NoSolution>> {
1164 let self_ty = goal.predicate.self_ty();
1165 let check_impls = || {
1166 let mut disqualifying_impl = None;
1167 self.cx().for_each_relevant_impl(
1168 goal.predicate.def_id(),
1169 goal.predicate.self_ty(),
1170 |impl_def_id| {
1171 disqualifying_impl = Some(impl_def_id);
1172 },
1173 );
1174 if let Some(def_id) = disqualifying_impl {
1175 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1176 return Some(Err(NoSolution));
1179 } else {
1180 None
1181 }
1182 };
1183
1184 match self_ty.kind() {
1185 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1191 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1192 }
1193
1194 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1197
1198 ty::Dynamic(..)
1201 | ty::Param(..)
1202 | ty::Foreign(..)
1203 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1204 | ty::Placeholder(..) => Some(Err(NoSolution)),
1205
1206 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1207
1208 ty::Coroutine(def_id, _)
1212 if self
1213 .cx()
1214 .is_trait_lang_item(goal.predicate.def_id(), SolverTraitLangItem::Unpin) =>
1215 {
1216 match self.cx().coroutine_movability(def_id) {
1217 Movability::Static => Some(Err(NoSolution)),
1218 Movability::Movable => Some(
1219 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1220 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1221 }),
1222 ),
1223 }
1224 }
1225
1226 ty::Alias(..) => None,
1231
1232 ty::Bool
1239 | ty::Char
1240 | ty::Int(_)
1241 | ty::Uint(_)
1242 | ty::Float(_)
1243 | ty::Str
1244 | ty::Array(_, _)
1245 | ty::Pat(_, _)
1246 | ty::Slice(_)
1247 | ty::RawPtr(_, _)
1248 | ty::Ref(_, _, _)
1249 | ty::FnDef(_, _)
1250 | ty::FnPtr(..)
1251 | ty::Closure(..)
1252 | ty::CoroutineClosure(..)
1253 | ty::Coroutine(_, _)
1254 | ty::CoroutineWitness(..)
1255 | ty::Never
1256 | ty::Tuple(_)
1257 | ty::Adt(_, _)
1258 | ty::UnsafeBinder(_) => check_impls(),
1259 ty::Error(_) => None,
1260 }
1261 }
1262
1263 fn probe_and_evaluate_goal_for_constituent_tys(
1268 &mut self,
1269 source: CandidateSource<I>,
1270 goal: Goal<I, TraitPredicate<I>>,
1271 constituent_tys: impl Fn(
1272 &EvalCtxt<'_, D>,
1273 I::Ty,
1274 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1275 ) -> Result<Candidate<I>, NoSolution> {
1276 self.probe_trait_candidate(source).enter(|ecx| {
1277 let goals =
1278 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1279 tys.into_iter()
1280 .map(|ty| {
1281 goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty))
1282 })
1283 .collect::<Vec<_>>()
1284 });
1285 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1286 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1287 })
1288 }
1289}
1290
1291#[derive(Debug, Clone, Copy)]
1302pub(super) enum TraitGoalProvenVia {
1303 Misc,
1309 ParamEnv,
1310 AliasBound,
1311}
1312
1313impl<D, I> EvalCtxt<'_, D>
1314where
1315 D: SolverDelegate<Interner = I>,
1316 I: Interner,
1317{
1318 pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1331 match self.typing_mode() {
1332 TypingMode::Coherence => return,
1333 TypingMode::Analysis { .. }
1334 | TypingMode::Borrowck { .. }
1335 | TypingMode::PostBorrowckAnalysis { .. }
1336 | TypingMode::PostAnalysis => {}
1337 }
1338
1339 if candidates
1340 .iter()
1341 .find(|c| {
1342 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1343 })
1344 .is_some_and(|c| has_only_region_constraints(c.result))
1345 {
1346 candidates.retain(|c| {
1347 if matches!(c.source, CandidateSource::Impl(_)) {
1348 debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1349 false
1350 } else {
1351 true
1352 }
1353 });
1354 }
1355 }
1356
1357 #[instrument(level = "debug", skip(self), ret)]
1358 pub(super) fn merge_trait_candidates(
1359 &mut self,
1360 candidate_preference_mode: CandidatePreferenceMode,
1361 mut candidates: Vec<Candidate<I>>,
1362 failed_candidate_info: FailedCandidateInfo,
1363 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1364 if let TypingMode::Coherence = self.typing_mode() {
1365 return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1366 Ok((response, Some(TraitGoalProvenVia::Misc)))
1367 } else {
1368 self.flounder(&candidates).map(|r| (r, None))
1369 };
1370 }
1371
1372 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1377 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1378 });
1379 if let Some(candidate) = trivial_builtin_impls.next() {
1380 assert!(trivial_builtin_impls.next().is_none());
1383 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1384 }
1385
1386 if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker)
1389 && candidates.iter().any(|c| {
1390 matches!(c.source, CandidateSource::AliasBound(AliasBoundKind::SelfBounds))
1391 })
1392 {
1393 let alias_bounds: Vec<_> = candidates
1394 .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(..)))
1395 .collect();
1396 return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1397 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1398 } else {
1399 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1400 };
1401 }
1402
1403 let has_non_global_where_bounds = candidates
1406 .iter()
1407 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1408 if has_non_global_where_bounds {
1409 let where_bounds: Vec<_> = candidates
1410 .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
1411 .collect();
1412 if let Some((response, info)) = self.try_merge_candidates(&where_bounds) {
1413 match info {
1414 MergeCandidateInfo::AlwaysApplicable(i) => {
1430 for (j, c) in where_bounds.into_iter().enumerate() {
1431 if i != j {
1432 self.ignore_candidate_head_usages(c.head_usages)
1433 }
1434 }
1435 self.ignore_candidate_head_usages(
1439 failed_candidate_info.param_env_head_usages,
1440 );
1441 }
1442 MergeCandidateInfo::EqualResponse => {}
1443 }
1444 return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
1445 } else {
1446 return Ok((self.bail_with_ambiguity(&where_bounds), None));
1447 };
1448 }
1449
1450 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound(_))) {
1452 let alias_bounds: Vec<_> = candidates
1453 .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(_)))
1454 .collect();
1455 return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1456 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1457 } else {
1458 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1459 };
1460 }
1461
1462 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1463 self.unsound_prefer_builtin_dyn_impl(&mut candidates);
1464
1465 let proven_via = if candidates
1470 .iter()
1471 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1472 {
1473 TraitGoalProvenVia::ParamEnv
1474 } else {
1475 candidates
1476 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1477 TraitGoalProvenVia::Misc
1478 };
1479
1480 if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1481 Ok((response, Some(proven_via)))
1482 } else {
1483 self.flounder(&candidates).map(|r| (r, None))
1484 }
1485 }
1486
1487 #[instrument(level = "trace", skip(self))]
1488 pub(super) fn compute_trait_goal(
1489 &mut self,
1490 goal: Goal<I, TraitPredicate<I>>,
1491 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1492 let (candidates, failed_candidate_info) =
1493 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1494 let candidate_preference_mode =
1495 CandidatePreferenceMode::compute(self.cx(), goal.predicate.def_id());
1496 self.merge_trait_candidates(candidate_preference_mode, candidates, failed_candidate_info)
1497 }
1498
1499 fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> {
1500 if let ty::Coroutine(def_id, _) = self_ty.kind() {
1501 match self.typing_mode() {
1502 TypingMode::Analysis {
1503 defining_opaque_types_and_generators: stalled_generators,
1504 } => {
1505 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1506 {
1507 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1508 }
1509 }
1510 TypingMode::Coherence
1511 | TypingMode::PostAnalysis
1512 | TypingMode::Borrowck { defining_opaque_types: _ }
1513 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1514 }
1515 }
1516
1517 None
1518 }
1519}