1use rustc_type_ir::data_structures::IndexSet;
4use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::TraitSolverLangItem;
7use rustc_type_ir::solve::CanonicalResponse;
8use rustc_type_ir::{
9 self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
10 Upcast as _, elaborate,
11};
12use tracing::{instrument, trace};
13
14use crate::delegate::SolverDelegate;
15use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16use crate::solve::assembly::{self, Candidate};
17use crate::solve::inspect::ProbeKind;
18use crate::solve::{
19 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
20 NoSolution, QueryResult,
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::PostBorrowckAnalysis { .. }
76 | TypingMode::PostAnalysis => return Err(NoSolution),
77 },
78
79 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
81 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
82
83 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
85 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
86 return Err(NoSolution);
87 }
88 };
89
90 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
91 let impl_args = ecx.fresh_args_for_item(impl_def_id);
92 ecx.record_impl_args(impl_args);
93 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
94
95 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
96 let where_clause_bounds = cx
97 .predicates_of(impl_def_id)
98 .iter_instantiated(cx, impl_args)
99 .map(|pred| goal.with(cx, pred));
100 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
101
102 let goal_clause: I::Clause = goal.predicate.upcast(cx);
106 for clause in elaborate::elaborate(cx, [goal_clause]) {
107 if matches!(
108 clause.kind().skip_binder(),
109 ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
110 ) {
111 ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
112 }
113 }
114
115 ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
116 })
117 }
118
119 fn consider_error_guaranteed_candidate(
120 ecx: &mut EvalCtxt<'_, D>,
121 _guar: I::ErrorGuaranteed,
122 ) -> Result<Candidate<I>, NoSolution> {
123 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
124 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
125 }
126
127 fn probe_and_match_goal_against_assumption(
128 ecx: &mut EvalCtxt<'_, D>,
129 source: CandidateSource<I>,
130 goal: Goal<I, Self>,
131 assumption: I::Clause,
132 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
133 ) -> Result<Candidate<I>, NoSolution> {
134 if let Some(trait_clause) = assumption.as_trait_clause() {
135 if trait_clause.def_id() == goal.predicate.def_id()
136 && trait_clause.polarity() == goal.predicate.polarity
137 {
138 if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
139 goal.predicate.trait_ref.args,
140 trait_clause.skip_binder().trait_ref.args,
141 ) {
142 return Err(NoSolution);
143 }
144
145 ecx.probe_trait_candidate(source).enter(|ecx| {
146 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
147 ecx.eq(
148 goal.param_env,
149 goal.predicate.trait_ref,
150 assumption_trait_pred.trait_ref,
151 )?;
152 then(ecx)
153 })
154 } else {
155 Err(NoSolution)
156 }
157 } else {
158 Err(NoSolution)
159 }
160 }
161
162 fn consider_auto_trait_candidate(
163 ecx: &mut EvalCtxt<'_, D>,
164 goal: Goal<I, Self>,
165 ) -> Result<Candidate<I>, NoSolution> {
166 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
167 return Err(NoSolution);
168 }
169
170 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
171 return result;
172 }
173
174 if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
177 && goal.predicate.self_ty().has_unsafe_fields()
178 {
179 return Err(NoSolution);
180 }
181
182 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
189 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
190 }
191
192 ecx.probe_and_evaluate_goal_for_constituent_tys(
193 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
194 goal,
195 structural_traits::instantiate_constituent_tys_for_auto_trait,
196 )
197 }
198
199 fn consider_trait_alias_candidate(
200 ecx: &mut EvalCtxt<'_, D>,
201 goal: Goal<I, Self>,
202 ) -> Result<Candidate<I>, NoSolution> {
203 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
204 return Err(NoSolution);
205 }
206
207 let cx = ecx.cx();
208
209 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
210 let nested_obligations = cx
211 .predicates_of(goal.predicate.def_id())
212 .iter_instantiated(cx, goal.predicate.trait_ref.args)
213 .map(|p| goal.with(cx, p));
214 ecx.add_goals(GoalSource::Misc, nested_obligations);
216 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
217 })
218 }
219
220 fn consider_builtin_sized_candidate(
221 ecx: &mut EvalCtxt<'_, D>,
222 goal: Goal<I, Self>,
223 ) -> Result<Candidate<I>, NoSolution> {
224 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
225 return Err(NoSolution);
226 }
227
228 ecx.probe_and_evaluate_goal_for_constituent_tys(
229 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
230 goal,
231 structural_traits::instantiate_constituent_tys_for_sized_trait,
232 )
233 }
234
235 fn consider_builtin_copy_clone_candidate(
236 ecx: &mut EvalCtxt<'_, D>,
237 goal: Goal<I, Self>,
238 ) -> Result<Candidate<I>, NoSolution> {
239 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
240 return Err(NoSolution);
241 }
242
243 ecx.probe_and_evaluate_goal_for_constituent_tys(
244 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
245 goal,
246 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
247 )
248 }
249
250 fn consider_builtin_fn_ptr_trait_candidate(
251 ecx: &mut EvalCtxt<'_, D>,
252 goal: Goal<I, Self>,
253 ) -> Result<Candidate<I>, NoSolution> {
254 let self_ty = goal.predicate.self_ty();
255 match goal.predicate.polarity {
256 ty::PredicatePolarity::Positive => {
258 if self_ty.is_fn_ptr() {
259 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
260 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
261 })
262 } else {
263 Err(NoSolution)
264 }
265 }
266 ty::PredicatePolarity::Negative => {
268 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
271 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
272 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
273 })
274 } else {
275 Err(NoSolution)
276 }
277 }
278 }
279 }
280
281 fn consider_builtin_fn_trait_candidates(
282 ecx: &mut EvalCtxt<'_, D>,
283 goal: Goal<I, Self>,
284 goal_kind: ty::ClosureKind,
285 ) -> Result<Candidate<I>, NoSolution> {
286 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
287 return Err(NoSolution);
288 }
289
290 let cx = ecx.cx();
291 let tupled_inputs_and_output =
292 match structural_traits::extract_tupled_inputs_and_output_from_callable(
293 cx,
294 goal.predicate.self_ty(),
295 goal_kind,
296 )? {
297 Some(a) => a,
298 None => {
299 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
300 }
301 };
302
303 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
306 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
307 });
308
309 let pred = tupled_inputs_and_output
310 .map_bound(|(inputs, _)| {
311 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
312 })
313 .upcast(cx);
314 Self::probe_and_consider_implied_clause(
315 ecx,
316 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
317 goal,
318 pred,
319 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
320 )
321 }
322
323 fn consider_builtin_async_fn_trait_candidates(
324 ecx: &mut EvalCtxt<'_, D>,
325 goal: Goal<I, Self>,
326 goal_kind: ty::ClosureKind,
327 ) -> Result<Candidate<I>, NoSolution> {
328 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
329 return Err(NoSolution);
330 }
331
332 let cx = ecx.cx();
333 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
334 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
335 cx,
336 goal.predicate.self_ty(),
337 goal_kind,
338 Region::new_static(cx),
340 )?;
341
342 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
345 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
346 ty::TraitRef::new(
347 cx,
348 cx.require_lang_item(TraitSolverLangItem::Sized),
349 [output_coroutine_ty],
350 )
351 },
352 );
353
354 let pred = tupled_inputs_and_output_and_coroutine
355 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
356 ty::TraitRef::new(
357 cx,
358 goal.predicate.def_id(),
359 [goal.predicate.self_ty(), tupled_inputs_ty],
360 )
361 })
362 .upcast(cx);
363 Self::probe_and_consider_implied_clause(
364 ecx,
365 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
366 goal,
367 pred,
368 [goal.with(cx, output_is_sized_pred)]
369 .into_iter()
370 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
371 .map(|goal| (GoalSource::ImplWhereBound, goal)),
372 )
373 }
374
375 fn consider_builtin_async_fn_kind_helper_candidate(
376 ecx: &mut EvalCtxt<'_, D>,
377 goal: Goal<I, Self>,
378 ) -> Result<Candidate<I>, NoSolution> {
379 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
380 panic!();
381 };
382
383 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
384 return Err(NoSolution);
386 };
387 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
388 if closure_kind.extends(goal_kind) {
389 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
390 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
391 } else {
392 Err(NoSolution)
393 }
394 }
395
396 fn consider_builtin_tuple_candidate(
403 ecx: &mut EvalCtxt<'_, D>,
404 goal: Goal<I, Self>,
405 ) -> Result<Candidate<I>, NoSolution> {
406 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
407 return Err(NoSolution);
408 }
409
410 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
411 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
412 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
413 } else {
414 Err(NoSolution)
415 }
416 }
417
418 fn consider_builtin_pointee_candidate(
419 ecx: &mut EvalCtxt<'_, D>,
420 goal: Goal<I, Self>,
421 ) -> Result<Candidate<I>, NoSolution> {
422 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
423 return Err(NoSolution);
424 }
425
426 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
427 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
428 }
429
430 fn consider_builtin_future_candidate(
431 ecx: &mut EvalCtxt<'_, D>,
432 goal: Goal<I, Self>,
433 ) -> Result<Candidate<I>, NoSolution> {
434 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
435 return Err(NoSolution);
436 }
437
438 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
439 return Err(NoSolution);
440 };
441
442 let cx = ecx.cx();
444 if !cx.coroutine_is_async(def_id) {
445 return Err(NoSolution);
446 }
447
448 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
452 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
453 }
454
455 fn consider_builtin_iterator_candidate(
456 ecx: &mut EvalCtxt<'_, D>,
457 goal: Goal<I, Self>,
458 ) -> Result<Candidate<I>, NoSolution> {
459 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
460 return Err(NoSolution);
461 }
462
463 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
464 return Err(NoSolution);
465 };
466
467 let cx = ecx.cx();
469 if !cx.coroutine_is_gen(def_id) {
470 return Err(NoSolution);
471 }
472
473 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
477 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
478 }
479
480 fn consider_builtin_fused_iterator_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 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
489 return Err(NoSolution);
490 };
491
492 let cx = ecx.cx();
494 if !cx.coroutine_is_gen(def_id) {
495 return Err(NoSolution);
496 }
497
498 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
500 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
501 }
502
503 fn consider_builtin_async_iterator_candidate(
504 ecx: &mut EvalCtxt<'_, D>,
505 goal: Goal<I, Self>,
506 ) -> Result<Candidate<I>, NoSolution> {
507 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
508 return Err(NoSolution);
509 }
510
511 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
512 return Err(NoSolution);
513 };
514
515 let cx = ecx.cx();
517 if !cx.coroutine_is_async_gen(def_id) {
518 return Err(NoSolution);
519 }
520
521 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
525 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
526 }
527
528 fn consider_builtin_coroutine_candidate(
529 ecx: &mut EvalCtxt<'_, D>,
530 goal: Goal<I, Self>,
531 ) -> Result<Candidate<I>, NoSolution> {
532 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
533 return Err(NoSolution);
534 }
535
536 let self_ty = goal.predicate.self_ty();
537 let ty::Coroutine(def_id, args) = self_ty.kind() else {
538 return Err(NoSolution);
539 };
540
541 let cx = ecx.cx();
543 if !cx.is_general_coroutine(def_id) {
544 return Err(NoSolution);
545 }
546
547 let coroutine = args.as_coroutine();
548 Self::probe_and_consider_implied_clause(
549 ecx,
550 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
551 goal,
552 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
553 .upcast(cx),
554 [],
557 )
558 }
559
560 fn consider_builtin_discriminant_kind_candidate(
561 ecx: &mut EvalCtxt<'_, D>,
562 goal: Goal<I, Self>,
563 ) -> Result<Candidate<I>, NoSolution> {
564 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
565 return Err(NoSolution);
566 }
567
568 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
570 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
571 }
572
573 fn consider_builtin_async_destruct_candidate(
574 ecx: &mut EvalCtxt<'_, D>,
575 goal: Goal<I, Self>,
576 ) -> Result<Candidate<I>, NoSolution> {
577 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
578 return Err(NoSolution);
579 }
580
581 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
583 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
584 }
585
586 fn consider_builtin_destruct_candidate(
587 ecx: &mut EvalCtxt<'_, D>,
588 goal: Goal<I, Self>,
589 ) -> Result<Candidate<I>, NoSolution> {
590 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
591 return Err(NoSolution);
592 }
593
594 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
597 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
598 }
599
600 fn consider_builtin_transmute_candidate(
601 ecx: &mut EvalCtxt<'_, D>,
602 goal: Goal<I, Self>,
603 ) -> Result<Candidate<I>, NoSolution> {
604 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
605 return Err(NoSolution);
606 }
607
608 if goal.has_non_region_placeholders() {
610 return Err(NoSolution);
611 }
612
613 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
614 let assume = ecx.structurally_normalize_const(
615 goal.param_env,
616 goal.predicate.trait_ref.args.const_at(2),
617 )?;
618
619 let certainty = ecx.is_transmutable(
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 _ => vec![],
790 }
791 })
792 }
793}
794
795impl<D, I> EvalCtxt<'_, D>
796where
797 D: SolverDelegate<Interner = I>,
798 I: Interner,
799{
800 fn consider_builtin_dyn_upcast_candidates(
810 &mut self,
811 goal: Goal<I, (I::Ty, I::Ty)>,
812 a_data: I::BoundExistentialPredicates,
813 a_region: I::Region,
814 b_data: I::BoundExistentialPredicates,
815 b_region: I::Region,
816 ) -> Vec<Candidate<I>> {
817 let cx = self.cx();
818 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
819
820 let mut responses = vec![];
821 let b_principal_def_id = b_data.principal_def_id();
824 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
825 responses.extend(self.consider_builtin_upcast_to_principal(
826 goal,
827 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
828 a_data,
829 a_region,
830 b_data,
831 b_region,
832 a_data.principal(),
833 ));
834 } else if let Some(a_principal) = a_data.principal() {
835 for (idx, new_a_principal) in
836 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
837 .enumerate()
838 .skip(1)
839 {
840 responses.extend(self.consider_builtin_upcast_to_principal(
841 goal,
842 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
843 a_data,
844 a_region,
845 b_data,
846 b_region,
847 Some(new_a_principal.map_bound(|trait_ref| {
848 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
849 })),
850 ));
851 }
852 }
853
854 responses
855 }
856
857 fn consider_builtin_unsize_to_dyn_candidate(
858 &mut self,
859 goal: Goal<I, (I::Ty, I::Ty)>,
860 b_data: I::BoundExistentialPredicates,
861 b_region: I::Region,
862 ) -> Result<Candidate<I>, NoSolution> {
863 let cx = self.cx();
864 let Goal { predicate: (a_ty, _), .. } = goal;
865
866 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
868 return Err(NoSolution);
869 }
870
871 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
872 ecx.add_goals(
875 GoalSource::ImplWhereBound,
876 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
877 );
878
879 ecx.add_goal(
881 GoalSource::ImplWhereBound,
882 goal.with(
883 cx,
884 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]),
885 ),
886 );
887
888 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
890 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
891 })
892 }
893
894 fn consider_builtin_upcast_to_principal(
895 &mut self,
896 goal: Goal<I, (I::Ty, I::Ty)>,
897 source: CandidateSource<I>,
898 a_data: I::BoundExistentialPredicates,
899 a_region: I::Region,
900 b_data: I::BoundExistentialPredicates,
901 b_region: I::Region,
902 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
903 ) -> Result<Candidate<I>, NoSolution> {
904 let param_env = goal.param_env;
905
906 let a_auto_traits: IndexSet<I::DefId> = a_data
910 .auto_traits()
911 .into_iter()
912 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
913 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
914 .filter(|def_id| self.cx().trait_is_auto(*def_id))
915 }))
916 .collect();
917
918 let projection_may_match =
923 |ecx: &mut EvalCtxt<'_, D>,
924 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
925 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
926 source_projection.item_def_id() == target_projection.item_def_id()
927 && ecx
928 .probe(|_| ProbeKind::UpcastProjectionCompatibility)
929 .enter(|ecx| -> Result<_, NoSolution> {
930 ecx.enter_forall(target_projection, |ecx, target_projection| {
931 let source_projection =
932 ecx.instantiate_binder_with_infer(source_projection);
933 ecx.eq(param_env, source_projection, target_projection)?;
934 ecx.try_evaluate_added_goals()
935 })
936 })
937 .is_ok()
938 };
939
940 self.probe_trait_candidate(source).enter(|ecx| {
941 for bound in b_data.iter() {
942 match bound.skip_binder() {
943 ty::ExistentialPredicate::Trait(target_principal) => {
946 let source_principal = upcast_principal.unwrap();
947 let target_principal = bound.rebind(target_principal);
948 ecx.enter_forall(target_principal, |ecx, target_principal| {
949 let source_principal =
950 ecx.instantiate_binder_with_infer(source_principal);
951 ecx.eq(param_env, source_principal, target_principal)?;
952 ecx.try_evaluate_added_goals()
953 })?;
954 }
955 ty::ExistentialPredicate::Projection(target_projection) => {
961 let target_projection = bound.rebind(target_projection);
962 let mut matching_projections =
963 a_data.projection_bounds().into_iter().filter(|source_projection| {
964 projection_may_match(ecx, *source_projection, target_projection)
965 });
966 let Some(source_projection) = matching_projections.next() else {
967 return Err(NoSolution);
968 };
969 if matching_projections.next().is_some() {
970 return ecx.evaluate_added_goals_and_make_canonical_response(
971 Certainty::AMBIGUOUS,
972 );
973 }
974 ecx.enter_forall(target_projection, |ecx, target_projection| {
975 let source_projection =
976 ecx.instantiate_binder_with_infer(source_projection);
977 ecx.eq(param_env, source_projection, target_projection)?;
978 ecx.try_evaluate_added_goals()
979 })?;
980 }
981 ty::ExistentialPredicate::AutoTrait(def_id) => {
983 if !a_auto_traits.contains(&def_id) {
984 return Err(NoSolution);
985 }
986 }
987 }
988 }
989
990 ecx.add_goal(
992 GoalSource::ImplWhereBound,
993 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
994 );
995
996 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
997 })
998 }
999
1000 fn consider_builtin_array_unsize(
1009 &mut self,
1010 goal: Goal<I, (I::Ty, I::Ty)>,
1011 a_elem_ty: I::Ty,
1012 b_elem_ty: I::Ty,
1013 ) -> Result<Candidate<I>, NoSolution> {
1014 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1015 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1016 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1017 }
1018
1019 fn consider_builtin_struct_unsize(
1033 &mut self,
1034 goal: Goal<I, (I::Ty, I::Ty)>,
1035 def: I::AdtDef,
1036 a_args: I::GenericArgs,
1037 b_args: I::GenericArgs,
1038 ) -> Result<Candidate<I>, NoSolution> {
1039 let cx = self.cx();
1040 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1041
1042 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1043 if unsizing_params.is_empty() {
1046 return Err(NoSolution);
1047 }
1048
1049 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1050
1051 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1052 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1053
1054 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1058 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1059 }));
1060 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1061
1062 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1065 self.add_goal(
1066 GoalSource::ImplWhereBound,
1067 goal.with(
1068 cx,
1069 ty::TraitRef::new(
1070 cx,
1071 cx.require_lang_item(TraitSolverLangItem::Unsize),
1072 [a_tail_ty, b_tail_ty],
1073 ),
1074 ),
1075 );
1076 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1077 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1078 }
1079
1080 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1085 &mut self,
1086 goal: Goal<I, TraitPredicate<I>>,
1087 ) -> Option<Result<Candidate<I>, NoSolution>> {
1088 let self_ty = goal.predicate.self_ty();
1089 match self_ty.kind() {
1090 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1096 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1097 }
1098
1099 ty::Dynamic(..)
1102 | ty::Param(..)
1103 | ty::Foreign(..)
1104 | ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
1105 | ty::Placeholder(..) => Some(Err(NoSolution)),
1106
1107 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1108
1109 ty::Coroutine(def_id, _)
1113 if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
1114 {
1115 match self.cx().coroutine_movability(def_id) {
1116 Movability::Static => Some(Err(NoSolution)),
1117 Movability::Movable => Some(
1118 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1119 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1120 }),
1121 ),
1122 }
1123 }
1124
1125 ty::Alias(..) => None,
1130
1131 ty::Bool
1140 | ty::Char
1141 | ty::Int(_)
1142 | ty::Uint(_)
1143 | ty::Float(_)
1144 | ty::Str
1145 | ty::Array(_, _)
1146 | ty::Pat(_, _)
1147 | ty::Slice(_)
1148 | ty::RawPtr(_, _)
1149 | ty::Ref(_, _, _)
1150 | ty::FnDef(_, _)
1151 | ty::FnPtr(..)
1152 | ty::Closure(..)
1153 | ty::CoroutineClosure(..)
1154 | ty::Coroutine(_, _)
1155 | ty::CoroutineWitness(..)
1156 | ty::Never
1157 | ty::Tuple(_)
1158 | ty::Adt(_, _)
1159 | ty::UnsafeBinder(_) => {
1160 let mut disqualifying_impl = None;
1161 self.cx().for_each_relevant_impl(
1162 goal.predicate.def_id(),
1163 goal.predicate.self_ty(),
1164 |impl_def_id| {
1165 disqualifying_impl = Some(impl_def_id);
1166 },
1167 );
1168 if let Some(def_id) = disqualifying_impl {
1169 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1170 return Some(Err(NoSolution));
1173 } else {
1174 None
1175 }
1176 }
1177 ty::Error(_) => None,
1178 }
1179 }
1180
1181 fn probe_and_evaluate_goal_for_constituent_tys(
1186 &mut self,
1187 source: CandidateSource<I>,
1188 goal: Goal<I, TraitPredicate<I>>,
1189 constituent_tys: impl Fn(
1190 &EvalCtxt<'_, D>,
1191 I::Ty,
1192 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1193 ) -> Result<Candidate<I>, NoSolution> {
1194 self.probe_trait_candidate(source).enter(|ecx| {
1195 let goals =
1196 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1197 tys.into_iter()
1198 .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)))
1199 .collect::<Vec<_>>()
1200 });
1201 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1202 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1203 })
1204 }
1205}
1206
1207#[derive(Debug, Clone, Copy)]
1218pub(super) enum TraitGoalProvenVia {
1219 Misc,
1225 ParamEnv,
1226 AliasBound,
1227}
1228
1229impl<D, I> EvalCtxt<'_, D>
1230where
1231 D: SolverDelegate<Interner = I>,
1232 I: Interner,
1233{
1234 pub(super) fn merge_trait_candidates(
1235 &mut self,
1236 goal: Goal<I, TraitPredicate<I>>,
1237 candidates: Vec<Candidate<I>>,
1238 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1239 if let TypingMode::Coherence = self.typing_mode() {
1240 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1241 return if let Some(response) = self.try_merge_responses(&all_candidates) {
1242 Ok((response, Some(TraitGoalProvenVia::Misc)))
1243 } else {
1244 self.flounder(&all_candidates).map(|r| (r, None))
1245 };
1246 }
1247
1248 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1253 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1254 });
1255 if let Some(candidate) = trivial_builtin_impls.next() {
1256 assert!(trivial_builtin_impls.next().is_none());
1259 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1260 }
1261
1262 let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
1265 CandidateSource::ParamEnv(idx) => {
1266 let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
1267 let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
1268 unreachable!("expected trait-bound: {where_bound:?}");
1269 };
1270
1271 if trait_pred.has_bound_vars() || !trait_pred.is_global() {
1272 return true;
1273 }
1274
1275 for p in goal.param_env.caller_bounds().iter() {
1280 if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
1281 if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
1282 return true;
1283 }
1284 }
1285 }
1286
1287 false
1288 }
1289 _ => false,
1290 });
1291 if has_non_global_where_bounds {
1292 let where_bounds: Vec<_> = candidates
1293 .iter()
1294 .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1295 .map(|c| c.result)
1296 .collect();
1297
1298 return if let Some(response) = self.try_merge_responses(&where_bounds) {
1299 Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
1300 } else {
1301 Ok((self.bail_with_ambiguity(&where_bounds), None))
1302 };
1303 }
1304
1305 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1306 let alias_bounds: Vec<_> = candidates
1307 .iter()
1308 .filter(|c| matches!(c.source, CandidateSource::AliasBound))
1309 .map(|c| c.result)
1310 .collect();
1311 return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1312 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1313 } else {
1314 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1315 };
1316 }
1317
1318 let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1319 if let Some(response) = self.try_merge_responses(&all_candidates) {
1320 Ok((response, Some(TraitGoalProvenVia::Misc)))
1321 } else {
1322 self.flounder(&all_candidates).map(|r| (r, None))
1323 }
1324 }
1325
1326 #[instrument(level = "trace", skip(self))]
1327 pub(super) fn compute_trait_goal(
1328 &mut self,
1329 goal: Goal<I, TraitPredicate<I>>,
1330 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1331 let candidates = self.assemble_and_evaluate_candidates(goal);
1332 self.merge_trait_candidates(goal, candidates)
1333 }
1334}