1use rustc_ast_ir::Movability;
4use rustc_type_ir::data_structures::IndexSet;
5use rustc_type_ir::fast_reject::DeepRejectCtxt;
6use rustc_type_ir::inherent::*;
7use rustc_type_ir::lang_items::TraitSolverLangItem;
8use rustc_type_ir::solve::CanonicalResponse;
9use rustc_type_ir::visit::TypeVisitableExt as _;
10use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
11use tracing::{instrument, trace};
12
13use crate::delegate::SolverDelegate;
14use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
15use crate::solve::assembly::{self, Candidate};
16use crate::solve::inspect::ProbeKind;
17use crate::solve::{
18 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
19 NoSolution, QueryResult,
20};
21
22impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
23where
24 D: SolverDelegate<Interner = I>,
25 I: Interner,
26{
27 fn self_ty(self) -> I::Ty {
28 self.self_ty()
29 }
30
31 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
32 self.trait_ref
33 }
34
35 fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
36 self.with_self_ty(cx, self_ty)
37 }
38
39 fn trait_def_id(self, _: I) -> I::DefId {
40 self.def_id()
41 }
42
43 fn consider_additional_alias_assumptions(
44 _ecx: &mut EvalCtxt<'_, D>,
45 _goal: Goal<I, Self>,
46 _alias_ty: ty::AliasTy<I>,
47 ) -> Vec<Candidate<I>> {
48 vec![]
49 }
50
51 fn consider_impl_candidate(
52 ecx: &mut EvalCtxt<'_, D>,
53 goal: Goal<I, TraitPredicate<I>>,
54 impl_def_id: I::DefId,
55 ) -> Result<Candidate<I>, NoSolution> {
56 let cx = ecx.cx();
57
58 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
59 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
60 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
61 {
62 return Err(NoSolution);
63 }
64
65 let impl_polarity = cx.impl_polarity(impl_def_id);
68 let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
69 (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
72 TypingMode::Coherence => Certainty::AMBIGUOUS,
73 TypingMode::Analysis { .. }
74 | TypingMode::PostBorrowckAnalysis { .. }
75 | TypingMode::PostAnalysis => return Err(NoSolution),
76 },
77
78 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
80 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
81
82 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
84 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
85 return Err(NoSolution);
86 }
87 };
88
89 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
90 let impl_args = ecx.fresh_args_for_item(impl_def_id);
91 ecx.record_impl_args(impl_args);
92 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
93
94 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
95 let where_clause_bounds = cx
96 .predicates_of(impl_def_id)
97 .iter_instantiated(cx, impl_args)
98 .map(|pred| goal.with(cx, pred));
99 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
100
101 let goal_clause: I::Clause = goal.predicate.upcast(cx);
105 for clause in elaborate::elaborate(cx, [goal_clause]) {
106 if matches!(
107 clause.kind().skip_binder(),
108 ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
109 ) {
110 ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
111 }
112 }
113
114 ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
115 })
116 }
117
118 fn consider_error_guaranteed_candidate(
119 ecx: &mut EvalCtxt<'_, D>,
120 _guar: I::ErrorGuaranteed,
121 ) -> Result<Candidate<I>, NoSolution> {
122 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
123 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
124 }
125
126 fn probe_and_match_goal_against_assumption(
127 ecx: &mut EvalCtxt<'_, D>,
128 source: CandidateSource<I>,
129 goal: Goal<I, Self>,
130 assumption: I::Clause,
131 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
132 ) -> Result<Candidate<I>, 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 Err(NoSolution);
142 }
143
144 ecx.probe_trait_candidate(source).enter(|ecx| {
145 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
146 ecx.eq(
147 goal.param_env,
148 goal.predicate.trait_ref,
149 assumption_trait_pred.trait_ref,
150 )?;
151 then(ecx)
152 })
153 } else {
154 Err(NoSolution)
155 }
156 } else {
157 Err(NoSolution)
158 }
159 }
160
161 fn consider_auto_trait_candidate(
162 ecx: &mut EvalCtxt<'_, D>,
163 goal: Goal<I, Self>,
164 ) -> Result<Candidate<I>, NoSolution> {
165 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
166 return Err(NoSolution);
167 }
168
169 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
170 return result;
171 }
172
173 if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
176 && goal.predicate.self_ty().has_unsafe_fields()
177 {
178 return Err(NoSolution);
179 }
180
181 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
188 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
189 }
190
191 ecx.probe_and_evaluate_goal_for_constituent_tys(
192 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
193 goal,
194 structural_traits::instantiate_constituent_tys_for_auto_trait,
195 )
196 }
197
198 fn consider_trait_alias_candidate(
199 ecx: &mut EvalCtxt<'_, D>,
200 goal: Goal<I, Self>,
201 ) -> Result<Candidate<I>, NoSolution> {
202 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
203 return Err(NoSolution);
204 }
205
206 let cx = ecx.cx();
207
208 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
209 let nested_obligations = cx
210 .predicates_of(goal.predicate.def_id())
211 .iter_instantiated(cx, goal.predicate.trait_ref.args)
212 .map(|p| goal.with(cx, p));
213 ecx.add_goals(GoalSource::Misc, nested_obligations);
215 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
216 })
217 }
218
219 fn consider_builtin_sized_candidate(
220 ecx: &mut EvalCtxt<'_, D>,
221 goal: Goal<I, Self>,
222 ) -> Result<Candidate<I>, NoSolution> {
223 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
224 return Err(NoSolution);
225 }
226
227 ecx.probe_and_evaluate_goal_for_constituent_tys(
228 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
229 goal,
230 structural_traits::instantiate_constituent_tys_for_sized_trait,
231 )
232 }
233
234 fn consider_builtin_copy_clone_candidate(
235 ecx: &mut EvalCtxt<'_, D>,
236 goal: Goal<I, Self>,
237 ) -> Result<Candidate<I>, NoSolution> {
238 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
239 return Err(NoSolution);
240 }
241
242 ecx.probe_and_evaluate_goal_for_constituent_tys(
243 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
244 goal,
245 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
246 )
247 }
248
249 fn consider_builtin_fn_ptr_trait_candidate(
250 ecx: &mut EvalCtxt<'_, D>,
251 goal: Goal<I, Self>,
252 ) -> Result<Candidate<I>, NoSolution> {
253 let self_ty = goal.predicate.self_ty();
254 match goal.predicate.polarity {
255 ty::PredicatePolarity::Positive => {
257 if self_ty.is_fn_ptr() {
258 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
259 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
260 })
261 } else {
262 Err(NoSolution)
263 }
264 }
265 ty::PredicatePolarity::Negative => {
267 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
270 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
271 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
272 })
273 } else {
274 Err(NoSolution)
275 }
276 }
277 }
278 }
279
280 fn consider_builtin_fn_trait_candidates(
281 ecx: &mut EvalCtxt<'_, D>,
282 goal: Goal<I, Self>,
283 goal_kind: ty::ClosureKind,
284 ) -> Result<Candidate<I>, NoSolution> {
285 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
286 return Err(NoSolution);
287 }
288
289 let cx = ecx.cx();
290 let tupled_inputs_and_output =
291 match structural_traits::extract_tupled_inputs_and_output_from_callable(
292 cx,
293 goal.predicate.self_ty(),
294 goal_kind,
295 )? {
296 Some(a) => a,
297 None => {
298 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
299 }
300 };
301
302 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
305 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
306 });
307
308 let pred = tupled_inputs_and_output
309 .map_bound(|(inputs, _)| {
310 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
311 })
312 .upcast(cx);
313 Self::probe_and_consider_implied_clause(
314 ecx,
315 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
316 goal,
317 pred,
318 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
319 )
320 }
321
322 fn consider_builtin_async_fn_trait_candidates(
323 ecx: &mut EvalCtxt<'_, D>,
324 goal: Goal<I, Self>,
325 goal_kind: ty::ClosureKind,
326 ) -> Result<Candidate<I>, NoSolution> {
327 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
328 return Err(NoSolution);
329 }
330
331 let cx = ecx.cx();
332 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
333 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
334 cx,
335 goal.predicate.self_ty(),
336 goal_kind,
337 Region::new_static(cx),
339 )?;
340
341 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
344 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
345 ty::TraitRef::new(
346 cx,
347 cx.require_lang_item(TraitSolverLangItem::Sized),
348 [output_coroutine_ty],
349 )
350 },
351 );
352
353 let pred = tupled_inputs_and_output_and_coroutine
354 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
355 ty::TraitRef::new(
356 cx,
357 goal.predicate.def_id(),
358 [goal.predicate.self_ty(), tupled_inputs_ty],
359 )
360 })
361 .upcast(cx);
362 Self::probe_and_consider_implied_clause(
363 ecx,
364 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
365 goal,
366 pred,
367 [goal.with(cx, output_is_sized_pred)]
368 .into_iter()
369 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
370 .map(|goal| (GoalSource::ImplWhereBound, goal)),
371 )
372 }
373
374 fn consider_builtin_async_fn_kind_helper_candidate(
375 ecx: &mut EvalCtxt<'_, D>,
376 goal: Goal<I, Self>,
377 ) -> Result<Candidate<I>, NoSolution> {
378 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
379 panic!();
380 };
381
382 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
383 return Err(NoSolution);
385 };
386 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
387 if closure_kind.extends(goal_kind) {
388 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
389 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
390 } else {
391 Err(NoSolution)
392 }
393 }
394
395 fn consider_builtin_tuple_candidate(
402 ecx: &mut EvalCtxt<'_, D>,
403 goal: Goal<I, Self>,
404 ) -> Result<Candidate<I>, NoSolution> {
405 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
406 return Err(NoSolution);
407 }
408
409 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
410 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
411 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
412 } else {
413 Err(NoSolution)
414 }
415 }
416
417 fn consider_builtin_pointee_candidate(
418 ecx: &mut EvalCtxt<'_, D>,
419 goal: Goal<I, Self>,
420 ) -> Result<Candidate<I>, NoSolution> {
421 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
422 return Err(NoSolution);
423 }
424
425 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
426 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
427 }
428
429 fn consider_builtin_future_candidate(
430 ecx: &mut EvalCtxt<'_, D>,
431 goal: Goal<I, Self>,
432 ) -> Result<Candidate<I>, NoSolution> {
433 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
434 return Err(NoSolution);
435 }
436
437 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
438 return Err(NoSolution);
439 };
440
441 let cx = ecx.cx();
443 if !cx.coroutine_is_async(def_id) {
444 return Err(NoSolution);
445 }
446
447 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
451 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
452 }
453
454 fn consider_builtin_iterator_candidate(
455 ecx: &mut EvalCtxt<'_, D>,
456 goal: Goal<I, Self>,
457 ) -> Result<Candidate<I>, NoSolution> {
458 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
459 return Err(NoSolution);
460 }
461
462 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
463 return Err(NoSolution);
464 };
465
466 let cx = ecx.cx();
468 if !cx.coroutine_is_gen(def_id) {
469 return Err(NoSolution);
470 }
471
472 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
476 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
477 }
478
479 fn consider_builtin_fused_iterator_candidate(
480 ecx: &mut EvalCtxt<'_, D>,
481 goal: Goal<I, Self>,
482 ) -> Result<Candidate<I>, NoSolution> {
483 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
484 return Err(NoSolution);
485 }
486
487 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
488 return Err(NoSolution);
489 };
490
491 let cx = ecx.cx();
493 if !cx.coroutine_is_gen(def_id) {
494 return Err(NoSolution);
495 }
496
497 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
499 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
500 }
501
502 fn consider_builtin_async_iterator_candidate(
503 ecx: &mut EvalCtxt<'_, D>,
504 goal: Goal<I, Self>,
505 ) -> Result<Candidate<I>, NoSolution> {
506 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
507 return Err(NoSolution);
508 }
509
510 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
511 return Err(NoSolution);
512 };
513
514 let cx = ecx.cx();
516 if !cx.coroutine_is_async_gen(def_id) {
517 return Err(NoSolution);
518 }
519
520 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
524 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
525 }
526
527 fn consider_builtin_coroutine_candidate(
528 ecx: &mut EvalCtxt<'_, D>,
529 goal: Goal<I, Self>,
530 ) -> Result<Candidate<I>, NoSolution> {
531 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
532 return Err(NoSolution);
533 }
534
535 let self_ty = goal.predicate.self_ty();
536 let ty::Coroutine(def_id, args) = self_ty.kind() else {
537 return Err(NoSolution);
538 };
539
540 let cx = ecx.cx();
542 if !cx.is_general_coroutine(def_id) {
543 return Err(NoSolution);
544 }
545
546 let coroutine = args.as_coroutine();
547 Self::probe_and_consider_implied_clause(
548 ecx,
549 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
550 goal,
551 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
552 .upcast(cx),
553 [],
556 )
557 }
558
559 fn consider_builtin_discriminant_kind_candidate(
560 ecx: &mut EvalCtxt<'_, D>,
561 goal: Goal<I, Self>,
562 ) -> Result<Candidate<I>, NoSolution> {
563 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
564 return Err(NoSolution);
565 }
566
567 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
569 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
570 }
571
572 fn consider_builtin_async_destruct_candidate(
573 ecx: &mut EvalCtxt<'_, D>,
574 goal: Goal<I, Self>,
575 ) -> Result<Candidate<I>, NoSolution> {
576 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
577 return Err(NoSolution);
578 }
579
580 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
582 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
583 }
584
585 fn consider_builtin_destruct_candidate(
586 ecx: &mut EvalCtxt<'_, D>,
587 goal: Goal<I, Self>,
588 ) -> Result<Candidate<I>, NoSolution> {
589 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
590 return Err(NoSolution);
591 }
592
593 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
596 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
597 }
598
599 fn consider_builtin_transmute_candidate(
600 ecx: &mut EvalCtxt<'_, D>,
601 goal: Goal<I, Self>,
602 ) -> Result<Candidate<I>, NoSolution> {
603 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
604 return Err(NoSolution);
605 }
606
607 if goal.has_non_region_placeholders() {
609 return Err(NoSolution);
610 }
611
612 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
613 let assume = ecx.structurally_normalize_const(
614 goal.param_env,
615 goal.predicate.trait_ref.args.const_at(2),
616 )?;
617
618 let certainty = ecx.is_transmutable(
619 goal.param_env,
620 goal.predicate.trait_ref.args.type_at(0),
621 goal.predicate.trait_ref.args.type_at(1),
622 assume,
623 )?;
624 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
625 })
626 }
627
628 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
638 ecx: &mut EvalCtxt<'_, D>,
639 goal: Goal<I, Self>,
640 ) -> Result<Candidate<I>, NoSolution> {
641 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
642 return Err(NoSolution);
643 }
644
645 let cx = ecx.cx();
646 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
647 let ty = goal.predicate.self_ty();
648 match ty.kind() {
649 ty::Ref(..) => {}
651 ty::Adt(def, _) if def.is_manually_drop() => {}
653 ty::Tuple(tys) => {
656 ecx.add_goals(
657 GoalSource::ImplWhereBound,
658 tys.iter().map(|elem_ty| {
659 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
660 }),
661 );
662 }
663 ty::Array(elem_ty, _) => {
664 ecx.add_goal(
665 GoalSource::ImplWhereBound,
666 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
667 );
668 }
669
670 ty::FnDef(..)
674 | ty::FnPtr(..)
675 | ty::Error(_)
676 | ty::Uint(_)
677 | ty::Int(_)
678 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
679 | ty::Bool
680 | ty::Float(_)
681 | ty::Char
682 | ty::RawPtr(..)
683 | ty::Never
684 | ty::Pat(..)
685 | ty::Dynamic(..)
686 | ty::Str
687 | ty::Slice(_)
688 | ty::Foreign(..)
689 | ty::Adt(..)
690 | ty::Alias(..)
691 | ty::Param(_)
692 | ty::Placeholder(..)
693 | ty::Closure(..)
694 | ty::CoroutineClosure(..)
695 | ty::Coroutine(..)
696 | ty::UnsafeBinder(_)
697 | ty::CoroutineWitness(..) => {
698 ecx.add_goal(
699 GoalSource::ImplWhereBound,
700 goal.with(
701 cx,
702 ty::TraitRef::new(
703 cx,
704 cx.require_lang_item(TraitSolverLangItem::Copy),
705 [ty],
706 ),
707 ),
708 );
709 }
710
711 ty::Bound(..)
712 | ty::Infer(
713 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
714 ) => {
715 panic!("unexpected type `{ty:?}`")
716 }
717 }
718
719 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
720 })
721 }
722
723 fn consider_structural_builtin_unsize_candidates(
731 ecx: &mut EvalCtxt<'_, D>,
732 goal: Goal<I, Self>,
733 ) -> Vec<Candidate<I>> {
734 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
735 return vec![];
736 }
737
738 let result_to_single = |result| match result {
739 Ok(resp) => vec![resp],
740 Err(NoSolution) => vec![],
741 };
742
743 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
744 let a_ty = goal.predicate.self_ty();
745 let Ok(b_ty) = ecx.structurally_normalize_ty(
748 goal.param_env,
749 goal.predicate.trait_ref.args.type_at(1),
750 ) else {
751 return vec![];
752 };
753
754 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
755 match (a_ty.kind(), b_ty.kind()) {
756 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
757
758 (_, ty::Infer(ty::TyVar(..))) => {
759 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
760 }
761
762 (
764 ty::Dynamic(a_data, a_region, ty::Dyn),
765 ty::Dynamic(b_data, b_region, ty::Dyn),
766 ) => ecx.consider_builtin_dyn_upcast_candidates(
767 goal, a_data, a_region, b_data, b_region,
768 ),
769
770 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
772 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
773 ),
774
775 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
777 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
778 }
779
780 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
782 if a_def.is_struct() && a_def == b_def =>
783 {
784 result_to_single(
785 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
786 )
787 }
788
789 (ty::Tuple(a_tys), ty::Tuple(b_tys))
791 if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
792 {
793 result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
794 }
795
796 _ => vec![],
797 }
798 })
799 }
800}
801
802impl<D, I> EvalCtxt<'_, D>
803where
804 D: SolverDelegate<Interner = I>,
805 I: Interner,
806{
807 fn consider_builtin_dyn_upcast_candidates(
817 &mut self,
818 goal: Goal<I, (I::Ty, I::Ty)>,
819 a_data: I::BoundExistentialPredicates,
820 a_region: I::Region,
821 b_data: I::BoundExistentialPredicates,
822 b_region: I::Region,
823 ) -> Vec<Candidate<I>> {
824 let cx = self.cx();
825 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
826
827 let mut responses = vec![];
828 let b_principal_def_id = b_data.principal_def_id();
831 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
832 responses.extend(self.consider_builtin_upcast_to_principal(
833 goal,
834 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
835 a_data,
836 a_region,
837 b_data,
838 b_region,
839 a_data.principal(),
840 ));
841 } else if let Some(a_principal) = a_data.principal() {
842 for (idx, new_a_principal) in
843 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
844 .enumerate()
845 .skip(1)
846 {
847 responses.extend(self.consider_builtin_upcast_to_principal(
848 goal,
849 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
850 a_data,
851 a_region,
852 b_data,
853 b_region,
854 Some(new_a_principal.map_bound(|trait_ref| {
855 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
856 })),
857 ));
858 }
859 }
860
861 responses
862 }
863
864 fn consider_builtin_unsize_to_dyn_candidate(
865 &mut self,
866 goal: Goal<I, (I::Ty, I::Ty)>,
867 b_data: I::BoundExistentialPredicates,
868 b_region: I::Region,
869 ) -> Result<Candidate<I>, NoSolution> {
870 let cx = self.cx();
871 let Goal { predicate: (a_ty, _), .. } = goal;
872
873 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
875 return Err(NoSolution);
876 }
877
878 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
879 ecx.add_goals(
882 GoalSource::ImplWhereBound,
883 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
884 );
885
886 ecx.add_goal(
888 GoalSource::ImplWhereBound,
889 goal.with(
890 cx,
891 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
892 ),
893 );
894
895 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
897 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
898 })
899 }
900
901 fn consider_builtin_upcast_to_principal(
902 &mut self,
903 goal: Goal<I, (I::Ty, I::Ty)>,
904 source: CandidateSource<I>,
905 a_data: I::BoundExistentialPredicates,
906 a_region: I::Region,
907 b_data: I::BoundExistentialPredicates,
908 b_region: I::Region,
909 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
910 ) -> Result<Candidate<I>, NoSolution> {
911 let param_env = goal.param_env;
912
913 let a_auto_traits: IndexSet<I::DefId> = a_data
917 .auto_traits()
918 .into_iter()
919 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
920 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
921 .filter(|def_id| self.cx().trait_is_auto(*def_id))
922 }))
923 .collect();
924
925 let projection_may_match =
930 |ecx: &mut EvalCtxt<'_, D>,
931 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
932 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
933 source_projection.item_def_id() == target_projection.item_def_id()
934 && ecx
935 .probe(|_| ProbeKind::UpcastProjectionCompatibility)
936 .enter(|ecx| -> Result<_, NoSolution> {
937 ecx.enter_forall(target_projection, |ecx, target_projection| {
938 let source_projection =
939 ecx.instantiate_binder_with_infer(source_projection);
940 ecx.eq(param_env, source_projection, target_projection)?;
941 ecx.try_evaluate_added_goals()
942 })
943 })
944 .is_ok()
945 };
946
947 self.probe_trait_candidate(source).enter(|ecx| {
948 for bound in b_data.iter() {
949 match bound.skip_binder() {
950 ty::ExistentialPredicate::Trait(target_principal) => {
953 let source_principal = upcast_principal.unwrap();
954 let target_principal = bound.rebind(target_principal);
955 ecx.enter_forall(target_principal, |ecx, target_principal| {
956 let source_principal =
957 ecx.instantiate_binder_with_infer(source_principal);
958 ecx.eq(param_env, source_principal, target_principal)?;
959 ecx.try_evaluate_added_goals()
960 })?;
961 }
962 ty::ExistentialPredicate::Projection(target_projection) => {
968 let target_projection = bound.rebind(target_projection);
969 let mut matching_projections =
970 a_data.projection_bounds().into_iter().filter(|source_projection| {
971 projection_may_match(ecx, *source_projection, target_projection)
972 });
973 let Some(source_projection) = matching_projections.next() else {
974 return Err(NoSolution);
975 };
976 if matching_projections.next().is_some() {
977 return ecx.evaluate_added_goals_and_make_canonical_response(
978 Certainty::AMBIGUOUS,
979 );
980 }
981 ecx.enter_forall(target_projection, |ecx, target_projection| {
982 let source_projection =
983 ecx.instantiate_binder_with_infer(source_projection);
984 ecx.eq(param_env, source_projection, target_projection)?;
985 ecx.try_evaluate_added_goals()
986 })?;
987 }
988 ty::ExistentialPredicate::AutoTrait(def_id) => {
990 if !a_auto_traits.contains(&def_id) {
991 return Err(NoSolution);
992 }
993 }
994 }
995 }
996
997 ecx.add_goal(
999 GoalSource::ImplWhereBound,
1000 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1001 );
1002
1003 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1004 })
1005 }
1006
1007 fn consider_builtin_array_unsize(
1016 &mut self,
1017 goal: Goal<I, (I::Ty, I::Ty)>,
1018 a_elem_ty: I::Ty,
1019 b_elem_ty: I::Ty,
1020 ) -> Result<Candidate<I>, NoSolution> {
1021 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1022 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1023 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1024 }
1025
1026 fn consider_builtin_struct_unsize(
1040 &mut self,
1041 goal: Goal<I, (I::Ty, I::Ty)>,
1042 def: I::AdtDef,
1043 a_args: I::GenericArgs,
1044 b_args: I::GenericArgs,
1045 ) -> Result<Candidate<I>, NoSolution> {
1046 let cx = self.cx();
1047 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1048
1049 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1050 if unsizing_params.is_empty() {
1053 return Err(NoSolution);
1054 }
1055
1056 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1057
1058 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1059 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1060
1061 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1065 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1066 }));
1067 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1068
1069 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1072 self.add_goal(
1073 GoalSource::ImplWhereBound,
1074 goal.with(
1075 cx,
1076 ty::TraitRef::new(
1077 cx,
1078 cx.require_lang_item(TraitSolverLangItem::Unsize),
1079 [a_tail_ty, b_tail_ty],
1080 ),
1081 ),
1082 );
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_tuple_unsize(
1098 &mut self,
1099 goal: Goal<I, (I::Ty, I::Ty)>,
1100 a_tys: I::Tys,
1101 b_tys: I::Tys,
1102 ) -> Result<Candidate<I>, NoSolution> {
1103 let cx = self.cx();
1104 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1105
1106 let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
1107 let b_last_ty = b_tys.last().unwrap();
1108
1109 let unsized_a_ty = Ty::new_tup_from_iter(cx, a_rest_tys.iter().copied().chain([b_last_ty]));
1111 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1112
1113 self.add_goal(
1115 GoalSource::ImplWhereBound,
1116 goal.with(
1117 cx,
1118 ty::TraitRef::new(
1119 cx,
1120 cx.require_lang_item(TraitSolverLangItem::Unsize),
1121 [a_last_ty, b_last_ty],
1122 ),
1123 ),
1124 );
1125 self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing)
1126 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1127 }
1128
1129 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1134 &mut self,
1135 goal: Goal<I, TraitPredicate<I>>,
1136 ) -> Option<Result<Candidate<I>, NoSolution>> {
1137 let self_ty = goal.predicate.self_ty();
1138 match self_ty.kind() {
1139 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1145 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1146 }
1147
1148 ty::Dynamic(..)
1151 | ty::Param(..)
1152 | ty::Foreign(..)
1153 | ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
1154 | ty::Placeholder(..) => Some(Err(NoSolution)),
1155
1156 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1157
1158 ty::Coroutine(def_id, _)
1162 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1163 {
1164 match self.cx().coroutine_movability(def_id) {
1165 Movability::Static => Some(Err(NoSolution)),
1166 Movability::Movable => Some(
1167 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1168 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1169 }),
1170 ),
1171 }
1172 }
1173
1174 ty::Alias(..) => None,
1179
1180 ty::Bool
1189 | ty::Char
1190 | ty::Int(_)
1191 | ty::Uint(_)
1192 | ty::Float(_)
1193 | ty::Str
1194 | ty::Array(_, _)
1195 | ty::Pat(_, _)
1196 | ty::Slice(_)
1197 | ty::RawPtr(_, _)
1198 | ty::Ref(_, _, _)
1199 | ty::FnDef(_, _)
1200 | ty::FnPtr(..)
1201 | ty::Closure(..)
1202 | ty::CoroutineClosure(..)
1203 | ty::Coroutine(_, _)
1204 | ty::CoroutineWitness(..)
1205 | ty::Never
1206 | ty::Tuple(_)
1207 | ty::Adt(_, _)
1208 | ty::UnsafeBinder(_) => {
1209 let mut disqualifying_impl = None;
1210 self.cx().for_each_relevant_impl(
1211 goal.predicate.def_id(),
1212 goal.predicate.self_ty(),
1213 |impl_def_id| {
1214 disqualifying_impl = Some(impl_def_id);
1215 },
1216 );
1217 if let Some(def_id) = disqualifying_impl {
1218 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1219 return Some(Err(NoSolution));
1222 } else {
1223 None
1224 }
1225 }
1226 ty::Error(_) => None,
1227 }
1228 }
1229
1230 fn probe_and_evaluate_goal_for_constituent_tys(
1235 &mut self,
1236 source: CandidateSource<I>,
1237 goal: Goal<I, TraitPredicate<I>>,
1238 constituent_tys: impl Fn(
1239 &EvalCtxt<'_, D>,
1240 I::Ty,
1241 ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
1242 ) -> Result<Candidate<I>, NoSolution> {
1243 self.probe_trait_candidate(source).enter(|ecx| {
1244 let goals = constituent_tys(ecx, goal.predicate.self_ty())?
1245 .into_iter()
1246 .map(|ty| {
1247 ecx.enter_forall(ty, |ecx, ty| {
1248 goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
1249 })
1250 })
1251 .collect::<Vec<_>>();
1252 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1253 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1254 })
1255 }
1256}
1257
1258#[derive(Debug, Clone, Copy)]
1269pub(super) enum TraitGoalProvenVia {
1270 Misc,
1276 ParamEnv,
1277 AliasBound,
1278}
1279
1280impl<D, I> EvalCtxt<'_, D>
1281where
1282 D: SolverDelegate<Interner = I>,
1283 I: Interner,
1284{
1285 pub(super) fn merge_trait_candidates(
1286 &mut self,
1287 goal: Goal<I, TraitPredicate<I>>,
1288 candidates: Vec<Candidate<I>>,
1289 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1290 if let TypingMode::Coherence = self.typing_mode() {
1291 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1292 return if let Some(response) = self.try_merge_responses(&all_candidates) {
1293 Ok((response, Some(TraitGoalProvenVia::Misc)))
1294 } else {
1295 self.flounder(&all_candidates).map(|r| (r, None))
1296 };
1297 }
1298
1299 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1304 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1305 });
1306 if let Some(candidate) = trivial_builtin_impls.next() {
1307 assert!(trivial_builtin_impls.next().is_none());
1310 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1311 }
1312
1313 let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
1316 CandidateSource::ParamEnv(idx) => {
1317 let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
1318 let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
1319 unreachable!("expected trait-bound: {where_bound:?}");
1320 };
1321
1322 if trait_pred.has_bound_vars() || !trait_pred.is_global() {
1323 return true;
1324 }
1325
1326 for p in goal.param_env.caller_bounds().iter() {
1331 if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
1332 if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
1333 return true;
1334 }
1335 }
1336 }
1337
1338 false
1339 }
1340 _ => false,
1341 });
1342 if has_non_global_where_bounds {
1343 let where_bounds: Vec<_> = candidates
1344 .iter()
1345 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1346 .map(|c| c.result)
1347 .collect();
1348
1349 return if let Some(response) = self.try_merge_responses(&where_bounds) {
1350 Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
1351 } else {
1352 Ok((self.bail_with_ambiguity(&where_bounds), None))
1353 };
1354 }
1355
1356 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1357 let alias_bounds: Vec<_> = candidates
1358 .iter()
1359 .filter(|c| matches!(c.source, CandidateSource::AliasBound))
1360 .map(|c| c.result)
1361 .collect();
1362 return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1363 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1364 } else {
1365 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1366 };
1367 }
1368
1369 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1370 if let Some(response) = self.try_merge_responses(&all_candidates) {
1371 Ok((response, Some(TraitGoalProvenVia::Misc)))
1372 } else {
1373 self.flounder(&all_candidates).map(|r| (r, None))
1374 }
1375 }
1376
1377 #[instrument(level = "trace", skip(self))]
1378 pub(super) fn compute_trait_goal(
1379 &mut self,
1380 goal: Goal<I, TraitPredicate<I>>,
1381 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1382 let candidates = self.assemble_and_evaluate_candidates(goal);
1383 self.merge_trait_candidates(goal, candidates)
1384 }
1385}