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