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
1920use derive_where::derive_where;
21use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
2223use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult};
24use crate::{Canonical, CanonicalVarValues, Interner};
2526/// Some `data` together with information about how they relate to the input
27/// of the canonical query.
28///
29/// This is only ever used as [CanonicalState]. Any type information in proof
30/// trees used mechanically has to be canonicalized as we otherwise leak
31/// inference variables from a nested `InferCtxt`.
32#[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)]33#[derive_where(Copy; I: Interner, T: Copy)]
34#[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,
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)]
35pub struct State<I: Interner, T> {
36pub var_values: CanonicalVarValues<I>,
37pub data: T,
38}
3940impl<I: Interner, T: Eq> Eqfor State<I, T> {}
4142pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
4344/// When evaluating a goal we also store the original values
45/// for the `CanonicalVarValues` of the canonicalized goal.
46/// We use this to map any [CanonicalState] from the local `InferCtxt`
47/// of the solver query to the `InferCtxt` of the caller.
48#[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)]49pub struct GoalEvaluation<I: Interner> {
50pub uncanonicalized_goal: Goal<I, I::Predicate>,
51pub orig_values: Vec<I::GenericArg>,
52pub final_revision: I::Probe,
53pub result: QueryResult<I>,
54}
5556/// A self-contained computation during trait solving. This either
57/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
58/// of a goal.
59#[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)]60pub struct Probe<I: Interner> {
61/// What happened inside of this probe in chronological order.
62pub steps: Vec<ProbeStep<I>>,
63pub kind: ProbeKind<I>,
64pub final_state: CanonicalState<I, ()>,
65}
6667#[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)]68pub enum ProbeStep<I: Interner> {
69/// We added a goal to the `EvalCtxt` which will get proven
70 /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
71AddGoal(GoalSource, CanonicalState<I, Goal<I, I::Predicate>>),
72/// A call to `probe` while proving the current goal. This is
73 /// used whenever there are multiple candidates to prove the
74 /// current goal.
75NestedProbe(Probe<I>),
76/// A trait goal was satisfied by an impl candidate.
77RecordImplArgs { impl_args: CanonicalState<I, I::GenericArgs> },
78/// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
79 /// `Certainty` was made. This is the certainty passed in, so it's not unified
80 /// with the certainty of the `try_evaluate_added_goals` that is done within;
81 /// if it's `Certainty::Yes`, then we can trust that the candidate is "finished"
82 /// and we didn't force ambiguity for some reason.
83MakeCanonicalResponse { shallow_certainty: Certainty },
84}
8586/// What kind of probe we're in. In case the probe represents a candidate, or
87/// the final result of the current goal - via [ProbeKind::Root] - we also
88/// store the [QueryResult].
89#[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)]90#[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)]
91pub enum ProbeKind<I: Interner> {
92/// The root inference context while proving a goal.
93Root { result: QueryResult<I> },
94/// Probe entered when normalizing the self ty during candidate assembly
95NormalizedSelfTyAssembly,
96/// A candidate for proving a trait or alias-relate goal.
97TraitCandidate { source: CandidateSource<I>, result: QueryResult<I> },
98/// Used in the probe that wraps normalizing the non-self type for the unsize
99 /// trait, which is also structurally matched on.
100UnsizeAssembly,
101/// Used to do a probe to find out what projection type(s) match a given
102 /// alias bound or projection predicate. For trait upcasting, this is used
103 /// to prove that the source type upholds all of the target type's object
104 /// bounds. For object type bounds, this is used when eagerly replacing
105 /// supertrait aliases.
106ProjectionCompatibility,
107/// Looking for param-env candidates that satisfy the trait ref for a projection.
108ShadowedEnvProbing,
109/// Try to unify an opaque type with an existing key in the storage.
110OpaqueTypeStorageLookup { result: QueryResult<I> },
111/// Checking that a rigid alias is well-formed.
112RigidAlias { result: QueryResult<I> },
113}