From 05e0f8740aacd7de77d515598da1f21a5c67866e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 15 May 2024 22:37:42 -0400 Subject: [PATCH 1/5] Uplift GenericArgKind, CanonicalVarValues, QueryInput and make NestedGoals generic --- Cargo.lock | 7 + compiler/rustc_infer/src/infer/at.rs | 26 ++- compiler/rustc_infer/src/traits/mod.rs | 4 +- compiler/rustc_middle/Cargo.toml | 1 + compiler/rustc_middle/src/infer/canonical.rs | 155 +----------------- compiler/rustc_middle/src/traits/solve.rs | 36 +--- compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_middle/src/ty/generic_args.rs | 19 ++- compiler/rustc_middle/src/ty/mod.rs | 15 +- compiler/rustc_middle/src/ty/predicate.rs | 1 - compiler/rustc_middle/src/ty/region.rs | 6 + compiler/rustc_middle/src/ty/sty.rs | 10 ++ compiler/rustc_next_trait_solver/Cargo.toml | 12 +- compiler/rustc_next_trait_solver/src/lib.rs | 1 + compiler/rustc_next_trait_solver/src/solve.rs | 1 + .../src/solve/assembly/structural_traits.rs | 5 +- .../src/solve/eval_ctxt/mod.rs | 30 ++-- .../rustc_trait_selection/src/solve/mod.rs | 6 +- compiler/rustc_type_ir/src/canonical.rs | 141 +++++++++++++++- compiler/rustc_type_ir/src/generic_arg.rs | 18 ++ compiler/rustc_type_ir/src/inherent.rs | 12 ++ compiler/rustc_type_ir/src/interner.rs | 13 +- compiler/rustc_type_ir/src/lib.rs | 10 +- compiler/rustc_type_ir/src/predicate.rs | 35 +--- compiler/rustc_type_ir/src/solve.rs | 80 +++++++++ 25 files changed, 377 insertions(+), 268 deletions(-) create mode 100644 compiler/rustc_next_trait_solver/src/solve.rs create mode 100644 compiler/rustc_type_ir/src/generic_arg.rs create mode 100644 compiler/rustc_type_ir/src/solve.rs diff --git a/Cargo.lock b/Cargo.lock index df4e4f326135e..536f49989fa05 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]] 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 Hash for Obligation<'_, T> { } } -impl<'tcx, P> From> for ty::Goal<'tcx, P> { +impl<'tcx, P> From> 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/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, V>; - -pub type CanonicalVarInfo<'tcx> = IrCanonicalVarInfo>; +use crate::ty::{self, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; +pub type Canonical<'tcx, V> = ir::Canonical, V>; +pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo>; +pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues>; pub type CanonicalVarInfos<'tcx> = &'tcx List>; impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { @@ -51,74 +48,6 @@ impl<'tcx> ty::TypeFoldable> 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 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/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index ef140860bab26..efb99047d3807 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,6 +1,8 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; +use rustc_next_trait_solver as ir; +pub use rustc_next_trait_solver::solve::*; use rustc_span::def_id::DefId; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; @@ -9,8 +11,6 @@ use crate::traits::Canonical; 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; @@ -19,6 +19,9 @@ pub mod inspect; pub use cache::{CacheData, EvaluationCache}; +pub type Goal<'tcx, P> = ir_solve::Goal, P>; +pub type QueryInput<'tcx, P> = ir_solve::QueryInput, P>; + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Response<'tcx> { pub certainty: Certainty, @@ -87,12 +90,6 @@ impl MaybeCause { } } -#[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>, -} - /// Additional constraints returned on success. #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct PredefinedOpaquesData<'tcx> { @@ -229,29 +226,6 @@ impl<'tcx> TypeVisitable> for PredefinedOpaques<'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, 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 { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 06299cdf86f67..1d3bc8b4bbefb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -90,6 +90,7 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type DefiningOpaqueTypes = &'tcx ty::List; + type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; type OwnItemArgs = &'tcx [ty::GenericArg<'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>; + /// 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> 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, P>; pub type TraitRef<'tcx> = ir::TraitRef>; pub type AliasTerm<'tcx> = ir::AliasTerm>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate>; 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> 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> 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> 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/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/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index e5d26e530ee52..dfb2bfc1b580a 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; @@ -11,10 +14,9 @@ use rustc_infer::traits::ObligationCause; use rustc_macros::{extension, HashStable}; 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, NestedGoals, PredefinedOpaques, + PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::{ @@ -23,8 +25,6 @@ use rustc_middle::ty::{ }; use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; -use std::io::Write; -use std::ops::ControlFlow; use crate::traits::coherence; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; @@ -85,7 +85,7 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, - nested_goals: NestedGoals<'tcx>, + nested_goals: NestedGoals>, // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`? // @@ -98,8 +98,12 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) inspect: ProofTreeBuilder<'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)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. +pub struct NestedGoals { /// 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 +114,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>>, + pub normalizes_to_goals: Vec>>, /// 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, Goal)>, } -impl<'tcx> NestedGoals<'tcx> { - pub(super) fn new() -> Self { +impl NestedGoals { + 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() } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 540ab738a2217..5a3c960d72da7 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; 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 { + pub var_values: I::GenericArgs, +} + +impl CanonicalVarValues { + 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 { + 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 { + CanonicalVarValues { var_values: Default::default() } + } + + #[inline] + pub fn len(&self) -> usize { + self.var_values.len() + } +} + +impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues { + type Item = I::GenericArg; + type IntoIter = ::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.into_iter() + } +} + +impl Index for CanonicalVarValues { + 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 { + 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>: + TypeSuperFoldable + 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) -> Self; @@ -79,6 +86,7 @@ pub trait GenericArgs>: + Eq + IntoIterator + Deref> + + Default { fn type_at(self, i: usize) -> I::Ty; @@ -111,3 +119,7 @@ pub trait BoundVars { fn has_no_bound_vars(&self) -> bool; } + +pub trait BoundVarLike { + fn var(self) -> BoundVar; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 78706b0e5a53b..69865602584ce 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -8,8 +8,8 @@ use crate::ir_print::IrPrint; 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: @@ -35,7 +35,7 @@ pub trait Interner: /// 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 + Hash + Eq; + type GenericArg: Copy + DebugWithInfcx + Hash + Eq + IntoKind>; type Term: Copy + Debug + Hash + Eq; type Binder>: BoundVars + TypeSuperVisitable; @@ -43,13 +43,14 @@ pub trait Interner: type BoundVar; type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; + type PredefinedOpaques: Copy + Debug + Hash + Eq; // Kinds of tys type Ty: Ty; type Tys: Tys; type FnInputTys: Copy + Debug + Hash + Eq + Deref; type ParamTy: Copy + Debug + Hash + Eq; - type BoundTy: Copy + Debug + Hash + Eq; + type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike; type PlaceholderTy: PlaceholderLike; // Things stored inside of tys @@ -66,7 +67,7 @@ pub trait Interner: type AliasConst: Copy + DebugWithInfcx + Hash + Eq; type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq; - type BoundConst: Copy + Debug + Hash + Eq; + type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; type ValueConst: Copy + Debug + Hash + Eq; type ExprConst: Copy + DebugWithInfcx + Hash + Eq; @@ -74,7 +75,7 @@ pub trait Interner: type Region: Region; 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; type InferRegion: Copy + DebugWithInfcx + 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 inherent::BoundVarLike 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 { - pub param_env: I::ParamEnv, - pub predicate: P, -} - -impl Goal { - pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast) -> Goal { - Goal { param_env, predicate: predicate.upcast(tcx) } - } - - /// Updates the goal to one with a different `predicate` but the same `param_env`. - pub fn with(self, tcx: I, predicate: impl Upcast) -> Goal { - 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..2a733dd02c2a6 --- /dev/null +++ b/compiler/rustc_type_ir/src/solve.rs @@ -0,0 +1,80 @@ +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::{Interner, NormalizesTo, Upcast}; + +/// 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 { + pub param_env: I::ParamEnv, + pub predicate: P, +} + +impl Goal { + pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast) -> Goal { + Goal { param_env, predicate: predicate.upcast(tcx) } + } + + /// Updates the goal to one with a different `predicate` but the same `param_env`. + pub fn with(self, tcx: I, predicate: impl Upcast) -> Goal { + 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: Clone"), + Copy(bound = "Goal: Copy"), + Hash(bound = "Goal: Hash"), + PartialEq(bound = "Goal: PartialEq"), + Eq(bound = "Goal: Eq"), + Debug(bound = "Goal: fmt::Debug") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct QueryInput { + pub goal: Goal, + pub predefined_opaques_in_body: I::PredefinedOpaques, +} From 0f528a4c08bbff98a4fa4d2dc20b23822e1a2dee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 May 2024 12:16:36 -0400 Subject: [PATCH 2/5] Uplift inspect into rustc_type_ir --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 29 +-- compiler/rustc_middle/src/traits/query.rs | 5 +- compiler/rustc_middle/src/traits/solve.rs | 161 +------------- .../rustc_middle/src/traits/solve/cache.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 10 +- .../src/solve/assembly/mod.rs | 8 +- .../src/solve/eval_ctxt/canonical.rs | 8 +- .../src/solve/eval_ctxt/mod.rs | 5 +- .../src/solve/eval_ctxt/probe.rs | 33 +-- .../src/solve/fulfill.rs | 27 ++- .../src/solve/inspect/analyse.rs | 21 +- .../src/solve/inspect/build.rs | 28 +-- .../rustc_trait_selection/src/solve/mod.rs | 2 +- .../src/solve/normalizes_to/mod.rs | 2 +- .../src/solve/trait_goals.rs | 6 +- compiler/rustc_type_ir/src/interner.rs | 5 +- compiler/rustc_type_ir/src/solve.rs | 200 +++++++++++++++++- .../src}/solve/inspect.rs | 137 +++++++----- .../src}/solve/inspect/format.rs | 22 +- 20 files changed, 399 insertions(+), 318 deletions(-) rename compiler/{rustc_middle/src/traits => rustc_type_ir/src}/solve/inspect.rs (55%) rename compiler/{rustc_middle/src/traits => rustc_type_ir/src}/solve/inspect/format.rs (90%) 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>, [] 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/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, } -#[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 }, - /// 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>>; -#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)] -pub struct NoSolution; - impl<'tcx> From> 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 efb99047d3807..c8c16ec1e2ce1 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -3,92 +3,22 @@ use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_next_trait_solver as ir; pub use rustc_next_trait_solver::solve::*; -use rustc_span::def_id::DefId; -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, }; -use super::BuiltinImplSource; - mod cache; -pub mod inspect; pub use cache::{CacheData, EvaluationCache}; -pub type Goal<'tcx, P> = ir_solve::Goal, P>; -pub type QueryInput<'tcx, P> = ir_solve::QueryInput, P>; - -#[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 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 }, - } - } -} +pub type Goal<'tcx, P> = ir::solve::Goal, P>; +pub type QueryInput<'tcx, P> = ir::solve::QueryInput, P>; +pub type QueryResult<'tcx> = ir::solve::QueryResult>; +pub type CandidateSource<'tcx> = ir::solve::CandidateSource>; +pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput, P>; +pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse>; /// Additional constraints returned on success. #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] @@ -107,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, NoSolution>; - #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); @@ -225,68 +143,3 @@ impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> { self.opaque_types.visit_with(visitor) } } - -/// 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 = Vec::new(); - /// // This uses the impl from the standard library to prove `Vec: 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(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(x: ::Assoc) { - /// // We prove `::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>]>, 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>]>, reached_depth: usize, encountered_overflow: bool, cycle_participants: FxHashSet>, @@ -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>]>, } /// 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 1d3bc8b4bbefb..b913577ad88d2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -89,19 +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; - type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; 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>> = Binder<'tcx, T>; type BoundVars = &'tcx List; type BoundVar = ty::BoundVariableKind; type CanonicalVars = CanonicalVarInfos<'tcx>; + type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; + type DefiningOpaqueTypes = &'tcx ty::List; + type ExternalConstraints = ExternalConstraints<'tcx>; + type GoalEvaluationSteps = &'tcx [solve::inspect::GoalEvaluationStep>]; + type Ty = Ty<'tcx>; type Tys = &'tcx List>; type FnInputTys = &'tcx [Ty<'tcx>]; 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>)>, @@ -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, NoSolution> { 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> { 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, 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> var_values: &[ty::GenericArg<'tcx>], max_input_universe: ty::UniverseIndex, data: T, -) -> inspect::CanonicalState<'tcx, T> { +) -> inspect::CanonicalState, 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, orig_values: &mut Vec>, - state: inspect::CanonicalState<'tcx, T>, + state: inspect::CanonicalState, 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 dfb2bfc1b580a..7ca15c1dd5966 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -147,7 +147,8 @@ impl<'tcx> InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>) { + ) -> (Result<(bool, Certainty), NoSolution>, Option>>) + { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) @@ -170,7 +171,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { infcx: &InferCtxt<'tcx>, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R, - ) -> (R, Option>) { + ) -> (R, Option>>) { let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mut search_graph = search_graph::SearchGraph::new(mode); 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>, { 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>, { #[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(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind<'tcx>, + F: FnOnce(&T) -> inspect::ProbeKind>, { 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>, + > { 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>, + > { 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> { + goal: &'a inspect::InspectGoal<'a, 'tcx>, + ) -> Vec> { 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>, 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>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result, - evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>, + evaluation_kind: inspect::CanonicalGoalEvaluationKind>, normalizes_to_term_hack: Option>, 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>>, + kind: inspect::ProbeKind>, + nested_goals: + Vec<(GoalSource, inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>)>, + final_state: inspect::CanonicalState, ()>, + impl_args: Option, 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> { self.kind } @@ -280,9 +281,9 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates: &mut Vec>, nested_goals: &mut Vec<( GoalSource, - inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>, + inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>, )>, - probe: &inspect::Probe<'tcx>, + probe: &inspect::Probe>, ) { 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>, normalizes_to_term_hack: Option>, 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..90caa2b3af10d 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -80,7 +80,7 @@ struct WipGoalEvaluation<'tcx> { } impl<'tcx> WipGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::GoalEvaluation<'tcx> { + fn finalize(self) -> inspect::GoalEvaluation> { inspect::GoalEvaluation { uncanonicalized_goal: self.uncanonicalized_goal, kind: match self.kind { @@ -105,7 +105,7 @@ pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> { Overflow, CycleInStack, ProvisionalCacheHit, - Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] }, + Interned { revisions: &'tcx [inspect::GoalEvaluationStep>] }, } impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> { @@ -130,7 +130,7 @@ struct WipCanonicalGoalEvaluation<'tcx> { } impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> { + fn finalize(self) -> inspect::CanonicalGoalEvaluation> { assert!(self.revisions.is_empty()); let kind = match self.kind.unwrap() { WipCanonicalGoalEvaluationKind::Overflow => { @@ -158,7 +158,7 @@ struct WipAddedGoalsEvaluation<'tcx> { } impl<'tcx> WipAddedGoalsEvaluation<'tcx> { - fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> { + fn finalize(self) -> inspect::AddedGoalsEvaluation> { inspect::AddedGoalsEvaluation { evaluations: self .evaluations @@ -209,7 +209,7 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { } } - fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { + fn finalize(self) -> inspect::GoalEvaluationStep> { let evaluation = self.evaluation.finalize(); match evaluation.kind { inspect::ProbeKind::Root { .. } => (), @@ -223,12 +223,12 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { struct WipProbe<'tcx> { initial_num_var_values: usize, steps: Vec>, - kind: Option>, - final_state: Option>, + kind: Option>>, + final_state: Option, ()>>, } impl<'tcx> WipProbe<'tcx> { - fn finalize(self) -> inspect::Probe<'tcx> { + fn finalize(self) -> inspect::Probe> { inspect::Probe { steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(), kind: self.kind.unwrap(), @@ -239,15 +239,15 @@ impl<'tcx> WipProbe<'tcx> { #[derive(Eq, PartialEq, Debug)] enum WipProbeStep<'tcx> { - AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>), + AddGoal(GoalSource, inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>), EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), NestedProbe(WipProbe<'tcx>), MakeCanonicalResponse { shallow_certainty: Certainty }, - RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, + RecordImplArgs { impl_args: inspect::CanonicalState, ty::GenericArgsRef<'tcx>> }, } impl<'tcx> WipProbeStep<'tcx> { - fn finalize(self) -> inspect::ProbeStep<'tcx> { + fn finalize(self) -> inspect::ProbeStep> { match self { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), @@ -281,7 +281,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { nested } - pub fn finalize(self) -> Option> { + pub fn finalize(self) -> Option>> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) @@ -356,7 +356,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn finalize_evaluation( &mut self, tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> { + ) -> Option<&'tcx [inspect::GoalEvaluationStep>]> { self.as_mut().map(|this| match this { DebugSolver::CanonicalGoalEvaluation(evaluation) => { let revisions = mem::take(&mut evaluation.revisions) @@ -474,7 +474,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>) { match self.as_mut() { None => {} Some(DebugSolver::GoalEvaluationStep(state)) => { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 5a3c960d72da7..b085d009d75af 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -74,7 +74,7 @@ enum GoalEvaluationKind { } #[extension(trait CanonicalResponseExt)] -impl<'tcx> Canonical<'tcx, Response<'tcx>> { +impl<'tcx> Canonical<'tcx, Response>> { 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..24baa2b54739d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -108,7 +108,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/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>, a_region: ty::Region<'tcx>, b_data: &'tcx ty::List>, @@ -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/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 69865602584ce..47ad62105f276 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -5,6 +5,7 @@ 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, @@ -28,7 +29,6 @@ pub trait Interner: + IrPrint> { type DefId: Copy + Debug + Hash + Eq; - type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; @@ -44,6 +44,9 @@ pub trait Interner: type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; type PredefinedOpaques: Copy + Debug + Hash + Eq; + type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; + type ExternalConstraints: Copy + Debug + Hash + Eq; + type GoalEvaluationSteps: Copy + Debug + Hash + Eq + Deref]>; // Kinds of tys type Ty: Ty; diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 2a733dd02c2a6..ca8fedf8dad80 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -1,3 +1,5 @@ +pub mod inspect; + use std::fmt; use std::hash::Hash; @@ -5,7 +7,22 @@ use std::hash::Hash; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{Interner, NormalizesTo, Upcast}; +use crate::{Canonical, CanonicalVarValues, Interner, NormalizesTo, Upcast}; + +pub type CanonicalInput::Predicate> = Canonical>; +pub type CanonicalResponse = Canonical>; +/// 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 = Result, 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`. @@ -78,3 +95,184 @@ pub struct QueryInput { pub goal: Goal, 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 { + /// A user written impl. + /// + /// ## Examples + /// + /// ```rust + /// fn main() { + /// let x: Vec = Vec::new(); + /// // This uses the impl from the standard library to prove `Vec: 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(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(x: ::Assoc) { + /// // We prove `::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 }, + /// 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 { + pub certainty: Certainty, + pub var_values: CanonicalVarValues, + /// 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 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 { + pub var_values: CanonicalVarValues, pub data: T, } -pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>; +pub type CanonicalState = Canonical>; /// 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> }, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub enum GoalEvaluationKind { + Root { orig_values: Vec }, 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 { + pub uncanonicalized_goal: Goal, + pub kind: GoalEvaluationKind, + pub evaluation: CanonicalGoalEvaluation, } -#[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 { + pub goal: CanonicalInput, + pub kind: CanonicalGoalEvaluationKind, + pub result: QueryResult, } -#[derive(Eq, PartialEq, Debug)] -pub enum CanonicalGoalEvaluationKind<'tcx> { +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub enum CanonicalGoalEvaluationKind { Overflow, CycleInStack, ProvisionalCacheHit, - Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] }, + Evaluation { revisions: I::GoalEvaluationSteps }, } -impl Debug for GoalEvaluation<'_> { +impl Debug for GoalEvaluation { 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>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))] +pub struct AddedGoalsEvaluation { + pub evaluations: Vec>>, pub result: Result, } -#[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 { + pub instantiated_goal: QueryInput, /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: Probe<'tcx>, + pub evaluation: Probe, } /// 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 { /// What happened inside of this probe in chronological order. - pub steps: Vec>, - pub kind: ProbeKind<'tcx>, - pub final_state: CanonicalState<'tcx, ()>, + pub steps: Vec>, + pub kind: ProbeKind, + pub final_state: CanonicalState, } -impl Debug for Probe<'_> { +impl Debug for Probe { 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 { /// 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>), /// The inside of a `EvalCtxt::try_evaluate_added_goals` call. - EvaluateGoals(AddedGoalsEvaluation<'tcx>), + EvaluateGoals(AddedGoalsEvaluation), /// 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), /// A trait goal was satisfied by an impl candidate. - RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, + RecordImplArgs { impl_args: CanonicalState }, /// 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 { /// The root inference context while proving a goal. - Root { result: QueryResult<'tcx> }, + Root { result: QueryResult }, /// Trying to normalize an alias by at least one step in `NormalizesTo`. - TryNormalizeNonRigid { result: QueryResult<'tcx> }, + TryNormalizeNonRigid { result: QueryResult }, /// 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, result: QueryResult }, /// 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 }, } 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, } 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(&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) -> 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, ) -> 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, ) -> 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) -> 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, ) -> std::fmt::Result { writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?; From 6ee22e184f210642ced80e24cf3c10f9166b8a39 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 May 2024 12:43:05 -0400 Subject: [PATCH 3/5] Make proof tree building generic --- Cargo.lock | 2 + compiler/rustc_trait_selection/Cargo.toml | 2 + .../src/solve/eval_ctxt/mod.rs | 6 +- .../src/solve/inspect/build.rs | 190 ++++++++++-------- .../src/solve/search_graph.rs | 4 +- 5 files changed, 111 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 536f49989fa05..75980bb570c1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4759,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", @@ -4778,6 +4779,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_transmute", + "rustc_type_ir", "smallvec", "tracing", ] diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 811eb4c98104e..c18f35a75171f 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" } @@ -25,6 +26,7 @@ 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" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end 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 7ca15c1dd5966..02064f31ef879 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -95,7 +95,7 @@ pub struct EvalCtxt<'a, 'tcx> { // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder<'tcx>, + pub(super) inspect: ProofTreeBuilder>, } #[derive(derivative::Derivative)] @@ -225,7 +225,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>, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, ) -> R { let intercrate = match search_graph.solver_mode() { @@ -287,7 +287,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>, ) -> QueryResult<'tcx> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 90caa2b3af10d..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>>, +pub(in crate::solve) struct ProofTreeBuilder { + state: Option>>, } /// 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 { Root, - GoalEvaluation(WipGoalEvaluation<'tcx>), - CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>), - GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), + GoalEvaluation(WipGoalEvaluation), + CanonicalGoalEvaluation(WipCanonicalGoalEvaluation), + GoalEvaluationStep(WipGoalEvaluationStep), } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { +impl From> for DebugSolver { + fn from(g: WipGoalEvaluation) -> DebugSolver { DebugSolver::GoalEvaluation(g) } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipCanonicalGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { +impl From> for DebugSolver { + fn from(g: WipCanonicalGoalEvaluation) -> DebugSolver { DebugSolver::CanonicalGoalEvaluation(g) } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> { +impl From> for DebugSolver { + fn from(g: WipGoalEvaluationStep) -> DebugSolver { 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>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipGoalEvaluation { + pub uncanonicalized_goal: Goal, + pub kind: WipGoalEvaluationKind, + pub evaluation: Option>, } -impl<'tcx> WipGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::GoalEvaluation> { +impl WipGoalEvaluation { + fn finalize(self) -> inspect::GoalEvaluation { 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> }, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +pub(in crate::solve) enum WipGoalEvaluationKind { + Root { orig_values: Vec }, 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 { Overflow, CycleInStack, ProvisionalCacheHit, - Interned { revisions: &'tcx [inspect::GoalEvaluationStep>] }, + Interned { revisions: I::GoalEvaluationSteps }, } -impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> { +impl std::fmt::Debug for WipCanonicalGoalEvaluationKind { 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>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipCanonicalGoalEvaluation { + goal: CanonicalInput, + kind: Option>, /// Only used for uncached goals. After we finished evaluating /// the goal, this is interned and moved into `kind`. - revisions: Vec>, - result: Option>, + revisions: Vec>, + result: Option>, } -impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { - fn finalize(self) -> inspect::CanonicalGoalEvaluation> { +impl WipCanonicalGoalEvaluation { + fn finalize(self) -> inspect::CanonicalGoalEvaluation { 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>>, +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +struct WipAddedGoalsEvaluation { + evaluations: Vec>>, result: Option>, } -impl<'tcx> WipAddedGoalsEvaluation<'tcx> { - fn finalize(self) -> inspect::AddedGoalsEvaluation> { +impl WipAddedGoalsEvaluation { + fn finalize(self) -> inspect::AddedGoalsEvaluation { 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 { /// 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>, - instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + var_values: Vec, + instantiated_goal: QueryInput, probe_depth: usize, - evaluation: WipProbe<'tcx>, + evaluation: WipProbe, } -impl<'tcx> WipGoalEvaluationStep<'tcx> { - fn current_evaluation_scope(&mut self) -> &mut WipProbe<'tcx> { +impl WipGoalEvaluationStep { + fn current_evaluation_scope(&mut self) -> &mut WipProbe { 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 { 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> { + fn finalize(self) -> inspect::GoalEvaluationStep { 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 { initial_num_var_values: usize, - steps: Vec>, - kind: Option>>, - final_state: Option, ()>>, + steps: Vec>, + kind: Option>, + final_state: Option>, } -impl<'tcx> WipProbe<'tcx> { - fn finalize(self) -> inspect::Probe> { +impl WipProbe { + fn finalize(self) -> inspect::Probe { 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, Goal<'tcx, ty::Predicate<'tcx>>>), - EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), - NestedProbe(WipProbe<'tcx>), +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +enum WipProbeStep { + AddGoal(GoalSource, inspect::CanonicalState>), + EvaluateGoals(WipAddedGoalsEvaluation), + NestedProbe(WipProbe), MakeCanonicalResponse { shallow_certainty: Certainty }, - RecordImplArgs { impl_args: inspect::CanonicalState, ty::GenericArgsRef<'tcx>> }, + RecordImplArgs { impl_args: inspect::CanonicalState }, } -impl<'tcx> WipProbeStep<'tcx> { - fn finalize(self) -> inspect::ProbeStep> { +impl WipProbeStep { + fn finalize(self) -> inspect::ProbeStep { match self { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), @@ -262,20 +272,21 @@ impl<'tcx> WipProbeStep<'tcx> { } } -impl<'tcx> ProofTreeBuilder<'tcx> { - fn new(state: impl Into>) -> ProofTreeBuilder<'tcx> { +// FIXME: Genericize this impl. +impl<'tcx> ProofTreeBuilder> { + fn new(state: impl Into>>) -> ProofTreeBuilder> { ProofTreeBuilder { state: Some(Box::new(state.into())) } } - fn nested>>(&self, state: impl FnOnce() -> T) -> Self { + fn nested>>>(&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>> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<'tcx> { + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder> { let mut nested = ProofTreeBuilder { state: self.state.take() }; nested.enter_probe(); nested @@ -293,7 +304,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { pub fn new_maybe_root( tcx: TyCtxt<'tcx>, generate_proof_tree: GenerateProofTree, - ) -> ProofTreeBuilder<'tcx> { + ) -> ProofTreeBuilder> { 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> { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder<'tcx> { + pub fn new_noop() -> ProofTreeBuilder> { 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, ty::Predicate<'tcx>>, orig_values: &[ty::GenericArg<'tcx>], kind: solve::GoalEvaluationKind, - ) -> ProofTreeBuilder<'tcx> { + ) -> ProofTreeBuilder> { 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>, + ) -> ProofTreeBuilder> { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -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>, + ) { 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>) { 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>) { 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, ty::Predicate<'tcx>>, + ) -> ProofTreeBuilder> { 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>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -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, 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, 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> { 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>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { 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>, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { // Check for overflow. let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { From 2ed1bdb479a049757081076bcf5533734e15a9d1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 May 2024 17:47:55 -0400 Subject: [PATCH 4/5] Stop using def_kind() in solver --- .../src/solve/normalizes_to/mod.rs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) 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 24baa2b54739d..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), } } From 8e1dba46176c936344adf9130fbee628f7461a8f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 May 2024 16:05:16 -0400 Subject: [PATCH 5/5] Move NormalizesTo back down I tried to rebase this down into the first commit but it is WAY too annoying x --- Cargo.lock | 2 ++ compiler/rustc_trait_selection/Cargo.toml | 2 ++ .../rustc_trait_selection/src/solve/eval_ctxt/mod.rs | 12 +++++++----- compiler/rustc_type_ir/src/solve.rs | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75980bb570c1d..186892af21c06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4775,11 +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_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index c18f35a75171f..1f4fb57d996cc 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -22,11 +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/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 02064f31ef879..70308d4359d22 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -11,11 +11,11 @@ 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, CanonicalInput, CanonicalResponse, Certainty, NestedGoals, PredefinedOpaques, + inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::specialization_graph; @@ -25,6 +25,8 @@ use rustc_middle::ty::{ }; use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; +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}; @@ -101,7 +103,7 @@ pub struct EvalCtxt<'a, 'tcx> { #[derive(derivative::Derivative)] #[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[derive(TyDecodable, TyEncodable, HashStable_NoContext)] // FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate. pub struct NestedGoals { /// These normalizes-to goals are treated specially during the evaluation @@ -114,9 +116,9 @@ pub struct NestedGoals { /// /// Forgetting to replace the RHS with a fresh inference variable when we evaluate /// this goal results in an ICE.. - pub normalizes_to_goals: Vec>>, + pub normalizes_to_goals: Vec>>, /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, Goal)>, + pub goals: Vec<(GoalSource, ir::solve::Goal)>, } impl NestedGoals { diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index ca8fedf8dad80..3c24e851d7b63 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -7,7 +7,7 @@ use std::hash::Hash; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{Canonical, CanonicalVarValues, Interner, NormalizesTo, Upcast}; +use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; pub type CanonicalInput::Predicate> = Canonical>; pub type CanonicalResponse = Canonical>;