From 715c178f0b52117c4c689c39a0921012bfbb2386 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 4 Apr 2021 12:55:47 +0200 Subject: [PATCH] Move TyBuilder to its own module --- crates/hir_ty/src/builder.rs | 211 ++++++++++++++++++++++++++++++++++ crates/hir_ty/src/lib.rs | 216 ++--------------------------------- 2 files changed, 222 insertions(+), 205 deletions(-) create mode 100644 crates/hir_ty/src/builder.rs diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs new file mode 100644 index 00000000000..ba158a74925 --- /dev/null +++ b/crates/hir_ty/src/builder.rs @@ -0,0 +1,211 @@ +//! `TyBuilder`, a helper for building instances of `Ty` and related types. + +use std::iter; + +use chalk_ir::{ + cast::{Cast, CastTo, Caster}, + interner::HasInterner, + AdtId, BoundVar, DebruijnIndex, Safety, Scalar, +}; +use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; +use smallvec::SmallVec; + +use crate::{ + db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, + CallableSig, FnPointer, FnSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, + TyDefId, TyKind, TypeWalk, ValueTyDefId, +}; + +pub struct TyBuilder { + data: D, + vec: SmallVec<[GenericArg; 2]>, + param_count: usize, +} + +impl TyBuilder { + fn new(data: D, param_count: usize) -> TyBuilder { + TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } + } + + fn build_internal(self) -> (D, Substitution) { + assert_eq!(self.vec.len(), self.param_count); + // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form + let subst = Substitution(self.vec); + (self.data, subst) + } + + pub fn push(mut self, arg: impl CastTo) -> Self { + self.vec.push(arg.cast(&Interner)); + self + } + + pub fn remaining(&self) -> usize { + self.param_count - 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)), + ) + } + + pub fn fill_with_unknown(self) -> Self { + self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) + } + + pub fn fill(mut self, filler: impl Iterator>) -> Self { + self.vec.extend(filler.take(self.remaining()).casted(&Interner)); + 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()); + self + } +} + +impl TyBuilder<()> { + pub fn unit() -> Ty { + TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) + } + + pub fn fn_ptr(sig: CallableSig) -> Ty { + TyKind::Function(FnPointer { + num_args: sig.params().len(), + sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, + substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), + }) + .intern(&Interner) + } + + pub fn builtin(builtin: BuiltinType) -> Ty { + match builtin { + BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), + BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), + BuiltinType::Str => TyKind::Str.intern(&Interner), + BuiltinType::Int(t) => { + TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) + } + BuiltinType::Uint(t) => { + TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) + } + BuiltinType::Float(t) => { + TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) + } + } + } + + pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into) -> TyBuilder<()> { + let def = def.into(); + let params = generics(db.upcast(), def); + let param_count = params.len(); + TyBuilder::new((), param_count) + } + + pub fn build(self) -> Substitution { + let ((), subst) = self.build_internal(); + subst + } +} + +impl TyBuilder { + pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder { + let generics = generics(db.upcast(), adt.into()); + let param_count = generics.len(); + TyBuilder::new(adt, param_count) + } + + pub fn fill_with_defaults( + mut self, + db: &dyn HirDatabase, + mut fallback: impl FnMut() -> Ty, + ) -> 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(self.vec.clone()); + self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); + } + } + self + } + + pub fn build(self) -> Ty { + let (adt, subst) = self.build_internal(); + TyKind::Adt(AdtId(adt), subst).intern(&Interner) + } +} + +pub struct Tuple(usize); +impl TyBuilder { + pub fn tuple(size: usize) -> TyBuilder { + TyBuilder::new(Tuple(size), size) + } + + pub fn build(self) -> Ty { + let (Tuple(size), subst) = self.build_internal(); + TyKind::Tuple(size, subst).intern(&Interner) + } +} + +impl TyBuilder { + pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder { + let generics = generics(db.upcast(), trait_id.into()); + let param_count = generics.len(); + TyBuilder::new(trait_id, param_count) + } + + pub fn build(self) -> TraitRef { + let (trait_id, substitution) = self.build_internal(); + TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } + } +} + +impl TyBuilder { + pub fn assoc_type_projection( + db: &dyn HirDatabase, + type_alias: TypeAliasId, + ) -> TyBuilder { + let generics = generics(db.upcast(), type_alias.into()); + let param_count = generics.len(); + TyBuilder::new(type_alias, param_count) + } + + pub fn build(self) -> ProjectionTy { + let (type_alias, substitution) = self.build_internal(); + ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } + } +} + +impl> TyBuilder> { + fn subst_binders(b: Binders) -> Self { + let param_count = b.num_binders; + TyBuilder::new(b, param_count) + } + + pub fn build(self) -> T { + let (b, subst) = self.build_internal(); + b.subst(&subst) + } +} + +impl TyBuilder> { + pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder> { + TyBuilder::subst_binders(db.ty(def.into())) + } + + pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> { + TyBuilder::subst_binders(db.impl_self_ty(def)) + } + + pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder> { + TyBuilder::subst_binders(db.value_ty(def)) + } +} diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index f99b70f2b94..ebdcc4804fb 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs @@ -14,6 +14,8 @@ mod lower; pub(crate) mod infer; pub(crate) mod utils; mod chalk_cast; +mod chalk_ext; +mod builder; pub mod display; pub mod db; @@ -23,22 +25,19 @@ pub mod diagnostics; mod tests; #[cfg(test)] mod test_db; -mod chalk_ext; -use std::{iter, mem, sync::Arc}; +use std::{mem, sync::Arc}; -use base_db::salsa; -use chalk_ir::{ - cast::{CastTo, Caster}, - interner::HasInterner, -}; -use hir_def::{ - builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, - GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, -}; +use chalk_ir::cast::{CastTo, Caster}; use itertools::Itertools; use smallvec::SmallVec; +use base_db::salsa; +use hir_def::{ + expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, + LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, +}; + use crate::{ db::HirDatabase, display::HirDisplay, @@ -46,6 +45,7 @@ use crate::{ }; pub use autoderef::autoderef; +pub use builder::TyBuilder; pub use chalk_ext::TyExt; pub use infer::{could_unify, InferenceResult, InferenceVar}; pub use lower::{ @@ -744,200 +744,6 @@ impl TypeWalk for CallableSig { } } -pub struct TyBuilder { - data: D, - vec: SmallVec<[GenericArg; 2]>, - param_count: usize, -} - -impl TyBuilder { - fn new(data: D, param_count: usize) -> TyBuilder { - TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } - } - - fn build_internal(self) -> (D, Substitution) { - assert_eq!(self.vec.len(), self.param_count); - // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form - let subst = Substitution(self.vec); - (self.data, subst) - } - - pub fn push(mut self, arg: impl CastTo) -> Self { - self.vec.push(arg.cast(&Interner)); - self - } - - fn remaining(&self) -> usize { - self.param_count - 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)), - ) - } - - pub fn fill_with_unknown(self) -> Self { - self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) - } - - pub fn fill(mut self, filler: impl Iterator>) -> Self { - self.vec.extend(filler.take(self.remaining()).casted(&Interner)); - 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()); - self - } -} - -impl TyBuilder<()> { - pub fn unit() -> Ty { - TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) - } - - pub fn fn_ptr(sig: CallableSig) -> Ty { - TyKind::Function(FnPointer { - num_args: sig.params().len(), - sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, - substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), - }) - .intern(&Interner) - } - - pub fn builtin(builtin: BuiltinType) -> Ty { - match builtin { - BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), - BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), - BuiltinType::Str => TyKind::Str.intern(&Interner), - BuiltinType::Int(t) => { - TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) - } - BuiltinType::Uint(t) => { - TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) - } - BuiltinType::Float(t) => { - TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) - } - } - } - - pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into) -> TyBuilder<()> { - let def = def.into(); - let params = generics(db.upcast(), def); - let param_count = params.len(); - TyBuilder::new((), param_count) - } - - pub fn build(self) -> Substitution { - let ((), subst) = self.build_internal(); - subst - } -} - -impl TyBuilder { - pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder { - let generics = generics(db.upcast(), adt.into()); - let param_count = generics.len(); - TyBuilder::new(adt, param_count) - } - - pub fn fill_with_defaults( - mut self, - db: &dyn HirDatabase, - mut fallback: impl FnMut() -> Ty, - ) -> 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(self.vec.clone()); - self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); - } - } - self - } - - pub fn build(self) -> Ty { - let (adt, subst) = self.build_internal(); - TyKind::Adt(AdtId(adt), subst).intern(&Interner) - } -} - -struct Tuple(usize); -impl TyBuilder { - pub fn tuple(size: usize) -> TyBuilder { - TyBuilder::new(Tuple(size), size) - } - - pub fn build(self) -> Ty { - let (Tuple(size), subst) = self.build_internal(); - TyKind::Tuple(size, subst).intern(&Interner) - } -} - -impl TyBuilder { - pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder { - let generics = generics(db.upcast(), trait_id.into()); - let param_count = generics.len(); - TyBuilder::new(trait_id, param_count) - } - - pub fn build(self) -> TraitRef { - let (trait_id, substitution) = self.build_internal(); - TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } - } -} - -impl TyBuilder { - pub fn assoc_type_projection( - db: &dyn HirDatabase, - type_alias: TypeAliasId, - ) -> TyBuilder { - let generics = generics(db.upcast(), type_alias.into()); - let param_count = generics.len(); - TyBuilder::new(type_alias, param_count) - } - - pub fn build(self) -> ProjectionTy { - let (type_alias, substitution) = self.build_internal(); - ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } - } -} - -impl> TyBuilder> { - fn subst_binders(b: Binders) -> Self { - let param_count = b.num_binders; - TyBuilder::new(b, param_count) - } - - pub fn build(self) -> T { - let (b, subst) = self.build_internal(); - b.subst(&subst) - } -} - -impl TyBuilder> { - pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder> { - TyBuilder::subst_binders(db.ty(def.into())) - } - - pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> { - TyBuilder::subst_binders(db.impl_self_ty(def)) - } - - pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder> { - TyBuilder::subst_binders(db.value_ty(def)) - } -} - impl Ty { pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { match self.kind(&Interner) {