1use std::{fmt::Debug, ops::ControlFlow};
7
8use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt};
9use rustc_type_ir::{
10 AliasRelationDirection, AliasTermKind, HostEffectPredicate, Interner, PredicatePolarity,
11 error::ExpectedFound,
12 inherent::{IntoKind, SliceLike, Span as _},
13 lang_items::SolverTraitLangItem,
14 solve::{Certainty, GoalSource, MaybeCause, NoSolution},
15};
16use tracing::{instrument, trace};
17
18use crate::next_solver::{
19 AliasTerm, Binder, ClauseKind, Const, ConstKind, DbInterner, PolyTraitPredicate, PredicateKind,
20 SolverContext, Span, Term, TraitPredicate, Ty, TyKind, TypeError,
21 fulfill::NextSolverError,
22 infer::{
23 InferCtxt,
24 select::SelectionError,
25 traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations},
26 },
27 inspect::{self, ProofTreeVisitor},
28 normalize::deeply_normalize_for_diagnostics,
29};
30
31#[derive(Debug)]
32pub struct FulfillmentError<'db> {
33 pub obligation: PredicateObligation<'db>,
34 pub code: FulfillmentErrorCode<'db>,
35 pub root_obligation: PredicateObligation<'db>,
39}
40
41impl<'db> FulfillmentError<'db> {
42 pub fn new(
43 obligation: PredicateObligation<'db>,
44 code: FulfillmentErrorCode<'db>,
45 root_obligation: PredicateObligation<'db>,
46 ) -> FulfillmentError<'db> {
47 FulfillmentError { obligation, code, root_obligation }
48 }
49
50 pub fn is_true_error(&self) -> bool {
51 match self.code {
52 FulfillmentErrorCode::Select(_)
53 | FulfillmentErrorCode::Project(_)
54 | FulfillmentErrorCode::Subtype(_, _)
55 | FulfillmentErrorCode::ConstEquate(_, _) => true,
56 FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
57 false
58 }
59 }
60 }
61}
62
63#[derive(Debug, Clone)]
64pub enum FulfillmentErrorCode<'db> {
65 Cycle(PredicateObligations<'db>),
68 Select(SelectionError<'db>),
69 Project(MismatchedProjectionTypes<'db>),
70 Subtype(ExpectedFound<Ty<'db>>, TypeError<'db>), ConstEquate(ExpectedFound<Const<'db>>, TypeError<'db>),
72 Ambiguity {
73 overflow: Option<bool>,
77 },
78}
79
80#[derive(Debug, Clone)]
81pub struct MismatchedProjectionTypes<'db> {
82 pub err: TypeError<'db>,
83}
84
85pub(super) fn fulfillment_error_for_no_solution<'db>(
86 infcx: &InferCtxt<'db>,
87 root_obligation: PredicateObligation<'db>,
88) -> FulfillmentError<'db> {
89 let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
90
91 let code = match obligation.predicate.kind().skip_binder() {
92 PredicateKind::Clause(ClauseKind::Projection(_)) => {
93 FulfillmentErrorCode::Project(
94 MismatchedProjectionTypes { err: TypeError::Mismatch },
96 )
97 }
98 PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, expected_ty)) => {
99 let ct_ty = match ct.kind() {
100 ConstKind::Unevaluated(uv) => {
101 infcx.interner.type_of(uv.def.into()).instantiate(infcx.interner, uv.args)
102 }
103 ConstKind::Param(param_ct) => param_ct.find_const_ty_from_env(obligation.param_env),
104 ConstKind::Value(cv) => cv.ty,
105 kind => panic!(
106 "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
107 ),
108 };
109 FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
110 ct,
111 ct_ty,
112 expected_ty,
113 })
114 }
115 PredicateKind::NormalizesTo(..) => {
116 FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
117 }
118 PredicateKind::AliasRelate(_, _, _) => {
119 FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
120 }
121 PredicateKind::Subtype(pred) => {
122 let (a, b) = infcx.enter_forall_and_leak_universe(
123 obligation.predicate.kind().rebind((pred.a, pred.b)),
124 );
125 let expected_found = ExpectedFound::new(a, b);
126 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
127 }
128 PredicateKind::Coerce(pred) => {
129 let (a, b) = infcx.enter_forall_and_leak_universe(
130 obligation.predicate.kind().rebind((pred.a, pred.b)),
131 );
132 let expected_found = ExpectedFound::new(b, a);
133 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
134 }
135 PredicateKind::Clause(_) | PredicateKind::DynCompatible(_) | PredicateKind::Ambiguous => {
136 FulfillmentErrorCode::Select(SelectionError::Unimplemented)
137 }
138 PredicateKind::ConstEquate(..) => {
139 panic!("unexpected goal: {obligation:?}")
140 }
141 };
142
143 FulfillmentError { obligation, code, root_obligation }
144}
145
146pub(super) fn fulfillment_error_for_stalled<'db>(
147 infcx: &InferCtxt<'db>,
148 root_obligation: PredicateObligation<'db>,
149) -> FulfillmentError<'db> {
150 let (code, refine_obligation) = infcx.probe(|_| {
151 match <&SolverContext<'db>>::from(infcx).evaluate_root_goal(
152 root_obligation.as_goal(),
153 Span::dummy(),
154 None,
155 ) {
156 Ok(GoalEvaluation {
157 certainty: Certainty::Maybe { cause: MaybeCause::Ambiguity, .. },
158 ..
159 }) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true),
160 Ok(GoalEvaluation {
161 certainty:
162 Certainty::Maybe {
163 cause:
164 MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
165 ..
166 },
167 ..
168 }) => (
169 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
170 false,
177 ),
178 Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => {
179 panic!(
180 "did not expect successful goal when collecting ambiguity errors for `{:?}`",
181 infcx.resolve_vars_if_possible(root_obligation.predicate),
182 )
183 }
184 Err(_) => {
185 panic!(
186 "did not expect selection error when collecting ambiguity errors for `{:?}`",
187 infcx.resolve_vars_if_possible(root_obligation.predicate),
188 )
189 }
190 }
191 });
192
193 FulfillmentError {
194 obligation: if refine_obligation {
195 find_best_leaf_obligation(infcx, &root_obligation, true)
196 } else {
197 root_obligation.clone()
198 },
199 code,
200 root_obligation,
201 }
202}
203
204pub(super) fn fulfillment_error_for_overflow<'db>(
205 infcx: &InferCtxt<'db>,
206 root_obligation: PredicateObligation<'db>,
207) -> FulfillmentError<'db> {
208 FulfillmentError {
209 obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
210 code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
211 root_obligation,
212 }
213}
214
215#[instrument(level = "debug", skip(infcx), ret)]
216fn find_best_leaf_obligation<'db>(
217 infcx: &InferCtxt<'db>,
218 obligation: &PredicateObligation<'db>,
219 consider_ambiguities: bool,
220) -> PredicateObligation<'db> {
221 let obligation = infcx.resolve_vars_if_possible(obligation.clone());
222 let obligation = infcx
228 .fudge_inference_if_ok(|| {
229 infcx
230 .visit_proof_tree(
231 obligation.as_goal(),
232 &mut BestObligation { obligation: obligation.clone(), consider_ambiguities },
233 )
234 .break_value()
235 .ok_or(())
236 })
237 .unwrap_or(obligation);
238 deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
239}
240
241struct BestObligation<'db> {
242 obligation: PredicateObligation<'db>,
243 consider_ambiguities: bool,
244}
245
246impl<'db> BestObligation<'db> {
247 fn with_derived_obligation(
248 &mut self,
249 derived_obligation: PredicateObligation<'db>,
250 and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'db>>::Result,
251 ) -> <Self as ProofTreeVisitor<'db>>::Result {
252 let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
253 let res = and_then(self);
254 self.obligation = old_obligation;
255 res
256 }
257
258 fn non_trivial_candidates<'a>(
263 &self,
264 goal: &'a inspect::InspectGoal<'a, 'db>,
265 ) -> Vec<inspect::InspectCandidate<'a, 'db>> {
266 let mut candidates = goal.candidates();
267 match self.consider_ambiguities {
268 true => {
269 candidates.retain(|candidate| candidate.result().is_ok());
273 }
274 false => {
275 candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
278 if candidates.len() > 1 {
282 candidates.retain(|candidate| {
283 goal.infcx().probe(|_| {
284 candidate.instantiate_nested_goals().iter().any(|nested_goal| {
285 matches!(
286 nested_goal.source(),
287 GoalSource::ImplWhereBound
288 | GoalSource::AliasBoundConstCondition
289 | GoalSource::AliasWellFormed
290 ) && nested_goal.result().is_err()
291 })
292 })
293 });
294 }
295 }
296 }
297
298 candidates
299 }
300
301 fn visit_well_formed_goal(
305 &mut self,
306 candidate: &inspect::InspectCandidate<'_, 'db>,
307 term: Term<'db>,
308 ) -> ControlFlow<PredicateObligation<'db>> {
309 let infcx = candidate.goal().infcx();
310 let param_env = candidate.goal().goal().param_env;
311
312 for obligation in wf::unnormalized_obligations(infcx, param_env, term).into_iter().flatten()
313 {
314 let nested_goal = candidate
315 .instantiate_proof_tree_for_nested_goal(GoalSource::Misc, obligation.as_goal());
316 match (self.consider_ambiguities, nested_goal.result()) {
318 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. }))
319 | (false, Err(_)) => {}
320 _ => continue,
321 }
322
323 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
324 }
325
326 ControlFlow::Break(self.obligation.clone())
327 }
328
329 fn detect_error_in_self_ty_normalization(
333 &mut self,
334 goal: &inspect::InspectGoal<'_, 'db>,
335 self_ty: Ty<'db>,
336 ) -> ControlFlow<PredicateObligation<'db>> {
337 assert!(!self.consider_ambiguities);
338 let interner = goal.infcx().interner;
339 if let TyKind::Alias(..) = self_ty.kind() {
340 let infer_term = goal.infcx().next_ty_var();
341 let pred = PredicateKind::AliasRelate(
342 self_ty.into(),
343 infer_term.into(),
344 AliasRelationDirection::Equate,
345 );
346 let obligation = Obligation::new(
347 interner,
348 self.obligation.cause.clone(),
349 goal.goal().param_env,
350 pred,
351 );
352 self.with_derived_obligation(obligation, |this| {
353 goal.infcx().visit_proof_tree_at_depth(
354 goal.goal().with(interner, pred),
355 goal.depth() + 1,
356 this,
357 )
358 })
359 } else {
360 ControlFlow::Continue(())
361 }
362 }
363
364 fn detect_trait_error_in_higher_ranked_projection(
372 &mut self,
373 goal: &inspect::InspectGoal<'_, 'db>,
374 ) -> ControlFlow<PredicateObligation<'db>> {
375 let interner = goal.infcx().interner;
376 if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
377 && !projection_clause.bound_vars().is_empty()
378 {
379 let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(interner));
380 let obligation = Obligation::new(
381 interner,
382 self.obligation.cause.clone(),
383 goal.goal().param_env,
384 deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
385 );
386 self.with_derived_obligation(obligation, |this| {
387 goal.infcx().visit_proof_tree_at_depth(
388 goal.goal().with(interner, pred),
389 goal.depth() + 1,
390 this,
391 )
392 })
393 } else {
394 ControlFlow::Continue(())
395 }
396 }
397
398 fn detect_non_well_formed_assoc_item(
405 &mut self,
406 goal: &inspect::InspectGoal<'_, 'db>,
407 alias: AliasTerm<'db>,
408 ) -> ControlFlow<PredicateObligation<'db>> {
409 let interner = goal.infcx().interner;
410 let obligation = Obligation::new(
411 interner,
412 self.obligation.cause.clone(),
413 goal.goal().param_env,
414 alias.trait_ref(interner),
415 );
416 self.with_derived_obligation(obligation, |this| {
417 goal.infcx().visit_proof_tree_at_depth(
418 goal.goal().with(interner, alias.trait_ref(interner)),
419 goal.depth() + 1,
420 this,
421 )
422 })
423 }
424
425 fn detect_error_from_empty_candidates(
428 &mut self,
429 goal: &inspect::InspectGoal<'_, 'db>,
430 ) -> ControlFlow<PredicateObligation<'db>> {
431 let interner = goal.infcx().interner;
432 let pred_kind = goal.goal().predicate.kind();
433
434 match pred_kind.no_bound_vars() {
435 Some(PredicateKind::Clause(ClauseKind::Trait(pred))) => {
436 self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
437 }
438 Some(PredicateKind::NormalizesTo(pred)) => {
439 if let AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst =
440 pred.alias.kind(interner)
441 {
442 self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
443 self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
444 }
445 }
446 Some(_) | None => {}
447 }
448
449 ControlFlow::Break(self.obligation.clone())
450 }
451}
452
453impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> {
454 type Result = ControlFlow<PredicateObligation<'db>>;
455
456 #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
457 fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'db>) -> Self::Result {
458 let interner = goal.infcx().interner;
459 match (self.consider_ambiguities, goal.result()) {
461 (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. })) | (false, Err(_)) => {
462 }
463 _ => return ControlFlow::Continue(()),
464 }
465
466 let pred = goal.goal().predicate;
467
468 let candidates = self.non_trivial_candidates(goal);
469 let candidate = match candidates.as_slice() {
470 [candidate] => candidate,
471 [] => return self.detect_error_from_empty_candidates(goal),
472 _ => return ControlFlow::Break(self.obligation.clone()),
473 };
474
475 let child_mode = match pred.kind().skip_binder() {
489 PredicateKind::Clause(ClauseKind::Trait(trait_pred)) => {
490 ChildMode::Trait(pred.kind().rebind(trait_pred))
491 }
492 PredicateKind::Clause(ClauseKind::HostEffect(host_pred)) => {
493 ChildMode::Host(pred.kind().rebind(host_pred))
494 }
495 PredicateKind::NormalizesTo(normalizes_to)
496 if matches!(
497 normalizes_to.alias.kind(interner),
498 AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
499 ) =>
500 {
501 ChildMode::Trait(pred.kind().rebind(TraitPredicate {
502 trait_ref: normalizes_to.alias.trait_ref(interner),
503 polarity: PredicatePolarity::Positive,
504 }))
505 }
506 PredicateKind::Clause(ClauseKind::WellFormed(term)) => {
507 return self.visit_well_formed_goal(candidate, term);
508 }
509 _ => ChildMode::PassThrough,
510 };
511
512 let nested_goals = candidate.instantiate_nested_goals();
513
514 for nested_goal in &nested_goals {
522 if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
523 && interner
524 .is_trait_lang_item(poly_trait_pred.def_id(), SolverTraitLangItem::FnPtrTrait)
525 && let Err(NoSolution) = nested_goal.result()
526 {
527 return ControlFlow::Break(self.obligation.clone());
528 }
529 }
530
531 for nested_goal in nested_goals {
532 trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
533
534 let nested_pred = nested_goal.goal().predicate;
535
536 let make_obligation = || Obligation {
537 cause: ObligationCause::dummy(),
538 param_env: nested_goal.goal().param_env,
539 predicate: nested_pred,
540 recursion_depth: self.obligation.recursion_depth + 1,
541 };
542
543 let obligation = match (child_mode, nested_goal.source()) {
544 (
545 ChildMode::Trait(_) | ChildMode::Host(_),
546 GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
547 ) => {
548 continue;
549 }
550 (ChildMode::Trait(_parent_trait_pred), GoalSource::ImplWhereBound) => {
551 make_obligation()
552 }
553 (
554 ChildMode::Host(_parent_host_pred),
555 GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
556 ) => make_obligation(),
557 (ChildMode::PassThrough, _)
558 | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
559 make_obligation()
560 }
561 };
562
563 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
564 }
565
566 if let Some(PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() {
569 goal.infcx().visit_proof_tree_at_depth(
570 goal.goal().with(interner, ClauseKind::WellFormed(lhs)),
571 goal.depth() + 1,
572 self,
573 )?;
574 goal.infcx().visit_proof_tree_at_depth(
575 goal.goal().with(interner, ClauseKind::WellFormed(rhs)),
576 goal.depth() + 1,
577 self,
578 )?;
579 }
580
581 self.detect_trait_error_in_higher_ranked_projection(goal)?;
582
583 ControlFlow::Break(self.obligation.clone())
584 }
585}
586
587#[derive(Debug, Copy, Clone)]
588enum ChildMode<'db> {
589 Trait(PolyTraitPredicate<'db>),
593 Host(Binder<'db, HostEffectPredicate<DbInterner<'db>>>),
597 PassThrough,
601}
602
603impl<'db> NextSolverError<'db> {
604 pub fn to_debuggable_error(&self, infcx: &InferCtxt<'db>) -> FulfillmentError<'db> {
605 match self {
606 NextSolverError::TrueError(obligation) => {
607 fulfillment_error_for_no_solution(infcx, obligation.clone())
608 }
609 NextSolverError::Ambiguity(obligation) => {
610 fulfillment_error_for_stalled(infcx, obligation.clone())
611 }
612 NextSolverError::Overflow(obligation) => {
613 fulfillment_error_for_overflow(infcx, obligation.clone())
614 }
615 }
616 }
617}
618
619mod wf {
620 use hir_def::{GeneralConstId, ItemContainerId};
621 use rustc_type_ir::inherent::{
622 AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _,
623 Ty as _,
624 };
625 use rustc_type_ir::lang_items::SolverTraitLangItem;
626 use rustc_type_ir::{
627 Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
628 };
629 use tracing::{debug, instrument};
630
631 use crate::next_solver::infer::InferCtxt;
632 use crate::next_solver::infer::traits::{Obligation, ObligationCause, PredicateObligations};
633 use crate::next_solver::{
634 Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, GenericArgs,
635 ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind,
636 };
637
638 pub(crate) fn unnormalized_obligations<'db>(
643 infcx: &InferCtxt<'db>,
644 param_env: ParamEnv<'db>,
645 term: Term<'db>,
646 ) -> Option<PredicateObligations<'db>> {
647 debug_assert_eq!(term, infcx.resolve_vars_if_possible(term));
648
649 if term.is_infer() {
653 return None;
654 }
655
656 let mut wf =
657 WfPredicates { infcx, param_env, out: PredicateObligations::new(), recursion_depth: 0 };
658 wf.add_wf_preds_for_term(term);
659 Some(wf.out)
660 }
661
662 struct WfPredicates<'a, 'db> {
663 infcx: &'a InferCtxt<'db>,
664 param_env: ParamEnv<'db>,
665 out: PredicateObligations<'db>,
666 recursion_depth: usize,
667 }
668
669 impl<'a, 'db> WfPredicates<'a, 'db> {
670 fn interner(&self) -> DbInterner<'db> {
671 self.infcx.interner
672 }
673
674 fn require_sized(&mut self, subty: Ty<'db>) {
675 if !subty.has_escaping_bound_vars() {
676 let cause = ObligationCause::new();
677 let trait_ref = TraitRef::new(
678 self.interner(),
679 self.interner().require_trait_lang_item(SolverTraitLangItem::Sized),
680 [subty],
681 );
682 self.out.push(Obligation::with_depth(
683 self.interner(),
684 cause,
685 self.recursion_depth,
686 self.param_env,
687 Binder::dummy(trait_ref),
688 ));
689 }
690 }
691
692 #[instrument(level = "debug", skip(self))]
694 fn add_wf_preds_for_term(&mut self, term: Term<'db>) {
695 term.visit_with(self);
696 debug!(?self.out);
697 }
698
699 #[instrument(level = "debug", skip(self))]
700 fn nominal_obligations(
701 &mut self,
702 def_id: SolverDefId,
703 args: GenericArgs<'db>,
704 ) -> PredicateObligations<'db> {
705 if let SolverDefId::TraitId(def_id) = def_id
710 && self.interner().is_trait_lang_item(def_id.into(), SolverTraitLangItem::Sized)
711 {
712 return Default::default();
713 }
714
715 self.interner()
716 .predicates_of(def_id)
717 .iter_instantiated(self.interner(), args)
718 .map(|pred| {
719 let cause = ObligationCause::new();
720 Obligation::with_depth(
721 self.interner(),
722 cause,
723 self.recursion_depth,
724 self.param_env,
725 pred,
726 )
727 })
728 .filter(|pred| !pred.has_escaping_bound_vars())
729 .collect()
730 }
731
732 fn add_wf_preds_for_dyn_ty(
733 &mut self,
734 _ty: Ty<'db>,
735 data: &[Binder<'db, ExistentialPredicate<'db>>],
736 region: Region<'db>,
737 ) {
738 if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
770 let implicit_bounds = object_region_bounds(self.interner(), data);
771
772 let explicit_bound = region;
773
774 self.out.reserve(implicit_bounds.len());
775 for implicit_bound in implicit_bounds {
776 let cause = ObligationCause::new();
777 let outlives = Binder::dummy(rustc_type_ir::OutlivesPredicate(
778 explicit_bound,
779 implicit_bound,
780 ));
781 self.out.push(Obligation::with_depth(
782 self.interner(),
783 cause,
784 self.recursion_depth,
785 self.param_env,
786 outlives,
787 ));
788 }
789
790 }
797 }
798 }
799
800 impl<'a, 'db> TypeVisitor<DbInterner<'db>> for WfPredicates<'a, 'db> {
801 type Result = ();
802
803 fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
804 debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
805
806 let tcx = self.interner();
807
808 match t.kind() {
809 TyKind::Bool
810 | TyKind::Char
811 | TyKind::Int(..)
812 | TyKind::Uint(..)
813 | TyKind::Float(..)
814 | TyKind::Error(_)
815 | TyKind::Str
816 | TyKind::CoroutineWitness(..)
817 | TyKind::Never
818 | TyKind::Param(_)
819 | TyKind::Bound(..)
820 | TyKind::Placeholder(..)
821 | TyKind::Foreign(..) => {
822 }
824
825 TyKind::Infer(rustc_type_ir::IntVar(_)) => {}
827
828 TyKind::Infer(rustc_type_ir::FloatVar(_)) => {}
830
831 TyKind::Slice(subty) => {
832 self.require_sized(subty);
833 }
834
835 TyKind::Array(subty, len) => {
836 self.require_sized(subty);
837 let cause = ObligationCause::new();
840 self.out.push(Obligation::with_depth(
841 tcx,
842 cause,
843 self.recursion_depth,
844 self.param_env,
845 Binder::dummy(PredicateKind::Clause(ClauseKind::ConstArgHasType(
846 len,
847 Ty::new_unit(self.interner()),
848 ))),
849 ));
850 }
851
852 TyKind::Pat(base_ty, _pat) => {
853 self.require_sized(base_ty);
854 }
855
856 TyKind::Tuple(tys) => {
857 if let Some((_last, rest)) = tys.split_last() {
858 for &elem in rest {
859 self.require_sized(elem);
860 }
861 }
862 }
863
864 TyKind::RawPtr(_, _) => {
865 }
867
868 TyKind::Alias(
869 rustc_type_ir::Projection | rustc_type_ir::Opaque | rustc_type_ir::Free,
870 data,
871 ) => {
872 let obligations = self.nominal_obligations(data.def_id, data.args);
873 self.out.extend(obligations);
874 }
875 TyKind::Alias(rustc_type_ir::Inherent, _data) => {
876 return;
877 }
878
879 TyKind::Adt(def, args) => {
880 let obligations = self.nominal_obligations(def.def_id().0.into(), args);
882 self.out.extend(obligations);
883 }
884
885 TyKind::FnDef(did, args) => {
886 let fn_sig = tcx.fn_sig(did).instantiate(tcx, args);
892 fn_sig.output().skip_binder().visit_with(self);
893
894 let did = match did.0 {
895 hir_def::CallableDefId::FunctionId(id) => id.into(),
896 hir_def::CallableDefId::StructId(id) => SolverDefId::Ctor(Ctor::Struct(id)),
897 hir_def::CallableDefId::EnumVariantId(id) => {
898 SolverDefId::Ctor(Ctor::Enum(id))
899 }
900 };
901 let obligations = self.nominal_obligations(did, args);
902 self.out.extend(obligations);
903 }
904
905 TyKind::Ref(r, rty, _) => {
906 if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
908 let cause = ObligationCause::new();
909 self.out.push(Obligation::with_depth(
910 tcx,
911 cause,
912 self.recursion_depth,
913 self.param_env,
914 Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(
915 rustc_type_ir::OutlivesPredicate(rty, r),
916 ))),
917 ));
918 }
919 }
920
921 TyKind::Coroutine(did, args, ..) => {
922 let obligations = self.nominal_obligations(did.0.into(), args);
930 self.out.extend(obligations);
931 }
932
933 TyKind::Closure(did, args) => {
934 let obligations = self.nominal_obligations(did.0.into(), args);
950 self.out.extend(obligations);
951 let upvars = args.as_closure().tupled_upvars_ty();
972 return upvars.visit_with(self);
973 }
974
975 TyKind::CoroutineClosure(did, args) => {
976 let obligations = self.nominal_obligations(did.0.into(), args);
978 self.out.extend(obligations);
979 let upvars = args.as_coroutine_closure().tupled_upvars_ty();
980 return upvars.visit_with(self);
981 }
982
983 TyKind::FnPtr(..) => {
984 }
987 TyKind::UnsafeBinder(_ty) => {}
988
989 TyKind::Dynamic(data, r) => {
990 self.add_wf_preds_for_dyn_ty(t, data.as_slice(), r);
995
996 if let Some(principal) = data.principal_def_id() {
1000 self.out.push(Obligation::with_depth(
1001 tcx,
1002 ObligationCause::new(),
1003 self.recursion_depth,
1004 self.param_env,
1005 Binder::dummy(PredicateKind::DynCompatible(principal)),
1006 ));
1007 }
1008 }
1009
1010 TyKind::Infer(_) => {
1023 let cause = ObligationCause::new();
1024 self.out.push(Obligation::with_depth(
1025 tcx,
1026 cause,
1027 self.recursion_depth,
1028 self.param_env,
1029 Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(t.into()))),
1030 ));
1031 }
1032 }
1033
1034 t.super_visit_with(self)
1035 }
1036
1037 fn visit_const(&mut self, c: Const<'db>) -> Self::Result {
1038 let tcx = self.interner();
1039
1040 match c.kind() {
1041 ConstKind::Unevaluated(uv) => {
1042 if !c.has_escaping_bound_vars() {
1043 let predicate =
1044 Binder::dummy(PredicateKind::Clause(ClauseKind::ConstEvaluatable(c)));
1045 let cause = ObligationCause::new();
1046 self.out.push(Obligation::with_depth(
1047 tcx,
1048 cause,
1049 self.recursion_depth,
1050 self.param_env,
1051 predicate,
1052 ));
1053
1054 if let GeneralConstId::ConstId(uv_def) = uv.def.0
1055 && let ItemContainerId::ImplId(impl_) =
1056 uv_def.loc(self.interner().db).container
1057 && self.interner().db.impl_signature(impl_).target_trait.is_none()
1058 {
1059 return; } else {
1061 let obligations = self.nominal_obligations(uv.def.into(), uv.args);
1062 self.out.extend(obligations);
1063 }
1064 }
1065 }
1066 ConstKind::Infer(_) => {
1067 let cause = ObligationCause::new();
1068
1069 self.out.push(Obligation::with_depth(
1070 tcx,
1071 cause,
1072 self.recursion_depth,
1073 self.param_env,
1074 Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(c.into()))),
1075 ));
1076 }
1077 ConstKind::Expr(_) => {
1078 let predicate =
1086 Binder::dummy(PredicateKind::Clause(ClauseKind::ConstEvaluatable(c)));
1087 let cause = ObligationCause::new();
1088 self.out.push(Obligation::with_depth(
1089 tcx,
1090 cause,
1091 self.recursion_depth,
1092 self.param_env,
1093 predicate,
1094 ));
1095 }
1096
1097 ConstKind::Error(_)
1098 | ConstKind::Param(_)
1099 | ConstKind::Bound(..)
1100 | ConstKind::Placeholder(..) => {
1101 }
1103 ConstKind::Value(..) => {
1104 }
1106 }
1107
1108 c.super_visit_with(self)
1109 }
1110
1111 fn visit_predicate(&mut self, _p: Predicate<'db>) -> Self::Result {
1112 panic!("predicate should not be checked for well-formedness");
1113 }
1114 }
1115
1116 pub(crate) fn object_region_bounds<'db>(
1131 interner: DbInterner<'db>,
1132 existential_predicates: &[Binder<'db, ExistentialPredicate<'db>>],
1133 ) -> Vec<Region<'db>> {
1134 let erased_self_ty = Ty::new_unit(interner);
1135
1136 let predicates = existential_predicates
1137 .iter()
1138 .map(|predicate| predicate.with_self_ty(interner, erased_self_ty));
1139
1140 rustc_type_ir::elaborate::elaborate(interner, predicates)
1141 .filter_map(|pred| {
1142 debug!(?pred);
1143 match pred.kind().skip_binder() {
1144 ClauseKind::TypeOutlives(rustc_type_ir::OutlivesPredicate(ref t, ref r)) => {
1145 if t == &erased_self_ty && !r.has_escaping_bound_vars() {
1155 Some(*r)
1156 } else {
1157 None
1158 }
1159 }
1160 ClauseKind::Trait(_)
1161 | ClauseKind::HostEffect(..)
1162 | ClauseKind::RegionOutlives(_)
1163 | ClauseKind::Projection(_)
1164 | ClauseKind::ConstArgHasType(_, _)
1165 | ClauseKind::WellFormed(_)
1166 | ClauseKind::UnstableFeature(_)
1167 | ClauseKind::ConstEvaluatable(_) => None,
1168 }
1169 })
1170 .collect()
1171 }
1172}