8328: Move things in hir_ty into submodules r=flodiebold a=flodiebold

 - all the types that will be replaced by Chalk go to `types`
 - `TypeWalk` impls go to `walk`
 - also fix signature of `Substitution::interned`

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2021-04-04 18:29:53 +00:00 committed by GitHub
commit 35614c7623
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 855 additions and 814 deletions

View file

@ -55,10 +55,11 @@ use hir_ty::{
autoderef, could_unify,
method_resolution::{self, TyFingerprint},
primitive::UintTy,
traits::{FnTrait, Solution, SolutionVariables},
traits::FnTrait,
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, TyVariableKind, WhereClause,
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution,
SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind,
TyVariableKind, WhereClause,
};
use itertools::Itertools;
use rustc_hash::FxHashSet;
@ -1822,7 +1823,7 @@ impl Type {
match db.trait_solve(self.krate, goal)? {
Solution::Unique(SolutionVariables(subst)) => subst
.value
.interned(&Interner)
.interned()
.first()
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
Solution::Ambig(_) => None,

View file

@ -12,10 +12,8 @@ use hir_expand::name::name;
use log::{info, warn};
use crate::{
db::HirDatabase,
traits::{InEnvironment, Solution},
AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, Ty,
TyBuilder, TyKind,
db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex,
InEnvironment, Interner, Solution, Ty, TyBuilder, TyKind,
};
const AUTODEREF_RECURSION_LIMIT: usize = 10;

View file

@ -33,7 +33,7 @@ impl<D> TyBuilder<D> {
fn build_internal(self) -> (D, Substitution) {
assert_eq!(self.vec.len(), self.param_count);
// FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form
let subst = Substitution(self.vec);
let subst = Substitution::intern(self.vec);
(self.data, subst)
}
@ -138,7 +138,7 @@ impl TyBuilder<hir_def::AdtId> {
self.vec.push(fallback().cast(&Interner));
} else {
// each default can depend on the previous parameters
let subst_so_far = Substitution(self.vec.clone());
let subst_so_far = Substitution::intern(self.vec.clone());
self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner));
}
}

View file

