rustc_hir_typeck/fn_ctxt/
inspect_obligations.rs1use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
4use rustc_middle::traits::solve::GoalSource;
5use rustc_middle::ty::{self, Ty, TypeVisitableExt};
6use rustc_span::Span;
7use rustc_trait_selection::solve::inspect::{
8 InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
9};
10use tracing::{debug, instrument, trace};
11
12use crate::FnCtxt;
13
14impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15 #[instrument(skip(self), level = "debug")]
18 pub(crate) fn obligations_for_self_ty(&self, self_ty: ty::TyVid) -> PredicateObligations<'tcx> {
19 if self.next_trait_solver() {
20 self.obligations_for_self_ty_next(self_ty)
21 } else {
22 let ty_var_root = self.root_var(self_ty);
23 let mut obligations = self.fulfillment_cx.borrow().pending_obligations();
24 trace!("pending_obligations = {:#?}", obligations);
25 obligations
26 .retain(|obligation| self.predicate_has_self_ty(obligation.predicate, ty_var_root));
27 obligations
28 }
29 }
30
31 #[instrument(level = "debug", skip(self), ret)]
32 fn predicate_has_self_ty(
33 &self,
34 predicate: ty::Predicate<'tcx>,
35 expected_vid: ty::TyVid,
36 ) -> bool {
37 match predicate.kind().skip_binder() {
38 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
39 self.type_matches_expected_vid(expected_vid, data.self_ty())
40 }
41 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
42 self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
43 }
44 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
45 | ty::PredicateKind::Subtype(..)
46 | ty::PredicateKind::Coerce(..)
47 | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
48 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
49 | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
50 | ty::PredicateKind::DynCompatible(..)
51 | ty::PredicateKind::NormalizesTo(..)
52 | ty::PredicateKind::AliasRelate(..)
53 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
54 | ty::PredicateKind::ConstEquate(..)
55 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
56 | ty::PredicateKind::Ambiguous => false,
57 }
58 }
59
60 #[instrument(level = "debug", skip(self), ret)]
61 fn type_matches_expected_vid(&self, expected_vid: ty::TyVid, ty: Ty<'tcx>) -> bool {
62 let ty = self.shallow_resolve(ty);
63 debug!(?ty);
64
65 match *ty.kind() {
66 ty::Infer(ty::TyVar(found_vid)) => {
67 self.root_var(expected_vid) == self.root_var(found_vid)
68 }
69 _ => false,
70 }
71 }
72
73 pub(crate) fn obligations_for_self_ty_next(
74 &self,
75 self_ty: ty::TyVid,
76 ) -> PredicateObligations<'tcx> {
77 let obligations = self.fulfillment_cx.borrow().pending_obligations();
78 debug!(?obligations);
79 let mut obligations_for_self_ty = PredicateObligations::new();
80 for obligation in obligations {
81 let mut visitor = NestedObligationsForSelfTy {
82 fcx: self,
83 self_ty,
84 obligations_for_self_ty: &mut obligations_for_self_ty,
85 root_cause: &obligation.cause,
86 };
87
88 let goal = obligation.as_goal();
89 self.visit_proof_tree(goal, &mut visitor);
90 }
91
92 obligations_for_self_ty.retain_mut(|obligation| {
93 obligation.predicate = self.resolve_vars_if_possible(obligation.predicate);
94 !obligation.predicate.has_placeholders()
95 });
96 obligations_for_self_ty
97 }
98}
99
100struct NestedObligationsForSelfTy<'a, 'tcx> {
101 fcx: &'a FnCtxt<'a, 'tcx>,
102 self_ty: ty::TyVid,
103 root_cause: &'a ObligationCause<'tcx>,
104 obligations_for_self_ty: &'a mut PredicateObligations<'tcx>,
105}
106
107impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
108 fn span(&self) -> Span {
109 self.root_cause.span
110 }
111
112 fn config(&self) -> InspectConfig {
113 InspectConfig { max_depth: 5 }
117 }
118
119 fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
120 let tcx = self.fcx.tcx;
121 let goal = inspect_goal.goal();
122 if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty)
123 && !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked)
136 {
137 self.obligations_for_self_ty.push(traits::Obligation::new(
138 tcx,
139 self.root_cause.clone(),
140 goal.param_env,
141 goal.predicate,
142 ));
143 }
144
145 if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
150 candidate.visit_nested_no_probe(self)
151 }
152 }
153}