Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_ty/src/builder.rs')
| -rw-r--r-- | crates/hir_ty/src/builder.rs | 177 |
1 files changed, 128 insertions, 49 deletions
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs index 76e5efc052..c507c42f5b 100644 --- a/crates/hir_ty/src/builder.rs +++ b/crates/hir_ty/src/builder.rs @@ -8,67 +8,136 @@ use chalk_ir::{ interner::HasInterner, AdtId, BoundVar, DebruijnIndex, Scalar, }; -use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; +use hir_def::{ + builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId, + TypeAliasId, +}; use smallvec::SmallVec; use crate::{ - db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, - CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, - TyKind, ValueTyDefId, + consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id, + to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg, + GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, + ValueTyDefId, }; +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParamKind { + Type, + Const(Ty), +} + /// This is a builder for `Ty` or anything that needs a `Substitution`. pub struct TyBuilder<D> { /// The `data` field is used to keep track of what we're building (e.g. an /// ADT, a `TraitRef`, ...). data: D, vec: SmallVec<[GenericArg; 2]>, - param_count: usize, + param_kinds: SmallVec<[ParamKind; 2]>, +} + +impl<A> TyBuilder<A> { + fn with_data<B>(self, data: B) -> TyBuilder<B> { + TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec } + } } impl<D> TyBuilder<D> { - fn new(data: D, param_count: usize) -> TyBuilder<D> { - TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } + fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> { + TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds } } fn build_internal(self) -> (D, Substitution) { - assert_eq!(self.vec.len(), self.param_count); + assert_eq!(self.vec.len(), self.param_kinds.len()); + for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) { + self.assert_match_kind(a, e); + } let subst = Substitution::from_iter(Interner, self.vec); (self.data, subst) } pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self { - self.vec.push(arg.cast(Interner)); + let arg = arg.cast(Interner); + let expected_kind = &self.param_kinds[self.vec.len()]; + let arg_kind = match arg.data(Interner) { + chalk_ir::GenericArgData::Ty(_) => ParamKind::Type, + chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"), + chalk_ir::GenericArgData::Const(c) => { + let c = c.data(Interner); + ParamKind::Const(c.ty.clone()) + } + }; + assert_eq!(*expected_kind, arg_kind); + self.vec.push(arg); self } pub fn remaining(&self) -> usize { - self.param_count - self.vec.len() + self.param_kinds.len() - self.vec.len() } pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { - self.fill( - (starting_from..) - .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)), - ) + // self.fill is inlined to make borrow checker happy + let mut this = self; + let other = this.param_kinds.iter().skip(this.vec.len()); + let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind { + ParamKind::Type => { + GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)) + .intern(Interner) + } + ParamKind::Const(ty) => GenericArgData::Const( + ConstData { + value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)), + ty: ty.clone(), + } + .intern(Interner), + ) + .intern(Interner), + }); + this.vec.extend(filler.take(this.remaining()).casted(Interner)); + assert_eq!(this.remaining(), 0); + this } pub fn fill_with_unknown(self) -> Self { - self.fill(iter::repeat(TyKind::Error.intern(Interner))) + // self.fill is inlined to make borrow checker happy + let mut this = self; + let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x { + ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner), + ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), + }); + this.vec.extend(filler.casted(Interner)); + assert_eq!(this.remaining(), 0); + this } - pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { - self.vec.extend(filler.take(self.remaining()).casted(Interner)); + pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self { + self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler)); assert_eq!(self.remaining(), 0); self } pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { assert!(self.vec.is_empty()); - assert!(parent_substs.len(Interner) <= self.param_count); - self.vec.extend(parent_substs.iter(Interner).cloned()); + assert!(parent_substs.len(Interner) <= self.param_kinds.len()); + self.extend(parent_substs.iter(Interner).cloned()); self } + + fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) { + for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) { + self.assert_match_kind(&x.0, &x.1); + } + self.vec.extend(it); + } + + fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) { + match (a.data(Interner), e) { + (chalk_ir::GenericArgData::Ty(_), ParamKind::Type) + | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (), + _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds), + } + } } impl TyBuilder<()> { @@ -101,16 +170,26 @@ impl TyBuilder<()> { TyKind::Slice(argument).intern(Interner) } - pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution { + pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution { let params = generics(db.upcast(), def.into()); - params.type_params_subst(db) + params.placeholder_subst(db) } pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> { let def = def.into(); let params = generics(db.upcast(), def); - let param_count = params.len(); - TyBuilder::new((), param_count) + TyBuilder::new( + (), + params + .iter() + .map(|(id, data)| match data { + TypeOrConstParamData::TypeParamData(_) => ParamKind::Type, + TypeOrConstParamData::ConstParamData(_) => { + ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id))) + } + }) + .collect(), + ) } pub fn build(self) -> Substitution { @@ -120,10 +199,8 @@ impl TyBuilder<()> { } impl TyBuilder<hir_def::AdtId> { - pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { - let generics = generics(db.upcast(), adt.into()); - let param_count = generics.len(); - TyBuilder::new(adt, param_count) + pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { + TyBuilder::subst_for_def(db, def).with_data(def) } pub fn fill_with_defaults( @@ -133,14 +210,15 @@ impl TyBuilder<hir_def::AdtId> { ) -> Self { let defaults = db.generic_defaults(self.data.into()); for default_ty in defaults.iter().skip(self.vec.len()) { - if default_ty.skip_binders().is_unknown() { - self.vec.push(fallback().cast(Interner)); - } else { - // each default can depend on the previous parameters - let subst_so_far = Substitution::from_iter(Interner, self.vec.clone()); - self.vec - .push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner)); - } + if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) { + if x.is_unknown() { + self.vec.push(fallback().cast(Interner)); + continue; + } + }; + // each default can depend on the previous parameters + let subst_so_far = Substitution::from_iter(Interner, self.vec.clone()); + self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner)); } self } @@ -154,7 +232,7 @@ impl TyBuilder<hir_def::AdtId> { pub struct Tuple(usize); impl TyBuilder<Tuple> { pub fn tuple(size: usize) -> TyBuilder<Tuple> { - TyBuilder::new(Tuple(size), size) + TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect()) } pub fn build(self) -> Ty { @@ -164,10 +242,8 @@ impl TyBuilder<Tuple> { } impl TyBuilder<TraitId> { - pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> { - let generics = generics(db.upcast(), trait_id.into()); - let param_count = generics.len(); - TyBuilder::new(trait_id, param_count) + pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> { + TyBuilder::subst_for_def(db, def).with_data(def) } pub fn build(self) -> TraitRef { @@ -177,13 +253,8 @@ impl TyBuilder<TraitId> { } impl TyBuilder<TypeAliasId> { - pub fn assoc_type_projection( - db: &dyn HirDatabase, - type_alias: TypeAliasId, - ) -> TyBuilder<TypeAliasId> { - let generics = generics(db.upcast(), type_alias.into()); - let param_count = generics.len(); - TyBuilder::new(type_alias, param_count) + pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> { + TyBuilder::subst_for_def(db, def).with_data(def) } pub fn build(self) -> ProjectionTy { @@ -194,8 +265,16 @@ impl TyBuilder<TypeAliasId> { impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> { fn subst_binders(b: Binders<T>) -> Self { - let param_count = b.binders.len(Interner); - TyBuilder::new(b, param_count) + let param_kinds = b + .binders + .iter(Interner) + .map(|x| match x { + chalk_ir::VariableKind::Ty(_) => ParamKind::Type, + chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"), + chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()), + }) + .collect(); + TyBuilder::new(b, param_kinds) } pub fn build(self) -> <T as Fold<Interner>>::Result { |