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, SizedTraitKind};
8use rustc_type_ir::{
9 self as ty, Interner, Movability, TraitPredicate, TraitRef, 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.polarity() != goal.predicate.polarity {
135 return Err(NoSolution);
136 }
137
138 if trait_clause.def_id() == goal.predicate.def_id() {
139 if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
140 goal.predicate.trait_ref.args,
141 trait_clause.skip_binder().trait_ref.args,
142 ) {
143 return Ok(());
144 }
145 }
146
147 if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
151 && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
152 {
153 let meta_sized_clause =
154 trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
155 return Self::fast_reject_assumption(ecx, goal, meta_sized_clause);
156 }
157 }
158
159 Err(NoSolution)
160 }
161
162 fn match_assumption(
163 ecx: &mut EvalCtxt<'_, D>,
164 goal: Goal<I, Self>,
165 assumption: I::Clause,
166 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
167 ) -> QueryResult<I> {
168 let trait_clause = assumption.as_trait_clause().unwrap();
169
170 if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
174 && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
175 {
176 let meta_sized_clause =
177 trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
178 return Self::match_assumption(ecx, goal, meta_sized_clause, then);
179 }
180
181 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
182 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
183
184 then(ecx)
185 }
186
187 fn consider_auto_trait_candidate(
188 ecx: &mut EvalCtxt<'_, D>,
189 goal: Goal<I, Self>,
190 ) -> Result<Candidate<I>, NoSolution> {
191 let cx = ecx.cx();
192 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
193 return Err(NoSolution);
194 }
195
196 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
197 return result;
198 }
199
200 if cx.trait_is_unsafe(goal.predicate.def_id())
203 && goal.predicate.self_ty().has_unsafe_fields()
204 {
205 return Err(NoSolution);
206 }
207
208 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
224 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
225 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
226 if item_bound
227 .as_trait_clause()
228 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
229 {
230 return Err(NoSolution);
231 }
232 }
233 }
234
235 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
237 return cand;
238 }
239
240 ecx.probe_and_evaluate_goal_for_constituent_tys(
241 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
242 goal,
243 structural_traits::instantiate_constituent_tys_for_auto_trait,
244 )
245 }
246
247 fn consider_trait_alias_candidate(
248 ecx: &mut EvalCtxt<'_, D>,
249 goal: Goal<I, Self>,
250 ) -> Result<Candidate<I>, NoSolution> {
251 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
252 return Err(NoSolution);
253 }
254
255 let cx = ecx.cx();
256
257 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
258 let nested_obligations = cx
259 .predicates_of(goal.predicate.def_id())
260 .iter_instantiated(cx, goal.predicate.trait_ref.args)
261 .map(|p| goal.with(cx, p));
262 ecx.add_goals(GoalSource::Misc, nested_obligations);
268 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
269 })
270 }
271
272 fn consider_builtin_sizedness_candidates(
273 ecx: &mut EvalCtxt<'_, D>,
274 goal: Goal<I, Self>,
275 sizedness: SizedTraitKind,
276 ) -> Result<Candidate<I>, NoSolution> {
277 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
278 return Err(NoSolution);
279 }
280
281 ecx.probe_and_evaluate_goal_for_constituent_tys(
282 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
283 goal,
284 |ecx, ty| {
285 structural_traits::instantiate_constituent_tys_for_sizedness_trait(
286 ecx, sizedness, ty,
287 )
288 },
289 )
290 }
291
292 fn consider_builtin_copy_clone_candidate(
293 ecx: &mut EvalCtxt<'_, D>,
294 goal: Goal<I, Self>,
295 ) -> Result<Candidate<I>, NoSolution> {
296 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
297 return Err(NoSolution);
298 }
299
300 if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
302 return cand;
303 }
304
305 ecx.probe_and_evaluate_goal_for_constituent_tys(
306 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
307 goal,
308 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
309 )
310 }
311
312 fn consider_builtin_fn_ptr_trait_candidate(
313 ecx: &mut EvalCtxt<'_, D>,
314 goal: Goal<I, Self>,
315 ) -> Result<Candidate<I>, NoSolution> {
316 let self_ty = goal.predicate.self_ty();
317 match goal.predicate.polarity {
318 ty::PredicatePolarity::Positive => {
320 if self_ty.is_fn_ptr() {
321 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
322 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
323 })
324 } else {
325 Err(NoSolution)
326 }
327 }
328 ty::PredicatePolarity::Negative => {
330 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
333 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
334 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
335 })
336 } else {
337 Err(NoSolution)
338 }
339 }
340 }
341 }
342
343 fn consider_builtin_fn_trait_candidates(
344 ecx: &mut EvalCtxt<'_, D>,
345 goal: Goal<I, Self>,
346 goal_kind: ty::ClosureKind,
347 ) -> Result<Candidate<I>, NoSolution> {
348 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
349 return Err(NoSolution);
350 }
351
352 let cx = ecx.cx();
353 let tupled_inputs_and_output =
354 match structural_traits::extract_tupled_inputs_and_output_from_callable(
355 cx,
356 goal.predicate.self_ty(),
357 goal_kind,
358 )? {
359 Some(a) => a,
360 None => {
361 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
362 }
363 };
364
365 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
368 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
369 });
370
371 let pred = tupled_inputs_and_output
372 .map_bound(|(inputs, _)| {
373 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
374 })
375 .upcast(cx);
376 Self::probe_and_consider_implied_clause(
377 ecx,
378 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
379 goal,
380 pred,
381 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
382 )
383 }
384
385 fn consider_builtin_async_fn_trait_candidates(
386 ecx: &mut EvalCtxt<'_, D>,
387 goal: Goal<I, Self>,
388 goal_kind: ty::ClosureKind,
389 ) -> Result<Candidate<I>, NoSolution> {
390 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
391 return Err(NoSolution);
392 }
393
394 let cx = ecx.cx();
395 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
396 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
397 cx,
398 goal.predicate.self_ty(),
399 goal_kind,
400 Region::new_static(cx),
402 )?;
403
404 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
407 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
408 ty::TraitRef::new(
409 cx,
410 cx.require_lang_item(TraitSolverLangItem::Sized),
411 [output_coroutine_ty],
412 )
413 },
414 );
415
416 let pred = tupled_inputs_and_output_and_coroutine
417 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
418 ty::TraitRef::new(
419 cx,
420 goal.predicate.def_id(),
421 [goal.predicate.self_ty(), tupled_inputs_ty],
422 )
423 })
424 .upcast(cx);
425 Self::probe_and_consider_implied_clause(
426 ecx,
427 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
428 goal,
429 pred,
430 [goal.with(cx, output_is_sized_pred)]
431 .into_iter()
432 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
433 .map(|goal| (GoalSource::ImplWhereBound, goal)),
434 )
435 }
436
437 fn consider_builtin_async_fn_kind_helper_candidate(
438 ecx: &mut EvalCtxt<'_, D>,
439 goal: Goal<I, Self>,
440 ) -> Result<Candidate<I>, NoSolution> {
441 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
442 panic!();
443 };
444
445 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
446 return Err(NoSolution);
448 };
449 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
450 if closure_kind.extends(goal_kind) {
451 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
452 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
453 } else {
454 Err(NoSolution)
455 }
456 }
457
458 fn consider_builtin_tuple_candidate(
465 ecx: &mut EvalCtxt<'_, D>,
466 goal: Goal<I, Self>,
467 ) -> Result<Candidate<I>, NoSolution> {
468 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
469 return Err(NoSolution);
470 }
471
472 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
473 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
474 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
475 } else {
476 Err(NoSolution)
477 }
478 }
479
480 fn consider_builtin_pointee_candidate(
481 ecx: &mut EvalCtxt<'_, D>,
482 goal: Goal<I, Self>,
483 ) -> Result<Candidate<I>, NoSolution> {
484 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
485 return Err(NoSolution);
486 }
487
488 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
489 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
490 }
491
492 fn consider_builtin_future_candidate(
493 ecx: &mut EvalCtxt<'_, D>,
494 goal: Goal<I, Self>,
495 ) -> Result<Candidate<I>, NoSolution> {
496 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
497 return Err(NoSolution);
498 }
499
500 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
501 return Err(NoSolution);
502 };
503
504 let cx = ecx.cx();
506 if !cx.coroutine_is_async(def_id) {
507 return Err(NoSolution);
508 }
509
510 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
514 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
515 }
516
517 fn consider_builtin_iterator_candidate(
518 ecx: &mut EvalCtxt<'_, D>,
519 goal: Goal<I, Self>,
520 ) -> Result<Candidate<I>, NoSolution> {
521 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
522 return Err(NoSolution);
523 }
524
525 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
526 return Err(NoSolution);
527 };
528
529 let cx = ecx.cx();
531 if !cx.coroutine_is_gen(def_id) {
532 return Err(NoSolution);
533 }
534
535 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
539 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
540 }
541
542 fn consider_builtin_fused_iterator_candidate(
543 ecx: &mut EvalCtxt<'_, D>,
544 goal: Goal<I, Self>,
545 ) -> Result<Candidate<I>, NoSolution> {
546 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
547 return Err(NoSolution);
548 }
549
550 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
551 return Err(NoSolution);
552 };
553
554 let cx = ecx.cx();
556 if !cx.coroutine_is_gen(def_id) {
557 return Err(NoSolution);
558 }
559
560 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
562 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
563 }
564
565 fn consider_builtin_async_iterator_candidate(
566 ecx: &mut EvalCtxt<'_, D>,
567 goal: Goal<I, Self>,
568 ) -> Result<Candidate<I>, NoSolution> {
569 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
570 return Err(NoSolution);
571 }
572
573 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
574 return Err(NoSolution);
575 };
576
577 let cx = ecx.cx();
579 if !cx.coroutine_is_async_gen(def_id) {
580 return Err(NoSolution);
581 }
582
583 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
587 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
588 }
589
590 fn consider_builtin_coroutine_candidate(
591 ecx: &mut EvalCtxt<'_, D>,
592 goal: Goal<I, Self>,
593 ) -> Result<Candidate<I>, NoSolution> {
594 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
595 return Err(NoSolution);
596 }
597
598 let self_ty = goal.predicate.self_ty();
599 let ty::Coroutine(def_id, args) = self_ty.kind() else {
600 return Err(NoSolution);
601 };
602
603 let cx = ecx.cx();
605 if !cx.is_general_coroutine(def_id) {
606 return Err(NoSolution);
607 }
608
609 let coroutine = args.as_coroutine();
610 Self::probe_and_consider_implied_clause(
611 ecx,
612 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
613 goal,
614 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
615 .upcast(cx),
616 [],
619 )
620 }
621
622 fn consider_builtin_discriminant_kind_candidate(
623 ecx: &mut EvalCtxt<'_, D>,
624 goal: Goal<I, Self>,
625 ) -> Result<Candidate<I>, NoSolution> {
626 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
627 return Err(NoSolution);
628 }
629
630 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
632 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
633 }
634
635 fn consider_builtin_destruct_candidate(
636 ecx: &mut EvalCtxt<'_, D>,
637 goal: Goal<I, Self>,
638 ) -> Result<Candidate<I>, NoSolution> {
639 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
640 return Err(NoSolution);
641 }
642
643 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
646 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
647 }
648
649 fn consider_builtin_transmute_candidate(
650 ecx: &mut EvalCtxt<'_, D>,
651 goal: Goal<I, Self>,
652 ) -> Result<Candidate<I>, NoSolution> {
653 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
654 return Err(NoSolution);
655 }
656
657 if goal.has_non_region_placeholders() {
659 return Err(NoSolution);
660 }
661
662 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
663 let assume = ecx.structurally_normalize_const(
664 goal.param_env,
665 goal.predicate.trait_ref.args.const_at(2),
666 )?;
667
668 let certainty = ecx.is_transmutable(
669 goal.predicate.trait_ref.args.type_at(0),
670 goal.predicate.trait_ref.args.type_at(1),
671 assume,
672 )?;
673 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
674 })
675 }
676
677 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
687 ecx: &mut EvalCtxt<'_, D>,
688 goal: Goal<I, Self>,
689 ) -> Result<Candidate<I>, NoSolution> {
690 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
691 return Err(NoSolution);
692 }
693
694 let cx = ecx.cx();
695 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
696 let ty = goal.predicate.self_ty();
697 match ty.kind() {
698 ty::Ref(..) => {}
700 ty::Adt(def, _) if def.is_manually_drop() => {}
702 ty::Tuple(tys) => {
705 ecx.add_goals(
706 GoalSource::ImplWhereBound,
707 tys.iter().map(|elem_ty| {
708 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
709 }),
710 );
711 }
712 ty::Array(elem_ty, _) => {
713 ecx.add_goal(
714 GoalSource::ImplWhereBound,
715 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
716 );
717 }
718
719 ty::FnDef(..)
723 | ty::FnPtr(..)
724 | ty::Error(_)
725 | ty::Uint(_)
726 | ty::Int(_)
727 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
728 | ty::Bool
729 | ty::Float(_)
730 | ty::Char
731 | ty::RawPtr(..)
732 | ty::Never
733 | ty::Pat(..)
734 | ty::Dynamic(..)
735 | ty::Str
736 | ty::Slice(_)
737 | ty::Foreign(..)
738 | ty::Adt(..)
739 | ty::Alias(..)
740 | ty::Param(_)
741 | ty::Placeholder(..)
742 | ty::Closure(..)
743 | ty::CoroutineClosure(..)
744 | ty::Coroutine(..)
745 | ty::UnsafeBinder(_)
746 | ty::CoroutineWitness(..) => {
747 ecx.add_goal(
748 GoalSource::ImplWhereBound,
749 goal.with(
750 cx,
751 ty::TraitRef::new(
752 cx,
753 cx.require_lang_item(TraitSolverLangItem::Copy),
754 [ty],
755 ),
756 ),
757 );
758 }
759
760 ty::Bound(..)
761 | ty::Infer(
762 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
763 ) => {
764 panic!("unexpected type `{ty:?}`")
765 }
766 }
767
768 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
769 })
770 }
771
772 fn consider_structural_builtin_unsize_candidates(
780 ecx: &mut EvalCtxt<'_, D>,
781 goal: Goal<I, Self>,
782 ) -> Vec<Candidate<I>> {
783 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
784 return vec![];
785 }
786
787 let result_to_single = |result| match result {
788 Ok(resp) => vec![resp],
789 Err(NoSolution) => vec![],
790 };
791
792 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
793 let a_ty = goal.predicate.self_ty();
794 let Ok(b_ty) = ecx.structurally_normalize_ty(
797 goal.param_env,
798 goal.predicate.trait_ref.args.type_at(1),
799 ) else {
800 return vec![];
801 };
802
803 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
804 match (a_ty.kind(), b_ty.kind()) {
805 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
806
807 (_, ty::Infer(ty::TyVar(..))) => {
808 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
809 }
810
811 (
813 ty::Dynamic(a_data, a_region, ty::Dyn),
814 ty::Dynamic(b_data, b_region, ty::Dyn),
815 ) => ecx.consider_builtin_dyn_upcast_candidates(
816 goal, a_data, a_region, b_data, b_region,
817 ),
818
819 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
821 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
822 ),
823
824 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
826 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
827 }
828
829 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
831 if a_def.is_struct() && a_def == b_def =>
832 {
833 result_to_single(
834 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
835 )
836 }
837
838 _ => vec![],
839 }
840 })
841 }
842}
843
844#[inline(always)]
850fn trait_predicate_with_def_id<I: Interner>(
851 cx: I,
852 clause: ty::Binder<I, ty::TraitPredicate<I>>,
853 did: I::DefId,
854) -> I::Clause {
855 clause
856 .map_bound(|c| TraitPredicate {
857 trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
858 polarity: c.polarity,
859 })
860 .upcast(cx)
861}
862
863impl<D, I> EvalCtxt<'_, D>
864where
865 D: SolverDelegate<Interner = I>,
866 I: Interner,
867{
868 fn consider_builtin_dyn_upcast_candidates(
878 &mut self,
879 goal: Goal<I, (I::Ty, I::Ty)>,
880 a_data: I::BoundExistentialPredicates,
881 a_region: I::Region,
882 b_data: I::BoundExistentialPredicates,
883 b_region: I::Region,
884 ) -> Vec<Candidate<I>> {
885 let cx = self.cx();
886 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
887
888 let mut responses = vec![];
889 let b_principal_def_id = b_data.principal_def_id();
892 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
893 responses.extend(self.consider_builtin_upcast_to_principal(
894 goal,
895 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
896 a_data,
897 a_region,
898 b_data,
899 b_region,
900 a_data.principal(),
901 ));
902 } else if let Some(a_principal) = a_data.principal() {
903 for (idx, new_a_principal) in
904 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
905 .enumerate()
906 .skip(1)
907 {
908 responses.extend(self.consider_builtin_upcast_to_principal(
909 goal,
910 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
911 a_data,
912 a_region,
913 b_data,
914 b_region,
915 Some(new_a_principal.map_bound(|trait_ref| {
916 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
917 })),
918 ));
919 }
920 }
921
922 responses
923 }
924
925 fn consider_builtin_unsize_to_dyn_candidate(
926 &mut self,
927 goal: Goal<I, (I::Ty, I::Ty)>,
928 b_data: I::BoundExistentialPredicates,
929 b_region: I::Region,
930 ) -> Result<Candidate<I>, NoSolution> {
931 let cx = self.cx();
932 let Goal { predicate: (a_ty, _), .. } = goal;
933
934 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
936 return Err(NoSolution);
937 }
938
939 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
940 ecx.add_goals(
943 GoalSource::ImplWhereBound,
944 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
945 );
946
947 ecx.add_goal(
949 GoalSource::ImplWhereBound,
950 goal.with(
951 cx,
952 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
953 ),
954 );
955
956 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
958 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
959 })
960 }
961
962 fn consider_builtin_upcast_to_principal(
963 &mut self,
964 goal: Goal<I, (I::Ty, I::Ty)>,
965 source: CandidateSource<I>,
966 a_data: I::BoundExistentialPredicates,
967 a_region: I::Region,
968 b_data: I::BoundExistentialPredicates,
969 b_region: I::Region,
970 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
971 ) -> Result<Candidate<I>, NoSolution> {
972 let param_env = goal.param_env;
973
974 let a_auto_traits: IndexSet<I::DefId> = a_data
978 .auto_traits()
979 .into_iter()
980 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
981 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
982 .filter(|def_id| self.cx().trait_is_auto(*def_id))
983 }))
984 .collect();
985
986 let projection_may_match =
991 |ecx: &mut EvalCtxt<'_, D>,
992 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
993 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
994 source_projection.item_def_id() == target_projection.item_def_id()
995 && ecx
996 .probe(|_| ProbeKind::ProjectionCompatibility)
997 .enter(|ecx| -> Result<_, NoSolution> {
998 ecx.enter_forall(target_projection, |ecx, target_projection| {
999 let source_projection =
1000 ecx.instantiate_binder_with_infer(source_projection);
1001 ecx.eq(param_env, source_projection, target_projection)?;
1002 ecx.try_evaluate_added_goals()
1003 })
1004 })
1005 .is_ok()
1006 };
1007
1008 self.probe_trait_candidate(source).enter(|ecx| {
1009 for bound in b_data.iter() {
1010 match bound.skip_binder() {
1011 ty::ExistentialPredicate::Trait(target_principal) => {
1014 let source_principal = upcast_principal.unwrap();
1015 let target_principal = bound.rebind(target_principal);
1016 ecx.enter_forall(target_principal, |ecx, target_principal| {
1017 let source_principal =
1018 ecx.instantiate_binder_with_infer(source_principal);
1019 ecx.eq(param_env, source_principal, target_principal)?;
1020 ecx.try_evaluate_added_goals()
1021 })?;
1022 }
1023 ty::ExistentialPredicate::Projection(target_projection) => {
1029 let target_projection = bound.rebind(target_projection);
1030 let mut matching_projections =
1031 a_data.projection_bounds().into_iter().filter(|source_projection| {
1032 projection_may_match(ecx, *source_projection, target_projection)
1033 });
1034 let Some(source_projection) = matching_projections.next() else {
1035 return Err(NoSolution);
1036 };
1037 if matching_projections.next().is_some() {
1038 return ecx.evaluate_added_goals_and_make_canonical_response(
1039 Certainty::AMBIGUOUS,
1040 );
1041 }
1042 ecx.enter_forall(target_projection, |ecx, target_projection| {
1043 let source_projection =
1044 ecx.instantiate_binder_with_infer(source_projection);
1045 ecx.eq(param_env, source_projection, target_projection)?;
1046 ecx.try_evaluate_added_goals()
1047 })?;
1048 }
1049 ty::ExistentialPredicate::AutoTrait(def_id) => {
1051 if !a_auto_traits.contains(&def_id) {
1052 return Err(NoSolution);
1053 }
1054 }
1055 }
1056 }
1057
1058 ecx.add_goal(
1060 GoalSource::ImplWhereBound,
1061 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1062 );
1063
1064 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1065 })
1066 }
1067
1068 fn consider_builtin_array_unsize(
1077 &mut self,
1078 goal: Goal<I, (I::Ty, I::Ty)>,
1079 a_elem_ty: I::Ty,
1080 b_elem_ty: I::Ty,
1081 ) -> Result<Candidate<I>, NoSolution> {
1082 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1083 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1084 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1085 }
1086
1087 fn consider_builtin_struct_unsize(
1101 &mut self,
1102 goal: Goal<I, (I::Ty, I::Ty)>,
1103 def: I::AdtDef,
1104 a_args: I::GenericArgs,
1105 b_args: I::GenericArgs,
1106 ) -> Result<Candidate<I>, NoSolution> {
1107 let cx = self.cx();
1108 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1109
1110 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1111 if unsizing_params.is_empty() {
1114 return Err(NoSolution);
1115 }
1116
1117 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1118
1119 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1120 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1121
1122 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1126 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1127 }));
1128 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1129
1130 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1133 self.add_goal(
1134 GoalSource::ImplWhereBound,
1135 goal.with(
1136 cx,
1137 ty::TraitRef::new(
1138 cx,
1139 cx.require_lang_item(TraitSolverLangItem::Unsize),
1140 [a_tail_ty, b_tail_ty],
1141 ),
1142 ),
1143 );
1144 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1145 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1146 }
1147
1148 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1153 &mut self,
1154 goal: Goal<I, TraitPredicate<I>>,
1155 ) -> Option<Result<Candidate<I>, NoSolution>> {
1156 let self_ty = goal.predicate.self_ty();
1157 let check_impls = || {
1158 let mut disqualifying_impl = None;
1159 self.cx().for_each_relevant_impl(
1160 goal.predicate.def_id(),
1161 goal.predicate.self_ty(),
1162 |impl_def_id| {
1163 disqualifying_impl = Some(impl_def_id);
1164 },
1165 );
1166 if let Some(def_id) = disqualifying_impl {
1167 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1168 return Some(Err(NoSolution));
1171 } else {
1172 None
1173 }
1174 };
1175
1176 match self_ty.kind() {
1177 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1183 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1184 }
1185
1186 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1189
1190 ty::Dynamic(..)
1193 | ty::Param(..)
1194 | ty::Foreign(..)
1195 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1196 | ty::Placeholder(..) => Some(Err(NoSolution)),
1197
1198 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1199
1200 ty::Coroutine(def_id, _)
1204 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1205 {
1206 match self.cx().coroutine_movability(def_id) {
1207 Movability::Static => Some(Err(NoSolution)),
1208 Movability::Movable => Some(
1209 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1210 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1211 }),
1212 ),
1213 }
1214 }
1215
1216 ty::Alias(..) => None,
1221
1222 ty::Bool
1231 | ty::Char
1232 | ty::Int(_)
1233 | ty::Uint(_)
1234 | ty::Float(_)
1235 | ty::Str
1236 | ty::Array(_, _)
1237 | ty::Pat(_, _)
1238 | ty::Slice(_)
1239 | ty::RawPtr(_, _)
1240 | ty::Ref(_, _, _)
1241 | ty::FnDef(_, _)
1242 | ty::FnPtr(..)
1243 | ty::Closure(..)
1244 | ty::CoroutineClosure(..)
1245 | ty::Coroutine(_, _)
1246 | ty::CoroutineWitness(..)
1247 | ty::Never
1248 | ty::Tuple(_)
1249 | ty::Adt(_, _)
1250 | ty::UnsafeBinder(_) => check_impls(),
1251 ty::Error(_) => None,
1252 }
1253 }
1254
1255 fn probe_and_evaluate_goal_for_constituent_tys(
1260 &mut self,
1261 source: CandidateSource<I>,
1262 goal: Goal<I, TraitPredicate<I>>,
1263 constituent_tys: impl Fn(
1264 &EvalCtxt<'_, D>,
1265 I::Ty,
1266 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1267 ) -> Result<Candidate<I>, NoSolution> {
1268 self.probe_trait_candidate(source).enter(|ecx| {
1269 let goals =
1270 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1271 tys.into_iter()
1272 .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)))
1273 .collect::<Vec<_>>()
1274 });
1275 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1276 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1277 })
1278 }
1279}
1280
1281#[derive(Debug, Clone, Copy)]
1292pub(super) enum TraitGoalProvenVia {
1293 Misc,
1299 ParamEnv,
1300 AliasBound,
1301}
1302
1303impl<D, I> EvalCtxt<'_, D>
1304where
1305 D: SolverDelegate<Interner = I>,
1306 I: Interner,
1307{
1308 pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1321 match self.typing_mode() {
1322 TypingMode::Coherence => return,
1323 TypingMode::Analysis { .. }
1324 | TypingMode::Borrowck { .. }
1325 | TypingMode::PostBorrowckAnalysis { .. }
1326 | TypingMode::PostAnalysis => {}
1327 }
1328
1329 if candidates
1330 .iter()
1331 .find(|c| {
1332 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1333 })
1334 .is_some_and(|c| has_only_region_constraints(c.result))
1335 {
1336 candidates.retain(|c| {
1337 if matches!(c.source, CandidateSource::Impl(_)) {
1338 debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1339 false
1340 } else {
1341 true
1342 }
1343 });
1344 }
1345 }
1346
1347 #[instrument(level = "debug", skip(self), ret)]
1348 pub(super) fn merge_trait_candidates(
1349 &mut self,
1350 mut candidates: Vec<Candidate<I>>,
1351 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1352 if let TypingMode::Coherence = self.typing_mode() {
1353 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1354 return if let Some(response) = self.try_merge_responses(&all_candidates) {
1355 Ok((response, Some(TraitGoalProvenVia::Misc)))
1356 } else {
1357 self.flounder(&all_candidates).map(|r| (r, None))
1358 };
1359 }
1360
1361 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1366 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1367 });
1368 if let Some(candidate) = trivial_builtin_impls.next() {
1369 assert!(trivial_builtin_impls.next().is_none());
1372 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1373 }
1374
1375 let has_non_global_where_bounds = candidates
1378 .iter()
1379 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1380 if has_non_global_where_bounds {
1381 let where_bounds: Vec<_> = candidates
1382 .iter()
1383 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1384 .map(|c| c.result)
1385 .collect();
1386 return if let Some(response) = self.try_merge_responses(&where_bounds) {
1387 Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
1388 } else {
1389 Ok((self.bail_with_ambiguity(&where_bounds), None))
1390 };
1391 }
1392
1393 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1394 let alias_bounds: Vec<_> = candidates
1395 .iter()
1396 .filter(|c| matches!(c.source, CandidateSource::AliasBound))
1397 .map(|c| c.result)
1398 .collect();
1399 return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1400 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1401 } else {
1402 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1403 };
1404 }
1405
1406 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1407 self.unsound_prefer_builtin_dyn_impl(&mut candidates);
1408
1409 let proven_via = if candidates
1414 .iter()
1415 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1416 {
1417 TraitGoalProvenVia::ParamEnv
1418 } else {
1419 candidates
1420 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1421 TraitGoalProvenVia::Misc
1422 };
1423
1424 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1425 if let Some(response) = self.try_merge_responses(&all_candidates) {
1426 Ok((response, Some(proven_via)))
1427 } else {
1428 self.flounder(&all_candidates).map(|r| (r, None))
1429 }
1430 }
1431
1432 #[instrument(level = "trace", skip(self))]
1433 pub(super) fn compute_trait_goal(
1434 &mut self,
1435 goal: Goal<I, TraitPredicate<I>>,
1436 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1437 let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1438 self.merge_trait_candidates(candidates)
1439 }
1440
1441 fn try_stall_coroutine_witness(
1442 &mut self,
1443 self_ty: I::Ty,
1444 ) -> Option<Result<Candidate<I>, NoSolution>> {
1445 if let ty::CoroutineWitness(def_id, _) = self_ty.kind() {
1446 match self.typing_mode() {
1447 TypingMode::Analysis {
1448 defining_opaque_types_and_generators: stalled_generators,
1449 } => {
1450 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1451 {
1452 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1453 }
1454 }
1455 TypingMode::Coherence
1456 | TypingMode::PostAnalysis
1457 | TypingMode::Borrowck { defining_opaque_types: _ }
1458 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1459 }
1460 }
1461
1462 None
1463 }
1464}