diff --git a/Cargo.lock b/Cargo.lock index df4e4f326135e..186892af21c06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4343,6 +4343,7 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_macros", + "rustc_next_trait_solver", "rustc_query_system", "rustc_serialize", "rustc_session", @@ -4451,7 +4452,13 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ + "derivative", + "rustc_ast_ir", + "rustc_data_structures", + "rustc_macros", + "rustc_serialize", "rustc_type_ir", + "rustc_type_ir_macros", ] [[package]] @@ -4752,6 +4759,7 @@ name = "rustc_trait_selection" version = "0.0.0" dependencies = [ "bitflags 2.5.0", + "derivative", "itertools 0.12.1", "rustc_ast", "rustc_ast_ir", @@ -4767,10 +4775,13 @@ dependencies = [ "rustc_next_trait_solver", "rustc_parse_format", "rustc_query_system", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", "rustc_transmute", + "rustc_type_ir", + "rustc_type_ir_macros", "smallvec", "tracing", ] diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index eaef715fe5dca..16057b6ad9dc1 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -385,19 +385,31 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - use GenericArgKind::*; TypeTrace { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { - (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)), - (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), - (Const(a), Const(b)) => { + (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { + Regions(ExpectedFound::new(a_is_expected, a, b)) + } + (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { + Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + } + (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } - (Lifetime(_), Type(_) | Const(_)) - | (Type(_), Lifetime(_) | Const(_)) - | (Const(_), Lifetime(_) | Type(_)) => { + ( + GenericArgKind::Lifetime(_), + GenericArgKind::Type(_) | GenericArgKind::Const(_), + ) + | ( + GenericArgKind::Type(_), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_), + ) + | ( + GenericArgKind::Const(_), + GenericArgKind::Lifetime(_) | GenericArgKind::Type(_), + ) => { bug!("relating different kinds: {a:?} {b:?}") } }, diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index d5def46ad3aae..0ae4340098bc6 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -78,9 +78,9 @@ impl<T: Hash> Hash for Obligation<'_, T> { } } -impl<'tcx, P> From<Obligation<'tcx, P>> for ty::Goal<'tcx, P> { +impl<'tcx, P> From<Obligation<'tcx, P>> for solve::Goal<'tcx, P> { fn from(value: Obligation<'tcx, P>) -> Self { - ty::Goal { param_env: value.param_env, predicate: value.predicate } + solve::Goal { param_env: value.param_env, predicate: value.predicate } } } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d1cdabc293dd8..ab0c598ea0c1b 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,6 +28,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } +rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 1371926873751..7392eb6c2bb4d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -61,7 +61,7 @@ macro_rules! arena_types { [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>, [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, - [] canonical_goal_evaluation: rustc_middle::traits::solve::inspect::GoalEvaluationStep<'tcx>, + [] canonical_goal_evaluation: rustc_next_trait_solver::solve::inspect::GoalEvaluationStep<rustc_middle::ty::TyCtxt<'tcx>>, [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, [] type_op_subtype: rustc_middle::infer::canonical::Canonical<'tcx, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index aee97d772229b..49bf03e9c7544 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -23,23 +23,20 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_type_ir::Canonical as IrCanonical; -use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo; +use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; +pub use rustc_type_ir as ir; pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind}; use smallvec::SmallVec; use std::collections::hash_map::Entry; -use std::ops::Index; use crate::infer::MemberConstraint; use crate::mir::ConstraintCategory; use crate::ty::GenericArg; -use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; - -pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>; - -pub type CanonicalVarInfo<'tcx> = IrCanonicalVarInfo<TyCtxt<'tcx>>; +use crate::ty::{self, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; +pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>; +pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>; +pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>; pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>; impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> { @@ -51,74 +48,6 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> { } } -/// A set of values corresponding to the canonical variables from some -/// `Canonical`. You can give these values to -/// `canonical_value.instantiate` to instantiate them into the canonical -/// value at the right places. -/// -/// When you canonicalize a value `V`, you get back one of these -/// vectors with the original values that were replaced by canonical -/// variables. You will need to supply it later to instantiate the -/// canonicalized query response. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub struct CanonicalVarValues<'tcx> { - pub var_values: ty::GenericArgsRef<'tcx>, -} - -impl CanonicalVarValues<'_> { - pub fn is_identity(&self) -> bool { - self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { - ty::GenericArgKind::Lifetime(r) => { - matches!(*r, ty::ReBound(ty::INNERMOST, br) if br.var.as_usize() == bv) - } - ty::GenericArgKind::Type(ty) => { - matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) - } - ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) - } - }) - } - - pub fn is_identity_modulo_regions(&self) -> bool { - let mut var = ty::BoundVar::ZERO; - for arg in self.var_values { - match arg.unpack() { - ty::GenericArgKind::Lifetime(r) => { - if let ty::ReBound(ty::INNERMOST, br) = *r - && var == br.var - { - var = var + 1; - } else { - // It's ok if this region var isn't unique - } - } - ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::INNERMOST, bt) = *ty.kind() - && var == bt.var - { - var = var + 1; - } else { - return false; - } - } - ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind() - && var == bc - { - var = var + 1; - } else { - return false; - } - } - } - } - - true - } -} - /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query @@ -218,78 +147,6 @@ TrivialTypeTraversalImpls! { crate::infer::canonical::Certainty, } -impl<'tcx> CanonicalVarValues<'tcx> { - // Given a list of canonical variables, construct a set of values which are - // the identity response. - pub fn make_identity( - tcx: TyCtxt<'tcx>, - infos: CanonicalVarInfos<'tcx>, - ) -> CanonicalVarValues<'tcx> { - CanonicalVarValues { - var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map( - |(i, info)| -> ty::GenericArg<'tcx> { - match info.kind { - CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into()) - .into() - } - CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(i), - kind: ty::BrAnon, - }; - ty::Region::new_bound(tcx, ty::INNERMOST, br).into() - } - CanonicalVarKind::Effect => ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - tcx.types.bool, - ) - .into(), - CanonicalVarKind::Const(_, ty) - | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - ty, - ) - .into(), - } - }, - )), - } - } - - /// Creates dummy var values which should not be used in a - /// canonical response. - pub fn dummy() -> CanonicalVarValues<'tcx> { - CanonicalVarValues { var_values: ty::List::empty() } - } - - #[inline] - pub fn len(&self) -> usize { - self.var_values.len() - } -} - -impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { - type Item = GenericArg<'tcx>; - type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>; - - fn into_iter(self) -> Self::IntoIter { - self.var_values.iter() - } -} - -impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { - type Output = GenericArg<'tcx>; - - fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { - &self.var_values[value.as_usize()] - } -} - #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { map: Lock< diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index fb796bf87a1dd..62e71c4db11fb 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -9,7 +9,6 @@ pub mod specialization_graph; mod structural_impls; pub mod util; -use crate::infer::canonical::Canonical; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::GenericArgsRef; @@ -32,6 +31,8 @@ use std::borrow::Cow; use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; +// FIXME: Remove this import and import via `solve::` +pub use rustc_next_trait_solver::solve::BuiltinImplSource; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -736,32 +737,6 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)] -pub enum BuiltinImplSource { - /// Some builtin impl we don't need to differentiate. This should be used - /// unless more specific information is necessary. - Misc, - /// A builtin impl for trait objects. - /// - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods - /// in that vtable. - Object { vtable_base: usize }, - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable - /// within that vtable. - TraitUpcasting { vtable_vptr_slot: Option<usize> }, - /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. - /// - /// This needs to be a separate variant as it is still unstable and we need to emit - /// a feature error when using it on stable. - TupleUnsizing, -} - -TrivialTypeTraversalImpls! { BuiltinImplSource } - #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 70f3532e3ab15..66e50307733d6 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -12,6 +12,8 @@ use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; +// FIXME: Remove this import and import via `traits::solve`. +pub use rustc_next_trait_solver::solve::NoSolution; pub mod type_op { use crate::ty::fold::TypeFoldable; @@ -89,9 +91,6 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)] -pub struct NoSolution; - impl<'tcx> From<TypeError<'tcx>> for NoSolution { fn from(_: TypeError<'tcx>) -> NoSolution { NoSolution diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index ef140860bab26..c8c16ec1e2ce1 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,97 +1,24 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; -use rustc_span::def_id::DefId; +use rustc_next_trait_solver as ir; +pub use rustc_next_trait_solver::solve::*; -use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; -use crate::traits::query::NoSolution; -use crate::traits::Canonical; +use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; -// FIXME(compiler-errors): remove this import in favor of `use rustc_middle::ty::Goal`. -pub use crate::ty::Goal; - -use super::BuiltinImplSource; mod cache; -pub mod inspect; pub use cache::{CacheData, EvaluationCache}; -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct Response<'tcx> { - pub certainty: Certainty, - pub var_values: CanonicalVarValues<'tcx>, - /// Additional constraints returned by this query. - pub external_constraints: ExternalConstraints<'tcx>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum Certainty { - Yes, - Maybe(MaybeCause), -} - -impl Certainty { - pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); - - /// Use this function to merge the certainty of multiple nested subgoals. - /// - /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested - /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`. - /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in - /// success, we merge these two responses. This results in ambiguity. - /// - /// If we unify ambiguity with overflow, we return overflow. This doesn't matter - /// inside of the solver as we do not distinguish ambiguity from overflow. It does - /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar` - /// in ambiguity without changing the inference state, we still want to tell the - /// user that `T: Baz` results in overflow. - pub fn unify_with(self, other: Certainty) -> Certainty { - match (self, other) { - (Certainty::Yes, Certainty::Yes) => Certainty::Yes, - (Certainty::Yes, Certainty::Maybe(_)) => other, - (Certainty::Maybe(_), Certainty::Yes) => self, - (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)), - } - } - - pub const fn overflow(suggest_increasing_limit: bool) -> Certainty { - Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }) - } -} - -/// Why we failed to evaluate a goal. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum MaybeCause { - /// We failed due to ambiguity. This ambiguity can either - /// be a true ambiguity, i.e. there are multiple different answers, - /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals. - Ambiguity, - /// We gave up due to an overflow, most often by hitting the recursion limit. - Overflow { suggest_increasing_limit: bool }, -} - -impl MaybeCause { - fn unify_with(self, other: MaybeCause) -> MaybeCause { - match (self, other) { - (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity, - (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other, - (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self, - ( - MaybeCause::Overflow { suggest_increasing_limit: a }, - MaybeCause::Overflow { suggest_increasing_limit: b }, - ) => MaybeCause::Overflow { suggest_increasing_limit: a || b }, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct QueryInput<'tcx, T> { - pub goal: Goal<'tcx, T>, - pub predefined_opaques_in_body: PredefinedOpaques<'tcx>, -} +pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>; +pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>; +pub type QueryResult<'tcx> = ir::solve::QueryResult<TyCtxt<'tcx>>; +pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>; +pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>; +pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>; /// Additional constraints returned on success. #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] @@ -110,18 +37,6 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { } } -pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>; - -pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; - -/// The result of evaluating a canonical query. -/// -/// FIXME: We use a different type than the existing canonical queries. This is because -/// we need to add a `Certainty` for `overflow` and may want to restructure this code without -/// having to worry about changes to currently used code. Once we've made progress on this -/// solver, merge the two responses again. -pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; - #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); @@ -228,91 +143,3 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { self.opaque_types.visit_with(visitor) } } - -/// Why a specific goal has to be proven. -/// -/// This is necessary as we treat nested goals different depending on -/// their source. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeVisitable, TypeFoldable)] -pub enum GoalSource { - Misc, - /// We're proving a where-bound of an impl. - /// - /// FIXME(-Znext-solver=coinductive): Explain how and why this - /// changes whether cycles are coinductive. - /// - /// This also impacts whether we erase constraints on overflow. - /// Erasing constraints is generally very useful for perf and also - /// results in better error messages by avoiding spurious errors. - /// We do not erase overflow constraints in `normalizes-to` goals unless - /// they are from an impl where-clause. This is necessary due to - /// backwards compatability, cc trait-system-refactor-initiatitive#70. - ImplWhereBound, - /// Instantiating a higher-ranked goal and re-proving it. - InstantiateHigherRanked, -} - -/// 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. - 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, - /// A candidate that is registered only during coherence to represent some - /// yet-unknown impl that could be produced downstream without violating orphan - /// rules. - // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`. - CoherenceUnknowable, -} diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs index 4f90af0a27c07..03ce7cf98cf7e 100644 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -17,7 +17,7 @@ pub struct EvaluationCache<'tcx> { #[derive(PartialEq, Eq)] pub struct CacheData<'tcx> { pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, + pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>, pub reached_depth: usize, pub encountered_overflow: bool, } @@ -28,7 +28,7 @@ impl<'tcx> EvaluationCache<'tcx> { &self, tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, - proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, + proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>, reached_depth: usize, encountered_overflow: bool, cycle_participants: FxHashSet<CanonicalInput<'tcx>>, @@ -105,7 +105,7 @@ struct Success<'tcx> { #[derive(Clone, Copy)] pub struct QueryData<'tcx> { pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>, + pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>, } /// The cache entry for a goal `CanonicalInput`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 06299cdf86f67..b913577ad88d2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -89,18 +89,23 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; - type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; type AdtDef = ty::AdtDef<'tcx>; + type GenericArgs = ty::GenericArgsRef<'tcx>; type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; - type Term = ty::Term<'tcx>; + type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; type BoundVars = &'tcx List<ty::BoundVariableKind>; type BoundVar = ty::BoundVariableKind; type CanonicalVars = CanonicalVarInfos<'tcx>; + type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; + type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; + type ExternalConstraints = ExternalConstraints<'tcx>; + type GoalEvaluationSteps = &'tcx [solve::inspect::GoalEvaluationStep<TyCtxt<'tcx>>]; + type Ty = Ty<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; type FnInputTys = &'tcx [Ty<'tcx>]; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 904c0c332a858..38b2987399a9a 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,6 +11,7 @@ use rustc_ast_ir::walk_visitable_list; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; +use rustc_macros::extension; use rustc_macros::{ Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, }; @@ -25,6 +26,8 @@ use std::num::NonZero; use std::ops::Deref; use std::ptr::NonNull; +pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>; + /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). /// To reduce memory usage, a `GenericArg` is an interned pointer, @@ -49,6 +52,14 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg } } +impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> { + type Kind = GenericArgKind<'tcx>; + + fn kind(self) -> Self::Kind { + self.unpack() + } +} + #[cfg(parallel_compiler)] unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend @@ -79,13 +90,7 @@ const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; -#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, HashStable)] -pub enum GenericArgKind<'tcx> { - Lifetime(ty::Region<'tcx>), - Type(Ty<'tcx>), - Const(ty::Const<'tcx>), -} - +#[extension(trait GenericArgPackExt<'tcx>)] impl<'tcx> GenericArgKind<'tcx> { #[inline] fn pack(self) -> GenericArg<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8ba083ec306e3..f07f12f8bf1cd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -28,7 +28,7 @@ use crate::ty::fast_reject::SimplifiedType; use crate::ty::util::Discr; pub use adt::*; pub use assoc::*; -pub use generic_args::*; +pub use generic_args::{GenericArgKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_ast as ast; @@ -97,13 +97,12 @@ pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, - ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, Goal, - NormalizesTo, OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, - PolyExistentialProjection, PolyExistentialTraitRef, PolyProjectionPredicate, - PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, - PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, - RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef, - TypeOutlivesPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, + OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, + PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, + PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, + PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, + TraitPredicate, TraitRef, TypeOutlivesPredicate, }; pub use self::region::{ BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index e490e060345df..644fca7c5fee9 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -12,7 +12,6 @@ use crate::ty::{ Upcast, UpcastFrom, WithCachedTypeInfo, }; -pub type Goal<'tcx, P> = ir::Goal<TyCtxt<'tcx>, P>; pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>; pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>; diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 8842ecd12e98f..7540f0ab83ff0 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -396,6 +396,12 @@ pub struct BoundRegion { pub kind: BoundRegionKind, } +impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion { + fn var(self) -> BoundVar { + self.var + } +} + impl core::fmt::Debug for BoundRegion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.kind { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9dbcd938e6eda..21520fa5c257c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1204,6 +1204,12 @@ pub struct BoundTy { pub kind: BoundTyKind, } +impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy { + fn var(self) -> BoundVar { + self.var + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundTyKind { @@ -1606,6 +1612,10 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { + fn new_bool(tcx: TyCtxt<'tcx>) -> Self { + tcx.types.bool + } + fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 9d496fd8e8175..8bcc21d82f85b 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,9 +5,19 @@ edition = "2021" [dependencies] rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +derivative = "2.2.0" +rustc_macros = { path = "../rustc_macros", optional = true } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } [features] default = ["nightly"] nightly = [ "rustc_type_ir/nightly", -] \ No newline at end of file + "rustc_macros", + "rustc_serialize", + "rustc_data_structures", + "rustc_ast_ir/nightly", +] diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index e5fc8f755e0a9..4202dc39fb2fb 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -1 +1,2 @@ pub mod canonicalizer; +pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs new file mode 100644 index 0000000000000..eba96facabc63 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve.rs @@ -0,0 +1 @@ +pub use rustc_type_ir::solve::*; diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 811eb4c98104e..1f4fb57d996cc 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +derivative = "2.2.0" itertools = "0.12" rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } @@ -21,10 +22,13 @@ rustc_middle = { path = "../rustc_middle" } rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_parse_format = { path = "../rustc_parse_format" } rustc_query_system = { path = "../rustc_query_system" } +rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } +rustc_type_ir = { path = "../rustc_type_ir" } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 4074ecdd74e56..b1dd6ae6611e0 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -25,7 +25,7 @@ pub(super) mod structural_traits; /// and the `result` when using the given `source`. #[derive(Debug, Clone)] pub(super) struct Candidate<'tcx> { - pub(super) source: CandidateSource, + pub(super) source: CandidateSource<'tcx>, pub(super) result: CanonicalResponse<'tcx>, } @@ -47,7 +47,7 @@ pub(super) trait GoalKind<'tcx>: /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, - source: CandidateSource, + source: CandidateSource<'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, @@ -58,7 +58,7 @@ pub(super) trait GoalKind<'tcx>: /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, - parent_source: CandidateSource, + parent_source: CandidateSource<'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>, @@ -76,7 +76,7 @@ pub(super) trait GoalKind<'tcx>: /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, - source: CandidateSource, + source: CandidateSource<'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, ) -> Result<Candidate<'tcx>, NoSolution> { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 90cc33e0275b6..cf826596392ce 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -6,9 +6,8 @@ use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; -use rustc_middle::ty::{ - self, Goal, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast, -}; +use rustc_middle::traits::solve::Goal; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast}; use rustc_span::sym; use crate::solve::EvalCtxt; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 2058650f288f9..52deb22098f4b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -40,13 +40,13 @@ trait ResponseT<'tcx> { fn var_values(&self) -> CanonicalVarValues<'tcx>; } -impl<'tcx> ResponseT<'tcx> for Response<'tcx> { +impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> { fn var_values(&self) -> CanonicalVarValues<'tcx> { self.var_values } } -impl<'tcx, T> ResponseT<'tcx> for inspect::State<'tcx, T> { +impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> { fn var_values(&self) -> CanonicalVarValues<'tcx> { self.var_values } @@ -384,7 +384,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>> var_values: &[ty::GenericArg<'tcx>], max_input_universe: ty::UniverseIndex, data: T, -) -> inspect::CanonicalState<'tcx, T> { +) -> inspect::CanonicalState<TyCtxt<'tcx>, T> { let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = state.fold_with(&mut EagerResolver::new(infcx)); @@ -414,7 +414,7 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt span: Span, param_env: ty::ParamEnv<'tcx>, orig_values: &mut Vec<ty::GenericArg<'tcx>>, - state: inspect::CanonicalState<'tcx, T>, + state: inspect::CanonicalState<TyCtxt<'tcx>, T>, ) -> T { // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index e5d26e530ee52..70308d4359d22 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,3 +1,6 @@ +use std::io::Write; +use std::ops::ControlFlow; + use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; @@ -8,13 +11,12 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; -use rustc_macros::{extension, HashStable}; +use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_middle::bug; use rustc_middle::infer::canonical::CanonicalVarInfos; -use rustc_middle::traits::solve::inspect; use rustc_middle::traits::solve::{ - CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData, - QueryResult, + inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, + PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::{ @@ -23,8 +25,8 @@ use rustc_middle::ty::{ }; use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; -use std::io::Write; -use std::ops::ControlFlow; +use rustc_type_ir::{self as ir, Interner}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::traits::coherence; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; @@ -85,7 +87,7 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, - nested_goals: NestedGoals<'tcx>, + nested_goals: NestedGoals<TyCtxt<'tcx>>, // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`? // @@ -95,11 +97,15 @@ pub struct EvalCtxt<'a, 'tcx> { // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder<'tcx>, + pub(super) inspect: ProofTreeBuilder<TyCtxt<'tcx>>, } -#[derive(Default, Debug, Clone)] -pub(super) struct NestedGoals<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[derive(TyDecodable, TyEncodable, HashStable_NoContext)] +// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. +pub struct NestedGoals<I: Interner> { /// These normalizes-to goals are treated specially during the evaluation /// loop. In each iteration we take the RHS of the projection, replace it with /// a fresh inference variable, and only after evaluating that goal do we @@ -110,17 +116,17 @@ pub(super) struct NestedGoals<'tcx> { /// /// Forgetting to replace the RHS with a fresh inference variable when we evaluate /// this goal results in an ICE.. - pub(super) normalizes_to_goals: Vec<Goal<'tcx, ty::NormalizesTo<'tcx>>>, + pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>, /// The rest of the goals which have not yet processed or remain ambiguous. - pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>, + pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>, } -impl<'tcx> NestedGoals<'tcx> { - pub(super) fn new() -> Self { +impl<I: Interner> NestedGoals<I> { + pub fn new() -> Self { Self { normalizes_to_goals: Vec::new(), goals: Vec::new() } } - pub(super) fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.normalizes_to_goals.is_empty() && self.goals.is_empty() } } @@ -143,7 +149,8 @@ impl<'tcx> InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>) { + ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) + { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) @@ -166,7 +173,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { infcx: &InferCtxt<'tcx>, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R, - ) -> (R, Option<inspect::GoalEvaluation<'tcx>>) { + ) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) { let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mut search_graph = search_graph::SearchGraph::new(mode); @@ -220,7 +227,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder<'tcx>, + canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, ) -> R { let intercrate = match search_graph.solver_mode() { @@ -282,7 +289,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder<'tcx>, + goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>, ) -> QueryResult<'tcx> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 47109c8ad5d2f..9edc489754ca9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -2,10 +2,9 @@ use crate::solve::assembly::Candidate; use super::EvalCtxt; use rustc_infer::traits::BuiltinImplSource; -use rustc_middle::traits::{ - query::NoSolution, - solve::{inspect, CandidateSource, QueryResult}, -}; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult}; +use rustc_middle::ty::TyCtxt; use std::marker::PhantomData; pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { @@ -16,7 +15,7 @@ pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind<'tcx>, + F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>, { pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; @@ -51,12 +50,12 @@ where pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> { cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>, - source: CandidateSource, + source: CandidateSource<'tcx>, } impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F> where - F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>, + F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>, { #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( @@ -72,7 +71,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// as expensive as necessary to output the desired information. pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind<'tcx>, + F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>, { ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } } @@ -80,16 +79,24 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, source: BuiltinImplSource, - ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>> - { + ) -> TraitProbeCtxt< + '_, + 'a, + 'tcx, + impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>, + > { self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( &mut self, - source: CandidateSource, - ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>> - { + source: CandidateSource<'tcx>, + ) -> TraitProbeCtxt< + '_, + 'a, + 'tcx, + impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>, + > { TraitProbeCtxt { cx: ProbeCtxt { ecx: self, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 625bcf33a16b0..4933080451daa 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -3,7 +3,6 @@ use std::ops::ControlFlow; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, @@ -15,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; use super::eval_ctxt::GenerateProofTree; -use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. @@ -319,8 +318,8 @@ impl<'tcx> BestObligation<'tcx> { /// *don't* hold and which have impl-where clauses that also don't hold. fn non_trivial_candidates<'a>( &self, - goal: &'a InspectGoal<'a, 'tcx>, - ) -> Vec<InspectCandidate<'a, 'tcx>> { + goal: &'a inspect::InspectGoal<'a, 'tcx>, + ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> { let mut candidates = goal.candidates(); match self.consider_ambiguities { true => { @@ -370,15 +369,17 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { self.obligation.cause.span } - fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { let candidates = self.non_trivial_candidates(goal); let [candidate] = candidates.as_slice() else { return ControlFlow::Break(self.obligation.clone()); }; // Don't walk into impls that have `do_not_recommend`. - if let ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } = - candidate.kind() + if let inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } = candidate.kind() && goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend) { return ControlFlow::Break(self.obligation.clone()); @@ -475,13 +476,16 @@ enum ChildMode<'tcx> { fn derive_cause<'tcx>( tcx: TyCtxt<'tcx>, - candidate_kind: ProbeKind<'tcx>, + candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>, mut cause: ObligationCause<'tcx>, idx: usize, parent_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> ObligationCause<'tcx> { match candidate_kind { - ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => { + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } => { if let Some((_, span)) = tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx) { @@ -495,7 +499,10 @@ fn derive_cause<'tcx>( }) } } - ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => { + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::BuiltinImpl(..), + result: _, + } => { cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived); } _ => {} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index b71a1b339cb81..e12c66b692850 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,7 +18,7 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal}; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_span::{Span, DUMMY_SP}; @@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> { orig_values: Vec<ty::GenericArg<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result<Certainty, NoSolution>, - evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>, + evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>, normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, } @@ -88,16 +88,17 @@ impl<'tcx> NormalizesToTermHack<'tcx> { pub struct InspectCandidate<'a, 'tcx> { goal: &'a InspectGoal<'a, 'tcx>, - kind: inspect::ProbeKind<'tcx>, - nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>, - final_state: inspect::CanonicalState<'tcx, ()>, - impl_args: Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>, + kind: inspect::ProbeKind<TyCtxt<'tcx>>, + nested_goals: + Vec<(GoalSource, inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>)>, + final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>, + impl_args: Option<inspect::CanonicalState<TyCtxt<'tcx>, ty::GenericArgsRef<'tcx>>>, result: QueryResult<'tcx>, shallow_certainty: Certainty, } impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { - pub fn kind(&self) -> inspect::ProbeKind<'tcx> { + pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> { self.kind } @@ -280,9 +281,9 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates: &mut Vec<InspectCandidate<'a, 'tcx>>, nested_goals: &mut Vec<( GoalSource, - inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>, + inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>, )>, - probe: &inspect::Probe<'tcx>, + probe: &inspect::Probe<TyCtxt<'tcx>>, ) { let mut shallow_certainty = None; let mut impl_args = None; @@ -387,7 +388,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { fn new( infcx: &'a InferCtxt<'tcx>, depth: usize, - root: inspect::GoalEvaluation<'tcx>, + root: inspect::GoalEvaluation<TyCtxt<'tcx>>, normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, ) -> Self { diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 9dd681f09e76e..803300c5196ca 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -9,11 +9,12 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::bug; use rustc_middle::infer::canonical::CanonicalVarValues; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{ +use rustc_middle::ty::{self, TyCtxt}; +use rustc_next_trait_solver::solve::{ CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, }; -use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; +use rustc_type_ir::Interner; use crate::solve::eval_ctxt::canonical; use crate::solve::{self, inspect, GenerateProofTree}; @@ -38,49 +39,51 @@ use crate::solve::{self, inspect, GenerateProofTree}; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder<'tcx> { - state: Option<Box<DebugSolver<'tcx>>>, +pub(in crate::solve) struct ProofTreeBuilder<I: Interner> { + state: Option<Box<DebugSolver<I>>>, } /// The current state of the proof tree builder, at most places /// in the code, only one or two variants are actually possible. /// /// We simply ICE in case that assumption is broken. -#[derive(Debug)] -enum DebugSolver<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +enum DebugSolver<I: Interner> { Root, - GoalEvaluation(WipGoalEvaluation<'tcx>), - CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>), - GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), + GoalEvaluation(WipGoalEvaluation<I>), + CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<I>), + GoalEvaluationStep(WipGoalEvaluationStep<I>), } -impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> { - fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { +impl<I: Interner> From<WipGoalEvaluation<I>> for DebugSolver<I> { + fn from(g: WipGoalEvaluation<I>) -> DebugSolver<I> { DebugSolver::GoalEvaluation(g) } } -impl<'tcx> From<WipCanonicalGoalEvaluation<'tcx>> for DebugSolver<'tcx> { - fn from(g: WipCanonicalGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { +impl<I: Interner> From<WipCanonicalGoalEvaluation<I>> for DebugSolver<I> { + fn from(g: WipCanonicalGoalEvaluation<I>) -> DebugSolver<I> { DebugSolver::CanonicalGoalEvaluation(g) } } -impl<'tcx> From<WipGoalEvaluationStep<'tcx>> for DebugSolver<'tcx> { - fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> { +impl<I: Interner> From<WipGoalEvaluationStep<I>> for DebugSolver<I> { + fn from(g: WipGoalEvaluationStep<I>) -> DebugSolver<I> { DebugSolver::GoalEvaluationStep(g) } } -#[derive(Eq, PartialEq, Debug)] -struct WipGoalEvaluation<'tcx> { - pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, - pub kind: WipGoalEvaluationKind<'tcx>, - pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipGoalEvaluation<I: Interner> { + pub uncanonicalized_goal: Goal<I, I::Predicate>, + pub kind: WipGoalEvaluationKind<I>, + pub evaluation: Option<WipCanonicalGoalEvaluation<I>>, } -impl<'tcx> WipGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::GoalEvaluation<'tcx> { +impl<I: Interner> WipGoalEvaluation<I> { + fn finalize(self) -> inspect::GoalEvaluation<I> { inspect::GoalEvaluation { uncanonicalized_goal: self.uncanonicalized_goal, kind: match self.kind { @@ -94,21 +97,23 @@ impl<'tcx> WipGoalEvaluation<'tcx> { } } -#[derive(Eq, PartialEq, Debug)] -pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> { - Root { orig_values: Vec<ty::GenericArg<'tcx>> }, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +pub(in crate::solve) enum WipGoalEvaluationKind<I: Interner> { + Root { orig_values: Vec<I::GenericArg> }, Nested, } -#[derive(Eq, PartialEq)] -pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""))] +pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<I: Interner> { Overflow, CycleInStack, ProvisionalCacheHit, - Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] }, + Interned { revisions: I::GoalEvaluationSteps }, } -impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> { +impl<I: Interner> std::fmt::Debug for WipCanonicalGoalEvaluationKind<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Overflow => write!(f, "Overflow"), @@ -119,18 +124,19 @@ impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> { } } -#[derive(Eq, PartialEq, Debug)] -struct WipCanonicalGoalEvaluation<'tcx> { - goal: CanonicalInput<'tcx>, - kind: Option<WipCanonicalGoalEvaluationKind<'tcx>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipCanonicalGoalEvaluation<I: Interner> { + goal: CanonicalInput<I>, + kind: Option<WipCanonicalGoalEvaluationKind<I>>, /// Only used for uncached goals. After we finished evaluating /// the goal, this is interned and moved into `kind`. - revisions: Vec<WipGoalEvaluationStep<'tcx>>, - result: Option<QueryResult<'tcx>>, + revisions: Vec<WipGoalEvaluationStep<I>>, + result: Option<QueryResult<I>>, } -impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> { +impl<I: Interner> WipCanonicalGoalEvaluation<I> { + fn finalize(self) -> inspect::CanonicalGoalEvaluation<I> { assert!(self.revisions.is_empty()); let kind = match self.kind.unwrap() { WipCanonicalGoalEvaluationKind::Overflow => { @@ -151,14 +157,15 @@ impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { } } -#[derive(Eq, PartialEq, Debug)] -struct WipAddedGoalsEvaluation<'tcx> { - evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipAddedGoalsEvaluation<I: Interner> { + evaluations: Vec<Vec<WipGoalEvaluation<I>>>, result: Option<Result<Certainty, NoSolution>>, } -impl<'tcx> WipAddedGoalsEvaluation<'tcx> { - fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> { +impl<I: Interner> WipAddedGoalsEvaluation<I> { + fn finalize(self) -> inspect::AddedGoalsEvaluation<I> { inspect::AddedGoalsEvaluation { evaluations: self .evaluations @@ -172,22 +179,23 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> { } } -#[derive(Eq, PartialEq, Debug)] -struct WipGoalEvaluationStep<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipGoalEvaluationStep<I: Interner> { /// Unlike `EvalCtxt::var_values`, we append a new /// generic arg here whenever we create a new inference /// variable. /// /// This is necessary as we otherwise don't unify these /// vars when instantiating multiple `CanonicalState`. - var_values: Vec<ty::GenericArg<'tcx>>, - instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + var_values: Vec<I::GenericArg>, + instantiated_goal: QueryInput<I, I::Predicate>, probe_depth: usize, - evaluation: WipProbe<'tcx>, + evaluation: WipProbe<I>, } -impl<'tcx> WipGoalEvaluationStep<'tcx> { - fn current_evaluation_scope(&mut self) -> &mut WipProbe<'tcx> { +impl<I: Interner> WipGoalEvaluationStep<I> { + fn current_evaluation_scope(&mut self) -> &mut WipProbe<I> { let mut current = &mut self.evaluation; for _ in 0..self.probe_depth { match current.steps.last_mut() { @@ -198,7 +206,7 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { current } - fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<'tcx> { + fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<I> { let mut current = &mut self.evaluation; loop { match current.steps.last_mut() { @@ -209,7 +217,7 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { } } - fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { + fn finalize(self) -> inspect::GoalEvaluationStep<I> { let evaluation = self.evaluation.finalize(); match evaluation.kind { inspect::ProbeKind::Root { .. } => (), @@ -219,16 +227,17 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { } } -#[derive(Eq, PartialEq, Debug)] -struct WipProbe<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipProbe<I: Interner> { initial_num_var_values: usize, - steps: Vec<WipProbeStep<'tcx>>, - kind: Option<inspect::ProbeKind<'tcx>>, - final_state: Option<inspect::CanonicalState<'tcx, ()>>, + steps: Vec<WipProbeStep<I>>, + kind: Option<inspect::ProbeKind<I>>, + final_state: Option<inspect::CanonicalState<I, ()>>, } -impl<'tcx> WipProbe<'tcx> { - fn finalize(self) -> inspect::Probe<'tcx> { +impl<I: Interner> WipProbe<I> { + fn finalize(self) -> inspect::Probe<I> { inspect::Probe { steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(), kind: self.kind.unwrap(), @@ -237,17 +246,18 @@ impl<'tcx> WipProbe<'tcx> { } } -#[derive(Eq, PartialEq, Debug)] -enum WipProbeStep<'tcx> { - AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>), - EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), - NestedProbe(WipProbe<'tcx>), +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +enum WipProbeStep<I: Interner> { + AddGoal(GoalSource, inspect::CanonicalState<I, Goal<I, I::Predicate>>), + EvaluateGoals(WipAddedGoalsEvaluation<I>), + NestedProbe(WipProbe<I>), MakeCanonicalResponse { shallow_certainty: Certainty }, - RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, + RecordImplArgs { impl_args: inspect::CanonicalState<I, I::GenericArgs> }, } -impl<'tcx> WipProbeStep<'tcx> { - fn finalize(self) -> inspect::ProbeStep<'tcx> { +impl<I: Interner> WipProbeStep<I> { + fn finalize(self) -> inspect::ProbeStep<I> { match self { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), @@ -262,26 +272,27 @@ impl<'tcx> WipProbeStep<'tcx> { } } -impl<'tcx> ProofTreeBuilder<'tcx> { - fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> { +// FIXME: Genericize this impl. +impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { + fn new(state: impl Into<DebugSolver<TyCtxt<'tcx>>>) -> ProofTreeBuilder<TyCtxt<'tcx>> { ProofTreeBuilder { state: Some(Box::new(state.into())) } } - fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self { + fn nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(&self, state: impl FnOnce() -> T) -> Self { ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) } } - fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { + fn as_mut(&mut self) -> Option<&mut DebugSolver<TyCtxt<'tcx>>> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<'tcx> { + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> { let mut nested = ProofTreeBuilder { state: self.state.take() }; nested.enter_probe(); nested } - pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { + pub fn finalize(self) -> Option<inspect::GoalEvaluation<TyCtxt<'tcx>>> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) @@ -293,7 +304,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn new_maybe_root( tcx: TyCtxt<'tcx>, generate_proof_tree: GenerateProofTree, - ) -> ProofTreeBuilder<'tcx> { + ) -> ProofTreeBuilder<TyCtxt<'tcx>> { match generate_proof_tree { GenerateProofTree::Never => ProofTreeBuilder::new_noop(), GenerateProofTree::IfEnabled => { @@ -311,11 +322,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn new_root() -> ProofTreeBuilder<'tcx> { + pub fn new_root() -> ProofTreeBuilder<TyCtxt<'tcx>> { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder<'tcx> { + pub fn new_noop() -> ProofTreeBuilder<TyCtxt<'tcx>> { ProofTreeBuilder { state: None } } @@ -325,10 +336,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub(in crate::solve) fn new_goal_evaluation( &mut self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>, orig_values: &[ty::GenericArg<'tcx>], kind: solve::GoalEvaluationKind, - ) -> ProofTreeBuilder<'tcx> { + ) -> ProofTreeBuilder<TyCtxt<'tcx>> { self.nested(|| WipGoalEvaluation { uncanonicalized_goal: goal, kind: match kind { @@ -343,8 +354,8 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn new_canonical_goal_evaluation( &mut self, - goal: CanonicalInput<'tcx>, - ) -> ProofTreeBuilder<'tcx> { + goal: CanonicalInput<TyCtxt<'tcx>>, + ) -> ProofTreeBuilder<TyCtxt<'tcx>> { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -356,7 +367,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn finalize_evaluation( &mut self, tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> { + ) -> Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]> { self.as_mut().map(|this| match this { DebugSolver::CanonicalGoalEvaluation(evaluation) => { let revisions = mem::take(&mut evaluation.revisions) @@ -371,7 +382,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> { }) } - pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) { + pub fn canonical_goal_evaluation( + &mut self, + canonical_goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>, + ) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { ( @@ -386,7 +400,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<'tcx>) { + pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<TyCtxt<'tcx>>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -397,7 +411,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation.state.unwrap()) { ( @@ -418,8 +432,8 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn new_goal_evaluation_step( &mut self, var_values: CanonicalVarValues<'tcx>, - instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, - ) -> ProofTreeBuilder<'tcx> { + instantiated_goal: QueryInput<TyCtxt<'tcx>, ty::Predicate<'tcx>>, + ) -> ProofTreeBuilder<TyCtxt<'tcx>> { self.nested(|| WipGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -433,7 +447,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<TyCtxt<'tcx>>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -474,7 +488,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<'tcx>) { + pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<TyCtxt<'tcx>>) { match self.as_mut() { None => {} Some(DebugSolver::GoalEvaluationStep(state)) => { @@ -510,7 +524,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { &mut self, infcx: &InferCtxt<'tcx>, max_input_universe: ty::UniverseIndex, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + goal: Goal<TyCtxt<'tcx>, ty::NormalizesTo<'tcx>>, ) { self.add_goal( infcx, @@ -525,7 +539,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { infcx: &InferCtxt<'tcx>, max_input_universe: ty::UniverseIndex, source: GoalSource, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>, ) { match self.as_mut() { None => {} @@ -579,7 +593,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder<'tcx> { + pub fn finish_probe(mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> { match self.as_mut() { None => {} Some(DebugSolver::GoalEvaluationStep(state)) => { @@ -627,7 +641,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn query_result(&mut self, result: QueryResult<'tcx>) { + pub fn query_result(&mut self, result: QueryResult<TyCtxt<'tcx>>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 540ab738a2217..b085d009d75af 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -20,11 +20,11 @@ use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, GoalSource, QueryResult, Response, + CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response, }; use rustc_middle::ty::{ - self, AliasRelationDirection, CoercePredicate, Goal, RegionOutlivesPredicate, SubtypePredicate, - Ty, TyCtxt, TypeOutlivesPredicate, UniverseIndex, + self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty, + TyCtxt, TypeOutlivesPredicate, UniverseIndex, }; mod alias_relate; @@ -74,7 +74,7 @@ enum GoalEvaluationKind { } #[extension(trait CanonicalResponseExt)] -impl<'tcx> Canonical<'tcx, Response<'tcx>> { +impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> { fn has_no_inference_or_external_constraints(&self) -> bool { self.value.external_constraints.region_constraints.is_empty() && self.value.var_values.is_identity() diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 7ab27374e7a27..8c492b62c1ade 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -3,7 +3,6 @@ use crate::traits::specialization_graph; use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; use super::{EvalCtxt, GoalSource}; -use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -54,23 +53,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let def_id = goal.predicate.def_id(); - match self.tcx().def_kind(def_id) { - DefKind::AssocTy | DefKind::AssocConst => { - match self.tcx().associated_item(def_id).container { - ty::AssocItemContainer::TraitContainer => { - let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) - } - ty::AssocItemContainer::ImplContainer => { - self.normalize_inherent_associated_type(goal) - } - } + match goal.predicate.alias.kind(self.tcx()) { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) } - DefKind::AnonConst => self.normalize_anon_const(goal), - DefKind::TyAlias => self.normalize_weak_type(goal), - DefKind::OpaqueTy => self.normalize_opaque_type(goal), - kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)), + ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), + ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), + ty::AliasTermKind::WeakTy => self.normalize_weak_type(goal), + ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal), } } @@ -108,7 +99,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, - source: CandidateSource, + source: CandidateSource<'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 60362aa01da8b..0164d44667c3f 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -253,8 +253,8 @@ impl<'tcx> SearchGraph<'tcx> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<'tcx>, - inspect: &mut ProofTreeBuilder<'tcx>, - mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, + inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { // Check for overflow. let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index b46edb32f72a1..9139c75d3999a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -103,7 +103,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, - source: CandidateSource, + source: CandidateSource<'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, @@ -821,7 +821,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn consider_builtin_upcast_to_principal( &mut self, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - source: CandidateSource, + source: CandidateSource<'tcx>, a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, a_region: ty::Region<'tcx>, b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, @@ -1149,7 +1149,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// wrapped in one. fn probe_and_evaluate_goal_for_constituent_tys( &mut self, - source: CandidateSource, + source: CandidateSource<'tcx>, goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn( &EvalCtxt<'_, 'tcx>, diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index efefd174cd6f0..1c30f03c6939a 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,11 +1,12 @@ #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; use std::hash::Hash; +use std::ops::Index; use crate::inherent::*; -use crate::{Interner, UniverseIndex}; +use crate::{self as ty, Interner, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are @@ -257,3 +258,139 @@ pub enum CanonicalTyVarKind { /// Floating-point type variable `?F` (that can only be unified with float types). Float, } + +/// A set of values corresponding to the canonical variables from some +/// `Canonical`. You can give these values to +/// `canonical_value.instantiate` to instantiate them into the canonical +/// value at the right places. +/// +/// When you canonicalize a value `V`, you get back one of these +/// vectors with the original values that were replaced by canonical +/// variables. You will need to supply it later to instantiate the +/// canonicalized query response. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Hash(bound = ""), + Debug(bound = "") +)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct CanonicalVarValues<I: Interner> { + pub var_values: I::GenericArgs, +} + +impl<I: Interner> CanonicalVarValues<I> { + pub fn is_identity(&self) -> bool { + self.var_values.into_iter().enumerate().all(|(bv, arg)| match arg.kind() { + ty::GenericArgKind::Lifetime(r) => { + matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv) + } + ty::GenericArgKind::Type(ty) => { + matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv) + } + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv) + } + }) + } + + pub fn is_identity_modulo_regions(&self) -> bool { + let mut var = ty::BoundVar::ZERO; + for arg in self.var_values { + match arg.kind() { + ty::GenericArgKind::Lifetime(r) => { + if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) { + var = var + 1; + } else { + // It's ok if this region var isn't an identity variable + } + } + ty::GenericArgKind::Type(ty) => { + if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) { + var = var + 1; + } else { + return false; + } + } + ty::GenericArgKind::Const(ct) => { + if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var()) + { + var = var + 1; + } else { + return false; + } + } + } + } + + true + } + + // Given a list of canonical variables, construct a set of values which are + // the identity response. + pub fn make_identity(tcx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> { + CanonicalVarValues { + var_values: tcx.mk_args_from_iter(infos.into_iter().enumerate().map( + |(i, info)| -> I::GenericArg { + match info.kind { + CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { + Ty::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { + Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } + CanonicalVarKind::Effect => Const::new_anon_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(i), + Ty::new_bool(tcx), + ) + .into(), + CanonicalVarKind::Const(_, ty) + | CanonicalVarKind::PlaceholderConst(_, ty) => Const::new_anon_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(i), + ty, + ) + .into(), + } + }, + )), + } + } + + /// Creates dummy var values which should not be used in a + /// canonical response. + pub fn dummy() -> CanonicalVarValues<I> { + CanonicalVarValues { var_values: Default::default() } + } + + #[inline] + pub fn len(&self) -> usize { + self.var_values.len() + } +} + +impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> { + type Item = I::GenericArg; + type IntoIter = <I::GenericArgs as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.into_iter() + } +} + +impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> { + type Output = I::GenericArg; + + fn index(&self, value: ty::BoundVar) -> &I::GenericArg { + &self.var_values[value.as_usize()] + } +} diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs new file mode 100644 index 0000000000000..622a40806083b --- /dev/null +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -0,0 +1,18 @@ +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; + +use crate::Interner; + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Debug(bound = ""), + Eq(bound = ""), + PartialEq(bound = "") +)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum GenericArgKind<I: Interner> { + Lifetime(I::Region), + Type(I::Ty), + Const(I::Const), +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 484f6c312588f..fa91fad86ab6d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -1,3 +1,8 @@ +//! Set of traits which are used to emulate the inherent impls that are present in `rustc_middle`. +//! It is customary to glob-import `rustc_type_ir::inherent::*` to bring all of these traits into +//! scope when programming in interner-agnostic settings, and to avoid importing any of these +//! directly elsewhere (i.e. specify the full path for an implementation downstream). + use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; @@ -21,6 +26,8 @@ pub trait Ty<I: Interner<Ty = Self>>: + TypeSuperFoldable<I> + Flags { + fn new_bool(interner: I) -> Self; + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self; @@ -79,6 +86,7 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: + Eq + IntoIterator<Item = I::GenericArg> + Deref<Target: Deref<Target = [I::GenericArg]>> + + Default { fn type_at(self, i: usize) -> I::Ty; @@ -111,3 +119,7 @@ pub trait BoundVars<I: Interner> { fn has_no_bound_vars(&self) -> bool; } + +pub trait BoundVarLike<I: Interner> { + fn var(self) -> BoundVar; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 78706b0e5a53b..47ad62105f276 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -5,11 +5,12 @@ use std::ops::Deref; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::solve::inspect::GoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, - DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, NormalizesTo, - ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind, + NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait Interner: @@ -28,14 +29,13 @@ pub trait Interner: + IrPrint<FnSig<Self>> { type DefId: Copy + Debug + Hash + Eq; - type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs<Self>; /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`, /// not including the args from the parent item (trait or impl). type OwnItemArgs: Copy + Debug + Hash + Eq; - type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq; + type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq + IntoKind<Kind = GenericArgKind<Self>>; type Term: Copy + Debug + Hash + Eq; type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>; @@ -43,13 +43,17 @@ pub trait Interner: type BoundVar; type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>; + type PredefinedOpaques: Copy + Debug + Hash + Eq; + type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; + type ExternalConstraints: Copy + Debug + Hash + Eq; + type GoalEvaluationSteps: Copy + Debug + Hash + Eq + Deref<Target = [GoalEvaluationStep<Self>]>; // Kinds of tys type Ty: Ty<Self>; type Tys: Tys<Self>; type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]>; type ParamTy: Copy + Debug + Hash + Eq; - type BoundTy: Copy + Debug + Hash + Eq; + type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type PlaceholderTy: PlaceholderLike; // Things stored inside of tys @@ -66,7 +70,7 @@ pub trait Interner: type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq; type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq; - type BoundConst: Copy + Debug + Hash + Eq; + type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type ValueConst: Copy + Debug + Hash + Eq; type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq; @@ -74,7 +78,7 @@ pub trait Interner: type Region: Region<Self>; type EarlyParamRegion: Copy + Debug + Hash + Eq; type LateParamRegion: Copy + Debug + Hash + Eq; - type BoundRegion: Copy + Debug + Hash + Eq; + type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Eq; type PlaceholderRegion: PlaceholderLike; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 26aa07c1f44f9..fa9bda9a2f754 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -19,13 +19,13 @@ use std::sync::Arc as Lrc; #[macro_use] pub mod visit; - #[cfg(feature = "nightly")] pub mod codec; pub mod fold; pub mod inherent; pub mod ir_print; pub mod lift; +pub mod solve; pub mod ty_info; pub mod ty_kind; @@ -35,6 +35,7 @@ mod canonical; mod const_kind; mod debug; mod flags; +mod generic_arg; mod infcx; mod interner; mod predicate; @@ -48,6 +49,7 @@ pub use codec::*; pub use const_kind::*; pub use debug::{DebugWithInfcx, WithInfcx}; pub use flags::*; +pub use generic_arg::*; pub use infcx::InferCtxtLike; pub use interner::*; pub use predicate::*; @@ -368,6 +370,12 @@ rustc_index::newtype_index! { pub struct BoundVar {} } +impl<I: Interner> inherent::BoundVarLike<I> for BoundVar { + fn var(self) -> BoundVar { + self + } +} + /// Represents the various closure traits in the language. This /// will determine the type of the environment (`self`, in the /// desugaring) argument that the closure expects. diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 35e045457df3b..c0619d782c681 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -8,42 +8,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::visit::TypeVisitableExt as _; use crate::{ - AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, Upcast, - WithInfcx, + AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx, }; -/// A goal is a statement, i.e. `predicate`, we want to prove -/// given some assumptions, i.e. `param_env`. -/// -/// Most of the time the `param_env` contains the `where`-bounds of the function -/// we're currently typechecking while the `predicate` is some trait bound. -#[derive(derivative::Derivative)] -#[derivative( - Clone(bound = "P: Clone"), - Copy(bound = "P: Copy"), - Hash(bound = "P: Hash"), - PartialEq(bound = "P: PartialEq"), - Eq(bound = "P: Eq"), - Debug(bound = "P: fmt::Debug") -)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] -pub struct Goal<I: Interner, P> { - pub param_env: I::ParamEnv, - pub predicate: P, -} - -impl<I: Interner, P> Goal<I, P> { - pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> { - Goal { param_env, predicate: predicate.upcast(tcx) } - } - - /// Updates the goal to one with a different `predicate` but the same `param_env`. - pub fn with<Q>(self, tcx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> { - Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) } - } -} - /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: /// ```ignore (illustrative) diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs new file mode 100644 index 0000000000000..3c24e851d7b63 --- /dev/null +++ b/compiler/rustc_type_ir/src/solve.rs @@ -0,0 +1,278 @@ +pub mod inspect; + +use std::fmt; +use std::hash::Hash; + +#[cfg(feature = "nightly")] +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; + +pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>; +pub type CanonicalResponse<I> = Canonical<I, Response<I>>; +/// The result of evaluating a canonical query. +/// +/// FIXME: We use a different type than the existing canonical queries. This is because +/// we need to add a `Certainty` for `overflow` and may want to restructure this code without +/// having to worry about changes to currently used code. Once we've made progress on this +/// solver, merge the two responses again. +pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct NoSolution; + +/// A goal is a statement, i.e. `predicate`, we want to prove +/// given some assumptions, i.e. `param_env`. +/// +/// Most of the time the `param_env` contains the `where`-bounds of the function +/// we're currently typechecking while the `predicate` is some trait bound. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "P: Clone"), + Copy(bound = "P: Copy"), + Hash(bound = "P: Hash"), + PartialEq(bound = "P: PartialEq"), + Eq(bound = "P: Eq"), + Debug(bound = "P: fmt::Debug") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct Goal<I: Interner, P> { + pub param_env: I::ParamEnv, + pub predicate: P, +} + +impl<I: Interner, P> Goal<I, P> { + pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> { + Goal { param_env, predicate: predicate.upcast(tcx) } + } + + /// Updates the goal to one with a different `predicate` but the same `param_env`. + pub fn with<Q>(self, tcx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> { + Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) } + } +} + +/// Why a specific goal has to be proven. +/// +/// This is necessary as we treat nested goals different depending on +/// their source. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum GoalSource { + Misc, + /// We're proving a where-bound of an impl. + /// + /// FIXME(-Znext-solver=coinductive): Explain how and why this + /// changes whether cycles are coinductive. + /// + /// This also impacts whether we erase constraints on overflow. + /// Erasing constraints is generally very useful for perf and also + /// results in better error messages by avoiding spurious errors. + /// We do not erase overflow constraints in `normalizes-to` goals unless + /// they are from an impl where-clause. This is necessary due to + /// backwards compatability, cc trait-system-refactor-initiatitive#70. + ImplWhereBound, + /// Instantiating a higher-ranked goal and re-proving it. + InstantiateHigherRanked, +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "Goal<I, P>: Clone"), + Copy(bound = "Goal<I, P>: Copy"), + Hash(bound = "Goal<I, P>: Hash"), + PartialEq(bound = "Goal<I, P>: PartialEq"), + Eq(bound = "Goal<I, P>: Eq"), + Debug(bound = "Goal<I, P>: fmt::Debug") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct QueryInput<I: Interner, P> { + pub goal: Goal<I, P>, + pub predefined_opaques_in_body: I::PredefinedOpaques, +} + +/// Possible ways the given goal can be proven. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +pub enum CandidateSource<I: Interner> { + /// 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(I::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. + 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, + /// A candidate that is registered only during coherence to represent some + /// yet-unknown impl that could be produced downstream without violating orphan + /// rules. + // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`. + CoherenceUnknowable, +} + +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +pub enum BuiltinImplSource { + /// Some builtin impl we don't need to differentiate. This should be used + /// unless more specific information is necessary. + Misc, + /// A builtin impl for trait objects. + /// + /// The vtable is formed by concatenating together the method lists of + /// the base object trait and all supertraits, pointers to supertrait vtable will + /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods + /// in that vtable. + Object { vtable_base: usize }, + /// The vtable is formed by concatenating together the method lists of + /// the base object trait and all supertraits, pointers to supertrait vtable will + /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable + /// within that vtable. + TraitUpcasting { vtable_vptr_slot: Option<usize> }, + /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. + /// + /// This needs to be a separate variant as it is still unstable and we need to emit + /// a feature error when using it on stable. + TupleUnsizing, +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct Response<I: Interner> { + pub certainty: Certainty, + pub var_values: CanonicalVarValues<I>, + /// Additional constraints returned by this query. + pub external_constraints: I::ExternalConstraints, +} + +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum Certainty { + Yes, + Maybe(MaybeCause), +} + +impl Certainty { + pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); + + /// Use this function to merge the certainty of multiple nested subgoals. + /// + /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested + /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`. + /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in + /// success, we merge these two responses. This results in ambiguity. + /// + /// If we unify ambiguity with overflow, we return overflow. This doesn't matter + /// inside of the solver as we do not distinguish ambiguity from overflow. It does + /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar` + /// in ambiguity without changing the inference state, we still want to tell the + /// user that `T: Baz` results in overflow. + pub fn unify_with(self, other: Certainty) -> Certainty { + match (self, other) { + (Certainty::Yes, Certainty::Yes) => Certainty::Yes, + (Certainty::Yes, Certainty::Maybe(_)) => other, + (Certainty::Maybe(_), Certainty::Yes) => self, + (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)), + } + } + + pub const fn overflow(suggest_increasing_limit: bool) -> Certainty { + Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }) + } +} + +/// Why we failed to evaluate a goal. +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum MaybeCause { + /// We failed due to ambiguity. This ambiguity can either + /// be a true ambiguity, i.e. there are multiple different answers, + /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals. + Ambiguity, + /// We gave up due to an overflow, most often by hitting the recursion limit. + Overflow { suggest_increasing_limit: bool }, +} + +impl MaybeCause { + fn unify_with(self, other: MaybeCause) -> MaybeCause { + match (self, other) { + (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity, + (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other, + (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self, + ( + MaybeCause::Overflow { suggest_increasing_limit: a }, + MaybeCause::Overflow { suggest_increasing_limit: b }, + ) => MaybeCause::Overflow { suggest_increasing_limit: a || b }, + } + } +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs similarity index 55% rename from compiler/rustc_middle/src/traits/solve/inspect.rs rename to compiler/rustc_type_ir/src/solve/inspect.rs index 9e94489902674..c4f6ee2669bef 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -18,16 +18,19 @@ //! //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use super::{ - CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, NoSolution, - QueryInput, QueryResult, -}; -use crate::{infer::canonical::CanonicalVarValues, ty}; -use format::ProofTreeFormatter; -use rustc_macros::{TypeFoldable, TypeVisitable}; +mod format; + use std::fmt::{Debug, Write}; +use std::hash::Hash; -mod format; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use self::format::ProofTreeFormatter; +use crate::solve::{ + CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, NoSolution, QueryInput, + QueryResult, +}; +use crate::{Canonical, CanonicalVarValues, Interner}; /// Some `data` together with information about how they relate to the input /// of the canonical query. @@ -35,96 +38,113 @@ mod format; /// This is only ever used as [CanonicalState]. Any type information in proof /// trees used mechanically has to be canonicalized as we otherwise leak /// inference variables from a nested `InferCtxt`. -#[derive(Debug, Clone, Copy, Eq, PartialEq, TypeFoldable, TypeVisitable)] -pub struct State<'tcx, T> { - pub var_values: CanonicalVarValues<'tcx>, +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "T: Clone"), + Copy(bound = "T: Copy"), + PartialEq(bound = "T: PartialEq"), + Eq(bound = "T: Eq"), + Hash(bound = "T: Hash"), + Debug(bound = "T: Debug") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub struct State<I: Interner, T> { + pub var_values: CanonicalVarValues<I>, pub data: T, } -pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>; +pub type CanonicalState<I, T> = Canonical<I, State<I, T>>; /// When evaluating the root goals we also store the /// original values for the `CanonicalVarValues` of the /// canonicalized goal. We use this to map any [CanonicalState] /// from the local `InferCtxt` of the solver query to /// the `InferCtxt` of the caller. -#[derive(Eq, PartialEq)] -pub enum GoalEvaluationKind<'tcx> { - Root { orig_values: Vec<ty::GenericArg<'tcx>> }, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub enum GoalEvaluationKind<I: Interner> { + Root { orig_values: Vec<I::GenericArg> }, Nested, } -#[derive(Eq, PartialEq)] -pub struct GoalEvaluation<'tcx> { - pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, - pub kind: GoalEvaluationKind<'tcx>, - pub evaluation: CanonicalGoalEvaluation<'tcx>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))] +pub struct GoalEvaluation<I: Interner> { + pub uncanonicalized_goal: Goal<I, I::Predicate>, + pub kind: GoalEvaluationKind<I>, + pub evaluation: CanonicalGoalEvaluation<I>, } -#[derive(Eq, PartialEq, Debug)] -pub struct CanonicalGoalEvaluation<'tcx> { - pub goal: CanonicalInput<'tcx>, - pub kind: CanonicalGoalEvaluationKind<'tcx>, - pub result: QueryResult<'tcx>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub struct CanonicalGoalEvaluation<I: Interner> { + pub goal: CanonicalInput<I>, + pub kind: CanonicalGoalEvaluationKind<I>, + pub result: QueryResult<I>, } -#[derive(Eq, PartialEq, Debug)] -pub enum CanonicalGoalEvaluationKind<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub enum CanonicalGoalEvaluationKind<I: Interner> { Overflow, CycleInStack, ProvisionalCacheHit, - Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] }, + Evaluation { revisions: I::GoalEvaluationSteps }, } -impl Debug for GoalEvaluation<'_> { +impl<I: Interner> Debug for GoalEvaluation<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ProofTreeFormatter::new(f).format_goal_evaluation(self) } } -#[derive(Eq, PartialEq)] -pub struct AddedGoalsEvaluation<'tcx> { - pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub struct AddedGoalsEvaluation<I: Interner> { + pub evaluations: Vec<Vec<GoalEvaluation<I>>>, pub result: Result<Certainty, NoSolution>, } -#[derive(Eq, PartialEq, Debug)] -pub struct GoalEvaluationStep<'tcx> { - pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub struct GoalEvaluationStep<I: Interner> { + pub instantiated_goal: QueryInput<I, I::Predicate>, /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: Probe<'tcx>, + pub evaluation: Probe<I>, } /// A self-contained computation during trait solving. This either /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation /// of a goal. -#[derive(Eq, PartialEq)] -pub struct Probe<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))] +pub struct Probe<I: Interner> { /// What happened inside of this probe in chronological order. - pub steps: Vec<ProbeStep<'tcx>>, - pub kind: ProbeKind<'tcx>, - pub final_state: CanonicalState<'tcx, ()>, + pub steps: Vec<ProbeStep<I>>, + pub kind: ProbeKind<I>, + pub final_state: CanonicalState<I, ()>, } -impl Debug for Probe<'_> { +impl<I: Interner> Debug for Probe<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ProofTreeFormatter::new(f).format_probe(self) } } -#[derive(Eq, PartialEq)] -pub enum ProbeStep<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub enum ProbeStep<I: Interner> { /// We added a goal to the `EvalCtxt` which will get proven /// the next time `EvalCtxt::try_evaluate_added_goals` is called. - AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>), + AddGoal(GoalSource, CanonicalState<I, Goal<I, I::Predicate>>), /// The inside of a `EvalCtxt::try_evaluate_added_goals` call. - EvaluateGoals(AddedGoalsEvaluation<'tcx>), + EvaluateGoals(AddedGoalsEvaluation<I>), /// A call to `probe` while proving the current goal. This is /// used whenever there are multiple candidates to prove the /// current goalby . - NestedProbe(Probe<'tcx>), + NestedProbe(Probe<I>), /// A trait goal was satisfied by an impl candidate. - RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, + RecordImplArgs { impl_args: CanonicalState<I, I::GenericArgs> }, /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with /// `Certainty` was made. This is the certainty passed in, so it's not unified /// with the certainty of the `try_evaluate_added_goals` that is done within; @@ -136,16 +156,25 @@ pub enum ProbeStep<'tcx> { /// What kind of probe we're in. In case the probe represents a candidate, or /// the final result of the current goal - via [ProbeKind::Root] - we also /// store the [QueryResult]. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum ProbeKind<'tcx> { +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Hash(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub enum ProbeKind<I: Interner> { /// The root inference context while proving a goal. - Root { result: QueryResult<'tcx> }, + Root { result: QueryResult<I> }, /// Trying to normalize an alias by at least one step in `NormalizesTo`. - TryNormalizeNonRigid { result: QueryResult<'tcx> }, + TryNormalizeNonRigid { result: QueryResult<I> }, /// Probe entered when normalizing the self ty during candidate assembly NormalizedSelfTyAssembly, /// A candidate for proving a trait or alias-relate goal. - TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> }, + TraitCandidate { source: CandidateSource<I>, result: QueryResult<I> }, /// Used in the probe that wraps normalizing the non-self type for the unsize /// trait, which is also structurally matched on. UnsizeAssembly, @@ -156,5 +185,5 @@ pub enum ProbeKind<'tcx> { /// Looking for param-env candidates that satisfy the trait ref for a projection. ShadowedEnvProbing, /// Try to unify an opaque type with an existing key in the storage. - OpaqueTypeStorageLookup { result: QueryResult<'tcx> }, + OpaqueTypeStorageLookup { result: QueryResult<I> }, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_type_ir/src/solve/inspect/format.rs similarity index 90% rename from compiler/rustc_middle/src/traits/solve/inspect/format.rs rename to compiler/rustc_type_ir/src/solve/inspect/format.rs index 5b3c50cb97323..44ade04cf98ca 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_type_ir/src/solve/inspect/format.rs @@ -1,7 +1,10 @@ +use std::marker::PhantomData; + use super::*; -pub(super) struct ProofTreeFormatter<'a, 'b> { +pub(super) struct ProofTreeFormatter<'a, 'b, I> { f: &'a mut (dyn Write + 'b), + _interner: PhantomData<I>, } enum IndentorState { @@ -36,23 +39,24 @@ impl Write for Indentor<'_, '_> { } } -impl<'a, 'b> ProofTreeFormatter<'a, 'b> { +impl<'a, 'b, I: Interner> ProofTreeFormatter<'a, 'b, I> { pub(super) fn new(f: &'a mut (dyn Write + 'b)) -> Self { - ProofTreeFormatter { f } + ProofTreeFormatter { f, _interner: PhantomData } } fn nested<F>(&mut self, func: F) -> std::fmt::Result where - F: FnOnce(&mut ProofTreeFormatter<'_, '_>) -> std::fmt::Result, + F: FnOnce(&mut ProofTreeFormatter<'_, '_, I>) -> std::fmt::Result, { write!(self.f, " {{")?; func(&mut ProofTreeFormatter { f: &mut Indentor { f: self.f, state: IndentorState::StartWithNewline }, + _interner: PhantomData, })?; writeln!(self.f, "}}") } - pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result { + pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<I>) -> std::fmt::Result { let goal_text = match eval.kind { GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL", GoalEvaluationKind::Nested => "GOAL", @@ -63,7 +67,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { pub(super) fn format_canonical_goal_evaluation( &mut self, - eval: &CanonicalGoalEvaluation<'_>, + eval: &CanonicalGoalEvaluation<I>, ) -> std::fmt::Result { writeln!(self.f, "GOAL: {:?}", eval.goal)?; @@ -89,13 +93,13 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { pub(super) fn format_evaluation_step( &mut self, - evaluation_step: &GoalEvaluationStep<'_>, + evaluation_step: &GoalEvaluationStep<I>, ) -> std::fmt::Result { writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; self.format_probe(&evaluation_step.evaluation) } - pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result { + pub(super) fn format_probe(&mut self, probe: &Probe<I>) -> std::fmt::Result { match &probe.kind { ProbeKind::Root { result } => { write!(self.f, "ROOT RESULT: {result:?}") @@ -150,7 +154,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { pub(super) fn format_added_goals_evaluation( &mut self, - added_goals_evaluation: &AddedGoalsEvaluation<'_>, + added_goals_evaluation: &AddedGoalsEvaluation<I>, ) -> std::fmt::Result { writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?;