Skip to main content

rustc_hir_typeck/fn_ctxt/
inspect_obligations.rs

1//! A utility module to inspect currently ambiguous obligations in the current context.
2
3use rustc_data_structures::unord::UnordSet;
4use rustc_hir::def_id::DefId;
5use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
6use rustc_middle::ty::{self, Ty, TypeVisitableExt};
7use rustc_span::Span;
8use rustc_trait_selection::solve::Certainty;
9use rustc_trait_selection::solve::inspect::{
10    InferCtxtProofTreeExt, InspectConfig, InspectGoal, ProofTreeVisitor,
11};
12use tracing::{debug, instrument, trace};
13
14use crate::FnCtxt;
15
16impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17    /// Returns a list of all obligations whose self type has been unified
18    /// with the unconstrained type `self_ty`.
19    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("obligations_for_self_ty",
                                    "rustc_hir_typeck::fn_ctxt::inspect_obligations",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"),
                                    ::tracing_core::__macro_support::Option::Some(19u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::inspect_obligations"),
                                    ::tracing_core::field::FieldSet::new(&["self_ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self_ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: PredicateObligations<'tcx> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            if self.next_trait_solver() {
                self.obligations_for_self_ty_next(self_ty)
            } else {
                let ty_var_root = self.root_var(self_ty);
                let mut obligations =
                    self.fulfillment_cx.borrow().pending_obligations();
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs:26",
                                        "rustc_hir_typeck::fn_ctxt::inspect_obligations",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"),
                                        ::tracing_core::__macro_support::Option::Some(26u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::inspect_obligations"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("pending_obligations = {0:#?}",
                                                                    obligations) as &dyn Value))])
                            });
                    } else { ; }
                };
                obligations.retain(|obligation|
                        self.predicate_has_self_ty(obligation.predicate,
                            ty_var_root));
                obligations
            }
        }
    }
}#[instrument(skip(self), level = "debug")]
20    pub(crate) fn obligations_for_self_ty(&self, self_ty: ty::TyVid) -> PredicateObligations<'tcx> {
21        if self.next_trait_solver() {
22            self.obligations_for_self_ty_next(self_ty)
23        } else {
24            let ty_var_root = self.root_var(self_ty);
25            let mut obligations = self.fulfillment_cx.borrow().pending_obligations();
26            trace!("pending_obligations = {:#?}", obligations);
27            obligations
28                .retain(|obligation| self.predicate_has_self_ty(obligation.predicate, ty_var_root));
29            obligations
30        }
31    }
32
33    x;#[instrument(level = "debug", skip(self), ret)]
34    fn predicate_has_self_ty(
35        &self,
36        predicate: ty::Predicate<'tcx>,
37        expected_vid: ty::TyVid,
38    ) -> bool {
39        match predicate.kind().skip_binder() {
40            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
41                self.type_matches_expected_vid(expected_vid, data.self_ty())
42            }
43            ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
44                self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
45            }
46            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
47            | ty::PredicateKind::Subtype(..)
48            | ty::PredicateKind::Coerce(..)
49            | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
50            | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
51            | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
52            | ty::PredicateKind::DynCompatible(..)
53            | ty::PredicateKind::NormalizesTo(..)
54            | ty::PredicateKind::AliasRelate(..)
55            | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
56            | ty::PredicateKind::ConstEquate(..)
57            | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
58            | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
59            | ty::PredicateKind::Ambiguous => false,
60        }
61    }
62
63    x;#[instrument(level = "debug", skip(self), ret)]
64    fn type_matches_expected_vid(&self, expected_vid: ty::TyVid, ty: Ty<'tcx>) -> bool {
65        let ty = self.shallow_resolve(ty);
66        debug!(?ty);
67
68        match *ty.kind() {
69            ty::Infer(ty::TyVar(found_vid)) => {
70                self.root_var(expected_vid) == self.root_var(found_vid)
71            }
72            _ => false,
73        }
74    }
75
76    pub(crate) fn obligations_for_self_ty_next(
77        &self,
78        self_ty: ty::TyVid,
79    ) -> PredicateObligations<'tcx> {
80        let obligations = self.fulfillment_cx.borrow().pending_obligations();
81        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs:81",
                        "rustc_hir_typeck::fn_ctxt::inspect_obligations",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"),
                        ::tracing_core::__macro_support::Option::Some(81u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::inspect_obligations"),
                        ::tracing_core::field::FieldSet::new(&["obligations"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&obligations)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?obligations);
82        let mut obligations_for_self_ty = PredicateObligations::new();
83        for obligation in obligations {
84            let mut visitor = NestedObligationsForSelfTy {
85                fcx: self,
86                self_ty,
87                obligations_for_self_ty: &mut obligations_for_self_ty,
88                root_cause: &obligation.cause,
89            };
90
91            let goal = obligation.as_goal();
92            self.visit_proof_tree(goal, &mut visitor);
93        }
94
95        obligations_for_self_ty.retain_mut(|obligation| {
96            obligation.predicate = self.resolve_vars_if_possible(obligation.predicate);
97            !obligation.predicate.has_placeholders()
98        });
99        obligations_for_self_ty
100    }
101
102    /// Only needed for the `From<{float}>` for `f32` type fallback.
103    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("from_float_for_f32_root_vids",
                                    "rustc_hir_typeck::fn_ctxt::inspect_obligations",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"),
                                    ::tracing_core::__macro_support::Option::Some(103u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::inspect_obligations"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: UnordSet<ty::FloatVid> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if self.next_trait_solver() {
                self.from_float_for_f32_root_vids_next()
            } else {
                let Some(from_trait) =
                    self.tcx.lang_items().from_trait() else {
                        return UnordSet::new();
                    };
                self.fulfillment_cx.borrow_mut().pending_obligations().into_iter().filter_map(|obligation|
                            {
                                self.predicate_from_float_for_f32_root_vid(from_trait,
                                    obligation.predicate)
                            }).collect()
            }
        }
    }
}#[instrument(skip(self), level = "debug")]
104    pub(crate) fn from_float_for_f32_root_vids(&self) -> UnordSet<ty::FloatVid> {
105        if self.next_trait_solver() {
106            self.from_float_for_f32_root_vids_next()
107        } else {
108            let Some(from_trait) = self.tcx.lang_items().from_trait() else {
109                return UnordSet::new();
110            };
111            self.fulfillment_cx
112                .borrow_mut()
113                .pending_obligations()
114                .into_iter()
115                .filter_map(|obligation| {
116                    self.predicate_from_float_for_f32_root_vid(from_trait, obligation.predicate)
117                })
118                .collect()
119        }
120    }
121
122    fn predicate_from_float_for_f32_root_vid(
123        &self,
124        from_trait: DefId,
125        predicate: ty::Predicate<'tcx>,
126    ) -> Option<ty::FloatVid> {
127        // The predicates we are looking for look like
128        // `TraitPredicate(<f32 as std::convert::From<{float}>>, polarity:Positive)`.
129        // They will have no bound variables.
130        match predicate.kind().no_bound_vars() {
131            Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
132                polarity: ty::PredicatePolarity::Positive,
133                trait_ref,
134            }))) if trait_ref.def_id == from_trait
135                && self.shallow_resolve(trait_ref.self_ty()).kind()
136                    == &ty::Float(ty::FloatTy::F32) =>
137            {
138                self.root_float_vid(trait_ref.args.type_at(1))
139            }
140            _ => None,
141        }
142    }
143
144    fn from_float_for_f32_root_vids_next(&self) -> UnordSet<ty::FloatVid> {
145        let Some(from_trait) = self.tcx.lang_items().from_trait() else {
146            return UnordSet::new();
147        };
148        let obligations = self.fulfillment_cx.borrow().pending_obligations();
149        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs:149",
                        "rustc_hir_typeck::fn_ctxt::inspect_obligations",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"),
                        ::tracing_core::__macro_support::Option::Some(149u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::inspect_obligations"),
                        ::tracing_core::field::FieldSet::new(&["obligations"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&obligations)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?obligations);
150        let mut vids = UnordSet::new();
151        for obligation in obligations {
152            let mut visitor = FindFromFloatForF32RootVids {
153                fcx: self,
154                from_trait,
155                vids: &mut vids,
156                span: obligation.cause.span,
157            };
158
159            let goal = obligation.as_goal();
160            self.visit_proof_tree(goal, &mut visitor);
161        }
162        vids
163    }
164}
165
166struct NestedObligationsForSelfTy<'a, 'tcx> {
167    fcx: &'a FnCtxt<'a, 'tcx>,
168    self_ty: ty::TyVid,
169    root_cause: &'a ObligationCause<'tcx>,
170    obligations_for_self_ty: &'a mut PredicateObligations<'tcx>,
171}
172
173impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> {
174    fn span(&self) -> Span {
175        self.root_cause.span
176    }
177
178    fn config(&self) -> InspectConfig {
179        // Using an intentionally low depth to minimize the chance of future
180        // breaking changes in case we adapt the approach later on. This also
181        // avoids any hangs for exponentially growing proof trees.
182        InspectConfig { max_depth: 5 }
183    }
184
185    fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
186        // No need to walk into goal subtrees that certainly hold, since they
187        // wouldn't then be stalled on an infer var.
188        if inspect_goal.result() == Ok(Certainty::Yes) {
189            return;
190        }
191
192        let tcx = self.fcx.tcx;
193        let goal = inspect_goal.goal();
194        if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {
195            self.obligations_for_self_ty.push(traits::Obligation::new(
196                tcx,
197                self.root_cause.clone(),
198                goal.param_env,
199                goal.predicate,
200            ));
201        }
202
203        // If there's a unique way to prove a given goal, recurse into
204        // that candidate. This means that for `impl<F: FnOnce(u32)> Trait<F> for () {}`
205        // and a `(): Trait<?0>` goal we recurse into the impl and look at
206        // the nested `?0: FnOnce(u32)` goal.
207        if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
208            candidate.visit_nested_no_probe(self)
209        }
210    }
211}
212
213struct FindFromFloatForF32RootVids<'a, 'tcx> {
214    fcx: &'a FnCtxt<'a, 'tcx>,
215    from_trait: DefId,
216    vids: &'a mut UnordSet<ty::FloatVid>,
217    span: Span,
218}
219
220impl<'tcx> ProofTreeVisitor<'tcx> for FindFromFloatForF32RootVids<'_, 'tcx> {
221    fn span(&self) -> Span {
222        self.span
223    }
224
225    fn config(&self) -> InspectConfig {
226        // Avoid hang from exponentially growing proof trees (see `cycle-modulo-ambig-aliases.rs`).
227        // 3 is more than enough for all occurrences in practice (a.k.a. `Into`).
228        InspectConfig { max_depth: 3 }
229    }
230
231    fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
232        if let Some(vid) = self
233            .fcx
234            .predicate_from_float_for_f32_root_vid(self.from_trait, inspect_goal.goal().predicate)
235        {
236            self.vids.insert(vid);
237        } else if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
238            let start_len = self.vids.len();
239            let _ = candidate.goal().infcx().commit_if_ok(|_| {
240                candidate.visit_nested_no_probe(self);
241                if self.vids.len() > start_len { Ok(()) } else { Err(()) }
242            });
243        }
244    }
245}