@ -123,7 +123,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
&self,
krate: CrateId,
goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
) -> Option<crate::traits::Solution>;
) -> Option<crate::Solution>;
#[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)]
fn program_clauses_for_chalk_env(

View file

@ -260,7 +260,7 @@ impl HirDisplay for ProjectionTy {
write!(f, "<{} as {}", first_parameter, trait_.name)?;
if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
f.write_joined(&self.substitution.interned()[1..], ", ")?;
write!(f, ">")?;
}
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@ -387,7 +387,7 @@ impl HirDisplay for Ty {
write!(f, ",)")?;
} else {
write!(f, "(")?;
f.write_joined(&*substs.0, ", ")?;
f.write_joined(&*substs.interned(), ", ")?;
write!(f, ")")?;
}
}
@ -415,7 +415,7 @@ impl HirDisplay for Ty {
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
write!(f, "<")?;
f.write_joined(&parameters.0[..total_len], ", ")?;
f.write_joined(&parameters.interned()[..total_len], ", ")?;
write!(f, ">")?;
}
}
@ -468,7 +468,7 @@ impl HirDisplay for Ty {
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
.filter(|defaults| !defaults.is_empty())
{
None => parameters.0.as_ref(),
None => parameters.interned().as_ref(),
Some(default_parameters) => {
let mut default_from = 0;
for (i, parameter) in parameters.iter(&Interner).enumerate() {
@ -490,11 +490,11 @@ impl HirDisplay for Ty {
}
}
}
&parameters.0[0..default_from]
&parameters.interned()[0..default_from]
}
}
} else {
parameters.0.as_ref()
parameters.interned().as_ref()
};
if !parameters_to_write.is_empty() {
write!(f, "<")?;
@ -517,7 +517,7 @@ impl HirDisplay for Ty {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
if parameters.len(&Interner) > 0 {
write!(f, "<")?;
f.write_joined(&*parameters.0, ", ")?;
f.write_joined(&*parameters.interned(), ", ")?;
write!(f, ">")?;
}
} else {
@ -727,13 +727,13 @@ fn write_bounds_like_dyn_trait(
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
write!(f, "{}", f.db.trait_data(trait_).name)?;
if let [_, params @ ..] = &*trait_ref.substitution.0 {
if let [_, params @ ..] = &*trait_ref.substitution.interned() {
if is_fn_trait {
if let Some(args) =
params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
{
write!(f, "(")?;
f.write_joined(&*args.0, ", ")?;
f.write_joined(&*args.interned(), ", ")?;
write!(f, ")")?;
}
} else if !params.is_empty() {
@ -789,7 +789,7 @@ impl TraitRef {
write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
f.write_joined(&self.substitution.interned()[1..], ", ")?;
write!(f, ">")?;
}
Ok(())

View file

@ -37,8 +37,8 @@ use stdx::impl_from;
use syntax::SmolStr;
use super::{
traits::{DomainGoal, Guidance, Solution},
InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeWalk,
DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
TypeWalk,
};
use crate::{
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,

View file

@ -7,7 +7,7 @@
use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
use hir_def::lang_item::LangItemTarget;
use crate::{autoderef, traits::Solution, Interner, Ty, TyBuilder, TyKind};
use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyKind};
use super::{InEnvironment, InferenceContext};

View file

@ -20,10 +20,10 @@ use crate::{
method_resolution, op,
primitive::{self, UintTy},
to_chalk_trait_id,
traits::{chalk::from_chalk, FnTrait, InEnvironment},
traits::{chalk::from_chalk, FnTrait},
utils::{generics, variant_data, Generics},
AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Rawness, Scalar, Substitution,
TraitRef, Ty, TyBuilder, TyKind,
AdtId, Binders, CallableDefId, FnPointer, FnSig, InEnvironment, Interner, Rawness, Scalar,
Substitution, TraitRef, Ty, TyBuilder, TyKind,
};
use super::{
@ -452,11 +452,7 @@ impl<'a> InferenceContext<'a> {
};
match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
substs
.interned(&Interner)
.get(idx)
.map(|a| a.assert_ty_ref(&Interner))
.cloned()
substs.interned().get(idx).map(|a| a.assert_ty_ref(&Interner)).cloned()
}),
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
let local_id = self.db.struct_data(*s).variant_data.field(name)?;

View file

@ -123,7 +123,7 @@ impl<'a> InferenceContext<'a> {
let ty = match &body[pat] {
&Pat::Tuple { ref args, ellipsis } => {
let expectations = match expected.as_tuple() {
Some(parameters) => &*parameters.0,
Some(parameters) => &*parameters.interned(),
_ => &[],
};
@ -239,7 +239,7 @@ impl<'a> InferenceContext<'a> {
let (inner_ty, alloc_ty) = match expected.as_adt() {
Some((adt, subst)) if adt == box_adt => (
subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
subst.interned(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
subst.interned().get(1).and_then(|a| a.ty(&Interner).cloned()),
),
_ => (self.result.standard_types.unknown.clone(), None),
};

View file

@ -98,7 +98,7 @@ impl<'a> InferenceContext<'a> {
let substs = ctx.substs_from_path(path, typable, true);
let ty = TyBuilder::value_ty(self.db, typable)
.use_parent_substs(&parent_substs)
.fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
.fill(substs.interned()[parent_substs.len(&Interner)..].iter().cloned())
.build();
Some(ty)
}

View file

@ -284,7 +284,7 @@ impl InferenceTable {
substs2: &Substitution,
depth: usize,
) -> bool {
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| {
substs1.iter(&Interner).zip(substs2.iter(&Interner)).all(|(t1, t2)| {
self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth)
})
}

View file

@ -16,6 +16,8 @@ pub(crate) mod utils;
mod chalk_cast;
mod chalk_ext;
mod builder;
mod walk;
mod types;
pub mod display;
pub mod db;
@ -26,23 +28,18 @@ mod tests;
#[cfg(test)]
mod test_db;
use std::{mem, sync::Arc};
use std::sync::Arc;
use chalk_ir::cast::{CastTo, Caster};
use itertools::Itertools;
use smallvec::SmallVec;
use base_db::salsa;
use hir_def::{
expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule,
LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId,
expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup,
TraitId, TypeAliasId, TypeParamId,
};
use crate::{
db::HirDatabase,
display::HirDisplay,
utils::{generics, make_mut_slice},
};
use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
pub use autoderef::autoderef;
pub use builder::TyBuilder;
@ -52,7 +49,9 @@ pub use lower::{
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
TyDefId, TyLoweringContext, ValueTyDefId,
};
pub use traits::{AliasEq, DomainGoal, InEnvironment, TraitEnvironment};
pub use traits::TraitEnvironment;
pub use types::*;
pub use walk::TypeWalk;
pub use chalk_ir::{
cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
@ -71,41 +70,6 @@ pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Lifetime {
Parameter(LifetimeParamId),
Static,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct OpaqueTy {
pub opaque_ty_id: OpaqueTyId,
pub substitution: Substitution,
}
impl TypeWalk for OpaqueTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ProjectionTy {
pub associated_ty_id: AssocTypeId,
pub substitution: Substitution,
}
impl ProjectionTy {
pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
TraitRef {
@ -115,7 +79,7 @@ impl ProjectionTy {
}
pub fn self_type_parameter(&self) -> &Ty {
&self.substitution.interned(&Interner)[0].assert_ty_ref(&Interner)
&self.substitution.interned()[0].assert_ty_ref(&Interner)
}
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
@ -126,322 +90,11 @@ impl ProjectionTy {
}
}
impl TypeWalk for ProjectionTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct DynTy {
/// The unknown self type.
pub bounds: Binders<QuantifiedWhereClauses>,
}
pub type FnSig = chalk_ir::FnSig<Interner>;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct FnPointer {
pub num_args: usize,
pub sig: FnSig,
pub substs: Substitution,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum AliasTy {
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
Projection(ProjectionTy),
/// An opaque type (`impl Trait`).
///
/// This is currently only used for return type impl trait; each instance of
/// `impl Trait` in a return type gets its own ID.
Opaque(OpaqueTy),
}
impl TypeWalk for AliasTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
AliasTy::Projection(it) => it.walk(f),
AliasTy::Opaque(it) => it.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
}
}
}
/// A type.
///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
/// the same thing (but in a different way).
///
/// This should be cheap to clone.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum TyKind {
/// Structures, enumerations and unions.
Adt(AdtId<Interner>, Substitution),
/// Represents an associated item like `Iterator::Item`. This is used
/// when we have tried to normalize a projection like `T::Item` but
/// couldn't find a better representation. In that case, we generate
/// an **application type** like `(Iterator::Item)<T>`.
AssociatedType(AssocTypeId, Substitution),
/// a scalar type like `bool` or `u32`
Scalar(Scalar),
/// A tuple type. For example, `(i32, bool)`.
Tuple(usize, Substitution),
/// An array with the given length. Written as `[T; n]`.
Array(Ty),
/// The pointee of an array slice. Written as `[T]`.
Slice(Ty),
/// A raw pointer. Written as `*mut T` or `*const T`
Raw(Mutability, Ty),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(Mutability, Ty),
/// This represents a placeholder for an opaque type in situations where we
/// don't know the hidden type (i.e. currently almost always). This is
/// analogous to the `AssociatedType` type constructor.
/// It is also used as the type of async block, with one type parameter
/// representing the Future::Output type.
OpaqueType(OpaqueTyId, Substitution),
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type, which is output (for a function
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
///
/// This includes tuple struct / enum variant constructors as well.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo}
/// ```
FnDef(FnDefId, Substitution),
/// The pointee of a string slice. Written as `str`.
Str,
/// The never type `!`.
Never,
/// The type of a specific closure.
///
/// The closure signature is stored in a `FnPtr` type in the first type
/// parameter.
Closure(ClosureId, Substitution),
/// Represents a foreign type declared in external blocks.
ForeignType(ForeignDefId),
/// A pointer to a function. Written as `fn() -> i32`.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
Function(FnPointer),
/// An "alias" type represents some form of type alias, such as:
/// - An associated type projection like `<T as Iterator>::Item`
/// - `impl Trait` types
/// - Named type aliases like `type Foo<X> = Vec<X>`
Alias(AliasTy),
/// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
/// {}` when we're type-checking the body of that function. In this
/// situation, we know this stands for *some* type, but don't know the exact
/// type.
Placeholder(PlaceholderIndex),
/// A bound type variable. This is used in various places: when representing
/// some polymorphic type like the type of function `fn f<T>`, the type
/// parameters get turned into variables; during trait resolution, inference
/// variables get turned into bound variables and back; and in `Dyn` the
/// `Self` type is represented with a bound variable as well.
BoundVar(BoundVar),
/// A type variable used during type checking.
InferenceVar(InferenceVar, TyVariableKind),
/// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
///
/// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
/// represents the `Self` type inside the bounds. This is currently
/// implicit; Chalk has the `Binders` struct to make it explicit, but it
/// didn't seem worth the overhead yet.
Dyn(DynTy),
/// A placeholder for a type which could not be computed; this is propagated
/// to avoid useless error messages. Doubles as a placeholder where type
/// variables are inserted before type checking, since we want to try to
/// infer a better type here anyway -- for the IDE use case, we want to try
/// to infer as much as possible even in the presence of type errors.
Unknown,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Ty(Arc<TyKind>);
impl TyKind {
pub fn intern(self, _interner: &Interner) -> Ty {
Ty(Arc::new(self))
}
}
impl Ty {
pub fn kind(&self, _interner: &Interner) -> &TyKind {
&self.0
}
pub fn interned_mut(&mut self) -> &mut TyKind {
Arc::make_mut(&mut self.0)
}
pub fn into_inner(self) -> TyKind {
Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericArg {
interned: GenericArgData,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum GenericArgData {
Ty(Ty),
}
impl GenericArg {
/// Constructs a generic argument using `GenericArgData`.
pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
GenericArg { interned: data }
}
/// Gets the interned value.
pub fn interned(&self) -> &GenericArgData {
&self.interned
}
/// Asserts that this is a type argument.
pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
self.ty(interner).unwrap()
}
/// Checks whether the generic argument is a type.
pub fn is_ty(&self, _interner: &Interner) -> bool {
match self.interned() {
GenericArgData::Ty(_) => true,
}
}
/// Returns the type if it is one, `None` otherwise.
pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
match self.interned() {
GenericArgData::Ty(t) => Some(t),
}
}
}
impl TypeWalk for GenericArg {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match &self.interned {
GenericArgData::Ty(ty) => {
ty.walk(f);
}
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match &mut self.interned {
GenericArgData::Ty(ty) => {
ty.walk_mut_binders(f, binders);
}
}
}
}
/// A list of substitutions for generic parameters.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Substitution(SmallVec<[GenericArg; 2]>);
impl TypeWalk for Substitution {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self.0.iter() {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in &mut self.0 {
t.walk_mut_binders(f, binders);
}
}
}
impl Substitution {
pub fn interned(&self, _: &Interner) -> &[GenericArg] {
&self.0
}
pub fn len(&self, _: &Interner) -> usize {
self.0.len()
}
pub fn is_empty(&self, _: &Interner) -> bool {
self.0.is_empty()
}
pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
&self.0[i]
}
pub fn empty(_: &Interner) -> Substitution {
Substitution(SmallVec::new())
}
pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
self.0.iter()
}
pub fn single(ty: Ty) -> Substitution {
Substitution({
Substitution::intern({
let mut v = SmallVec::new();
v.push(ty.cast(&Interner));
v
@ -449,18 +102,13 @@ impl Substitution {
}
pub fn prefix(&self, n: usize) -> Substitution {
Substitution(self.0[..std::cmp::min(self.0.len(), n)].into())
Substitution::intern(self.interned()[..std::cmp::min(self.len(&Interner), n)].into())
}
pub fn suffix(&self, n: usize) -> Substitution {
Substitution(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into())
}
pub fn from_iter(
interner: &Interner,
elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
) -> Self {
Substitution(elements.into_iter().casted(interner).collect())
Substitution::intern(
self.interned()[self.len(&Interner) - std::cmp::min(self.len(&Interner), n)..].into(),
)
}
}
@ -469,12 +117,6 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
generics(db.upcast(), id.parent).param_idx(id)
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Binders<T> {
pub num_binders: usize,
pub value: T,
}
impl<T> Binders<T> {
pub fn new(num_binders: usize, value: T) -> Self {
Self { num_binders, value }
@ -522,27 +164,6 @@ impl<T: TypeWalk> Binders<T> {
}
}
impl<T: TypeWalk> TypeWalk for Binders<T> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.value.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.value.walk_mut_binders(f, binders.shifted_in())
}
}
/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TraitRef {
pub trait_id: ChalkTraitId,
pub substitution: Substitution,
}
impl TraitRef {
pub fn self_type_parameter(&self) -> &Ty {
&self.substitution.at(&Interner, 0).assert_ty_ref(&Interner)
@ -553,30 +174,6 @@ impl TraitRef {
}
}
impl TypeWalk for TraitRef {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
/// parameters of a generic item.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WhereClause {
/// The given trait needs to be implemented for its type parameters.
Implemented(TraitRef),
/// An associated type bindings like in `Iterator<Item = T>`.
AliasEq(AliasEq),
}
impl WhereClause {
pub fn is_implemented(&self) -> bool {
matches!(self, WhereClause::Implemented(_))
@ -593,56 +190,6 @@ impl WhereClause {
}
}
impl TypeWalk for WhereClause {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
}
}
}
pub type QuantifiedWhereClause = Binders<WhereClause>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
impl QuantifiedWhereClauses {
pub fn from_iter(
_interner: &Interner,
elements: impl IntoIterator<Item = QuantifiedWhereClause>,
) -> Self {
QuantifiedWhereClauses(elements.into_iter().collect())
}
pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
&self.0
}
}
/// Basically a claim (currently not validated / checked) that the contained
/// type / trait ref contains no inference variables; any inference variables it
/// contained have been replaced by bound variables, and `kinds` tells us how
/// many there are and whether they were normal or float/int variables. This is
/// used to erase irrelevant differences between types before using them in
/// queries.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Canonical<T> {
pub value: T,
pub binders: CanonicalVarKinds,
}
impl<T> Canonical<T> {
pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
let kinds = kinds.into_iter().map(|tk| {
@ -679,7 +226,7 @@ impl CallableSig {
.substs
.clone()
.shift_bound_vars_out(DebruijnIndex::ONE)
.interned(&Interner)
.interned()
.iter()
.map(|arg| arg.assert_ty_ref(&Interner).clone())
.collect(),
@ -696,24 +243,6 @@ impl CallableSig {
}
}
impl TypeWalk for CallableSig {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self.params_and_return.iter() {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in make_mut_slice(&mut self.params_and_return) {
t.walk_mut_binders(f, binders);
}
}
}
impl Ty {
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
match self.kind(&Interner) {
@ -984,200 +513,6 @@ impl Ty {
}
}
/// This allows walking structures that contain types to do something with those
/// types, similar to Chalk's `Fold` trait.
pub trait TypeWalk {
fn walk(&self, f: &mut impl FnMut(&Ty));
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
}
/// Walk the type, counting entered binders.
///
/// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
/// to the innermost binder, 1 to the next, etc.. So when we want to
/// substitute a certain bound variable, we can't just walk the whole type
/// and blindly replace each instance of a certain index; when we 'enter'
/// things that introduce new bound variables, we have to keep track of
/// that. Currently, the only thing that introduces bound variables on our
/// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
/// variable for the self type.
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
);
fn fold_binders(
mut self,
f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
binders: DebruijnIndex,
) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty_mut, binders| {
let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
*ty_mut = f(ty, binders);
},
binders,
);
self
}
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
where
Self: Sized,
{
self.walk_mut(&mut |ty_mut| {
let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
*ty_mut = f(ty);
});
self
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars(self, substs: &Substitution) -> Self
where
Self: Sized,
{
self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty, binders| {
if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
if bound.debruijn >= binders {
*ty = substs.0[bound.index]
.assert_ty_ref(&Interner)
.clone()
.shift_bound_vars(binders);
}
}
},
depth,
);
self
}
/// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
fn shift_bound_vars(self, n: DebruijnIndex) -> Self
where
Self: Sized,
{
self.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
/// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
fn shift_bound_vars_out(self, n: DebruijnIndex) -> Self
where
Self: Sized + std::fmt::Debug,
{
self.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
.intern(&Interner)
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
}
impl TypeWalk for Ty {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self.kind(&Interner) {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
for t in p_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
for t in o_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
TyKind::Dyn(dyn_ty) => {
for p in dyn_ty.bounds.value.interned().iter() {
p.walk(f);
}
}
TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
ty.walk(f);
}
_ => {
if let Some(substs) = self.substs() {
for t in substs.iter(&Interner) {
t.walk(f);
}
}
}
}
f(self);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self.interned_mut() {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
p_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Dyn(dyn_ty) => {
for p in make_mut_slice(&mut dyn_ty.bounds.value.0) {
p.walk_mut_binders(f, binders.shifted_in());
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
o_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
ty.walk_mut_binders(f, binders);
}
_ => {
if let Some(substs) = self.substs_mut() {
substs.walk_mut_binders(f, binders);
}
}
}
f(self, binders);
}
}
impl<T: TypeWalk> TypeWalk for Vec<T> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in self {
t.walk_mut_binders(f, binders);
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId {
ReturnTypeImplTrait(hir_def::FunctionId, u16),

View file

@ -800,7 +800,7 @@ pub fn implements_trait_unique(
let goal = generic_implements_goal(db, env, trait_, ty.clone());
let solution = db.trait_solve(krate, goal);
matches!(solution, Some(crate::traits::Solution::Unique(_)))
matches!(solution, Some(crate::Solution::Unique(_)))
}
/// This creates Substs for a trait with the given Self type and type variables

View file

@ -8,8 +8,8 @@ use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use crate::{
db::HirDatabase, AliasTy, Canonical, DebruijnIndex, HirDisplay, Substitution, Ty, TyKind,
TypeWalk, WhereClause,
db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
Solution, SolutionVariables, Ty, TyKind, WhereClause,
};
use self::chalk::{from_chalk, Interner, ToChalk};
@ -70,55 +70,6 @@ impl Default for TraitEnvironment {
}
}
/// Something (usually a goal), along with an environment.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InEnvironment<T> {
pub environment: chalk_ir::Environment<Interner>,
pub goal: T,
}
impl<T> InEnvironment<T> {
pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
InEnvironment { environment, goal: value }
}
}
/// Something that needs to be proven (by Chalk) during type checking, e.g. that
/// a certain type implements a certain trait. Proving the Obligation might
/// result in additional information about inference variables.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DomainGoal {
Holds(WhereClause),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AliasEq {
pub alias: AliasTy,
pub ty: Ty,
}
impl TypeWalk for AliasEq {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.ty.walk(f);
match &self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk(f),
AliasTy::Opaque(opaque) => opaque.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.ty.walk_mut_binders(f, binders);
match &mut self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
}
}
}
/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
db: &dyn HirDatabase,
@ -246,41 +197,6 @@ fn solution_from_chalk(
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SolutionVariables(pub Canonical<Substitution>);
#[derive(Clone, Debug, PartialEq, Eq)]
/// A (possible) solution for a proposed goal.
pub enum Solution {
/// The goal indeed holds, and there is a unique value for all existential
/// variables.
Unique(SolutionVariables),
/// The goal may be provable in multiple ways, but regardless we may have some guidance
/// for type inference. In this case, we don't return any lifetime
/// constraints, since we have not "committed" to any particular solution
/// yet.
Ambig(Guidance),
}
#[derive(Clone, Debug, PartialEq, Eq)]
/// When a goal holds ambiguously (e.g., because there are multiple possible
/// solutions), we issue a set of *guidance* back to type inference.
pub enum Guidance {
/// The existential variables *must* have the given values if the goal is
/// ever to hold, but that alone isn't enough to guarantee the goal will
/// actually hold.
Definite(SolutionVariables),
/// There are multiple plausible values for the existentials, but the ones
/// here are suggested as the preferred choice heuristically. These should
/// be used for inference fallback only.
Suggested(SolutionVariables),
/// There's no useful information to feed back to type inference
Unknown,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
FnOnce,

View file

@ -10,11 +10,9 @@ use base_db::salsa::InternKey;
use hir_def::{GenericDefId, TypeAliasId};
use crate::{
db::HirDatabase,
primitive::UintTy,
traits::{Canonical, DomainGoal},
AliasTy, CallableDefId, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy,
QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
db::HirDatabase, primitive::UintTy, AliasTy, CallableDefId, Canonical, DomainGoal, FnPointer,
GenericArg, InEnvironment, OpaqueTy, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution,
TraitRef, Ty, TypeWalk, WhereClause,
};
use super::interner::*;
@ -220,8 +218,8 @@ impl ToChalk for GenericArg {
type Chalk = chalk_ir::GenericArg<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
match self.interned {
crate::GenericArgData::Ty(ty) => ty.to_chalk(db).cast(&Interner),
match self.interned() {
crate::GenericArgData::Ty(ty) => ty.clone().to_chalk(db).cast(&Interner),
}
}
@ -249,7 +247,7 @@ impl ToChalk for Substitution {
parameters: chalk_ir::Substitution<Interner>,
) -> Substitution {
let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
Substitution(tys)
Substitution::intern(tys)
}
}
@ -546,7 +544,7 @@ pub(super) fn generic_predicate_to_inline_bound(
// have the expected self type
return None;
}
let args_no_self = trait_ref.substitution.interned(&Interner)[1..]
let args_no_self = trait_ref.substitution.interned()[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect();
@ -558,7 +556,7 @@ pub(super) fn generic_predicate_to_inline_bound(
return None;
}
let trait_ = projection_ty.trait_(db);
let args_no_self = projection_ty.substitution.interned(&Interner)[1..]
let args_no_self = projection_ty.substitution.interned()[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect();

416
crates/hir_ty/src/types.rs Normal file
View file

@ -0,0 +1,416 @@
//! This is the home of `Ty` etc. until they get replaced by their chalk_ir
//! equivalents.
use std::sync::Arc;
use chalk_ir::{
cast::{CastTo, Caster},
BoundVar, Mutability, Scalar, TyVariableKind,
};
use hir_def::LifetimeParamId;
use smallvec::SmallVec;
use crate::{
AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, FnDefId, FnSig, ForeignDefId,
InferenceVar, Interner, OpaqueTyId, PlaceholderIndex,
};
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Lifetime {
Parameter(LifetimeParamId),
Static,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct OpaqueTy {
pub opaque_ty_id: OpaqueTyId,
pub substitution: Substitution,
}
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ProjectionTy {
pub associated_ty_id: AssocTypeId,
pub substitution: Substitution,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct DynTy {
/// The unknown self type.
pub bounds: Binders<QuantifiedWhereClauses>,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct FnPointer {
pub num_args: usize,
pub sig: FnSig,
pub substs: Substitution,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum AliasTy {
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
Projection(ProjectionTy),
/// An opaque type (`impl Trait`).
///
/// This is currently only used for return type impl trait; each instance of
/// `impl Trait` in a return type gets its own ID.
Opaque(OpaqueTy),
}
/// A type.
///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
/// the same thing (but in a different way).
///
/// This should be cheap to clone.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum TyKind {
/// Structures, enumerations and unions.
Adt(chalk_ir::AdtId<Interner>, Substitution),
/// Represents an associated item like `Iterator::Item`. This is used
/// when we have tried to normalize a projection like `T::Item` but
/// couldn't find a better representation. In that case, we generate
/// an **application type** like `(Iterator::Item)<T>`.
AssociatedType(AssocTypeId, Substitution),
/// a scalar type like `bool` or `u32`
Scalar(Scalar),
/// A tuple type. For example, `(i32, bool)`.
Tuple(usize, Substitution),
/// An array with the given length. Written as `[T; n]`.
Array(Ty),
/// The pointee of an array slice. Written as `[T]`.
Slice(Ty),
/// A raw pointer. Written as `*mut T` or `*const T`
Raw(Mutability, Ty),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(Mutability, Ty),
/// This represents a placeholder for an opaque type in situations where we
/// don't know the hidden type (i.e. currently almost always). This is
/// analogous to the `AssociatedType` type constructor.
/// It is also used as the type of async block, with one type parameter
/// representing the Future::Output type.
OpaqueType(OpaqueTyId, Substitution),
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type, which is output (for a function
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
///
/// This includes tuple struct / enum variant constructors as well.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo}
/// ```
FnDef(FnDefId, Substitution),
/// The pointee of a string slice. Written as `str`.
Str,
/// The never type `!`.
Never,
/// The type of a specific closure.
///
/// The closure signature is stored in a `FnPtr` type in the first type
/// parameter.
Closure(ClosureId, Substitution),
/// Represents a foreign type declared in external blocks.
ForeignType(ForeignDefId),
/// A pointer to a function. Written as `fn() -> i32`.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
Function(FnPointer),
/// An "alias" type represents some form of type alias, such as:
/// - An associated type projection like `<T as Iterator>::Item`
/// - `impl Trait` types
/// - Named type aliases like `type Foo<X> = Vec<X>`
Alias(AliasTy),
/// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
/// {}` when we're type-checking the body of that function. In this
/// situation, we know this stands for *some* type, but don't know the exact
/// type.
Placeholder(PlaceholderIndex),
/// A bound type variable. This is used in various places: when representing
/// some polymorphic type like the type of function `fn f<T>`, the type
/// parameters get turned into variables; during trait resolution, inference
/// variables get turned into bound variables and back; and in `Dyn` the
/// `Self` type is represented with a bound variable as well.
BoundVar(BoundVar),
/// A type variable used during type checking.
InferenceVar(InferenceVar, TyVariableKind),
/// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
///
/// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
/// represents the `Self` type inside the bounds. This is currently
/// implicit; Chalk has the `Binders` struct to make it explicit, but it
/// didn't seem worth the overhead yet.
Dyn(DynTy),
/// A placeholder for a type which could not be computed; this is propagated
/// to avoid useless error messages. Doubles as a placeholder where type
/// variables are inserted before type checking, since we want to try to
/// infer a better type here anyway -- for the IDE use case, we want to try
/// to infer as much as possible even in the presence of type errors.
Unknown,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Ty(Arc<TyKind>);
impl TyKind {
pub fn intern(self, _interner: &Interner) -> Ty {
Ty(Arc::new(self))
}
}
impl Ty {
pub fn kind(&self, _interner: &Interner) -> &TyKind {
&self.0
}
pub fn interned_mut(&mut self) -> &mut TyKind {
Arc::make_mut(&mut self.0)
}
pub fn into_inner(self) -> TyKind {
Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericArg {
interned: GenericArgData,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum GenericArgData {
Ty(Ty),
}
impl GenericArg {
/// Constructs a generic argument using `GenericArgData`.
pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
GenericArg { interned: data }
}
/// Gets the interned value.
pub fn interned(&self) -> &GenericArgData {
&self.interned
}
/// Asserts that this is a type argument.
pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
self.ty(interner).unwrap()
}
/// Checks whether the generic argument is a type.
pub fn is_ty(&self, _interner: &Interner) -> bool {
match self.interned() {
GenericArgData::Ty(_) => true,
}
}
/// Returns the type if it is one, `None` otherwise.
pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
match self.interned() {
GenericArgData::Ty(t) => Some(t),
}
}
pub fn interned_mut(&mut self) -> &mut GenericArgData {
&mut self.interned
}
}
/// A list of substitutions for generic parameters.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Substitution(SmallVec<[GenericArg; 2]>);
impl Substitution {
pub fn interned(&self) -> &[GenericArg] {
&self.0
}
pub fn len(&self, _: &Interner) -> usize {
self.0.len()
}
pub fn is_empty(&self, _: &Interner) -> bool {
self.0.is_empty()
}
pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
&self.0[i]
}
pub fn empty(_: &Interner) -> Substitution {
Substitution(SmallVec::new())
}
pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
self.0.iter()
}
pub fn from_iter(
interner: &Interner,
elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
) -> Self {
Substitution(elements.into_iter().casted(interner).collect())
}
// We can hopefully add this to Chalk
pub fn intern(interned: SmallVec<[GenericArg; 2]>) -> Substitution {
Substitution(interned)
}
pub fn interned_mut(&mut self) -> &mut SmallVec<[GenericArg; 2]> {
&mut self.0
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Binders<T> {
pub num_binders: usize,
pub value: T,
}
/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TraitRef {
pub trait_id: ChalkTraitId,
pub substitution: Substitution,
}
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
/// parameters of a generic item.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WhereClause {
/// The given trait needs to be implemented for its type parameters.
Implemented(TraitRef),
/// An associated type bindings like in `Iterator<Item = T>`.
AliasEq(AliasEq),
}
pub type QuantifiedWhereClause = Binders<WhereClause>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
impl QuantifiedWhereClauses {
pub fn from_iter(
_interner: &Interner,
elements: impl IntoIterator<Item = QuantifiedWhereClause>,
) -> Self {
QuantifiedWhereClauses(elements.into_iter().collect())
}
pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
&self.0
}
pub fn interned_mut(&mut self) -> &mut Arc<[QuantifiedWhereClause]> {
&mut self.0
}
}
/// Basically a claim (currently not validated / checked) that the contained
/// type / trait ref contains no inference variables; any inference variables it
/// contained have been replaced by bound variables, and `kinds` tells us how
/// many there are and whether they were normal or float/int variables. This is
/// used to erase irrelevant differences between types before using them in
/// queries.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Canonical<T> {
pub value: T,
pub binders: CanonicalVarKinds,
}
/// Something (usually a goal), along with an environment.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InEnvironment<T> {
pub environment: chalk_ir::Environment<Interner>,
pub goal: T,
}
impl<T> InEnvironment<T> {
pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
InEnvironment { environment, goal: value }
}
}
/// Something that needs to be proven (by Chalk) during type checking, e.g. that
/// a certain type implements a certain trait. Proving the Obligation might
/// result in additional information about inference variables.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DomainGoal {
Holds(WhereClause),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AliasEq {
pub alias: AliasTy,
pub ty: Ty,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SolutionVariables(pub Canonical<Substitution>);
#[derive(Clone, Debug, PartialEq, Eq)]
/// A (possible) solution for a proposed goal.
pub enum Solution {
/// The goal indeed holds, and there is a unique value for all existential
/// variables.
Unique(SolutionVariables),
/// The goal may be provable in multiple ways, but regardless we may have some guidance
/// for type inference. In this case, we don't return any lifetime
/// constraints, since we have not "committed" to any particular solution
/// yet.
Ambig(Guidance),
}
#[derive(Clone, Debug, PartialEq, Eq)]
/// When a goal holds ambiguously (e.g., because there are multiple possible
/// solutions), we issue a set of *guidance* back to type inference.
pub enum Guidance {
/// The existential variables *must* have the given values if the goal is
/// ever to hold, but that alone isn't enough to guarantee the goal will
/// actually hold.
Definite(SolutionVariables),
/// There are multiple plausible values for the existentials, but the ones
/// here are suggested as the preferred choice heuristically. These should
/// be used for inference fallback only.
Suggested(SolutionVariables),
/// There's no useful information to feed back to type inference
Unknown,
}

381
crates/hir_ty/src/walk.rs Normal file
View file

@ -0,0 +1,381 @@
//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
//! `Visit`).
use std::mem;
use chalk_ir::DebruijnIndex;
use crate::{
utils::make_mut_slice, AliasEq, AliasTy, Binders, CallableSig, GenericArg, GenericArgData,
Interner, OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
};
/// This allows walking structures that contain types to do something with those
/// types, similar to Chalk's `Fold` trait.
pub trait TypeWalk {
fn walk(&self, f: &mut impl FnMut(&Ty));
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
}
/// Walk the type, counting entered binders.
///
/// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
/// to the innermost binder, 1 to the next, etc.. So when we want to
/// substitute a certain bound variable, we can't just walk the whole type
/// and blindly replace each instance of a certain index; when we 'enter'
/// things that introduce new bound variables, we have to keep track of
/// that. Currently, the only thing that introduces bound variables on our
/// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
/// variable for the self type.
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
);
fn fold_binders(
mut self,
f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
binders: DebruijnIndex,
) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty_mut, binders| {
let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
*ty_mut = f(ty, binders);
},
binders,
);
self
}
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
where
Self: Sized,
{
self.walk_mut(&mut |ty_mut| {
let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
*ty_mut = f(ty);
});
self
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars(self, substs: &Substitution) -> Self
where
Self: Sized,
{
self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty, binders| {
if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
if bound.debruijn >= binders {
*ty = substs.interned()[bound.index]
.assert_ty_ref(&Interner)
.clone()
.shift_bound_vars(binders);
}
}
},
depth,
);
self
}
/// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
fn shift_bound_vars(self, n: DebruijnIndex) -> Self
where
Self: Sized,
{
self.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
/// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
fn shift_bound_vars_out(self, n: DebruijnIndex) -> Self
where
Self: Sized + std::fmt::Debug,
{
self.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
.intern(&Interner)
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
}
impl TypeWalk for Ty {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self.kind(&Interner) {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
for t in p_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
for t in o_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
TyKind::Dyn(dyn_ty) => {
for p in dyn_ty.bounds.value.interned().iter() {
p.walk(f);
}
}
TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
ty.walk(f);
}
_ => {
if let Some(substs) = self.substs() {
for t in substs.iter(&Interner) {
t.walk(f);
}
}
}
}
f(self);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self.interned_mut() {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
p_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Dyn(dyn_ty) => {
for p in make_mut_slice(dyn_ty.bounds.value.interned_mut()) {
p.walk_mut_binders(f, binders.shifted_in());
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
o_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
ty.walk_mut_binders(f, binders);
}
_ => {
if let Some(substs) = self.substs_mut() {
substs.walk_mut_binders(f, binders);
}
}
}
f(self, binders);
}
}
impl<T: TypeWalk> TypeWalk for Vec<T> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in self {
t.walk_mut_binders(f, binders);
}
}
}
impl TypeWalk for OpaqueTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for ProjectionTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for AliasTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
AliasTy::Projection(it) => it.walk(f),
AliasTy::Opaque(it) => it.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
}
}
}
impl TypeWalk for GenericArg {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match &self.interned() {
GenericArgData::Ty(ty) => {
ty.walk(f);
}
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self.interned_mut() {
GenericArgData::Ty(ty) => {
ty.walk_mut_binders(f, binders);
}
}
}
}
impl TypeWalk for Substitution {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self.iter(&Interner) {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in self.interned_mut() {
t.walk_mut_binders(f, binders);
}
}
}
impl<T: TypeWalk> TypeWalk for Binders<T> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.value.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.value.walk_mut_binders(f, binders.shifted_in())
}
}
impl TypeWalk for TraitRef {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for WhereClause {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
}
}
}
impl TypeWalk for CallableSig {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self.params_and_return.iter() {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in make_mut_slice(&mut self.params_and_return) {
t.walk_mut_binders(f, binders);
}
}
}
impl TypeWalk for AliasEq {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.ty.walk(f);
match &self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk(f),
AliasTy::Opaque(opaque) => opaque.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.ty.walk_mut_binders(f, binders);
match &mut self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
}
}
}