Skip to main content

rustc_type_ir/solve/
inspect.rs

1//! Data structure used to inspect trait solver behavior.
2//!
3//! During trait solving we optionally build "proof trees", the root of
4//! which is a [GoalEvaluation]. These  trees are used by the compiler
5//! to inspect the behavior of the trait solver and to access its internal
6//! state, e.g. for diagnostics and when selecting impls during codegen.
7//!
8//! Because each nested goal in the solver gets [canonicalized] separately
9//! and we discard inference progress via "probes", we cannot mechanically
10//! use proof trees without somehow "lifting up" data local to the current
11//! `InferCtxt`. To use the data from evaluation we therefore canonicalize
12//! it and store it as a [CanonicalState].
13//!
14//! Proof trees are only shallow, we do not compute the proof tree for nested
15//! goals. Visiting proof trees instead recomputes nested goals in the parents
16//! inference context when necessary.
17//!
18//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
19
20use derive_where::derive_where;
21use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
22use thin_vec::ThinVec;
23
24use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult};
25use crate::{Canonical, CanonicalVarValues, Interner};
26
27/// Some `data` together with information about how they relate to the input
28/// of the canonical query.
29///
30/// This is only ever used as [CanonicalState]. Any type information in proof
31/// trees used mechanically has to be canonicalized as we otherwise leak
32/// inference variables from a nested `InferCtxt`.
33#[automatically_derived]
impl<I: Interner, T> ::core::marker::Copy for State<I, T> where I: Interner,
    T: Copy {
}#[derive_where(Clone, PartialEq, Hash, Debug; I: Interner, T)]
34#[derive_where(Copy; I: Interner, T: Copy)]
35#[derive(const _: () =
    {
        impl<I: Interner, T> ::rustc_type_ir::TypeVisitable<I> for State<I, T>
            where I: Interner,
            CanonicalVarValues<I>: ::rustc_type_ir::TypeVisitable<I>,
            T: ::rustc_type_ir::TypeVisitable<I> {
            fn visit_with<__V: ::rustc_type_ir::TypeVisitor<I>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    State { var_values: ref __binding_0, data: ref __binding_1 }
                        => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_type_ir::VisitorResult>::output()
            }
        }
    };TypeVisitable_Generic, GenericTypeVisitable, const _: () =
    {
        impl<I: Interner, T> ::rustc_type_ir::TypeFoldable<I> for State<I, T>
            where I: Interner, T: ::rustc_type_ir::TypeFoldable<I>,
            CanonicalVarValues<I>: ::rustc_type_ir::TypeFoldable<I>,
            T: ::rustc_type_ir::TypeFoldable<I> {
            fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<I>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        State { var_values: __binding_0, data: __binding_1 } => {
                            State {
                                var_values: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                data: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_type_ir::TypeFolder<I>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    State { var_values: __binding_0, data: __binding_1 } => {
                        State {
                            var_values: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            data: ::rustc_type_ir::TypeFoldable::fold_with(__binding_1,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable_Generic)]
36pub struct State<I: Interner, T> {
37    pub var_values: CanonicalVarValues<I>,
38    pub data: T,
39}
40
41impl<I: Interner, T: Eq> Eq for State<I, T> {}
42
43pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
44
45/// When evaluating a goal we also store the original values
46/// for the `CanonicalVarValues` of the canonicalized goal.
47/// We use this to map any [CanonicalState] from the local `InferCtxt`
48/// of the solver query to the `InferCtxt` of the caller.
49#[automatically_derived]
impl<I: Interner> ::core::hash::Hash for GoalEvaluation<I> where I: Interner {
    fn hash<__H: ::core::hash::Hasher>(&self, __state: &mut __H) {
        match self {
            GoalEvaluation {
                uncanonicalized_goal: ref __field_uncanonicalized_goal,
                orig_values: ref __field_orig_values,
                final_revision: ref __field_final_revision,
                result: ref __field_result } => {
                ::core::hash::Hash::hash(__field_uncanonicalized_goal,
                    __state);
                ::core::hash::Hash::hash(__field_orig_values, __state);
                ::core::hash::Hash::hash(__field_final_revision, __state);
                ::core::hash::Hash::hash(__field_result, __state);
            }
        }
    }
}#[derive_where(PartialEq, Eq, Hash; I: Interner)]
50pub struct GoalEvaluation<I: Interner> {
51    pub uncanonicalized_goal: Goal<I, I::Predicate>,
52    pub orig_values: ThinVec<I::GenericArg>,
53    pub final_revision: I::Probe,
54    pub result: QueryResult<I>,
55}
56
57/// A self-contained computation during trait solving. This either
58/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
59/// of a goal.
60#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for Probe<I> where I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            Probe {
                steps: ref __field_steps,
                kind: ref __field_kind,
                final_state: ref __field_final_state } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "Probe");
                ::core::fmt::DebugStruct::field(&mut __builder, "steps",
                    __field_steps);
                ::core::fmt::DebugStruct::field(&mut __builder, "kind",
                    __field_kind);
                ::core::fmt::DebugStruct::field(&mut __builder, "final_state",
                    __field_final_state);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
61pub struct Probe<I: Interner> {
62    /// What happened inside of this probe in chronological order.
63    pub steps: Vec<ProbeStep<I>>,
64    pub kind: ProbeKind<I>,
65    pub final_state: CanonicalState<I, ()>,
66}
67
68#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for ProbeStep<I> where I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            ProbeStep::AddGoal(ref __field_0, ref __field_1) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "AddGoal");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::field(&mut __builder, __field_1);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            ProbeStep::NestedProbe(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "NestedProbe");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            ProbeStep::RecordImplArgs { impl_args: ref __field_impl_args } =>
                {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "RecordImplArgs");
                ::core::fmt::DebugStruct::field(&mut __builder, "impl_args",
                    __field_impl_args);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
            ProbeStep::MakeCanonicalResponse {
                shallow_certainty: ref __field_shallow_certainty } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f,
                        "MakeCanonicalResponse");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "shallow_certainty", __field_shallow_certainty);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
69pub enum ProbeStep<I: Interner> {
70    /// We added a goal to the `EvalCtxt` which will get proven
71    /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
72    AddGoal(GoalSource, CanonicalState<I, Goal<I, I::Predicate>>),
73    /// A call to `probe` while proving the current goal. This is
74    /// used whenever there are multiple candidates to prove the
75    /// current goal.
76    NestedProbe(Probe<I>),
77    /// A trait goal was satisfied by an impl candidate.
78    RecordImplArgs { impl_args: CanonicalState<I, I::GenericArgs> },
79    /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
80    /// `Certainty` was made. This is the certainty passed in, so it's not unified
81    /// with the certainty of the `try_evaluate_added_goals` that is done within;
82    /// if it's `Certainty::Yes`, then we can trust that the candidate is "finished"
83    /// and we didn't force ambiguity for some reason.
84    MakeCanonicalResponse { shallow_certainty: Certainty },
85}
86
87/// What kind of probe we're in. In case the probe represents a candidate, or
88/// the final result of the current goal - via [ProbeKind::Root] - we also
89/// store the [QueryResult].
90#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for ProbeKind<I> where I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            ProbeKind::Root { result: ref __field_result } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "Root");
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
            ProbeKind::NormalizedSelfTyAssembly =>
                ::core::fmt::Formatter::write_str(__f,
                    "NormalizedSelfTyAssembly"),
            ProbeKind::TraitCandidate {
                source: ref __field_source, result: ref __field_result } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "TraitCandidate");
                ::core::fmt::DebugStruct::field(&mut __builder, "source",
                    __field_source);
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
            ProbeKind::UnsizeAssembly =>
                ::core::fmt::Formatter::write_str(__f, "UnsizeAssembly"),
            ProbeKind::ProjectionCompatibility =>
                ::core::fmt::Formatter::write_str(__f,
                    "ProjectionCompatibility"),
            ProbeKind::ShadowedEnvProbing =>
                ::core::fmt::Formatter::write_str(__f, "ShadowedEnvProbing"),
            ProbeKind::OpaqueTypeStorageLookup { result: ref __field_result }
                => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f,
                        "OpaqueTypeStorageLookup");
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
            ProbeKind::RigidAlias { result: ref __field_result } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "RigidAlias");
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
91#[derive(const _: () =
    {
        impl<I: Interner> ::rustc_type_ir::TypeVisitable<I> for ProbeKind<I>
            where I: Interner,
            QueryResult<I>: ::rustc_type_ir::TypeVisitable<I>,
            CandidateSource<I>: ::rustc_type_ir::TypeVisitable<I> {
            fn visit_with<__V: ::rustc_type_ir::TypeVisitor<I>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    ProbeKind::Root { result: ref __binding_0 } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                    ProbeKind::NormalizedSelfTyAssembly => {}
                    ProbeKind::TraitCandidate {
                        source: ref __binding_0, result: ref __binding_1 } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                    ProbeKind::UnsizeAssembly => {}
                    ProbeKind::ProjectionCompatibility => {}
                    ProbeKind::ShadowedEnvProbing => {}
                    ProbeKind::OpaqueTypeStorageLookup { result: ref __binding_0
                        } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                    ProbeKind::RigidAlias { result: ref __binding_0 } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_type_ir::VisitorResult>::output()
            }
        }
    };TypeVisitable_Generic, GenericTypeVisitable, const _: () =
    {
        impl<I: Interner> ::rustc_type_ir::TypeFoldable<I> for ProbeKind<I>
            where I: Interner,
            QueryResult<I>: ::rustc_type_ir::TypeFoldable<I>,
            CandidateSource<I>: ::rustc_type_ir::TypeFoldable<I> {
            fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<I>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        ProbeKind::Root { result: __binding_0 } => {
                            ProbeKind::Root {
                                result: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                            }
                        }
                        ProbeKind::NormalizedSelfTyAssembly => {
                            ProbeKind::NormalizedSelfTyAssembly
                        }
                        ProbeKind::TraitCandidate {
                            source: __binding_0, result: __binding_1 } => {
                            ProbeKind::TraitCandidate {
                                source: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                result: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                            }
                        }
                        ProbeKind::UnsizeAssembly => { ProbeKind::UnsizeAssembly }
                        ProbeKind::ProjectionCompatibility => {
                            ProbeKind::ProjectionCompatibility
                        }
                        ProbeKind::ShadowedEnvProbing => {
                            ProbeKind::ShadowedEnvProbing
                        }
                        ProbeKind::OpaqueTypeStorageLookup { result: __binding_0 }
                            => {
                            ProbeKind::OpaqueTypeStorageLookup {
                                result: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                            }
                        }
                        ProbeKind::RigidAlias { result: __binding_0 } => {
                            ProbeKind::RigidAlias {
                                result: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_type_ir::TypeFolder<I>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    ProbeKind::Root { result: __binding_0 } => {
                        ProbeKind::Root {
                            result: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                        }
                    }
                    ProbeKind::NormalizedSelfTyAssembly => {
                        ProbeKind::NormalizedSelfTyAssembly
                    }
                    ProbeKind::TraitCandidate {
                        source: __binding_0, result: __binding_1 } => {
                        ProbeKind::TraitCandidate {
                            source: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            result: ::rustc_type_ir::TypeFoldable::fold_with(__binding_1,
                                __folder),
                        }
                    }
                    ProbeKind::UnsizeAssembly => { ProbeKind::UnsizeAssembly }
                    ProbeKind::ProjectionCompatibility => {
                        ProbeKind::ProjectionCompatibility
                    }
                    ProbeKind::ShadowedEnvProbing => {
                        ProbeKind::ShadowedEnvProbing
                    }
                    ProbeKind::OpaqueTypeStorageLookup { result: __binding_0 }
                        => {
                        ProbeKind::OpaqueTypeStorageLookup {
                            result: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                        }
                    }
                    ProbeKind::RigidAlias { result: __binding_0 } => {
                        ProbeKind::RigidAlias {
                            result: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable_Generic)]
92pub enum ProbeKind<I: Interner> {
93    /// The root inference context while proving a goal.
94    Root { result: QueryResult<I> },
95    /// Probe entered when normalizing the self ty during candidate assembly
96    NormalizedSelfTyAssembly,
97    /// A candidate for proving a trait or alias-relate goal.
98    TraitCandidate { source: CandidateSource<I>, result: QueryResult<I> },
99    /// Used in the probe that wraps normalizing the non-self type for the unsize
100    /// trait, which is also structurally matched on.
101    UnsizeAssembly,
102    /// Used to do a probe to find out what projection type(s) match a given
103    /// alias bound or projection predicate. For trait upcasting, this is used
104    /// to prove that the source type upholds all of the target type's object
105    /// bounds. For object type bounds, this is used when eagerly replacing
106    /// supertrait aliases.
107    ProjectionCompatibility,
108    /// Looking for param-env candidates that satisfy the trait ref for a projection.
109    ShadowedEnvProbing,
110    /// Try to unify an opaque type with an existing key in the storage.
111    OpaqueTypeStorageLookup { result: QueryResult<I> },
112    /// Checking that a rigid alias is well-formed.
113    RigidAlias { result: QueryResult<I> },
114}