mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #8328
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:
commit
35614c7623
17 changed files with 855 additions and 814 deletions
|
@ -55,10 +55,11 @@ use hir_ty::{
|
||||||
autoderef, could_unify,
|
autoderef, could_unify,
|
||||||
method_resolution::{self, TyFingerprint},
|
method_resolution::{self, TyFingerprint},
|
||||||
primitive::UintTy,
|
primitive::UintTy,
|
||||||
traits::{FnTrait, Solution, SolutionVariables},
|
traits::FnTrait,
|
||||||
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
|
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
|
||||||
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Substitution,
|
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution,
|
||||||
TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, TyVariableKind, WhereClause,
|
SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind,
|
||||||
|
TyVariableKind, WhereClause,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
@ -1822,7 +1823,7 @@ impl Type {
|
||||||
match db.trait_solve(self.krate, goal)? {
|
match db.trait_solve(self.krate, goal)? {
|
||||||
Solution::Unique(SolutionVariables(subst)) => subst
|
Solution::Unique(SolutionVariables(subst)) => subst
|
||||||
.value
|
.value
|
||||||
.interned(&Interner)
|
.interned()
|
||||||
.first()
|
.first()
|
||||||
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
|
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
|
||||||
Solution::Ambig(_) => None,
|
Solution::Ambig(_) => None,
|
||||||
|
|
|
@ -12,10 +12,8 @@ use hir_expand::name::name;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex,
|
||||||
traits::{InEnvironment, Solution},
|
InEnvironment, Interner, Solution, Ty, TyBuilder, TyKind,
|
||||||
AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, Ty,
|
|
||||||
TyBuilder, TyKind,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl<D> TyBuilder<D> {
|
||||||
fn build_internal(self) -> (D, Substitution) {
|
fn build_internal(self) -> (D, Substitution) {
|
||||||
assert_eq!(self.vec.len(), self.param_count);
|
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
|
// 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)
|
(self.data, subst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ impl TyBuilder<hir_def::AdtId> {
|
||||||
self.vec.push(fallback().cast(&Interner));
|
self.vec.push(fallback().cast(&Interner));
|
||||||
} else {
|
} else {
|
||||||
// each default can depend on the previous parameters
|
// 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));
|
self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
&self,
|
&self,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
|
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)]
|
#[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)]
|
||||||
fn program_clauses_for_chalk_env(
|
fn program_clauses_for_chalk_env(
|
||||||
|
|
|
@ -260,7 +260,7 @@ impl HirDisplay for ProjectionTy {
|
||||||
write!(f, "<{} as {}", first_parameter, trait_.name)?;
|
write!(f, "<{} as {}", first_parameter, trait_.name)?;
|
||||||
if self.substitution.len(&Interner) > 1 {
|
if self.substitution.len(&Interner) > 1 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
|
f.write_joined(&self.substitution.interned()[1..], ", ")?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
|
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, ",)")?;
|
write!(f, ",)")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
f.write_joined(&*substs.0, ", ")?;
|
f.write_joined(&*substs.interned(), ", ")?;
|
||||||
write!(f, ")")?;
|
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?
|
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
||||||
if total_len > 0 {
|
if total_len > 0 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(¶meters.0[..total_len], ", ")?;
|
f.write_joined(¶meters.interned()[..total_len], ", ")?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,7 @@ impl HirDisplay for Ty {
|
||||||
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
|
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
|
||||||
.filter(|defaults| !defaults.is_empty())
|
.filter(|defaults| !defaults.is_empty())
|
||||||
{
|
{
|
||||||
None => parameters.0.as_ref(),
|
None => parameters.interned().as_ref(),
|
||||||
Some(default_parameters) => {
|
Some(default_parameters) => {
|
||||||
let mut default_from = 0;
|
let mut default_from = 0;
|
||||||
for (i, parameter) in parameters.iter(&Interner).enumerate() {
|
for (i, parameter) in parameters.iter(&Interner).enumerate() {
|
||||||
|
@ -490,11 +490,11 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
¶meters.0[0..default_from]
|
¶meters.interned()[0..default_from]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parameters.0.as_ref()
|
parameters.interned().as_ref()
|
||||||
};
|
};
|
||||||
if !parameters_to_write.is_empty() {
|
if !parameters_to_write.is_empty() {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
|
@ -517,7 +517,7 @@ impl HirDisplay for Ty {
|
||||||
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
|
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
|
||||||
if parameters.len(&Interner) > 0 {
|
if parameters.len(&Interner) > 0 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(&*parameters.0, ", ")?;
|
f.write_joined(&*parameters.interned(), ", ")?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -727,13 +727,13 @@ fn write_bounds_like_dyn_trait(
|
||||||
// existential) here, which is the only thing that's
|
// existential) here, which is the only thing that's
|
||||||
// possible in actual Rust, and hence don't print it
|
// possible in actual Rust, and hence don't print it
|
||||||
write!(f, "{}", f.db.trait_data(trait_).name)?;
|
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 is_fn_trait {
|
||||||
if let Some(args) =
|
if let Some(args) =
|
||||||
params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
|
params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
|
||||||
{
|
{
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
f.write_joined(&*args.0, ", ")?;
|
f.write_joined(&*args.interned(), ", ")?;
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
}
|
}
|
||||||
} else if !params.is_empty() {
|
} else if !params.is_empty() {
|
||||||
|
@ -789,7 +789,7 @@ impl TraitRef {
|
||||||
write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
|
write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
|
||||||
if self.substitution.len(&Interner) > 1 {
|
if self.substitution.len(&Interner) > 1 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
|
f.write_joined(&self.substitution.interned()[1..], ", ")?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -37,8 +37,8 @@ use stdx::impl_from;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
traits::{DomainGoal, Guidance, Solution},
|
DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
|
||||||
InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeWalk,
|
TypeWalk,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
|
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
|
use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
|
||||||
use hir_def::lang_item::LangItemTarget;
|
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};
|
use super::{InEnvironment, InferenceContext};
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ use crate::{
|
||||||
method_resolution, op,
|
method_resolution, op,
|
||||||
primitive::{self, UintTy},
|
primitive::{self, UintTy},
|
||||||
to_chalk_trait_id,
|
to_chalk_trait_id,
|
||||||
traits::{chalk::from_chalk, FnTrait, InEnvironment},
|
traits::{chalk::from_chalk, FnTrait},
|
||||||
utils::{generics, variant_data, Generics},
|
utils::{generics, variant_data, Generics},
|
||||||
AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Rawness, Scalar, Substitution,
|
AdtId, Binders, CallableDefId, FnPointer, FnSig, InEnvironment, Interner, Rawness, Scalar,
|
||||||
TraitRef, Ty, TyBuilder, TyKind,
|
Substitution, TraitRef, Ty, TyBuilder, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -452,11 +452,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
};
|
};
|
||||||
match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
|
match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
|
||||||
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
|
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
|
||||||
substs
|
substs.interned().get(idx).map(|a| a.assert_ty_ref(&Interner)).cloned()
|
||||||
.interned(&Interner)
|
|
||||||
.get(idx)
|
|
||||||
.map(|a| a.assert_ty_ref(&Interner))
|
|
||||||
.cloned()
|
|
||||||
}),
|
}),
|
||||||
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
|
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
|
||||||
let local_id = self.db.struct_data(*s).variant_data.field(name)?;
|
let local_id = self.db.struct_data(*s).variant_data.field(name)?;
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
let ty = match &body[pat] {
|
let ty = match &body[pat] {
|
||||||
&Pat::Tuple { ref args, ellipsis } => {
|
&Pat::Tuple { ref args, ellipsis } => {
|
||||||
let expectations = match expected.as_tuple() {
|
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() {
|
let (inner_ty, alloc_ty) = match expected.as_adt() {
|
||||||
Some((adt, subst)) if adt == box_adt => (
|
Some((adt, subst)) if adt == box_adt => (
|
||||||
subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
|
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),
|
_ => (self.result.standard_types.unknown.clone(), None),
|
||||||
};
|
};
|
||||||
|
|
|
@ -98,7 +98,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
let substs = ctx.substs_from_path(path, typable, true);
|
let substs = ctx.substs_from_path(path, typable, true);
|
||||||
let ty = TyBuilder::value_ty(self.db, typable)
|
let ty = TyBuilder::value_ty(self.db, typable)
|
||||||
.use_parent_substs(&parent_substs)
|
.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();
|
.build();
|
||||||
Some(ty)
|
Some(ty)
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,7 +284,7 @@ impl InferenceTable {
|
||||||
substs2: &Substitution,
|
substs2: &Substitution,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) -> bool {
|
) -> 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)
|
self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ pub(crate) mod utils;
|
||||||
mod chalk_cast;
|
mod chalk_cast;
|
||||||
mod chalk_ext;
|
mod chalk_ext;
|
||||||
mod builder;
|
mod builder;
|
||||||
|
mod walk;
|
||||||
|
mod types;
|
||||||
|
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
@ -26,23 +28,18 @@ mod tests;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_db;
|
mod test_db;
|
||||||
|
|
||||||
use std::{mem, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chalk_ir::cast::{CastTo, Caster};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use base_db::salsa;
|
use base_db::salsa;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule,
|
expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup,
|
||||||
LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId,
|
TraitId, TypeAliasId, TypeParamId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
|
||||||
db::HirDatabase,
|
|
||||||
display::HirDisplay,
|
|
||||||
utils::{generics, make_mut_slice},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use autoderef::autoderef;
|
pub use autoderef::autoderef;
|
||||||
pub use builder::TyBuilder;
|
pub use builder::TyBuilder;
|
||||||
|
@ -52,7 +49,9 @@ pub use lower::{
|
||||||
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
|
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
|
||||||
TyDefId, TyLoweringContext, ValueTyDefId,
|
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::{
|
pub use chalk_ir::{
|
||||||
cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
|
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>;
|
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 {
|
impl ProjectionTy {
|
||||||
pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
|
pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
|
||||||
TraitRef {
|
TraitRef {
|
||||||
|
@ -115,7 +79,7 @@ impl ProjectionTy {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_type_parameter(&self) -> &Ty {
|
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 {
|
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>;
|
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 {
|
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 {
|
pub fn single(ty: Ty) -> Substitution {
|
||||||
Substitution({
|
Substitution::intern({
|
||||||
let mut v = SmallVec::new();
|
let mut v = SmallVec::new();
|
||||||
v.push(ty.cast(&Interner));
|
v.push(ty.cast(&Interner));
|
||||||
v
|
v
|
||||||
|
@ -449,18 +102,13 @@ impl Substitution {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prefix(&self, n: usize) -> 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 {
|
pub fn suffix(&self, n: usize) -> Substitution {
|
||||||
Substitution(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into())
|
Substitution::intern(
|
||||||
}
|
self.interned()[self.len(&Interner) - std::cmp::min(self.len(&Interner), n)..].into(),
|
||||||
|
)
|
||||||
pub fn from_iter(
|
|
||||||
interner: &Interner,
|
|
||||||
elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
|
|
||||||
) -> Self {
|
|
||||||
Substitution(elements.into_iter().casted(interner).collect())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,12 +117,6 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
|
||||||
generics(db.upcast(), id.parent).param_idx(id)
|
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> {
|
impl<T> Binders<T> {
|
||||||
pub fn new(num_binders: usize, value: T) -> Self {
|
pub fn new(num_binders: usize, value: T) -> Self {
|
||||||
Self { num_binders, value }
|
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 {
|
impl TraitRef {
|
||||||
pub fn self_type_parameter(&self) -> &Ty {
|
pub fn self_type_parameter(&self) -> &Ty {
|
||||||
&self.substitution.at(&Interner, 0).assert_ty_ref(&Interner)
|
&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 {
|
impl WhereClause {
|
||||||
pub fn is_implemented(&self) -> bool {
|
pub fn is_implemented(&self) -> bool {
|
||||||
matches!(self, WhereClause::Implemented(_))
|
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> {
|
impl<T> Canonical<T> {
|
||||||
pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
|
pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
|
||||||
let kinds = kinds.into_iter().map(|tk| {
|
let kinds = kinds.into_iter().map(|tk| {
|
||||||
|
@ -679,7 +226,7 @@ impl CallableSig {
|
||||||
.substs
|
.substs
|
||||||
.clone()
|
.clone()
|
||||||
.shift_bound_vars_out(DebruijnIndex::ONE)
|
.shift_bound_vars_out(DebruijnIndex::ONE)
|
||||||
.interned(&Interner)
|
.interned()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| arg.assert_ty_ref(&Interner).clone())
|
.map(|arg| arg.assert_ty_ref(&Interner).clone())
|
||||||
.collect(),
|
.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 {
|
impl Ty {
|
||||||
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
|
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
|
||||||
match self.kind(&Interner) {
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub enum ImplTraitId {
|
pub enum ImplTraitId {
|
||||||
ReturnTypeImplTrait(hir_def::FunctionId, u16),
|
ReturnTypeImplTrait(hir_def::FunctionId, u16),
|
||||||
|
|
|
@ -800,7 +800,7 @@ pub fn implements_trait_unique(
|
||||||
let goal = generic_implements_goal(db, env, trait_, ty.clone());
|
let goal = generic_implements_goal(db, env, trait_, ty.clone());
|
||||||
let solution = db.trait_solve(krate, goal);
|
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
|
/// This creates Substs for a trait with the given Self type and type variables
|
||||||
|
|
|
@ -8,8 +8,8 @@ use hir_def::{lang_item::LangItemTarget, TraitId};
|
||||||
use stdx::panic_context;
|
use stdx::panic_context;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, AliasTy, Canonical, DebruijnIndex, HirDisplay, Substitution, Ty, TyKind,
|
db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
|
||||||
TypeWalk, WhereClause,
|
Solution, SolutionVariables, Ty, TyKind, WhereClause,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::chalk::{from_chalk, Interner, ToChalk};
|
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.
|
/// Solve a trait goal using Chalk.
|
||||||
pub(crate) fn trait_solve_query(
|
pub(crate) fn trait_solve_query(
|
||||||
db: &dyn HirDatabase,
|
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)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum FnTrait {
|
pub enum FnTrait {
|
||||||
FnOnce,
|
FnOnce,
|
||||||
|
|
|
@ -10,11 +10,9 @@ use base_db::salsa::InternKey;
|
||||||
use hir_def::{GenericDefId, TypeAliasId};
|
use hir_def::{GenericDefId, TypeAliasId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase, primitive::UintTy, AliasTy, CallableDefId, Canonical, DomainGoal, FnPointer,
|
||||||
primitive::UintTy,
|
GenericArg, InEnvironment, OpaqueTy, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution,
|
||||||
traits::{Canonical, DomainGoal},
|
TraitRef, Ty, TypeWalk, WhereClause,
|
||||||
AliasTy, CallableDefId, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy,
|
|
||||||
QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::interner::*;
|
use super::interner::*;
|
||||||
|
@ -220,8 +218,8 @@ impl ToChalk for GenericArg {
|
||||||
type Chalk = chalk_ir::GenericArg<Interner>;
|
type Chalk = chalk_ir::GenericArg<Interner>;
|
||||||
|
|
||||||
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
|
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
|
||||||
match self.interned {
|
match self.interned() {
|
||||||
crate::GenericArgData::Ty(ty) => ty.to_chalk(db).cast(&Interner),
|
crate::GenericArgData::Ty(ty) => ty.clone().to_chalk(db).cast(&Interner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +247,7 @@ impl ToChalk for Substitution {
|
||||||
parameters: chalk_ir::Substitution<Interner>,
|
parameters: chalk_ir::Substitution<Interner>,
|
||||||
) -> Substitution {
|
) -> Substitution {
|
||||||
let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
|
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
|
// have the expected self type
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let args_no_self = trait_ref.substitution.interned(&Interner)[1..]
|
let args_no_self = trait_ref.substitution.interned()[1..]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
|
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -558,7 +556,7 @@ pub(super) fn generic_predicate_to_inline_bound(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let trait_ = projection_ty.trait_(db);
|
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()
|
.iter()
|
||||||
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
|
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
416
crates/hir_ty/src/types.rs
Normal file
416
crates/hir_ty/src/types.rs
Normal 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
381
crates/hir_ty/src/walk.rs
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue