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::TraitSolverLangItem;
7use rustc_type_ir::solve::CanonicalResponse;
8use rustc_type_ir::{
9 self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
10 Upcast as _, elaborate,
11};
12use tracing::{instrument, trace};
13
14use crate::delegate::SolverDelegate;
15use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
17use crate::solve::inspect::ProbeKind;
18use crate::solve::{
19 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
20 NoSolution, ParamEnvSource,
21};
22
23impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
24where
25 D: SolverDelegate<Interner = I>,
26 I: Interner,
27{
28 fn self_ty(self) -> I::Ty {
29 self.self_ty()
30 }
31
32 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
33 self.trait_ref
34 }
35
36 fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
37 self.with_self_ty(cx, self_ty)
38 }
39
40 fn trait_def_id(self, _: I) -> I::DefId {
41 self.def_id()
42 }
43
44 fn consider_additional_alias_assumptions(
45 _ecx: &mut EvalCtxt<'_, D>,
46 _goal: Goal<I, Self>,
47 _alias_ty: ty::AliasTy<I>,
48 ) -> Vec<Candidate<I>> {
49 vec![]
50 }
51
52 fn consider_impl_candidate(
53 ecx: &mut EvalCtxt<'_, D>,
54 goal: Goal<I, TraitPredicate<I>>,
55 impl_def_id: I::DefId,
56 ) -> Result<Candidate<I>, NoSolution> {
57 let cx = ecx.cx();
58
59 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
60 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
61 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
62 {
63 return Err(NoSolution);
64 }
65
66 let impl_polarity = cx.impl_polarity(impl_def_id);
69 let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
70 (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
73 TypingMode::Coherence => Certainty::AMBIGUOUS,
74 TypingMode::Analysis { .. }
75 | TypingMode::Borrowck { .. }
76 | TypingMode::PostBorrowckAnalysis { .. }
77 | TypingMode::PostAnalysis => return Err(NoSolution),
78 },
79
80 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
82 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
83
84 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
86 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
87 return Err(NoSolution);
88 }
89 };
90
91 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
92 let impl_args = ecx.fresh_args_for_item(impl_def_id);
93 ecx.record_impl_args(impl_args);
94 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
95
96 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
97 let where_clause_bounds = cx
98 .predicates_of(impl_def_id)
99 .iter_instantiated(cx, impl_args)
100 .map(|pred| goal.with(cx, pred));
101 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
102
103 let goal_clause: I::Clause = goal.predicate.upcast(cx);
107 for clause in elaborate::elaborate(cx, [goal_clause]) {
108 if matches!(
109 clause.kind().skip_binder(),
110 ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
111 ) {
112 ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
113 }
114 }
115
116 ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
117 })
118 }
119
120 fn consider_error_guaranteed_candidate(
121 ecx: &mut EvalCtxt<'_, D>,
122 _guar: I::ErrorGuaranteed,
123 ) -> Result<Candidate<I>, NoSolution> {
124 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
125 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
126 }
127
128 fn fast_reject_assumption(
129 ecx: &mut EvalCtxt<'_, D>,
130 goal: Goal<I, Self>,
131 assumption: I::Clause,
132 ) -> Result<(), NoSolution> {
133 if let Some(trait_clause) = assumption.as_trait_clause() {
134 if trait_clause.def_id() == goal.predicate.def_id()
135 && trait_clause.polarity() == goal.predicate.polarity
136 {
137 if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
138 goal.predicate.trait_ref.args,
139 trait_clause.skip_binder().trait_ref.args,
140 ) {
141 return Ok(());
142 }
143 }
144 }
145
146 Err(NoSolution)
147 }
148
149 fn match_assumption(
150 ecx: &mut EvalCtxt<'_, D>,
151 goal: Goal<I, Self>,
152 assumption: I::Clause,
153 ) -> Result<(), NoSolution> {
154 let trait_clause = assumption.as_trait_clause().unwrap();
155
156 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
157 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
158
159 Ok(())
160 }
161
162 fn consider_auto_trait_candidate(
163 ecx: &mut EvalCtxt<'_, D>,
164 goal: Goal<I, Self>,
165 ) -> Result<Candidate<I>, NoSolution> {
166 let cx = ecx.cx();
167 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
168 return Err(NoSolution);
169 }
170
171 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
172 return result;
173 }
174
175 if cx.trait_is_unsafe(goal.predicate.def_id())
178 && goal.predicate.self_ty().has_unsafe_fields()
179 {
180 return Err(NoSolution);
181 }
182
183 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
199 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
200 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
201 if item_bound
202 .as_trait_clause()
203 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
204 {
205 return Err(NoSolution);
206 }
207 }
208 }
209
210 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
212 return cand;
213 }
214
215 ecx.probe_and_evaluate_goal_for_constituent_tys(
216 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
217 goal,
218 structural_traits::instantiate_constituent_tys_for_auto_trait,
219 )
220 }
221
222 fn consider_trait_alias_candidate(
223 ecx: &mut EvalCtxt<'_, D>,
224 goal: Goal<I, Self>,
225 ) -> Result<Candidate<I>, NoSolution> {
226 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
227 return Err(NoSolution);
228 }
229
230 let cx = ecx.cx();
231
232 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
233 let nested_obligations = cx
234 .predicates_of(goal.predicate.def_id())
235 .iter_instantiated(cx, goal.predicate.trait_ref.args)
236 .map(|p| goal.with(cx, p));
237 ecx.add_goals(GoalSource::Misc, nested_obligations);
239 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
240 })
241 }
242
243 fn consider_builtin_sized_candidate(
244 ecx: &mut EvalCtxt<'_, D>,
245 goal: Goal<I, Self>,
246 ) -> Result<Candidate<I>, NoSolution> {
247 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
248 return Err(NoSolution);
249 }
250
251 ecx.probe_and_evaluate_goal_for_constituent_tys(
252 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
253 goal,
254 structural_traits::instantiate_constituent_tys_for_sized_trait,
255 )
256 }
257
258 fn consider_builtin_copy_clone_candidate(
259 ecx: &mut EvalCtxt<'_, D>,
260 goal: Goal<I, Self>,
261 ) -> Result<Candidate<I>, NoSolution> {
262 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
263 return Err(NoSolution);
264 }
265
266 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
268 return cand;
269 }
270
271 ecx.probe_and_evaluate_goal_for_constituent_tys(
272 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
273 goal,
274 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
275 )
276 }
277
278 fn consider_builtin_fn_ptr_trait_candidate(
279 ecx: &mut EvalCtxt<'_, D>,
280 goal: Goal<I, Self>,
281 ) -> Result<Candidate<I>, NoSolution> {
282 let self_ty = goal.predicate.self_ty();
283 match goal.predicate.polarity {
284 ty::PredicatePolarity::Positive => {
286 if self_ty.is_fn_ptr() {
287 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
288 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
289 })
290 } else {
291 Err(NoSolution)
292 }
293 }
294 ty::PredicatePolarity::Negative => {
296 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
299 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
300 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
301 })
302 } else {
303 Err(NoSolution)
304 }
305 }
306 }
307 }
308
309 fn consider_builtin_fn_trait_candidates(
310 ecx: &mut EvalCtxt<'_, D>,
311 goal: Goal<I, Self>,
312 goal_kind: ty::ClosureKind,
313 ) -> Result<Candidate<I>, NoSolution> {
314 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
315 return Err(NoSolution);
316 }
317
318 let cx = ecx.cx();
319 let tupled_inputs_and_output =
320 match structural_traits::extract_tupled_inputs_and_output_from_callable(
321 cx,
322 goal.predicate.self_ty(),
323 goal_kind,
324 )? {
325 Some(a) => a,
326 None => {
327 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
328 }
329 };
330
331 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
334 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
335 });
336
337 let pred = tupled_inputs_and_output
338 .map_bound(|(inputs, _)| {
339 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
340 })
341 .upcast(cx);
342 Self::probe_and_consider_implied_clause(
343 ecx,
344 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
345 goal,
346 pred,
347 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
348 )
349 }
350
351 fn consider_builtin_async_fn_trait_candidates(
352 ecx: &mut EvalCtxt<'_, D>,
353 goal: Goal<I, Self>,
354 goal_kind: ty::ClosureKind,
355 ) -> Result<Candidate<I>, NoSolution> {
356 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
357 return Err(NoSolution);
358 }
359
360 let cx = ecx.cx();
361 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
362 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
363 cx,
364 goal.predicate.self_ty(),
365 goal_kind,
366 Region::new_static(cx),
368 )?;
369
370 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
373 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
374 ty::TraitRef::new(
375 cx,
376 cx.require_lang_item(TraitSolverLangItem::Sized),
377 [output_coroutine_ty],
378 )
379 },
380 );
381
382 let pred = tupled_inputs_and_output_and_coroutine
383 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
384 ty::TraitRef::new(
385 cx,
386 goal.predicate.def_id(),
387 [goal.predicate.self_ty(), tupled_inputs_ty],
388 )
389 })
390 .upcast(cx);
391 Self::probe_and_consider_implied_clause(
392 ecx,
393 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
394 goal,
395 pred,
396 [goal.with(cx, output_is_sized_pred)]
397 .into_iter()
398 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
399 .map(|goal| (GoalSource::ImplWhereBound, goal)),
400 )
401 }
402
403 fn consider_builtin_async_fn_kind_helper_candidate(
404 ecx: &mut EvalCtxt<'_, D>,
405 goal: Goal<I, Self>,
406 ) -> Result<Candidate<I>, NoSolution> {
407 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
408 panic!();
409 };
410
411 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
412 return Err(NoSolution);
414 };
415 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
416 if closure_kind.extends(goal_kind) {
417 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
418 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
419 } else {
420 Err(NoSolution)
421 }
422 }
423
424 fn consider_builtin_tuple_candidate(
431 ecx: &mut EvalCtxt<'_, D>,
432 goal: Goal<I, Self>,
433 ) -> Result<Candidate<I>, NoSolution> {
434 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
435 return Err(NoSolution);
436 }
437
438 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
439 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
440 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
441 } else {
442 Err(NoSolution)
443 }
444 }
445
446 fn consider_builtin_pointee_candidate(
447 ecx: &mut EvalCtxt<'_, D>,
448 goal: Goal<I, Self>,
449 ) -> Result<Candidate<I>, NoSolution> {
450 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
451 return Err(NoSolution);
452 }
453
454 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
455 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
456 }
457
458 fn consider_builtin_future_candidate(
459 ecx: &mut EvalCtxt<'_, D>,
460 goal: Goal<I, Self>,
461 ) -> Result<Candidate<I>, NoSolution> {
462 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
463 return Err(NoSolution);
464 }
465
466 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
467 return Err(NoSolution);
468 };
469
470 let cx = ecx.cx();
472 if !cx.coroutine_is_async(def_id) {
473 return Err(NoSolution);
474 }
475
476 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
480 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
481 }
482
483 fn consider_builtin_iterator_candidate(
484 ecx: &mut EvalCtxt<'_, D>,
485 goal: Goal<I, Self>,
486 ) -> Result<Candidate<I>, NoSolution> {
487 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
488 return Err(NoSolution);
489 }
490
491 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
492 return Err(NoSolution);
493 };
494
495 let cx = ecx.cx();
497 if !cx.coroutine_is_gen(def_id) {
498 return Err(NoSolution);
499 }
500
501 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
505 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
506 }
507
508 fn consider_builtin_fused_iterator_candidate(
509 ecx: &mut EvalCtxt<'_, D>,
510 goal: Goal<I, Self>,
511 ) -> Result<Candidate<I>, NoSolution> {
512 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
513 return Err(NoSolution);
514 }
515
516 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
517 return Err(NoSolution);
518 };
519
520 let cx = ecx.cx();
522 if !cx.coroutine_is_gen(def_id) {
523 return Err(NoSolution);
524 }
525
526 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
528 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
529 }
530
531 fn consider_builtin_async_iterator_candidate(
532 ecx: &mut EvalCtxt<'_, D>,
533 goal: Goal<I, Self>,
534 ) -> Result<Candidate<I>, NoSolution> {
535 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
536 return Err(NoSolution);
537 }
538
539 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
540 return Err(NoSolution);
541 };
542
543 let cx = ecx.cx();
545 if !cx.coroutine_is_async_gen(def_id) {
546 return Err(NoSolution);
547 }
548
549 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
553 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
554 }
555
556 fn consider_builtin_coroutine_candidate(
557 ecx: &mut EvalCtxt<'_, D>,
558 goal: Goal<I, Self>,
559 ) -> Result<Candidate<I>, NoSolution> {
560 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
561 return Err(NoSolution);
562 }
563
564 let self_ty = goal.predicate.self_ty();
565 let ty::Coroutine(def_id, args) = self_ty.kind() else {
566 return Err(NoSolution);
567 };
568
569 let cx = ecx.cx();
571 if !cx.is_general_coroutine(def_id) {
572 return Err(NoSolution);
573 }
574
575 let coroutine = args.as_coroutine();
576 Self::probe_and_consider_implied_clause(
577 ecx,
578 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
579 goal,
580 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
581 .upcast(cx),
582 [],
585 )
586 }
587
588 fn consider_builtin_discriminant_kind_candidate(
589 ecx: &mut EvalCtxt<'_, D>,
590 goal: Goal<I, Self>,
591 ) -> Result<Candidate<I>, NoSolution> {
592 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
593 return Err(NoSolution);
594 }
595
596 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
598 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
599 }
600
601 fn consider_builtin_destruct_candidate(
602 ecx: &mut EvalCtxt<'_, D>,
603 goal: Goal<I, Self>,
604 ) -> Result<Candidate<I>, NoSolution> {
605 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
606 return Err(NoSolution);
607 }
608
609 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
612 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
613 }
614
615 fn consider_builtin_transmute_candidate(
616 ecx: &mut EvalCtxt<'_, D>,
617 goal: Goal<I, Self>,
618 ) -> Result<Candidate<I>, NoSolution> {
619 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
620 return Err(NoSolution);
621 }
622
623 if goal.has_non_region_placeholders() {
625 return Err(NoSolution);
626 }
627
628 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
629 let assume = ecx.structurally_normalize_const(
630 goal.param_env,
631 goal.predicate.trait_ref.args.const_at(2),
632 )?;
633
634 let certainty = ecx.is_transmutable(
635 goal.predicate.trait_ref.args.type_at(0),
636 goal.predicate.trait_ref.args.type_at(1),
637 assume,
638 )?;
639 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
640 })
641 }
642
643 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
653 ecx: &mut EvalCtxt<'_, D>,
654 goal: Goal<I, Self>,
655 ) -> Result<Candidate<I>, NoSolution> {
656 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
657 return Err(NoSolution);
658 }
659
660 let cx = ecx.cx();
661 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
662 let ty = goal.predicate.self_ty();
663 match ty.kind() {
664 ty::Ref(..) => {}
666 ty::Adt(def, _) if def.is_manually_drop() => {}
668 ty::Tuple(tys) => {
671 ecx.add_goals(
672 GoalSource::ImplWhereBound,
673 tys.iter().map(|elem_ty| {
674 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
675 }),
676 );
677 }
678 ty::Array(elem_ty, _) => {
679 ecx.add_goal(
680 GoalSource::ImplWhereBound,
681 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
682 );
683 }
684
685 ty::FnDef(..)
689 | ty::FnPtr(..)
690 | ty::Error(_)
691 | ty::Uint(_)
692 | ty::Int(_)
693 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
694 | ty::Bool
695 | ty::Float(_)
696 | ty::Char
697 | ty::RawPtr(..)
698 | ty::Never
699 | ty::Pat(..)
700 | ty::Dynamic(..)
701 | ty::Str
702 | ty::Slice(_)
703 | ty::Foreign(..)
704 | ty::Adt(..)
705 | ty::Alias(..)
706 | ty::Param(_)
707 | ty::Placeholder(..)
708 | ty::Closure(..)
709 | ty::CoroutineClosure(..)
710 | ty::Coroutine(..)
711 | ty::UnsafeBinder(_)
712 | ty::CoroutineWitness(..) => {
713 ecx.add_goal(
714 GoalSource::ImplWhereBound,
715 goal.with(
716 cx,
717 ty::TraitRef::new(
718 cx,
719 cx.require_lang_item(TraitSolverLangItem::Copy),
720 [ty],
721 ),
722 ),
723 );
724 }
725
726 ty::Bound(..)
727 | ty::Infer(
728 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
729 ) => {
730 panic!("unexpected type `{ty:?}`")
731 }
732 }
733
734 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
735 })
736 }
737
738 fn consider_structural_builtin_unsize_candidates(
746 ecx: &mut EvalCtxt<'_, D>,
747 goal: Goal<I, Self>,
748 ) -> Vec<Candidate<I>> {
749 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
750 return vec![];
751 }
752
753 let result_to_single = |result| match result {
754 Ok(resp) => vec![resp],
755 Err(NoSolution) => vec![],
756 };
757
758 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
759 let a_ty = goal.predicate.self_ty();
760 let Ok(b_ty) = ecx.structurally_normalize_ty(
763 goal.param_env,
764 goal.predicate.trait_ref.args.type_at(1),
765 ) else {
766 return vec![];
767 };
768
769 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
770 match (a_ty.kind(), b_ty.kind()) {
771 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
772
773 (_, ty::Infer(ty::TyVar(..))) => {
774 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
775 }
776
777 (
779 ty::Dynamic(a_data, a_region, ty::Dyn),
780 ty::Dynamic(b_data, b_region, ty::Dyn),
781 ) => ecx.consider_builtin_dyn_upcast_candidates(
782 goal, a_data, a_region, b_data, b_region,
783 ),
784
785 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
787 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
788 ),
789
790 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
792 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
793 }
794
795 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
797 if a_def.is_struct() && a_def == b_def =>
798 {
799 result_to_single(
800 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
801 )
802 }
803
804 _ => vec![],
805 }
806 })
807 }
808}
809
810impl<D, I> EvalCtxt<'_, D>
811where
812 D: SolverDelegate<Interner = I>,
813 I: Interner,
814{
815 fn consider_builtin_dyn_upcast_candidates(
825 &mut self,
826 goal: Goal<I, (I::Ty, I::Ty)>,
827 a_data: I::BoundExistentialPredicates,
828 a_region: I::Region,
829 b_data: I::BoundExistentialPredicates,
830 b_region: I::Region,
831 ) -> Vec<Candidate<I>> {
832 let cx = self.cx();
833 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
834
835 let mut responses = vec![];
836 let b_principal_def_id = b_data.principal_def_id();
839 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
840 responses.extend(self.consider_builtin_upcast_to_principal(
841 goal,
842 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
843 a_data,
844 a_region,
845 b_data,
846 b_region,
847 a_data.principal(),
848 ));
849 } else if let Some(a_principal) = a_data.principal() {
850 for (idx, new_a_principal) in
851 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
852 .enumerate()
853 .skip(1)
854 {
855 responses.extend(self.consider_builtin_upcast_to_principal(
856 goal,
857 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
858 a_data,
859 a_region,
860 b_data,
861 b_region,
862 Some(new_a_principal.map_bound(|trait_ref| {
863 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
864 })),
865 ));
866 }
867 }
868
869 responses
870 }
871
872 fn consider_builtin_unsize_to_dyn_candidate(
873 &mut self,
874 goal: Goal<I, (I::Ty, I::Ty)>,
875 b_data: I::BoundExistentialPredicates,
876 b_region: I::Region,
877 ) -> Result<Candidate<I>, NoSolution> {
878 let cx = self.cx();
879 let Goal { predicate: (a_ty, _), .. } = goal;
880
881 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
883 return Err(NoSolution);
884 }
885
886 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
887 ecx.add_goals(
890 GoalSource::ImplWhereBound,
891 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
892 );
893
894 ecx.add_goal(
896 GoalSource::ImplWhereBound,
897 goal.with(
898 cx,
899 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
900 ),
901 );
902
903 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
905 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
906 })
907 }
908
909 fn consider_builtin_upcast_to_principal(
910 &mut self,
911 goal: Goal<I, (I::Ty, I::Ty)>,
912 source: CandidateSource<I>,
913 a_data: I::BoundExistentialPredicates,
914 a_region: I::Region,
915 b_data: I::BoundExistentialPredicates,
916 b_region: I::Region,
917 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
918 ) -> Result<Candidate<I>, NoSolution> {
919 let param_env = goal.param_env;
920
921 let a_auto_traits: IndexSet<I::DefId> = a_data
925 .auto_traits()
926 .into_iter()
927 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
928 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
929 .filter(|def_id| self.cx().trait_is_auto(*def_id))
930 }))
931 .collect();
932
933 let projection_may_match =
938 |ecx: &mut EvalCtxt<'_, D>,
939 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
940 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
941 source_projection.item_def_id() == target_projection.item_def_id()
942 && ecx
943 .probe(|_| ProbeKind::ProjectionCompatibility)
944 .enter(|ecx| -> Result<_, NoSolution> {
945 ecx.enter_forall(target_projection, |ecx, target_projection| {
946 let source_projection =
947 ecx.instantiate_binder_with_infer(source_projection);
948 ecx.eq(param_env, source_projection, target_projection)?;
949 ecx.try_evaluate_added_goals()
950 })
951 })
952 .is_ok()
953 };
954
955 self.probe_trait_candidate(source).enter(|ecx| {
956 for bound in b_data.iter() {
957 match bound.skip_binder() {
958 ty::ExistentialPredicate::Trait(target_principal) => {
961 let source_principal = upcast_principal.unwrap();
962 let target_principal = bound.rebind(target_principal);
963 ecx.enter_forall(target_principal, |ecx, target_principal| {
964 let source_principal =
965 ecx.instantiate_binder_with_infer(source_principal);
966 ecx.eq(param_env, source_principal, target_principal)?;
967 ecx.try_evaluate_added_goals()
968 })?;
969 }
970 ty::ExistentialPredicate::Projection(target_projection) => {
976 let target_projection = bound.rebind(target_projection);
977 let mut matching_projections =
978 a_data.projection_bounds().into_iter().filter(|source_projection| {
979 projection_may_match(ecx, *source_projection, target_projection)
980 });
981 let Some(source_projection) = matching_projections.next() else {
982 return Err(NoSolution);
983 };
984 if matching_projections.next().is_some() {
985 return ecx.evaluate_added_goals_and_make_canonical_response(
986 Certainty::AMBIGUOUS,
987 );
988 }
989 ecx.enter_forall(target_projection, |ecx, target_projection| {
990 let source_projection =
991 ecx.instantiate_binder_with_infer(source_projection);
992 ecx.eq(param_env, source_projection, target_projection)?;
993 ecx.try_evaluate_added_goals()
994 })?;
995 }
996 ty::ExistentialPredicate::AutoTrait(def_id) => {
998 if !a_auto_traits.contains(&def_id) {
999 return Err(NoSolution);
1000 }
1001 }
1002 }
1003 }
1004
1005 ecx.add_goal(
1007 GoalSource::ImplWhereBound,
1008 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1009 );
1010
1011 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1012 })
1013 }
1014
1015 fn consider_builtin_array_unsize(
1024 &mut self,
1025 goal: Goal<I, (I::Ty, I::Ty)>,
1026 a_elem_ty: I::Ty,
1027 b_elem_ty: I::Ty,
1028 ) -> Result<Candidate<I>, NoSolution> {
1029 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1030 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1031 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1032 }
1033
1034 fn consider_builtin_struct_unsize(
1048 &mut self,
1049 goal: Goal<I, (I::Ty, I::Ty)>,
1050 def: I::AdtDef,
1051 a_args: I::GenericArgs,
1052 b_args: I::GenericArgs,
1053 ) -> Result<Candidate<I>, NoSolution> {
1054 let cx = self.cx();
1055 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1056
1057 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1058 if unsizing_params.is_empty() {
1061 return Err(NoSolution);
1062 }
1063
1064 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1065
1066 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1067 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1068
1069 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1073 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1074 }));
1075 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1076
1077 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1080 self.add_goal(
1081 GoalSource::ImplWhereBound,
1082 goal.with(
1083 cx,
1084 ty::TraitRef::new(
1085 cx,
1086 cx.require_lang_item(TraitSolverLangItem::Unsize),
1087 [a_tail_ty, b_tail_ty],
1088 ),
1089 ),
1090 );
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 disqualify_auto_trait_candidate_due_to_possible_impl(
1100 &mut self,
1101 goal: Goal<I, TraitPredicate<I>>,
1102 ) -> Option<Result<Candidate<I>, NoSolution>> {
1103 let self_ty = goal.predicate.self_ty();
1104 let check_impls = || {
1105 let mut disqualifying_impl = None;
1106 self.cx().for_each_relevant_impl(
1107 goal.predicate.def_id(),
1108 goal.predicate.self_ty(),
1109 |impl_def_id| {
1110 disqualifying_impl = Some(impl_def_id);
1111 },
1112 );
1113 if let Some(def_id) = disqualifying_impl {
1114 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1115 return Some(Err(NoSolution));
1118 } else {
1119 None
1120 }
1121 };
1122
1123 match self_ty.kind() {
1124 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1130 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1131 }
1132
1133 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1136
1137 ty::Dynamic(..)
1140 | ty::Param(..)
1141 | ty::Foreign(..)
1142 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1143 | ty::Placeholder(..) => Some(Err(NoSolution)),
1144
1145 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1146
1147 ty::Coroutine(def_id, _)
1151 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1152 {
1153 match self.cx().coroutine_movability(def_id) {
1154 Movability::Static => Some(Err(NoSolution)),
1155 Movability::Movable => Some(
1156 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1157 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1158 }),
1159 ),
1160 }
1161 }
1162
1163 ty::Alias(..) => None,
1168
1169 ty::Bool
1178 | ty::Char
1179 | ty::Int(_)
1180 | ty::Uint(_)
1181 | ty::Float(_)
1182 | ty::Str
1183 | ty::Array(_, _)
1184 | ty::Pat(_, _)
1185 | ty::Slice(_)
1186 | ty::RawPtr(_, _)
1187 | ty::Ref(_, _, _)
1188 | ty::FnDef(_, _)
1189 | ty::FnPtr(..)
1190 | ty::Closure(..)
1191 | ty::CoroutineClosure(..)
1192 | ty::Coroutine(_, _)
1193 | ty::CoroutineWitness(..)
1194 | ty::Never
1195 | ty::Tuple(_)
1196 | ty::Adt(_, _)
1197 | ty::UnsafeBinder(_) => check_impls(),
1198 ty::Error(_) => None,
1199 }
1200 }
1201
1202 fn probe_and_evaluate_goal_for_constituent_tys(
1207 &mut self,
1208 source: CandidateSource<I>,
1209 goal: Goal<I, TraitPredicate<I>>,
1210 constituent_tys: impl Fn(
1211 &EvalCtxt<'_, D>,
1212 I::Ty,
1213 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1214 ) -> Result<Candidate<I>, NoSolution> {
1215 self.probe_trait_candidate(source).enter(|ecx| {
1216 let goals =
1217 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1218 tys.into_iter()
1219 .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)))
1220 .collect::<Vec<_>>()
1221 });
1222 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1223 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1224 })
1225 }
1226}
1227
1228#[derive(Debug, Clone, Copy)]
1239pub(super) enum TraitGoalProvenVia {
1240 Misc,
1246 ParamEnv,
1247 AliasBound,
1248}
1249
1250impl<D, I> EvalCtxt<'_, D>
1251where
1252 D: SolverDelegate<Interner = I>,
1253 I: Interner,
1254{
1255 #[instrument(level = "debug", skip(self), ret)]
1256 pub(super) fn merge_trait_candidates(
1257 &mut self,
1258 mut candidates: Vec<Candidate<I>>,
1259 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1260 if let TypingMode::Coherence = self.typing_mode() {
1261 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1262 return if let Some(response) = self.try_merge_responses(&all_candidates) {
1263 Ok((response, Some(TraitGoalProvenVia::Misc)))
1264 } else {
1265 self.flounder(&all_candidates).map(|r| (r, None))
1266 };
1267 }
1268
1269 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1274 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1275 });
1276 if let Some(candidate) = trivial_builtin_impls.next() {
1277 assert!(trivial_builtin_impls.next().is_none());
1280 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1281 }
1282
1283 let has_non_global_where_bounds = candidates
1286 .iter()
1287 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1288 if has_non_global_where_bounds {
1289 let where_bounds: Vec<_> = candidates
1290 .iter()
1291 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1292 .map(|c| c.result)
1293 .collect();
1294 return if let Some(response) = self.try_merge_responses(&where_bounds) {
1295 Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
1296 } else {
1297 Ok((self.bail_with_ambiguity(&where_bounds), None))
1298 };
1299 }
1300
1301 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1302 let alias_bounds: Vec<_> = candidates
1303 .iter()
1304 .filter(|c| matches!(c.source, CandidateSource::AliasBound))
1305 .map(|c| c.result)
1306 .collect();
1307 return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1308 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1309 } else {
1310 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1311 };
1312 }
1313
1314 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1315
1316 let proven_via = if candidates
1321 .iter()
1322 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1323 {
1324 TraitGoalProvenVia::ParamEnv
1325 } else {
1326 candidates
1327 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1328 TraitGoalProvenVia::Misc
1329 };
1330
1331 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1332 if let Some(response) = self.try_merge_responses(&all_candidates) {
1333 Ok((response, Some(proven_via)))
1334 } else {
1335 self.flounder(&all_candidates).map(|r| (r, None))
1336 }
1337 }
1338
1339 #[instrument(level = "trace", skip(self))]
1340 pub(super) fn compute_trait_goal(
1341 &mut self,
1342 goal: Goal<I, TraitPredicate<I>>,
1343 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1344 let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1345 self.merge_trait_candidates(candidates)
1346 }
1347
1348 fn try_stall_coroutine_witness(
1349 &mut self,
1350 self_ty: I::Ty,
1351 ) -> Option<Result<Candidate<I>, NoSolution>> {
1352 if let ty::CoroutineWitness(def_id, _) = self_ty.kind() {
1353 match self.typing_mode() {
1354 TypingMode::Analysis {
1355 defining_opaque_types_and_generators: stalled_generators,
1356 } => {
1357 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1358 {
1359 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1360 }
1361 }
1362 TypingMode::Coherence
1363 | TypingMode::PostAnalysis
1364 | TypingMode::Borrowck { defining_opaque_types: _ }
1365 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1366 }
1367 }
1368
1369 None
1370 }
1371}