Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lib.rs')
-rw-r--r--crates/hir-ty/src/lib.rs903
1 files changed, 236 insertions, 667 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index e787fd9b1e..25579e04ed 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -3,35 +3,32 @@
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_index;
+// FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but
+// temporarily switched to crates.io versions due to hardships that working on them from rustc
+// demands corresponding changes on rust-analyzer at the same time.
+// For details, see the zulip discussion below:
+// https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/relying.20on.20in-tree.20.60rustc_type_ir.60.2F.60rustc_next_trait_solver.60/with/541055689
-#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_index as rustc_index;
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_abi;
-
-#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_abi as rustc_abi;
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_pattern_analysis;
-
-#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
-mod builder;
-mod chalk_db;
-mod chalk_ext;
-mod drop;
+extern crate ra_ap_rustc_ast_ir as rustc_ast_ir;
+
+extern crate ra_ap_rustc_type_ir as rustc_type_ir;
+
+extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
+
+extern crate self as hir_ty;
+
mod infer;
mod inhabitedness;
-mod interner;
mod lower;
-mod mapping;
+pub mod next_solver;
+mod specialization;
mod target_feature;
-mod tls;
mod utils;
pub mod autoderef;
@@ -39,6 +36,7 @@ pub mod consteval;
pub mod db;
pub mod diagnostics;
pub mod display;
+pub mod drop;
pub mod dyn_compatibility;
pub mod generics;
pub mod lang_items;
@@ -56,160 +54,70 @@ mod variance;
use std::hash::Hash;
-use chalk_ir::{
- NoSolution,
- fold::{Shift, TypeFoldable},
- interner::HasInterner,
-};
-use either::Either;
-use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness};
+use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness};
use hir_expand::name::Name;
use indexmap::{IndexMap, map::Entry};
use intern::{Symbol, sym};
-use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
+use rustc_type_ir::{
+ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
+ inherent::{IntoKind, SliceLike, Ty as _},
+};
use syntax::ast::{ConstArg, make};
use traits::FnTrait;
use triomphe::Arc;
use crate::{
- consteval::unknown_const,
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
- generics::Generics,
infer::unify::InferenceTable,
+ next_solver::{
+ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical,
+ CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, PolyFnSig, Predicate,
+ Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
+ },
};
pub use autoderef::autoderef;
-pub use builder::{ParamKind, TyBuilder};
-pub use chalk_ext::*;
-pub use drop::DropGlue;
pub use infer::{
Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult,
InferenceTyDiagnosticSource, OverloadedDeref, PointerCast,
cast::CastError,
- closure::{CaptureKind, CapturedItem},
+ closure::analysis::{CaptureKind, CapturedItem},
could_coerce, could_unify, could_unify_deeply,
};
-pub use interner::Interner;
pub use lower::{
- ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext,
- ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*,
-};
-pub use mapping::{
- ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
- lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
- to_foreign_def_id, to_placeholder_idx,
+ LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId,
+ associated_type_shorthand_candidates, diagnostics::*,
};
pub use method_resolution::check_orphan_rules;
+pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
pub use target_feature::TargetFeatures;
pub use traits::TraitEnvironment;
-pub use utils::{Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call};
-pub use variance::Variance;
-
-pub use chalk_ir::{
- AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
- cast::Cast,
- visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+pub use utils::{
+ TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits,
+ is_fn_unsafe_to_call, target_feature_is_safe_in_target,
};
-pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
-pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
-pub type FnDefId = chalk_ir::FnDefId<Interner>;
-pub type ClosureId = chalk_ir::ClosureId<Interner>;
-pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
-pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
-
-pub type VariableKind = chalk_ir::VariableKind<Interner>;
-pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
-pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
-/// Represents generic parameters and an item bound by them. When the item has parent, the binders
-/// also contain the generic parameters for its parent. See chalk's documentation for details.
-///
-/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
-/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
-/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
-/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
-/// motivation in detail.
-pub type Binders<T> = chalk_ir::Binders<T>;
-/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
-/// it contains generic arguments for both its parent and itself. See chalk's documentation for
-/// details.
-///
-/// See `Binders` for the constraint on the ordering.
-pub type Substitution = chalk_ir::Substitution<Interner>;
-pub type GenericArg = chalk_ir::GenericArg<Interner>;
-pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
-
-pub type Ty = chalk_ir::Ty<Interner>;
-pub type TyKind = chalk_ir::TyKind<Interner>;
-pub type TypeFlags = chalk_ir::TypeFlags;
-pub type DynTy = chalk_ir::DynTy<Interner>;
-pub type FnPointer = chalk_ir::FnPointer<Interner>;
-// pub type FnSubst = chalk_ir::FnSubst<Interner>; // a re-export so we don't lose the tuple constructor
-pub use chalk_ir::FnSubst;
-pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
-pub type AliasTy = chalk_ir::AliasTy<Interner>;
-pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
-pub type InferenceVar = chalk_ir::InferenceVar;
-
-pub type Lifetime = chalk_ir::Lifetime<Interner>;
-pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
-pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
-
-pub type Const = chalk_ir::Const<Interner>;
-pub type ConstData = chalk_ir::ConstData<Interner>;
-pub type ConstValue = chalk_ir::ConstValue<Interner>;
-pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
-
-pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
-pub type TraitRef = chalk_ir::TraitRef<Interner>;
-pub type QuantifiedWhereClause = Binders<WhereClause>;
-pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
-pub type Canonical<T> = chalk_ir::Canonical<T>;
-
-pub type FnSig = chalk_ir::FnSig<Interner>;
-
-pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
-pub type Environment = chalk_ir::Environment<Interner>;
-pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
-pub type Goal = chalk_ir::Goal<Interner>;
-pub type AliasEq = chalk_ir::AliasEq<Interner>;
-pub type Solution = chalk_solve::Solution<Interner>;
-pub type Constraint = chalk_ir::Constraint<Interner>;
-pub type Constraints = chalk_ir::Constraints<Interner>;
-pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
-pub type Guidance = chalk_solve::Guidance<Interner>;
-pub type WhereClause = chalk_ir::WhereClause<Interner>;
-
-pub type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>;
-pub type GoalData = chalk_ir::GoalData<Interner>;
-pub type Goals = chalk_ir::Goals<Interner>;
-pub type ProgramClauseData = chalk_ir::ProgramClauseData<Interner>;
-pub type ProgramClause = chalk_ir::ProgramClause<Interner>;
-pub type ProgramClauses = chalk_ir::ProgramClauses<Interner>;
-pub type TyData = chalk_ir::TyData<Interner>;
-pub type Variances = chalk_ir::Variances<Interner>;
-
/// A constant can have reference to other things. Memory map job is holding
/// the necessary bits of memory of the const eval session to keep the constant
/// meaningful.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
-pub enum MemoryMap {
+pub enum MemoryMap<'db> {
#[default]
Empty,
Simple(Box<[u8]>),
- Complex(Box<ComplexMemoryMap>),
+ Complex(Box<ComplexMemoryMap<'db>>),
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
-pub struct ComplexMemoryMap {
+pub struct ComplexMemoryMap<'db> {
memory: IndexMap<usize, Box<[u8]>, FxBuildHasher>,
- vtable: VTableMap,
+ vtable: VTableMap<'db>,
}
-impl ComplexMemoryMap {
+impl ComplexMemoryMap<'_> {
fn insert(&mut self, addr: usize, val: Box<[u8]>) {
match self.memory.entry(addr) {
Entry::Occupied(mut e) => {
@@ -224,8 +132,8 @@ impl ComplexMemoryMap {
}
}
-impl MemoryMap {
- pub fn vtable_ty(&self, id: usize) -> Result<&Ty, MirEvalError> {
+impl<'db> MemoryMap<'db> {
+ pub fn vtable_ty(&self, id: usize) -> Result<Ty<'db>, MirEvalError<'db>> {
match self {
MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)),
MemoryMap::Complex(cm) => cm.vtable.ty(id),
@@ -241,8 +149,8 @@ impl MemoryMap {
/// allocator function as `f` and it will return a mapping of old addresses to new addresses.
fn transform_addresses(
&self,
- mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError>,
- ) -> Result<FxHashMap<usize, usize>, MirEvalError> {
+ mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError<'db>>,
+ ) -> Result<FxHashMap<usize, usize>, MirEvalError<'db>> {
let mut transform = |(addr, val): (&usize, &[u8])| {
let addr = *addr;
let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) };
@@ -275,112 +183,11 @@ impl MemoryMap {
}
}
-/// A concrete constant value
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstScalar {
- Bytes(Box<[u8]>, MemoryMap),
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- UnevaluatedConst(GeneralConstId, Substitution),
- /// Case of an unknown value that rustc might know but we don't
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
- // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
- Unknown,
-}
-
-impl Hash for ConstScalar {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- core::mem::discriminant(self).hash(state);
- if let ConstScalar::Bytes(b, _) = self {
- b.hash(state)
- }
- }
-}
-
/// Return an index of a parameter in the generic type parameter list by it's id.
pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
generics::generics(db, id.parent).type_or_const_param_idx(id)
}
-pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
-where
- T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
-{
- Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
-}
-
-pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
- which_is_const: impl Iterator<Item = Option<Ty>>,
- value: T,
-) -> Binders<T> {
- Binders::new(
- VariableKinds::from_iter(
- Interner,
- which_is_const.map(|x| {
- if let Some(ty) = x {
- chalk_ir::VariableKind::Const(ty)
- } else {
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
- }
- }),
- ),
- value,
- )
-}
-
-pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
- value: T,
-) -> Binders<T> {
- Binders::new(
- VariableKinds::from_iter(
- Interner,
- std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
- ),
- value,
- )
-}
-
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
- db: &dyn HirDatabase,
- generics: &Generics,
- value: T,
-) -> Binders<T> {
- Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value)
-}
-
-pub(crate) fn variable_kinds_from_iter(
- db: &dyn HirDatabase,
- iter: impl Iterator<Item = hir_def::GenericParamId>,
-) -> VariableKinds {
- VariableKinds::from_iter(
- Interner,
- iter.map(|x| match x {
- hir_def::GenericParamId::ConstParamId(id) => {
- chalk_ir::VariableKind::Const(db.const_param_ty(id))
- }
- hir_def::GenericParamId::TypeParamId(_) => {
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
- }
- hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
- }),
- )
-}
-
-// FIXME: get rid of this, just replace it by FnPointer
-/// A function signature as seen by type inference: Several parameter types and
-/// one return type.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct CallableSig {
- params_and_return: Arc<[Ty]>,
- is_varargs: bool,
- safety: Safety,
- abi: FnAbi,
-}
-
-has_interner!(CallableSig);
-
#[derive(Debug, Copy, Clone, Eq)]
pub enum FnAbi {
Aapcs,
@@ -524,371 +331,151 @@ impl FnAbi {
}
}
-/// A polymorphic function signature.
-pub type PolyFnSig = Binders<CallableSig>;
-
-impl CallableSig {
- pub fn from_params_and_return(
- params: impl Iterator<Item = Ty>,
- ret: Ty,
- is_varargs: bool,
- safety: Safety,
- abi: FnAbi,
- ) -> CallableSig {
- let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1);
- params_and_return.extend(params);
- params_and_return.push(ret);
- CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
- }
-
- pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
- let callable_def = ToChalk::from_chalk(db, def);
- let sig = db.callable_item_signature(callable_def);
- sig.substitute(Interner, substs)
- }
- pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
- CallableSig {
- // FIXME: what to do about lifetime params? -> return PolyFnSig
- params_and_return: Arc::from_iter(
- fn_ptr
- .substitution
- .clone()
- .shifted_out_to(Interner, DebruijnIndex::ONE)
- .expect("unexpected lifetime vars in fn ptr")
- .0
- .as_slice(Interner)
- .iter()
- .map(|arg| arg.assert_ty_ref(Interner).clone()),
- ),
- is_varargs: fn_ptr.sig.variadic,
- safety: fn_ptr.sig.safety,
- abi: fn_ptr.sig.abi,
- }
- }
-
- pub fn to_fn_ptr(&self) -> FnPointer {
- FnPointer {
- num_binders: 0,
- sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs },
- substitution: FnSubst(Substitution::from_iter(
- Interner,
- self.params_and_return.iter().cloned(),
- )),
- }
- }
-
- pub fn abi(&self) -> FnAbi {
- self.abi
- }
-
- pub fn params(&self) -> &[Ty] {
- &self.params_and_return[0..self.params_and_return.len() - 1]
- }
-
- pub fn ret(&self) -> &Ty {
- &self.params_and_return[self.params_and_return.len() - 1]
- }
-}
-
-impl TypeFoldable<Interner> for CallableSig {
- fn try_fold_with<E>(
- self,
- folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
- outer_binder: DebruijnIndex,
- ) -> Result<Self, E> {
- let vec = self.params_and_return.to_vec();
- let folded = vec.try_fold_with(folder, outer_binder)?;
- Ok(CallableSig {
- params_and_return: folded.into(),
- is_varargs: self.is_varargs,
- safety: self.safety,
- abi: self.abi,
- })
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub enum ImplTraitId {
- ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
- TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
- AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
-}
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTraits {
- pub(crate) impl_traits: Arena<ImplTrait>,
-}
-
-has_interner!(ImplTraits);
-
-#[derive(PartialEq, Eq, Debug, Hash)]
-pub struct ImplTrait {
- pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
-}
-
-pub type ImplTraitIdx = Idx<ImplTrait>;
-
-pub fn static_lifetime() -> Lifetime {
- LifetimeData::Static.intern(Interner)
-}
-
-pub fn error_lifetime() -> Lifetime {
- LifetimeData::Error.intern(Interner)
-}
-
-pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
- t: T,
- for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
- for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
-) -> T {
- use chalk_ir::fold::TypeFolder;
-
- #[derive(chalk_derive::FallibleTypeFolder)]
- #[has_interner(Interner)]
- struct FreeVarFolder<
- F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
- F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
- >(F1, F2);
- impl<F1: FnMut(BoundVar, DebruijnIndex) -> Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const>
- TypeFolder<Interner> for FreeVarFolder<F1, F2>
- {
- fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
- self.0(bound_var, outer_binder)
- }
-
- fn fold_free_var_const(
- &mut self,
- ty: Ty,
- bound_var: BoundVar,
- outer_binder: DebruijnIndex,
- ) -> Const {
- self.1(ty, bound_var, outer_binder)
- }
- }
- t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
-}
-
-pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
- t: T,
- mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
- binders: DebruijnIndex,
-) -> T {
- fold_tys_and_consts(
- t,
- |x, d| match x {
- Either::Left(x) => Either::Left(for_ty(x, d)),
- Either::Right(x) => Either::Right(x),
- },
- binders,
- )
-}
-
-pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
- t: T,
- f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
- binders: DebruijnIndex,
-) -> T {
- use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
- #[derive(chalk_derive::FallibleTypeFolder)]
- #[has_interner(Interner)]
- struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
- impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
- for TyFolder<F>
- {
- fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
- let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
- self.0(Either::Left(ty), outer_binder).left().unwrap()
- }
-
- fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
- self.0(Either::Right(c), outer_binder).right().unwrap()
- }
- }
- t.fold_with(&mut TyFolder(f), binders)
-}
-
-pub(crate) fn fold_generic_args<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
- t: T,
- f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData,
- binders: DebruijnIndex,
-) -> T {
- use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
- #[derive(chalk_derive::FallibleTypeFolder)]
- #[has_interner(Interner)]
- struct TyFolder<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData>(F);
- impl<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData> TypeFolder<Interner>
- for TyFolder<F>
- {
- fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
- let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
- self.0(GenericArgData::Ty(ty), outer_binder)
- .intern(Interner)
- .ty(Interner)
- .unwrap()
- .clone()
- }
-
- fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
- self.0(GenericArgData::Const(c), outer_binder)
- .intern(Interner)
- .constant(Interner)
- .unwrap()
- .clone()
- }
-
- fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime {
- let lt = lt.super_fold_with(self.as_dyn(), outer_binder);
- self.0(GenericArgData::Lifetime(lt), outer_binder)
- .intern(Interner)
- .lifetime(Interner)
- .unwrap()
- .clone()
- }
- }
- t.fold_with(&mut TyFolder(f), binders)
+pub enum ImplTraitId<'db> {
+ ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>),
+ TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>),
}
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
/// ensures there are no unbound variables or inference variables anywhere in
/// the `t`.
-pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
+pub fn replace_errors_with_variables<'db, T>(interner: DbInterner<'db>, t: &T) -> Canonical<'db, T>
where
- T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
+ T: rustc_type_ir::TypeFoldable<DbInterner<'db>> + Clone,
{
- use chalk_ir::{
- Fallible,
- fold::{FallibleTypeFolder, TypeSuperFoldable},
- };
- struct ErrorReplacer {
- vars: usize,
+ use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable};
+ struct ErrorReplacer<'db> {
+ interner: DbInterner<'db>,
+ vars: Vec<CanonicalVarKind<'db>>,
+ binder: rustc_type_ir::DebruijnIndex,
}
- impl FallibleTypeFolder<Interner> for ErrorReplacer {
- type Error = NoSolution;
-
- fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
- if let TyKind::Error = ty.kind(Interner) {
- let index = self.vars;
- self.vars += 1;
- Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
- } else {
- ty.try_super_fold_with(self.as_dyn(), outer_binder)
+ impl<'db> FallibleTypeFolder<DbInterner<'db>> for ErrorReplacer<'db> {
+ #[cfg(debug_assertions)]
+ type Error = ();
+ #[cfg(not(debug_assertions))]
+ type Error = std::convert::Infallible;
+
+ fn cx(&self) -> DbInterner<'db> {
+ self.interner
+ }
+
+ fn try_fold_binder<T>(&mut self, t: Binder<'db, T>) -> Result<Binder<'db, T>, Self::Error>
+ where
+ T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
+ {
+ self.binder.shift_in(1);
+ let result = t.try_super_fold_with(self);
+ self.binder.shift_out(1);
+ result
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
+ if !t.has_type_flags(
+ rustc_type_ir::TypeFlags::HAS_ERROR
+ | rustc_type_ir::TypeFlags::HAS_TY_INFER
+ | rustc_type_ir::TypeFlags::HAS_CT_INFER
+ | rustc_type_ir::TypeFlags::HAS_RE_INFER,
+ ) {
+ return Ok(t);
}
- }
- fn try_fold_inference_ty(
- &mut self,
- _var: InferenceVar,
- _kind: TyVariableKind,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Ty> {
- if cfg!(debug_assertions) {
- // we don't want to just panic here, because then the error message
- // won't contain the whole thing, which would not be very helpful
- Err(NoSolution)
- } else {
- Ok(TyKind::Error.intern(Interner))
+ #[cfg(debug_assertions)]
+ let error = || Err(());
+ #[cfg(not(debug_assertions))]
+ let error = || Ok(Ty::new_error(self.interner, crate::next_solver::ErrorGuaranteed));
+
+ match t.kind() {
+ TyKind::Error(_) => {
+ let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
+ self.vars.push(CanonicalVarKind::Ty {
+ ui: rustc_type_ir::UniverseIndex::ZERO,
+ sub_root: var,
+ });
+ Ok(Ty::new_bound(
+ self.interner,
+ self.binder,
+ BoundTy { var, kind: BoundTyKind::Anon },
+ ))
+ }
+ TyKind::Infer(_) => error(),
+ TyKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => error(),
+ _ => t.try_super_fold_with(self),
}
}
- fn try_fold_free_var_ty(
- &mut self,
- _bound_var: BoundVar,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Ty> {
- if cfg!(debug_assertions) {
- // we don't want to just panic here, because then the error message
- // won't contain the whole thing, which would not be very helpful
- Err(NoSolution)
- } else {
- Ok(TyKind::Error.intern(Interner))
+ fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
+ if !ct.has_type_flags(
+ rustc_type_ir::TypeFlags::HAS_ERROR
+ | rustc_type_ir::TypeFlags::HAS_TY_INFER
+ | rustc_type_ir::TypeFlags::HAS_CT_INFER
+ | rustc_type_ir::TypeFlags::HAS_RE_INFER,
+ ) {
+ return Ok(ct);
}
- }
- fn try_fold_inference_const(
- &mut self,
- ty: Ty,
- _var: InferenceVar,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Const> {
- if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
- }
-
- fn try_fold_free_var_const(
- &mut self,
- ty: Ty,
- _bound_var: BoundVar,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Const> {
- if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
- }
+ #[cfg(debug_assertions)]
+ let error = || Err(());
+ #[cfg(not(debug_assertions))]
+ let error = || Ok(Const::error(self.interner));
- fn try_fold_inference_lifetime(
- &mut self,
- _var: InferenceVar,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Lifetime> {
- if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) }
+ match ct.kind() {
+ ConstKind::Error(_) => {
+ let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
+ self.vars.push(CanonicalVarKind::Const(rustc_type_ir::UniverseIndex::ZERO));
+ Ok(Const::new_bound(self.interner, self.binder, BoundConst { var }))
+ }
+ ConstKind::Infer(_) => error(),
+ ConstKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+ error()
+ }
+ _ => ct.try_super_fold_with(self),
+ }
}
- fn try_fold_free_var_lifetime(
- &mut self,
- _bound_var: BoundVar,
- _outer_binder: DebruijnIndex,
- ) -> Fallible<Lifetime> {
- if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) }
+ fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
+ #[cfg(debug_assertions)]
+ let error = || Err(());
+ #[cfg(not(debug_assertions))]
+ let error = || Ok(Region::error(self.interner));
+
+ match region.kind() {
+ RegionKind::ReError(_) => {
+ let var = rustc_type_ir::BoundVar::from_usize(self.vars.len());
+ self.vars.push(CanonicalVarKind::Region(rustc_type_ir::UniverseIndex::ZERO));
+ Ok(Region::new_bound(
+ self.interner,
+ self.binder,
+ BoundRegion { var, kind: BoundRegionKind::Anon },
+ ))
+ }
+ RegionKind::ReVar(_) => error(),
+ RegionKind::ReBound(BoundVarIndexKind::Bound(index), _) if index > self.binder => {
+ error()
+ }
+ _ => Ok(region),
+ }
}
}
- let mut error_replacer = ErrorReplacer { vars: 0 };
- let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
+
+ let mut error_replacer =
+ ErrorReplacer { vars: Vec::new(), binder: rustc_type_ir::DebruijnIndex::ZERO, interner };
+ let value = match t.clone().try_fold_with(&mut error_replacer) {
Ok(t) => t,
Err(_) => panic!("Encountered unbound or inference vars in {t:?}"),
};
- let kinds = (0..error_replacer.vars).map(|_| {
- chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Ty(TyVariableKind::General),
- chalk_ir::UniverseIndex::ROOT,
- )
- });
- Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
+ Canonical {
+ value,
+ max_universe: rustc_type_ir::UniverseIndex::ZERO,
+ variables: CanonicalVars::new_from_iter(interner, error_replacer.vars),
+ }
}
-pub fn callable_sig_from_fn_trait(
- self_ty: &Ty,
- trait_env: Arc<TraitEnvironment>,
- db: &dyn HirDatabase,
-) -> Option<(FnTrait, CallableSig)> {
+pub fn callable_sig_from_fn_trait<'db>(
+ self_ty: Ty<'db>,
+ trait_env: Arc<TraitEnvironment<'db>>,
+ db: &'db dyn HirDatabase,
+) -> Option<(FnTrait, PolyFnSig<'db>)> {
let krate = trait_env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
let output_assoc_type = fn_once_trait
@@ -896,57 +483,48 @@ pub fn callable_sig_from_fn_trait(
.associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
let mut table = InferenceTable::new(db, trait_env.clone());
- let b = TyBuilder::trait_ref(db, fn_once_trait);
- if b.remaining() != 2 {
- return None;
- }
// Register two obligations:
// - Self: FnOnce<?args_ty>
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
- let args_ty = table.new_type_var();
- let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
- let projection = TyBuilder::assoc_type_projection(
- db,
- output_assoc_type,
- Some(trait_ref.substitution.clone()),
- )
- .build();
-
- let block = trait_env.block;
- let trait_env = trait_env.env.clone();
- let obligation =
- InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() };
- let canonical = table.canonicalize(obligation.clone());
- if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
- table.register_obligation(obligation.goal);
- let return_ty = table.normalize_projection_ty(projection);
+ let args_ty = table.next_ty_var();
+ let args = [self_ty, args_ty];
+ let trait_ref = TraitRef::new(table.interner(), fn_once_trait.into(), args);
+ let projection = Ty::new_alias(
+ table.interner(),
+ rustc_type_ir::AliasTyKind::Projection,
+ AliasTy::new(table.interner(), output_assoc_type.into(), args),
+ );
+
+ let pred = Predicate::upcast_from(trait_ref, table.interner());
+ if !table.try_obligation(pred).no_solution() {
+ table.register_obligation(pred);
+ let return_ty = table.normalize_alias_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
let fn_x_trait = fn_x.get_id(db, krate)?;
- trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
- let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
- goal: trait_ref.clone().cast(Interner),
- environment: trait_env.clone(),
- };
- let canonical = table.canonicalize(obligation.clone());
- if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
+ let trait_ref = TraitRef::new(table.interner(), fn_x_trait.into(), args);
+ if !table
+ .try_obligation(Predicate::upcast_from(trait_ref, table.interner()))
+ .no_solution()
+ {
let ret_ty = table.resolve_completely(return_ty);
let args_ty = table.resolve_completely(args_ty);
- let params = args_ty
- .as_tuple()?
- .iter(Interner)
- .map(|it| it.assert_ty_ref(Interner))
- .cloned();
+ let TyKind::Tuple(params) = args_ty.kind() else {
+ return None;
+ };
+ let inputs_and_output = Tys::new_from_iter(
+ table.interner(),
+ params.iter().chain(std::iter::once(ret_ty)),
+ );
return Some((
fn_x,
- CallableSig::from_params_and_return(
- params,
- ret_ty,
- false,
- Safety::Safe,
- FnAbi::RustCall,
- ),
+ Binder::dummy(FnSig {
+ inputs_and_output,
+ c_variadic: false,
+ safety: abi::Safety::Safe,
+ abi: FnAbi::RustCall,
+ }),
));
}
}
@@ -956,74 +534,43 @@ pub fn callable_sig_from_fn_trait(
}
}
-struct PlaceholderCollector<'db> {
- db: &'db dyn HirDatabase,
- placeholders: FxHashSet<TypeOrConstParamId>,
-}
-
-impl PlaceholderCollector<'_> {
- fn collect(&mut self, idx: PlaceholderIndex) {
- let id = from_placeholder_idx(self.db, idx);
- self.placeholders.insert(id);
- }
+struct ParamCollector {
+ params: FxHashSet<TypeOrConstParamId>,
}
-impl TypeVisitor<Interner> for PlaceholderCollector<'_> {
- type BreakTy = ();
-
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn visit_ty(
- &mut self,
- ty: &Ty,
- outer_binder: DebruijnIndex,
- ) -> std::ops::ControlFlow<Self::BreakTy> {
- let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER;
- let TyData { kind, flags } = ty.data(Interner);
+impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for ParamCollector {
+ type Result = ();
- if let TyKind::Placeholder(idx) = kind {
- self.collect(*idx);
- } else if flags.intersects(has_placeholder_bits) {
- return ty.super_visit_with(self, outer_binder);
- } else {
- // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate
- // that there are no placeholders.
+ fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result {
+ if let TyKind::Param(param) = ty.kind() {
+ self.params.insert(param.id.into());
}
- std::ops::ControlFlow::Continue(())
+ ty.super_visit_with(self);
}
- fn visit_const(
- &mut self,
- constant: &chalk_ir::Const<Interner>,
- _outer_binder: DebruijnIndex,
- ) -> std::ops::ControlFlow<Self::BreakTy> {
- if let chalk_ir::ConstValue::Placeholder(idx) = constant.data(Interner).value {
- self.collect(idx);
+ fn visit_const(&mut self, konst: Const<'db>) -> Self::Result {
+ if let ConstKind::Param(param) = konst.kind() {
+ self.params.insert(param.id.into());
}
- std::ops::ControlFlow::Continue(())
+
+ konst.super_visit_with(self);
}
}
-/// Returns unique placeholders for types and consts contained in `value`.
-pub fn collect_placeholders<T>(value: &T, db: &dyn HirDatabase) -> Vec<TypeOrConstParamId>
+/// Returns unique params for types and consts contained in `value`.
+pub fn collect_params<'db, T>(value: &T) -> Vec<TypeOrConstParamId>
where
- T: ?Sized + TypeVisitable<Interner>,
+ T: ?Sized + rustc_type_ir::TypeVisitable<DbInterner<'db>>,
{
- let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() };
- _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
- collector.placeholders.into_iter().collect()
+ let mut collector = ParamCollector { params: FxHashSet::default() };
+ value.visit_with(&mut collector);
+ Vec::from_iter(collector.params)
}
-pub fn known_const_to_ast(
- konst: &Const,
- db: &dyn HirDatabase,
+pub fn known_const_to_ast<'db>(
+ konst: Const<'db>,
+ db: &'db dyn HirDatabase,
display_target: DisplayTarget,
) -> Option<ConstArg> {
Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
@@ -1045,3 +592,25 @@ pub(crate) enum DeclOrigin {
pub(crate) struct DeclContext {
pub(crate) origin: DeclOrigin,
}
+
+pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
+ use std::env;
+ use std::sync::LazyLock;
+ use tracing_subscriber::{Registry, layer::SubscriberExt};
+ use tracing_tree::HierarchicalLayer;
+
+ static ENABLE: LazyLock<bool> = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok());
+ if !*ENABLE {
+ return None;
+ }
+
+ let filter: tracing_subscriber::filter::Targets =
+ env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default();
+ let layer = HierarchicalLayer::default()
+ .with_indent_lines(true)
+ .with_ansi(false)
+ .with_indent_amount(2)
+ .with_writer(std::io::stderr);
+ let subscriber = Registry::default().with(filter).with(layer);
+ Some(tracing::subscriber::set_default(subscriber))
+}