Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 26 additions & 196 deletions crates/hir-ty/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
//! `TyBuilder`, a helper for building instances of `Ty` and related types.

use chalk_ir::{
AdtId, DebruijnIndex, Scalar,
cast::{Cast, CastTo, Caster},
DebruijnIndex, Scalar,
cast::{Cast, Caster},
};
use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
use hir_def::{GenericDefId, GenericParamId, TraitId, builtin_type::BuiltinType};
use smallvec::SmallVec;

use crate::{
BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
TraitRef, Ty, TyDefId, TyExt, TyKind,
BoundVar, GenericArg, GenericArgData, Interner, Substitution, TraitRef, Ty, TyKind,
consteval::unknown_const_as_generic,
db::HirDatabase,
error_lifetime,
Expand All @@ -19,18 +18,18 @@ use crate::{
DbInterner, EarlyBinder,
mapping::{ChalkToNextSolver, NextSolverToChalk},
},
primitive, to_assoc_type_id, to_chalk_trait_id,
primitive, to_chalk_trait_id,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamKind {
pub(crate) enum ParamKind {
Type,
Lifetime,
Const(Ty),
}

/// This is a builder for `Ty` or anything that needs a `Substitution`.
pub struct TyBuilder<D> {
pub(crate) struct TyBuilder<D> {
/// The `data` field is used to keep track of what we're building (e.g. an
/// ADT, a `TraitRef`, ...).
data: D,
Expand Down Expand Up @@ -60,10 +59,6 @@ impl<D> TyBuilder<D> {
Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
}

fn new_empty(data: D) -> Self {
TyBuilder::new(data, SmallVec::new(), None)
}

fn build_internal(self) -> (D, Substitution) {
assert_eq!(
self.vec.len(),
Expand All @@ -83,35 +78,15 @@ impl<D> TyBuilder<D> {
(self.data, subst)
}

pub fn build_into_subst(self) -> Substitution {
self.build_internal().1
}

pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
assert!(self.remaining() > 0);
let arg = arg.cast(Interner);
let expected_kind = &self.param_kinds[self.vec.len()];

let arg_kind = match arg.data(Interner) {
GenericArgData::Ty(_) => ParamKind::Type,
GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
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 {
pub(crate) fn remaining(&self) -> usize {
self.param_kinds.len() - self.vec.len()
}

pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
pub(crate) fn fill_with_bound_vars(
self,
debruijn: DebruijnIndex,
starting_from: usize,
) -> Self {
// self.fill is inlined to make borrow checker happy
let mut this = self;
let other = &this.param_kinds[this.vec.len()..];
Expand All @@ -129,22 +104,6 @@ impl<D> TyBuilder<D> {
this
}

pub fn fill_with_unknown(self) -> Self {
let interner = DbInterner::conjure();
// self.fill is inlined to make borrow checker happy
let mut this = self;
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
ParamKind::Const(ty) => {
unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
}
ParamKind::Lifetime => error_lifetime().cast(Interner),
});
this.vec.extend(filler.casted(Interner));
assert_eq!(this.remaining(), 0);
this
}

#[tracing::instrument(skip_all)]
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
self.fill(|x| {
Expand All @@ -157,7 +116,7 @@ impl<D> TyBuilder<D> {
})
}

pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
pub(crate) fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
assert_eq!(self.remaining(), 0);
self
Expand All @@ -174,28 +133,11 @@ impl<D> TyBuilder<D> {
}

impl TyBuilder<()> {
pub fn unit() -> Ty {
TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
}

// FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well
pub fn discr_ty() -> Ty {
TyKind::Scalar(chalk_ir::Scalar::Int(chalk_ir::IntTy::I128)).intern(Interner)
}

pub fn bool() -> Ty {
TyKind::Scalar(chalk_ir::Scalar::Bool).intern(Interner)
}

pub fn usize() -> Ty {
pub(crate) fn usize() -> Ty {
TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
}

pub fn fn_ptr(sig: CallableSig) -> Ty {
TyKind::Function(sig.to_fn_ptr()).intern(Interner)
}

pub fn builtin(builtin: BuiltinType) -> Ty {
pub(crate) fn builtin(builtin: BuiltinType) -> Ty {
match builtin {
BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
Expand All @@ -212,16 +154,10 @@ impl TyBuilder<()> {
}
}

pub fn slice(argument: Ty) -> Ty {
TyKind::Slice(argument).intern(Interner)
}

pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
let params = generics(db, def.into());
params.placeholder_subst(db)
}

pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
pub(crate) fn unknown_subst(
db: &dyn HirDatabase,
def: impl Into<GenericDefId>,
) -> Substitution {
let interner = DbInterner::conjure();
let params = generics(db, def.into());
Substitution::from_iter(
Expand All @@ -239,7 +175,7 @@ impl TyBuilder<()> {
}

#[tracing::instrument(skip_all)]
pub fn subst_for_def(
pub(crate) fn subst_for_def(
db: &dyn HirDatabase,
def: impl Into<GenericDefId>,
parent_subst: Option<Substitution>,
Expand All @@ -257,139 +193,33 @@ impl TyBuilder<()> {
TyBuilder::new((), params, parent_subst)
}

pub fn build(self) -> Substitution {
pub(crate) fn build(self) -> Substitution {
let ((), subst) = self.build_internal();
subst
}
}

impl TyBuilder<hir_def::AdtId> {
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
TyBuilder::subst_for_def(db, def, None).with_data(def)
}

pub fn fill_with_defaults(
mut self,
db: &dyn HirDatabase,
mut fallback: impl FnMut() -> Ty,
) -> Self {
let interner = DbInterner::conjure();
// Note that we're building ADT, so we never have parent generic parameters.
let defaults = db.generic_defaults(self.data.into());

if let Some(defaults) = defaults.get(self.vec.len()..) {
for default_ty in defaults {
// NOTE(skip_binders): we only check if the arg type is error type.
if let Some(x) = default_ty.skip_binders().ty(Interner)
&& x.is_unknown()
{
self.vec.push(fallback().cast(Interner));
continue;
}
// Each default can only depend on the previous parameters.
self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
}
}

// The defaults may be missing if no param has default, so fill that.
let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
ParamKind::Type => fallback().cast(Interner),
ParamKind::Const(ty) => {
unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
}
ParamKind::Lifetime => error_lifetime().cast(Interner),
});
self.vec.extend(filler.casted(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<Tuple> {
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
TyBuilder::new(Tuple(size), std::iter::repeat_n(ParamKind::Type, size).collect(), None)
}

pub fn build(self) -> Ty {
let (Tuple(size), subst) = self.build_internal();
TyKind::Tuple(size, subst).intern(Interner)
}

pub fn tuple_with<I>(elements: I) -> Ty
where
I: IntoIterator<Item = Ty>,
<I as IntoIterator>::IntoIter: ExactSizeIterator,
{
let elements = elements.into_iter();
let len = elements.len();
let mut b =
TyBuilder::new(Tuple(len), std::iter::repeat_n(ParamKind::Type, len).collect(), None);
for e in elements {
b = b.push(e);
}
b.build()
}
}

impl TyBuilder<TraitId> {
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
pub(crate) fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
TyBuilder::subst_for_def(db, def, None).with_data(def)
}

pub fn build(self) -> TraitRef {
pub(crate) fn build(self) -> TraitRef {
let (trait_id, substitution) = self.build_internal();
TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
}
}

impl TyBuilder<TypeAliasId> {
pub fn assoc_type_projection(
db: &dyn HirDatabase,
def: TypeAliasId,
parent_subst: Option<Substitution>,
) -> TyBuilder<TypeAliasId> {
TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
}

pub fn build(self) -> ProjectionTy {
let (type_alias, substitution) = self.build_internal();
ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
}
}

impl<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>> TyBuilder<EarlyBinder<'db, T>> {
pub fn build(self, interner: DbInterner<'db>) -> T {
pub(crate) fn build(self, interner: DbInterner<'db>) -> T {
let (b, subst) = self.build_internal();
let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner);
b.instantiate(interner, args)
}
}

impl<'db> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
pub fn def_ty(
db: &'db dyn HirDatabase,
def: TyDefId,
parent_subst: Option<Substitution>,
) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
let poly_ty = db.ty(def);
let id: GenericDefId = match def {
TyDefId::BuiltinType(_) => {
assert!(parent_subst.is_none());
return TyBuilder::new_empty(poly_ty);
}
TyDefId::AdtId(id) => id.into(),
TyDefId::TypeAliasId(id) => id.into(),
};
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
}

pub fn impl_self_ty(
pub(crate) fn impl_self_ty(
db: &'db dyn HirDatabase,
def: hir_def::ImplId,
) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
Expand Down
Loading