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::{debug, 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, QueryResult, has_only_region_constraints,
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 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
154 ) -> QueryResult<I> {
155 let trait_clause = assumption.as_trait_clause().unwrap();
156
157 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
158 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
159
160 then(ecx)
161 }
162
163 fn consider_auto_trait_candidate(
164 ecx: &mut EvalCtxt<'_, D>,
165 goal: Goal<I, Self>,
166 ) -> Result<Candidate<I>, NoSolution> {
167 let cx = ecx.cx();
168 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
169 return Err(NoSolution);
170 }
171
172 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
173 return result;
174 }
175
176 if cx.trait_is_unsafe(goal.predicate.def_id())
179 && goal.predicate.self_ty().has_unsafe_fields()
180 {
181 return Err(NoSolution);
182 }
183
184 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
200 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
201 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
202 if item_bound
203 .as_trait_clause()
204 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
205 {
206 return Err(NoSolution);
207 }
208 }
209 }
210
211 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
213 return cand;
214 }
215
216 ecx.probe_and_evaluate_goal_for_constituent_tys(
217 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
218 goal,
219 structural_traits::instantiate_constituent_tys_for_auto_trait,
220 )
221 }
222
223 fn consider_trait_alias_candidate(
224 ecx: &mut EvalCtxt<'_, D>,
225 goal: Goal<I, Self>,
226 ) -> Result<Candidate<I>, NoSolution> {
227 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
228 return Err(NoSolution);
229 }
230
231 let cx = ecx.cx();
232
233 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
234 let nested_obligations = cx
235 .predicates_of(goal.predicate.def_id())
236 .iter_instantiated(cx, goal.predicate.trait_ref.args)
237 .map(|p| goal.with(cx, p));
238 ecx.add_goals(GoalSource::Misc, nested_obligations);
240 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
241 })
242 }
243
244 fn consider_builtin_sized_candidate(
245 ecx: &mut EvalCtxt<'_, D>,
246 goal: Goal<I, Self>,
247 ) -> Result<Candidate<I>, NoSolution> {
248 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
249 return Err(NoSolution);
250 }
251
252 ecx.probe_and_evaluate_goal_for_constituent_tys(
253 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
254 goal,
255 structural_traits::instantiate_constituent_tys_for_sized_trait,
256 )
257 }
258
259 fn consider_builtin_copy_clone_candidate(
260 ecx: &mut EvalCtxt<'_, D>,
261 goal: Goal<I, Self>,
262 ) -> Result<Candidate<I>, NoSolution> {
263 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
264 return Err(NoSolution);
265 }
266
267 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
269 return cand;
270 }
271
272 ecx.probe_and_evaluate_goal_for_constituent_tys(
273 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
274 goal,
275 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
276 )
277 }
278
279 fn consider_builtin_fn_ptr_trait_candidate(
280 ecx: &mut EvalCtxt<'_, D>,
281 goal: Goal<I, Self>,
282 ) -> Result<Candidate<I>, NoSolution> {
283 let self_ty = goal.predicate.self_ty();
284 match goal.predicate.polarity {
285 ty::PredicatePolarity::Positive => {
287 if self_ty.is_fn_ptr() {
288 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
289 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
290 })
291 } else {
292 Err(NoSolution)
293 }
294 }
295 ty::PredicatePolarity::Negative => {
297 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
300 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
301 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
302 })
303 } else {
304 Err(NoSolution)
305 }
306 }
307 }
308 }
309
310 fn consider_builtin_fn_trait_candidates(
311 ecx: &mut EvalCtxt<'_, D>,
312 goal: Goal<I, Self>,
313 goal_kind: ty::ClosureKind,
314 ) -> Result<Candidate<I>, NoSolution> {
315 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
316 return Err(NoSolution);
317 }
318
319 let cx = ecx.cx();
320 let tupled_inputs_and_output =
321 match structural_traits::extract_tupled_inputs_and_output_from_callable(
322 cx,
323 goal.predicate.self_ty(),
324 goal_kind,
325 )? {
326 Some(a) => a,
327 None => {
328 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
329 }
330 };
331
332 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
335 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
336 });
337
338 let pred = tupled_inputs_and_output
339 .map_bound(|(inputs, _)| {
340 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
341 })
342 .upcast(cx);
343 Self::probe_and_consider_implied_clause(
344 ecx,
345 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
346 goal,
347 pred,
348 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
349 )
350 }
351
352 fn consider_builtin_async_fn_trait_candidates(
353 ecx: &mut EvalCtxt<'_, D>,
354 goal: Goal<I, Self>,
355 goal_kind: ty::ClosureKind,
356 ) -> Result<Candidate<I>, NoSolution> {
357 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
358 return Err(NoSolution);
359 }
360
361 let cx = ecx.cx();
362 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
363 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
364 cx,
365 goal.predicate.self_ty(),
366 goal_kind,
367 Region::new_static(cx),
369 )?;
370
371 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
374 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
375 ty::TraitRef::new(
376 cx,
377 cx.require_lang_item(TraitSolverLangItem::Sized),
378 [output_coroutine_ty],
379 )
380 },
381 );
382
383 let pred = tupled_inputs_and_output_and_coroutine
384 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
385 ty::TraitRef::new(
386 cx,
387 goal.predicate.def_id(),
388 [goal.predicate.self_ty(), tupled_inputs_ty],
389 )
390 })
391 .upcast(cx);
392 Self::probe_and_consider_implied_clause(
393 ecx,
394 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
395 goal,
396 pred,
397 [goal.with(cx, output_is_sized_pred)]
398 .into_iter()
399 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
400 .map(|goal| (GoalSource::ImplWhereBound, goal)),
401 )
402 }
403
404 fn consider_builtin_async_fn_kind_helper_candidate(
405 ecx: &mut EvalCtxt<'_, D>,
406 goal: Goal<I, Self>,
407 ) -> Result<Candidate<I>, NoSolution> {
408 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
409 panic!();
410 };
411
412 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
413 return Err(NoSolution);
415 };
416 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
417 if closure_kind.extends(goal_kind) {
418 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
419 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
420 } else {
421 Err(NoSolution)
422 }
423 }
424
425 fn consider_builtin_tuple_candidate(
432 ecx: &mut EvalCtxt<'_, D>,
433 goal: Goal<I, Self>,
434 ) -> Result<Candidate<I>, NoSolution> {
435 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
436 return Err(NoSolution);
437 }
438
439 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
440 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
441 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
442 } else {
443 Err(NoSolution)
444 }
445 }
446
447 fn consider_builtin_pointee_candidate(
448 ecx: &mut EvalCtxt<'_, D>,
449 goal: Goal<I, Self>,
450 ) -> Result<Candidate<I>, NoSolution> {
451 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
452 return Err(NoSolution);
453 }
454
455 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
456 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
457 }
458
459 fn consider_builtin_future_candidate(
460 ecx: &mut EvalCtxt<'_, D>,
461 goal: Goal<I, Self>,
462 ) -> Result<Candidate<I>, NoSolution> {
463 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
464 return Err(NoSolution);
465 }
466
467 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
468 return Err(NoSolution);
469 };
470
471 let cx = ecx.cx();
473 if !cx.coroutine_is_async(def_id) {
474 return Err(NoSolution);
475 }
476
477 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
481 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
482 }
483
484 fn consider_builtin_iterator_candidate(
485 ecx: &mut EvalCtxt<'_, D>,
486 goal: Goal<I, Self>,
487 ) -> Result<Candidate<I>, NoSolution> {
488 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
489 return Err(NoSolution);
490 }
491
492 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
493 return Err(NoSolution);
494 };
495
496 let cx = ecx.cx();
498 if !cx.coroutine_is_gen(def_id) {
499 return Err(NoSolution);
500 }
501
502 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
506 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
507 }
508
509 fn consider_builtin_fused_iterator_candidate(
510 ecx: &mut EvalCtxt<'_, D>,
511 goal: Goal<I, Self>,
512 ) -> Result<Candidate<I>, NoSolution> {
513 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
514 return Err(NoSolution);
515 }
516
517 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
518 return Err(NoSolution);
519 };
520
521 let cx = ecx.cx();
523 if !cx.coroutine_is_gen(def_id) {
524 return Err(NoSolution);
525 }
526
527 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
529 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
530 }
531
532 fn consider_builtin_async_iterator_candidate(
533 ecx: &mut EvalCtxt<'_, D>,
534 goal: Goal<I, Self>,
535 ) -> Result<Candidate<I>, NoSolution> {
536 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
537 return Err(NoSolution);
538 }
539
540 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
541 return Err(NoSolution);
542 };
543
544 let cx = ecx.cx();
546 if !cx.coroutine_is_async_gen(def_id) {
547 return Err(NoSolution);
548 }
549
550 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
554 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
555 }
556
557 fn consider_builtin_coroutine_candidate(
558 ecx: &mut EvalCtxt<'_, D>,
559 goal: Goal<I, Self>,
560 ) -> Result<Candidate<I>, NoSolution> {
561 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
562 return Err(NoSolution);
563 }
564
565 let self_ty = goal.predicate.self_ty();
566 let ty::Coroutine(def_id, args) = self_ty.kind() else {
567 return Err(NoSolution);
568 };
569
570 let cx = ecx.cx();
572 if !cx.is_general_coroutine(def_id) {
573 return Err(NoSolution);
574 }
575
576 let coroutine = args.as_coroutine();
577 Self::probe_and_consider_implied_clause(
578 ecx,
579 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
580 goal,
581 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
582 .upcast(cx),
583 [],
586 )
587 }
588
589 fn consider_builtin_discriminant_kind_candidate(
590 ecx: &mut EvalCtxt<'_, D>,
591 goal: Goal<I, Self>,
592 ) -> Result<Candidate<I>, NoSolution> {
593 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
594 return Err(NoSolution);
595 }
596
597 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
599 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
600 }
601
602 fn consider_builtin_destruct_candidate(
603 ecx: &mut EvalCtxt<'_, D>,
604 goal: Goal<I, Self>,
605 ) -> Result<Candidate<I>, NoSolution> {
606 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
607 return Err(NoSolution);
608 }
609
610 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
613 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
614 }
615
616 fn consider_builtin_transmute_candidate(
617 ecx: &mut EvalCtxt<'_, D>,
618 goal: Goal<I, Self>,
619 ) -> Result<Candidate<I>, NoSolution> {
620 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
621 return Err(NoSolution);
622 }
623
624 if goal.has_non_region_placeholders() {
626 return Err(NoSolution);
627 }
628
629 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
630 let assume = ecx.structurally_normalize_const(
631 goal.param_env,
632 goal.predicate.trait_ref.args.const_at(2),
633 )?;
634
635 let certainty = ecx.is_transmutable(
636 goal.predicate.trait_ref.args.type_at(0),
637 goal.predicate.trait_ref.args.type_at(1),
638 assume,
639 )?;
640 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
641 })
642 }
643
644 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
654 ecx: &mut EvalCtxt<'_, D>,
655 goal: Goal<I, Self>,
656 ) -> Result<Candidate<I>, NoSolution> {
657 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
658 return Err(NoSolution);
659 }
660
661 let cx = ecx.cx();
662 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
663 let ty = goal.predicate.self_ty();
664 match ty.kind() {
665 ty::Ref(..) => {}
667 ty::Adt(def, _) if def.is_manually_drop() => {}
669 ty::Tuple(tys) => {
672 ecx.add_goals(
673 GoalSource::ImplWhereBound,
674 tys.iter().map(|elem_ty| {
675 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
676 }),
677 );
678 }
679 ty::Array(elem_ty, _) => {
680 ecx.add_goal(
681 GoalSource::ImplWhereBound,
682 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
683 );
684 }
685
686 ty::FnDef(..)
690 | ty::FnPtr(..)
691 | ty::Error(_)
692 | ty::Uint(_)
693 | ty::Int(_)
694 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
695 | ty::Bool
696 | ty::Float(_)
697 | ty::Char
698 | ty::RawPtr(..)
699 | ty::Never
700 | ty::Pat(..)
701 | ty::Dynamic(..)
702 | ty::Str
703 | ty::Slice(_)
704 | ty::Foreign(..)
705 | ty::Adt(..)
706 | ty::Alias(..)
707 | ty::Param(_)
708 | ty::Placeholder(..)
709 | ty::Closure(..)
710 | ty::CoroutineClosure(..)
711 | ty::Coroutine(..)
712 | ty::UnsafeBinder(_)
713 | ty::CoroutineWitness(..) => {
714 ecx.add_goal(
715 GoalSource::ImplWhereBound,
716 goal.with(
717 cx,
718 ty::TraitRef::new(
719 cx,
720 cx.require_lang_item(TraitSolverLangItem::Copy),
721 [ty],
722 ),
723 ),
724 );
725 }
726
727 ty::Bound(..)
728 | ty::Infer(
729 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
730 ) => {
731 panic!("unexpected type `{ty:?}`")
732 }
733 }
734
735 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
736 })
737 }
738
739 fn consider_structural_builtin_unsize_candidates(
747 ecx: &mut EvalCtxt<'_, D>,
748 goal: Goal<I, Self>,
749 ) -> Vec<Candidate<I>> {
750 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
751 return vec![];
752 }
753
754 let result_to_single = |result| match result {
755 Ok(resp) => vec![resp],
756 Err(NoSolution) => vec![],
757 };
758
759 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
760 let a_ty = goal.predicate.self_ty();
761 let Ok(b_ty) = ecx.structurally_normalize_ty(
764 goal.param_env,
765 goal.predicate.trait_ref.args.type_at(1),
766 ) else {
767 return vec![];
768 };
769
770 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
771 match (a_ty.kind(), b_ty.kind()) {
772 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
773
774 (_, ty::Infer(ty::TyVar(..))) => {
775 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
776 }
777
778 (
780 ty::Dynamic(a_data, a_region, ty::Dyn),
781 ty::Dynamic(b_data, b_region, ty::Dyn),
782 ) => ecx.consider_builtin_dyn_upcast_candidates(
783 goal, a_data, a_region, b_data, b_region,
784 ),
785
786 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
788 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
789 ),
790
791 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
793 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
794 }
795
796 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
798 if a_def.is_struct() && a_def == b_def =>
799 {
800 result_to_single(
801 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
802 )
803 }
804
805 _ => vec![],
806 }
807 })
808 }
809}
810
811impl<D, I> EvalCtxt<'_, D>
812where
813 D: SolverDelegate<Interner = I>,
814 I: Interner,
815{
816 fn consider_builtin_dyn_upcast_candidates(
826 &mut self,
827 goal: Goal<I, (I::Ty, I::Ty)>,
828 a_data: I::BoundExistentialPredicates,
829 a_region: I::Region,
830 b_data: I::BoundExistentialPredicates,
831 b_region: I::Region,
832 ) -> Vec<Candidate<I>> {
833 let cx = self.cx();
834 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
835
836 let mut responses = vec![];
837 let b_principal_def_id = b_data.principal_def_id();
840 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
841 responses.extend(self.consider_builtin_upcast_to_principal(
842 goal,
843 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
844 a_data,
845 a_region,
846 b_data,
847 b_region,
848 a_data.principal(),
849 ));
850 } else if let Some(a_principal) = a_data.principal() {
851 for (idx, new_a_principal) in
852 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
853 .enumerate()
854 .skip(1)
855 {
856 responses.extend(self.consider_builtin_upcast_to_principal(
857 goal,
858 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
859 a_data,
860 a_region,
861 b_data,
862 b_region,
863 Some(new_a_principal.map_bound(|trait_ref| {
864 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
865 })),
866 ));
867 }
868 }
869
870 responses
871 }
872
873 fn consider_builtin_unsize_to_dyn_candidate(
874 &mut self,
875 goal: Goal<I, (I::Ty, I::Ty)>,
876 b_data: I::BoundExistentialPredicates,
877 b_region: I::Region,
878 ) -> Result<Candidate<I>, NoSolution> {
879 let cx = self.cx();
880 let Goal { predicate: (a_ty, _), .. } = goal;
881
882 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
884 return Err(NoSolution);
885 }
886
887 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
888 ecx.add_goals(
891 GoalSource::ImplWhereBound,
892 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
893 );
894
895 ecx.add_goal(
897 GoalSource::ImplWhereBound,
898 goal.with(
899 cx,
900 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
901 ),
902 );
903
904 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
906 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
907 })
908 }
909
910 fn consider_builtin_upcast_to_principal(
911 &mut self,
912 goal: Goal<I, (I::Ty, I::Ty)>,
913 source: CandidateSource<I>,
914 a_data: I::BoundExistentialPredicates,
915 a_region: I::Region,
916 b_data: I::BoundExistentialPredicates,
917 b_region: I::Region,
918 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
919 ) -> Result<Candidate<I>, NoSolution> {
920 let param_env = goal.param_env;
921
922 let a_auto_traits: IndexSet<I::DefId> = a_data
926 .auto_traits()
927 .into_iter()
928 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
929 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
930 .filter(|def_id| self.cx().trait_is_auto(*def_id))
931 }))
932 .collect();
933
934 let projection_may_match =
939 |ecx: &mut EvalCtxt<'_, D>,
940 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
941 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
942 source_projection.item_def_id() == target_projection.item_def_id()
943 && ecx
944 .probe(|_| ProbeKind::ProjectionCompatibility)
945 .enter(|ecx| -> Result<_, NoSolution> {
946 ecx.enter_forall(target_projection, |ecx, target_projection| {
947 let source_projection =
948 ecx.instantiate_binder_with_infer(source_projection);
949 ecx.eq(param_env, source_projection, target_projection)?;
950 ecx.try_evaluate_added_goals()
951 })
952 })
953 .is_ok()
954 };
955
956 self.probe_trait_candidate(source).enter(|ecx| {
957 for bound in b_data.iter() {
958 match bound.skip_binder() {
959 ty::ExistentialPredicate::Trait(target_principal) => {
962 let source_principal = upcast_principal.unwrap();
963 let target_principal = bound.rebind(target_principal);
964 ecx.enter_forall(target_principal, |ecx, target_principal| {
965 let source_principal =
966 ecx.instantiate_binder_with_infer(source_principal);
967 ecx.eq(param_env, source_principal, target_principal)?;
968 ecx.try_evaluate_added_goals()
969 })?;
970 }
971 ty::ExistentialPredicate::Projection(target_projection) => {
977 let target_projection = bound.rebind(target_projection);
978 let mut matching_projections =
979 a_data.projection_bounds().into_iter().filter(|source_projection| {
980 projection_may_match(ecx, *source_projection, target_projection)
981 });
982 let Some(source_projection) = matching_projections.next() else {
983 return Err(NoSolution);
984 };
985 if matching_projections.next().is_some() {
986 return ecx.evaluate_added_goals_and_make_canonical_response(
987 Certainty::AMBIGUOUS,
988 );
989 }
990 ecx.enter_forall(target_projection, |ecx, target_projection| {
991 let source_projection =
992 ecx.instantiate_binder_with_infer(source_projection);
993 ecx.eq(param_env, source_projection, target_projection)?;
994 ecx.try_evaluate_added_goals()
995 })?;
996 }
997 ty::ExistentialPredicate::AutoTrait(def_id) => {
999 if !a_auto_traits.contains(&def_id) {
1000 return Err(NoSolution);
1001 }
1002 }
1003 }
1004 }
1005
1006 ecx.add_goal(
1008 GoalSource::ImplWhereBound,
1009 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1010 );
1011
1012 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1013 })
1014 }
1015
1016 fn consider_builtin_array_unsize(
1025 &mut self,
1026 goal: Goal<I, (I::Ty, I::Ty)>,
1027 a_elem_ty: I::Ty,
1028 b_elem_ty: I::Ty,
1029 ) -> Result<Candidate<I>, NoSolution> {
1030 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1031 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1032 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1033 }
1034
1035 fn consider_builtin_struct_unsize(
1049 &mut self,
1050 goal: Goal<I, (I::Ty, I::Ty)>,
1051 def: I::AdtDef,
1052 a_args: I::GenericArgs,
1053 b_args: I::GenericArgs,
1054 ) -> Result<Candidate<I>, NoSolution> {
1055 let cx = self.cx();
1056 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1057
1058 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1059 if unsizing_params.is_empty() {
1062 return Err(NoSolution);
1063 }
1064
1065 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1066
1067 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1068 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1069
1070 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1074 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1075 }));
1076 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1077
1078 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1081 self.add_goal(
1082 GoalSource::ImplWhereBound,
1083 goal.with(
1084 cx,
1085 ty::TraitRef::new(
1086 cx,
1087 cx.require_lang_item(TraitSolverLangItem::Unsize),
1088 [a_tail_ty, b_tail_ty],
1089 ),
1090 ),
1091 );
1092 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1093 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1094 }
1095
1096 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1101 &mut self,
1102 goal: Goal<I, TraitPredicate<I>>,
1103 ) -> Option<Result<Candidate<I>, NoSolution>> {
1104 let self_ty = goal.predicate.self_ty();
1105 let check_impls = || {
1106 let mut disqualifying_impl = None;
1107 self.cx().for_each_relevant_impl(
1108 goal.predicate.def_id(),
1109 goal.predicate.self_ty(),
1110 |impl_def_id| {
1111 disqualifying_impl = Some(impl_def_id);
1112 },
1113 );
1114 if let Some(def_id) = disqualifying_impl {
1115 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1116 return Some(Err(NoSolution));
1119 } else {
1120 None
1121 }
1122 };
1123
1124 match self_ty.kind() {
1125 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1131 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1132 }
1133
1134 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1137
1138 ty::Dynamic(..)
1141 | ty::Param(..)
1142 | ty::Foreign(..)
1143 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1144 | ty::Placeholder(..) => Some(Err(NoSolution)),
1145
1146 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1147
1148 ty::Coroutine(def_id, _)
1152 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1153 {
1154 match self.cx().coroutine_movability(def_id) {
1155 Movability::Static => Some(Err(NoSolution)),
1156 Movability::Movable => Some(
1157 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1158 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1159 }),
1160 ),
1161 }
1162 }
1163
1164 ty::Alias(..) => None,
1169
1170 ty::Bool
1179 | ty::Char
1180 | ty::Int(_)
1181 | ty::Uint(_)
1182 | ty::Float(_)
1183 | ty::Str
1184 | ty::Array(_, _)
1185 | ty::Pat(_, _)
1186 | ty::Slice(_)
1187 | ty::RawPtr(_, _)
1188 | ty::Ref(_, _, _)
1189 | ty::FnDef(_, _)
1190 | ty::FnPtr(..)
1191 | ty::Closure(..)
1192 | ty::CoroutineClosure(..)
1193 | ty::Coroutine(_, _)
1194 | ty::CoroutineWitness(..)
1195 | ty::Never
1196 | ty::Tuple(_)
1197 | ty::Adt(_, _)
1198 | ty::UnsafeBinder(_) => check_impls(),
1199 ty::Error(_) => None,
1200 }
1201 }
1202
1203 fn probe_and_evaluate_goal_for_constituent_tys(
1208 &mut self,
1209 source: CandidateSource<I>,
1210 goal: Goal<I, TraitPredicate<I>>,
1211 constituent_tys: impl Fn(
1212 &EvalCtxt<'_, D>,
1213 I::Ty,
1214 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1215 ) -> Result<Candidate<I>, NoSolution> {
1216 self.probe_trait_candidate(source).enter(|ecx| {
1217 let goals =
1218 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1219 tys.into_iter()
1220 .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)))
1221 .collect::<Vec<_>>()
1222 });
1223 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1224 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1225 })
1226 }
1227}
1228
1229#[derive(Debug, Clone, Copy)]
1240pub(super) enum TraitGoalProvenVia {
1241 Misc,
1247 ParamEnv,
1248 AliasBound,
1249}
1250
1251impl<D, I> EvalCtxt<'_, D>
1252where
1253 D: SolverDelegate<Interner = I>,
1254 I: Interner,
1255{
1256 pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1269 match self.typing_mode() {
1270 TypingMode::Coherence => return,
1271 TypingMode::Analysis { .. }
1272 | TypingMode::Borrowck { .. }
1273 | TypingMode::PostBorrowckAnalysis { .. }
1274 | TypingMode::PostAnalysis => {}
1275 }
1276
1277 if candidates
1278 .iter()
1279 .find(|c| {
1280 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1281 })
1282 .is_some_and(|c| has_only_region_constraints(c.result))
1283 {
1284 candidates.retain(|c| {
1285 if matches!(c.source, CandidateSource::Impl(_)) {
1286 debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1287 false
1288 } else {
1289 true
1290 }
1291 });
1292 }
1293 }
1294
1295 #[instrument(level = "debug", skip(self), ret)]
1296 pub(super) fn merge_trait_candidates(
1297 &mut self,
1298 mut candidates: Vec<Candidate<I>>,
1299 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1300 if let TypingMode::Coherence = self.typing_mode() {
1301 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1302 return if let Some(response) = self.try_merge_responses(&all_candidates) {
1303 Ok((response, Some(TraitGoalProvenVia::Misc)))
1304 } else {
1305 self.flounder(&all_candidates).map(|r| (r, None))
1306 };
1307 }
1308
1309 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1314 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1315 });
1316 if let Some(candidate) = trivial_builtin_impls.next() {
1317 assert!(trivial_builtin_impls.next().is_none());
1320 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1321 }
1322
1323 let has_non_global_where_bounds = candidates
1326 .iter()
1327 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1328 if has_non_global_where_bounds {
1329 let where_bounds: Vec<_> = candidates
1330 .iter()
1331 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1332 .map(|c| c.result)
1333 .collect();
1334 return if let Some(response) = self.try_merge_responses(&where_bounds) {
1335 Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
1336 } else {
1337 Ok((self.bail_with_ambiguity(&where_bounds), None))
1338 };
1339 }
1340
1341 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1342 let alias_bounds: Vec<_> = candidates
1343 .iter()
1344 .filter(|c| matches!(c.source, CandidateSource::AliasBound))
1345 .map(|c| c.result)
1346 .collect();
1347 return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1348 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1349 } else {
1350 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1351 };
1352 }
1353
1354 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1355 self.unsound_prefer_builtin_dyn_impl(&mut candidates);
1356
1357 let proven_via = if candidates
1362 .iter()
1363 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1364 {
1365 TraitGoalProvenVia::ParamEnv
1366 } else {
1367 candidates
1368 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1369 TraitGoalProvenVia::Misc
1370 };
1371
1372 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1373 if let Some(response) = self.try_merge_responses(&all_candidates) {
1374 Ok((response, Some(proven_via)))
1375 } else {
1376 self.flounder(&all_candidates).map(|r| (r, None))
1377 }
1378 }
1379
1380 #[instrument(level = "trace", skip(self))]
1381 pub(super) fn compute_trait_goal(
1382 &mut self,
1383 goal: Goal<I, TraitPredicate<I>>,
1384 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1385 let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1386 self.merge_trait_candidates(candidates)
1387 }
1388
1389 fn try_stall_coroutine_witness(
1390 &mut self,
1391 self_ty: I::Ty,
1392 ) -> Option<Result<Candidate<I>, NoSolution>> {
1393 if let ty::CoroutineWitness(def_id, _) = self_ty.kind() {
1394 match self.typing_mode() {
1395 TypingMode::Analysis {
1396 defining_opaque_types_and_generators: stalled_generators,
1397 } => {
1398 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1399 {
1400 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1401 }
1402 }
1403 TypingMode::Coherence
1404 | TypingMode::PostAnalysis
1405 | TypingMode::Borrowck { defining_opaque_types: _ }
1406 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1407 }
1408 }
1409
1410 None
1411 }
1412}