Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

canonicalize in inspect, work towards intercrate_ambiguity_causes support #114810

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 62 additions & 6 deletions compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use std::ops::ControlFlow;

use rustc_data_structures::intern::Interned;

use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
use crate::traits::query::NoSolution;
use crate::traits::{Canonical, DefiningAnchor};
use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
TypeVisitor,
};
use rustc_data_structures::intern::Interned;
use rustc_span::def_id::DefId;

mod cache;
pub mod inspect;

pub use cache::{CacheData, EvaluationCache};

use super::BuiltinImplSource;

/// A goal is a statement, i.e. `predicate`, we want to prove
/// given some assumptions, i.e. `param_env`.
///
Expand Down Expand Up @@ -230,8 +232,62 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
No,
/// Possible ways the given goal can be proven.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CandidateSource {
/// A user written impl.
///
/// ## Examples
///
/// ```rust
/// fn main() {
/// let x: Vec<u32> = Vec::new();
/// // This uses the impl from the standard library to prove `Vec<T>: Clone`.
/// let y = x.clone();
/// }
/// ```
Impl(DefId),
/// A builtin impl generated by the compiler. When adding a new special
/// trait, try to use actual impls whenever possible. Builtin impls should
/// only be used in cases where the impl cannot be manually be written.
///
/// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
/// For a list of all traits with builtin impls, check out the
/// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
BuiltinImpl(BuiltinImplSource),
/// An assumption from the environment.
///
/// More precisely we've used the `n-th` assumption in the `param_env`.
///
/// ## Examples
///
/// ```rust
/// fn is_clone<T: Clone>(x: T) -> (T, T) {
/// // This uses the assumption `T: Clone` from the `where`-bounds
/// // to prove `T: Clone`.
/// (x.clone(), x)
/// }
/// ```
ParamEnv(usize),
/// If the self type is an alias type, e.g. an opaque type or a projection,
/// we know the bounds on that alias to hold even without knowing its concrete
/// underlying type.
///
/// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
/// the self type.
///
/// ## Examples
///
/// ```rust
/// trait Trait {
/// type Assoc: Clone;
/// }
///
/// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
/// // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
/// // in the trait definition.
/// let _y = x.clone();
/// }
/// ```
AliasBound,
}
90 changes: 47 additions & 43 deletions compiler/rustc_middle/src/traits/solve/inspect.rs
Original file line number Diff line number Diff line change
@@ -1,90 +1,94 @@
use super::{
CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult,
};
use super::{CandidateSource, CanonicalInput, Certainty, Goal, NoSolution, QueryResult};
use crate::infer::canonical::{Canonical, CanonicalVarValues};
use crate::ty;
use format::ProofTreeFormatter;
use std::fmt::{Debug, Write};

mod format;

#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
#[derive(Debug, Clone, Eq, PartialEq, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct State<'tcx, T> {
pub var_values: CanonicalVarValues<'tcx>,
pub data: T,
}
pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CacheHit {
Provisional,
Global,
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalEvaluation<'tcx> {
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
pub canonicalized_goal: CanonicalInput<'tcx>,
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum IsNormalizesToHack {
Yes,
No,
}

pub kind: GoalEvaluationKind<'tcx>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub struct RootGoalEvaluation<'tcx> {
pub goal: Goal<'tcx, ty::Predicate<'tcx>>,
pub orig_values: Vec<ty::GenericArg<'tcx>>,
pub evaluation: CanonicalGoalEvaluation<'tcx>,
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}

pub struct NestedGoalEvaluation<'tcx> {
pub goal: CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>,
pub orig_values: CanonicalState<'tcx, Vec<ty::GenericArg<'tcx>>>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub evaluation: CanonicalGoalEvaluation<'tcx>,
pub returned_goals: Vec<CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
}

pub struct CanonicalGoalEvaluation<'tcx> {
pub goal: CanonicalInput<'tcx>,
pub data: GoalEvaluationData<'tcx>,
pub result: QueryResult<'tcx>,
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub enum GoalEvaluationKind<'tcx> {
pub enum GoalEvaluationData<'tcx> {
CacheHit(CacheHit),
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
}
impl Debug for GoalEvaluation<'_> {
impl Debug for RootGoalEvaluation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter::new(f).format_goal_evaluation(self)
ProofTreeFormatter::new(f).format_root_goal_evaluation(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct AddedGoalsEvaluation<'tcx> {
pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
pub evaluations: Vec<Vec<NestedGoalEvaluation<'tcx>>>,
pub result: Result<Certainty, NoSolution>,
}
impl Debug for AddedGoalsEvaluation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter::new(f).format_nested_goal_evaluation(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalEvaluationStep<'tcx> {
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,

pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub candidates: Vec<GoalCandidate<'tcx>>,

pub result: QueryResult<'tcx>,
}
impl Debug for GoalEvaluationStep<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter::new(f).format_evaluation_step(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalCandidate<'tcx> {
pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub candidates: Vec<GoalCandidate<'tcx>>,
pub kind: CandidateKind<'tcx>,
pub kind: ProbeKind<'tcx>,
}

#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
pub enum CandidateKind<'tcx> {
#[derive(Debug, PartialEq, Eq)]
pub enum ProbeKind<'tcx> {
/// Probe entered when normalizing the self ty during candidate assembly
NormalizedSelfTyAssembly,
/// A normal candidate for proving a goal
Candidate { name: String, result: QueryResult<'tcx> },
/// Some candidate to prove the current goal.
///
/// FIXME: Remove this in favor of always using more strongly typed variants.
MiscCandidate { name: &'static str, result: QueryResult<'tcx> },
/// A candidate for proving a trait or alias-relate goal.
TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly,
/// During upcasting from some source object to target object type, used to
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
UpcastProbe,
}
impl Debug for GoalCandidate<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter::new(f).format_candidate(self)
}
UpcastProjectionCompatibility,
}
Loading