8309: Introduce `GenericArg` like in Chalk r=flodiebold a=flodiebold

Plus some more adaptations to Substitution.

Lots of `assert_ty_ref` that we should revisit when introducing lifetime/const parameters.

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2021-04-03 09:19:55 +00:00 committed by GitHub
commit 8289b96216
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 323 additions and 161 deletions

View file

@ -1829,9 +1829,11 @@ impl Type {
);
match db.trait_solve(self.krate, goal)? {
Solution::Unique(SolutionVariables(subst)) => {
subst.value.first().map(|ty| self.derived(ty.clone()))
}
Solution::Unique(SolutionVariables(subst)) => subst
.value
.interned(&Interner)
.first()
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
Solution::Ambig(_) => None,
}
}
@ -1889,7 +1891,9 @@ impl Type {
| TyKind::Tuple(_, substs)
| TyKind::OpaqueType(_, substs)
| TyKind::FnDef(_, substs)
| TyKind::Closure(_, substs) => substs.iter().any(go),
| TyKind::Closure(_, substs) => {
substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
}
TyKind::Array(ty) | TyKind::Slice(ty) | TyKind::Raw(_, ty) | TyKind::Ref(_, ty) => {
go(ty)
@ -1928,7 +1932,10 @@ impl Type {
pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
if let TyKind::Tuple(_, substs) = &self.ty.interned(&Interner) {
substs.iter().map(|ty| self.derived(ty.clone())).collect()
substs
.iter(&Interner)
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone()))
.collect()
} else {
Vec::new()
}
@ -1973,8 +1980,9 @@ impl Type {
.strip_references()
.substs()
.into_iter()
.flat_map(|substs| substs.iter())
.map(move |ty| self.derived(ty.clone()))
.flat_map(|substs| substs.iter(&Interner))
.filter_map(|arg| arg.ty(&Interner).cloned())
.map(move |ty| self.derived(ty))
}
pub fn iterate_method_candidates<T>(
@ -2080,7 +2088,7 @@ impl Type {
substs: &Substitution,
cb: &mut impl FnMut(Type),
) {
for ty in substs.iter() {
for ty in substs.iter(&Interner).filter_map(|a| a.ty(&Interner)) {
walk_type(db, &type_.derived(ty.clone()), cb);
}
}
@ -2096,7 +2104,12 @@ impl Type {
WhereClause::Implemented(trait_ref) => {
cb(type_.clone());
// skip the self type. it's likely the type we just got the bounds from
for ty in trait_ref.substitution.iter().skip(1) {
for ty in trait_ref
.substitution
.iter(&Interner)
.skip(1)
.filter_map(|a| a.ty(&Interner))
{
walk_type(db, &type_.derived(ty.clone()), cb);
}
}

View file

@ -131,7 +131,7 @@ fn deref_by_trait(
// new variables in that case
for i in 1..vars.0.binders.len(&Interner) {
if vars.0.value[i - 1].interned(&Interner)
if vars.0.value.at(&Interner, i - 1).assert_ty_ref(&Interner).interned(&Interner)
!= &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
{
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
@ -139,7 +139,12 @@ fn deref_by_trait(
}
}
Some(Canonical {
value: vars.0.value[vars.0.value.len() - 1].clone(),
value: vars
.0
.value
.at(&Interner, vars.0.value.len(&Interner) - 1)
.assert_ty_ref(&Interner)
.clone(),
binders: vars.0.binders.clone(),
})
}

View file

@ -5,7 +5,7 @@ use chalk_ir::{
interner::HasInterner,
};
use crate::{AliasEq, DomainGoal, Interner, TraitRef, WhereClause};
use crate::{AliasEq, DomainGoal, GenericArg, GenericArgData, Interner, TraitRef, Ty, WhereClause};
macro_rules! has_interner {
($t:ty) => {
@ -17,6 +17,8 @@ macro_rules! has_interner {
has_interner!(WhereClause);
has_interner!(DomainGoal);
has_interner!(GenericArg);
has_interner!(Ty);
impl CastTo<WhereClause> for TraitRef {
fn cast_to(self, _interner: &Interner) -> WhereClause {
@ -36,6 +38,12 @@ impl CastTo<DomainGoal> for WhereClause {
}
}
impl CastTo<GenericArg> for Ty {
fn cast_to(self, interner: &Interner) -> GenericArg {
GenericArg::new(interner, GenericArgData::Ty(self))
}
}
macro_rules! transitive_impl {
($a:ty, $b:ty, $c:ty) => {
impl CastTo<$c> for $a {
@ -51,3 +59,15 @@ macro_rules! transitive_impl {
transitive_impl!(TraitRef, WhereClause, DomainGoal);
transitive_impl!(AliasEq, WhereClause, DomainGoal);
macro_rules! reflexive_impl {
($a:ty) => {
impl CastTo<$a> for $a {
fn cast_to(self, _interner: &Interner) -> $a {
self
}
}
};
}
reflexive_impl!(GenericArg);

View file

@ -392,7 +392,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
_ => return,
};
if params.len() > 0 && params[0] == mismatch.actual {
if params.len(&Interner) > 0
&& params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual)
{
let (_, source_map) = db.body_with_source_map(self.owner);
if let Ok(source_ptr) = source_map.expr_syntax(id) {

View file

@ -792,7 +792,10 @@ fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Opt
Pat::Tuple { .. } => {
let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
Some(Constructor::Tuple {
arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(),
arity: cx.infer.type_of_pat[pat_id]
.as_tuple()
.ok_or(MatchCheckErr::Unknown)?
.len(&Interner),
})
}
Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {

View file

@ -8,7 +8,7 @@ use hir_def::{
find_path,
generics::TypeParamProvenance,
item_scope::ItemInNs,
path::{GenericArg, Path, PathKind},
path::{Path, PathKind},
type_ref::{TypeBound, TypeRef},
visibility::Visibility,
AssocContainerId, Lookup, ModuleId, TraitId,
@ -18,7 +18,7 @@ use hir_expand::name::Name;
use crate::{
db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
CallableDefId, CallableSig, DomainGoal, ImplTraitId, Interner, Lifetime, OpaqueTy,
CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy,
ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TyKind, WhereClause,
};
@ -251,16 +251,16 @@ impl HirDisplay for ProjectionTy {
}
let trait_ = f.db.trait_data(self.trait_(f.db));
let first_parameter = self.substitution[0].into_displayable(
let first_parameter = self.self_type_parameter().into_displayable(
f.db,
f.max_size,
f.omit_verbose_types,
f.display_target,
);
write!(f, "<{} as {}", first_parameter, trait_.name)?;
if self.substitution.len() > 1 {
if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
f.write_joined(&self.substitution[1..], ", ")?;
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
write!(f, ">")?;
}
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@ -274,7 +274,15 @@ impl HirDisplay for OpaqueTy {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
self.substitution[0].hir_fmt(f)
self.substitution.at(&Interner, 0).hir_fmt(f)
}
}
impl HirDisplay for GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self.interned() {
crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
}
}
}
@ -373,9 +381,9 @@ impl HirDisplay for Ty {
}
}
TyKind::Tuple(_, substs) => {
if substs.len() == 1 {
if substs.len(&Interner) == 1 {
write!(f, "(")?;
substs[0].hir_fmt(f)?;
substs.at(&Interner, 0).hir_fmt(f)?;
write!(f, ",)")?;
} else {
write!(f, "(")?;
@ -399,7 +407,7 @@ impl HirDisplay for Ty {
write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
}
};
if parameters.len() > 0 {
if parameters.len(&Interner) > 0 {
let generics = generics(f.db.upcast(), def.into());
let (parent_params, self_param, type_params, _impl_trait_params) =
generics.provenance_split();
@ -451,7 +459,7 @@ impl HirDisplay for Ty {
}
}
if parameters.len() > 0 {
if parameters.len(&Interner) > 0 {
let parameters_to_write = if f.display_target.is_source_code()
|| f.omit_verbose_types()
{
@ -463,9 +471,11 @@ impl HirDisplay for Ty {
None => parameters.0.as_ref(),
Some(default_parameters) => {
let mut default_from = 0;
for (i, parameter) in parameters.iter().enumerate() {
match (parameter.interned(&Interner), default_parameters.get(i))
{
for (i, parameter) in parameters.iter(&Interner).enumerate() {
match (
parameter.assert_ty_ref(&Interner).interned(&Interner),
default_parameters.get(i),
) {
(&TyKind::Unknown, _) | (_, None) => {
default_from = i + 1;
}
@ -473,7 +483,8 @@ impl HirDisplay for Ty {
let actual_default = default_parameter
.clone()
.subst(&parameters.prefix(i));
if parameter != &actual_default {
if parameter.assert_ty_ref(&Interner) != &actual_default
{
default_from = i + 1;
}
}
@ -504,7 +515,7 @@ impl HirDisplay for Ty {
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
if parameters.len() > 0 {
if parameters.len(&Interner) > 0 {
write!(f, "<")?;
f.write_joined(&*parameters.0, ", ")?;
write!(f, ">")?;
@ -537,7 +548,7 @@ impl HirDisplay for Ty {
}
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
write!(f, "impl Future<Output = ")?;
parameters[0].hir_fmt(f)?;
parameters.at(&Interner, 0).hir_fmt(f)?;
write!(f, ">")?;
}
}
@ -548,7 +559,7 @@ impl HirDisplay for Ty {
DisplaySourceCodeError::Closure,
));
}
let sig = substs[0].callable_sig(f.db);
let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
if let Some(sig) = sig {
if sig.params().is_empty() {
write!(f, "||")?;
@ -718,7 +729,9 @@ fn write_bounds_like_dyn_trait(
write!(f, "{}", f.db.trait_data(trait_).name)?;
if let [_, params @ ..] = &*trait_ref.substitution.0 {
if is_fn_trait {
if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
if let Some(args) =
params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
{
write!(f, "(")?;
f.write_joined(&*args.0, ", ")?;
write!(f, ")")?;
@ -767,16 +780,16 @@ impl TraitRef {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
self.substitution[0].hir_fmt(f)?;
self.self_type_parameter().hir_fmt(f)?;
if use_as {
write!(f, " as ")?;
} else {
write!(f, ": ")?;
}
write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
if self.substitution.len() > 1 {
if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
f.write_joined(&self.substitution[1..], ", ")?;
f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
write!(f, ">")?;
}
Ok(())
@ -1016,11 +1029,11 @@ impl HirDisplay for Path {
}
}
impl HirDisplay for GenericArg {
impl HirDisplay for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self {
GenericArg::Type(ty) => ty.hir_fmt(f),
GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
}
}
}

View file

@ -100,7 +100,7 @@ impl<'a> InferenceContext<'a> {
},
(TyKind::Closure(.., substs), TyKind::Function { .. }) => {
from_ty = substs[0].clone();
from_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
}
_ => {}

View file

@ -266,7 +266,7 @@ impl<'a> InferenceContext<'a> {
let sig_ty = TyKind::Function(FnPointer {
num_args: sig_tys.len() - 1,
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
substs: Substitution(sig_tys.clone().into()),
substs: Substitution::from_iter(&Interner, sig_tys.clone()),
})
.intern(&Interner);
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
@ -406,7 +406,7 @@ impl<'a> InferenceContext<'a> {
self.unify(&ty, &expected.ty);
let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty);
let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner));
let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it));
for field in fields.iter() {
@ -456,9 +456,13 @@ impl<'a> InferenceContext<'a> {
.unwrap_or(true)
};
match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) {
TyKind::Tuple(_, substs) => {
name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
}
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
substs
.interned(&Interner)
.get(idx)
.map(|a| a.assert_ty_ref(&Interner))
.cloned()
}),
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
let local_id = self.db.struct_data(*s).variant_data.field(name)?;
let field = FieldId { parent: (*s).into(), local_id };
@ -635,7 +639,7 @@ impl<'a> InferenceContext<'a> {
let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
match (range_type, lhs_ty, rhs_ty) {
(RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
Some(adt) => Ty::adt_ty(adt, Substitution::empty()),
Some(adt) => Ty::adt_ty(adt, Substitution::empty(&Interner)),
None => self.err_ty(),
},
(RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
@ -694,8 +698,8 @@ impl<'a> InferenceContext<'a> {
Expr::Tuple { exprs } => {
let mut tys = match expected.ty.interned(&Interner) {
TyKind::Tuple(_, substs) => substs
.iter()
.cloned()
.iter(&Interner)
.map(|a| a.assert_ty_ref(&Interner).clone())
.chain(repeat_with(|| self.table.new_type_var()))
.take(exprs.len())
.collect::<Vec<_>>(),
@ -706,7 +710,7 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
}
TyKind::Tuple(tys.len(), Substitution(tys.into())).intern(&Interner)
TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
}
Expr::Array(array) => {
let elem_ty = match expected.ty.interned(&Interner) {
@ -953,7 +957,7 @@ impl<'a> InferenceContext<'a> {
substs.push(self.err_ty());
}
assert_eq!(substs.len(), total_len);
Substitution(substs.into())
Substitution::from_iter(&Interner, substs)
}
fn register_obligations_for_call(&mut self, callable_ty: &Ty) {

View file

@ -35,7 +35,7 @@ impl<'a> InferenceContext<'a> {
}
self.unify(&ty, expected);
let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty);
let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner));
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
let (pre, post) = match ellipsis {
@ -74,7 +74,7 @@ impl<'a> InferenceContext<'a> {
self.unify(&ty, expected);
let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty);
let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner));
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
for subpat in subpats {
@ -134,7 +134,8 @@ impl<'a> InferenceContext<'a> {
};
let n_uncovered_patterns = expectations.len().saturating_sub(args.len());
let err_ty = self.err_ty();
let mut expectations_iter = expectations.iter().chain(repeat(&err_ty));
let mut expectations_iter =
expectations.iter().map(|a| a.assert_ty_ref(&Interner)).chain(repeat(&err_ty));
let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
@ -142,7 +143,8 @@ impl<'a> InferenceContext<'a> {
inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
TyKind::Tuple(inner_tys.len(), Substitution(inner_tys.into())).intern(&Interner)
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(&Interner, inner_tys))
.intern(&Interner)
}
Pat::Or(ref pats) => {
if let Some((first_pat, rest)) = pats.split_first() {
@ -236,9 +238,10 @@ impl<'a> InferenceContext<'a> {
Pat::Box { inner } => match self.resolve_boxed_box() {
Some(box_adt) => {
let (inner_ty, alloc_ty) = match expected.as_adt() {
Some((adt, subst)) if adt == box_adt => {
(subst[0].clone(), subst.get(1).cloned())
}
Some((adt, subst)) if adt == box_adt => (
subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
subst.interned(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
),
_ => (self.result.standard_types.unknown.clone(), None),
};

View file

@ -97,12 +97,12 @@ impl<'a> InferenceContext<'a> {
let ty = self.db.value_ty(typable);
// self_subst is just for the parent
let parent_substs = self_subst.unwrap_or_else(Substitution::empty);
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(&Interner));
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
let substs = ctx.substs_from_path(path, typable, true);
let full_substs = Substitution::builder(substs.len())
let full_substs = Substitution::builder(substs.len(&Interner))
.use_parent_substs(&parent_substs)
.fill(substs.0[parent_substs.len()..].iter().cloned())
.fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
.build();
let ty = ty.subst(&full_substs);
Some(ty)

View file

@ -129,29 +129,28 @@ impl<T> Canonicalized<T> {
solution: Canonical<Substitution>,
) {
// the solution may contain new variables, which we need to convert to new inference vars
let new_vars = Substitution(
solution
.binders
.iter(&Interner)
.map(|k| match k.kind {
VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(),
VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(),
VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(),
// HACK: Chalk can sometimes return new lifetime variables. We
// want to just skip them, but to not mess up the indices of
// other variables, we'll just create a new type variable in
// their place instead. This should not matter (we never see the
// actual *uses* of the lifetime variable).
VariableKind::Lifetime => ctx.table.new_type_var(),
_ => panic!("const variable in solution"),
})
.collect(),
let new_vars = Substitution::from_iter(
&Interner,
solution.binders.iter(&Interner).map(|k| match k.kind {
VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(),
VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(),
VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(),
// HACK: Chalk can sometimes return new lifetime variables. We
// want to just skip them, but to not mess up the indices of
// other variables, we'll just create a new type variable in
// their place instead. This should not matter (we never see the
// actual *uses* of the lifetime variable).
VariableKind::Lifetime => ctx.table.new_type_var(),
_ => panic!("const variable in solution"),
}),
);
for (i, ty) in solution.value.into_iter().enumerate() {
for (i, ty) in solution.value.iter(&Interner).enumerate() {
let (v, k) = self.free_vars[i];
// eagerly replace projections in the type; we may be getting types
// e.g. from where clauses where this hasn't happened yet
let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
let ty = ctx.normalize_associated_types_in(
ty.assert_ty_ref(&Interner).clone().subst_bound_vars(&new_vars),
);
ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty);
}
}
@ -163,13 +162,13 @@ pub fn could_unify(t1: &Ty, t2: &Ty) -> bool {
pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
let mut table = InferenceTable::new();
let vars = Substitution(
let vars = Substitution::from_iter(
&Interner,
tys.binders
.iter(&Interner)
// we always use type vars here because we want everything to
// fallback to Unknown in the end (kind of hacky, as below)
.map(|_| table.new_type_var())
.collect(),
.map(|_| table.new_type_var()),
);
let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
@ -178,7 +177,8 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
}
// default any type vars that weren't unified back to their original bound vars
// (kind of hacky)
for (i, var) in vars.iter().enumerate() {
for (i, var) in vars.iter(&Interner).enumerate() {
let var = var.assert_ty_ref(&Interner);
if &*table.resolve_ty_shallow(var) == var {
table.unify(
var,
@ -188,7 +188,10 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
}
Some(
Substitution::builder(tys.binders.len(&Interner))
.fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
.fill(
vars.iter(&Interner)
.map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())),
)
.build(),
)
}
@ -284,7 +287,9 @@ impl InferenceTable {
substs2: &Substitution,
depth: usize,
) -> bool {
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth))
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| {
self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth)
})
}
fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {

View file

@ -24,9 +24,10 @@ mod tests;
#[cfg(test)]
mod test_db;
use std::{iter, mem, ops::Deref, sync::Arc};
use std::{iter, mem, sync::Arc};
use base_db::salsa;
use chalk_ir::cast::{CastTo, Caster};
use hir_def::{
builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId,
GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId,
@ -109,7 +110,7 @@ impl ProjectionTy {
}
pub fn self_type_parameter(&self) -> &Ty {
&self.substitution[0]
&self.substitution.interned(&Interner)[0].assert_ty_ref(&Interner)
}
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
@ -324,9 +325,72 @@ impl Ty {
}
}
#[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<[Ty; 2]>);
pub struct Substitution(SmallVec<[GenericArg; 2]>);
impl TypeWalk for Substitution {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
@ -347,18 +411,34 @@ impl TypeWalk for Substitution {
}
impl Substitution {
pub fn interned(&self, _: &Interner) -> &[Ty] {
pub fn interned(&self, _: &Interner) -> &[GenericArg] {
&self.0
}
pub fn empty() -> Substitution {
pub fn len(&self, _: &Interner) -> usize {
self.0.len()
}
pub fn is_empty(&self, _: &Interner) -> bool {
self.0.is_empty()
}
pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
&self.0[i]
}
pub fn empty(_: &Interner) -> Substitution {
Substitution(SmallVec::new())
}
pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
self.0.iter()
}
pub fn single(ty: Ty) -> Substitution {
Substitution({
let mut v = SmallVec::new();
v.push(ty);
v.push(ty.cast(&Interner));
v
})
}
@ -371,15 +451,11 @@ impl Substitution {
Substitution(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into())
}
pub fn as_single(&self) -> &Ty {
if self.0.len() != 1 {
panic!("expected substs of len 1, got {:?}", self);
}
&self.0[0]
}
pub fn from_iter(_interner: &Interner, elements: impl IntoIterator<Item = Ty>) -> Self {
Substitution(elements.into_iter().collect())
pub fn from_iter(
interner: &Interner,
elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
) -> Self {
Substitution(elements.into_iter().casted(interner).collect())
}
/// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
@ -387,11 +463,11 @@ impl Substitution {
db: &dyn HirDatabase,
generic_params: &Generics,
) -> Substitution {
Substitution(
Substitution::from_iter(
&Interner,
generic_params
.iter()
.map(|(id, _)| TyKind::Placeholder(to_placeholder_idx(db, id)).intern(&Interner))
.collect(),
.map(|(id, _)| TyKind::Placeholder(to_placeholder_idx(db, id)).intern(&Interner)),
)
}
@ -403,12 +479,12 @@ impl Substitution {
/// Return Substs that replace each parameter by a bound variable.
pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substitution {
Substitution(
Substitution::from_iter(
&Interner,
generic_params
.iter()
.enumerate()
.map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner))
.collect(),
.map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)),
)
}
@ -435,18 +511,18 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
#[derive(Debug, Clone)]
pub struct SubstsBuilder {
vec: Vec<Ty>,
vec: Vec<GenericArg>,
param_count: usize,
}
impl SubstsBuilder {
pub fn build(self) -> Substitution {
assert_eq!(self.vec.len(), self.param_count);
Substitution(self.vec.into())
Substitution::from_iter(&Interner, self.vec)
}
pub fn push(mut self, ty: Ty) -> Self {
self.vec.push(ty);
pub fn push(mut self, ty: impl CastTo<GenericArg>) -> Self {
self.vec.push(ty.cast(&Interner));
self
}
@ -465,28 +541,20 @@ impl SubstsBuilder {
self.fill(iter::repeat(TyKind::Unknown.intern(&Interner)))
}
pub fn fill(mut self, filler: impl Iterator<Item = Ty>) -> Self {
self.vec.extend(filler.take(self.remaining()));
pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> 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() <= self.param_count);
self.vec.extend(parent_substs.iter().cloned());
assert!(parent_substs.len(&Interner) <= self.param_count);
self.vec.extend(parent_substs.iter(&Interner).cloned());
self
}
}
impl Deref for Substitution {
type Target = [Ty];
fn deref(&self) -> &[Ty] {
&self.0
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Binders<T> {
pub num_binders: usize,
@ -535,7 +603,7 @@ impl<T: Clone> Binders<&T> {
impl<T: TypeWalk> Binders<T> {
/// Substitutes all variables.
pub fn subst(self, subst: &Substitution) -> T {
assert_eq!(subst.len(), self.num_binders);
assert_eq!(subst.len(&Interner), self.num_binders);
self.value.subst_bound_vars(subst)
}
}
@ -563,7 +631,7 @@ pub struct TraitRef {
impl TraitRef {
pub fn self_type_parameter(&self) -> &Ty {
&self.substitution[0]
&self.substitution.at(&Interner, 0).assert_ty_ref(&Interner)
}
pub fn hir_trait_id(&self) -> TraitId {
@ -699,14 +767,20 @@ impl CallableSig {
.shift_bound_vars_out(DebruijnIndex::ONE)
.interned(&Interner)
.iter()
.cloned()
.map(|arg| arg.assert_ty_ref(&Interner).clone())
.collect(),
is_varargs: fn_ptr.sig.variadic,
}
}
pub fn from_substs(substs: &Substitution) -> CallableSig {
CallableSig { params_and_return: substs.iter().cloned().collect(), is_varargs: false }
CallableSig {
params_and_return: substs
.iter(&Interner)
.map(|arg| arg.assert_ty_ref(&Interner).clone())
.collect(),
is_varargs: false,
}
}
pub fn params(&self) -> &[Ty] {
@ -738,7 +812,7 @@ impl TypeWalk for CallableSig {
impl Ty {
pub fn unit() -> Self {
TyKind::Tuple(0, Substitution::empty()).intern(&Interner)
TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner)
}
pub fn adt_ty(adt: hir_def::AdtId, substs: Substitution) -> Ty {
@ -908,7 +982,7 @@ impl Ty {
Some(sig.subst(&parameters))
}
TyKind::Closure(.., substs) => {
let sig_param = &substs[0];
let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
sig_param.callable_sig(db)
}
_ => None,
@ -960,7 +1034,7 @@ impl Ty {
0,
WhereClause::Implemented(TraitRef {
trait_id: to_chalk_trait_id(future_trait),
substitution: Substitution::empty(),
substitution: Substitution::empty(&Interner),
}),
);
Some(vec![impl_bound])
@ -1109,7 +1183,10 @@ pub trait TypeWalk {
&mut |ty, binders| {
if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
if bound.debruijn >= binders {
*ty = substs.0[bound.index].clone().shift_bound_vars(binders);
*ty = substs.0[bound.index]
.assert_ty_ref(&Interner)
.clone()
.shift_bound_vars(binders);
}
}
},
@ -1156,12 +1233,12 @@ impl TypeWalk for Ty {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self.interned(&Interner) {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
for t in p_ty.substitution.iter() {
for t in p_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
for t in o_ty.substitution.iter() {
for t in o_ty.substitution.iter(&Interner) {
t.walk(f);
}
}
@ -1175,7 +1252,7 @@ impl TypeWalk for Ty {
}
_ => {
if let Some(substs) = self.substs() {
for t in substs.iter() {
for t in substs.iter(&Interner) {
t.walk(f);
}
}

View file

@ -178,9 +178,10 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::Placeholder => TyKind::Unknown.intern(&Interner),
TypeRef::Fn(params, is_varargs) => {
let substs = Substitution(params.iter().map(|tr| self.lower_ty(tr)).collect());
let substs =
Substitution::from_iter(&Interner, params.iter().map(|tr| self.lower_ty(tr)));
TyKind::Function(FnPointer {
num_args: substs.len() - 1,
num_args: substs.len(&Interner) - 1,
sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
substs,
})
@ -625,7 +626,7 @@ impl<'a> TyLoweringContext<'a> {
for default_ty in defaults.iter().skip(substs.len()) {
// each default can depend on the previous parameters
let substs_so_far = Substitution(substs.clone().into());
let substs_so_far = Substitution::from_iter(&Interner, substs.clone());
substs.push(default_ty.clone().subst(&substs_so_far));
}
}
@ -638,7 +639,7 @@ impl<'a> TyLoweringContext<'a> {
}
assert_eq!(substs.len(), total_len);
Substitution(substs.into())
Substitution::from_iter(&Interner, substs)
}
fn lower_trait_ref_from_path(
@ -1062,7 +1063,7 @@ fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
let generics = generics(db.upcast(), def.into());
let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST);
Binders::new(
substs.len(),
substs.len(&Interner),
TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner),
)
}
@ -1107,7 +1108,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
let generics = generics(db.upcast(), def.into());
let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST);
Binders::new(
substs.len(),
substs.len(&Interner),
TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner),
)
}
@ -1134,7 +1135,7 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
let generics = generics(db.upcast(), def.parent.into());
let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST);
Binders::new(
substs.len(),
substs.len(&Interner),
TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner),
)
}
@ -1142,7 +1143,7 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
let generics = generics(db.upcast(), adt.into());
let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST);
Binders::new(substs.len(), Ty::adt_ty(adt, substs))
Binders::new(substs.len(&Interner), Ty::adt_ty(adt, substs))
}
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {

View file

@ -720,7 +720,7 @@ pub(crate) fn inherent_impl_substs(
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
UniverseIndex::ROOT,
))
.take(vars.len()),
.take(vars.len(&Interner)),
);
let tys = Canonical {
binders: CanonicalVarKinds::from_iter(&Interner, kinds),
@ -732,7 +732,8 @@ pub(crate) fn inherent_impl_substs(
// Unknown. I think this can only really happen if self_ty contained
// Unknown, and in that case we want the result to contain Unknown in those
// places again.
substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.binders.len(&Interner)))
substs
.map(|s| fallback_bound_vars(s.suffix(vars.len(&Interner)), self_ty.binders.len(&Interner)))
}
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@ -821,7 +822,7 @@ fn generic_implements_goal(
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
UniverseIndex::ROOT,
))
.take(substs.len() - 1),
.take(substs.len(&Interner) - 1),
);
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
let obligation = trait_ref.cast(&Interner);

View file

@ -138,7 +138,7 @@ pub(crate) fn trait_solve_query(
..
})) = &goal.value.goal
{
if let TyKind::BoundVar(_) = &projection_ty.substitution[0].interned(&Interner) {
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter().interned(&Interner) {
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
return Some(Solution::Ambig(Guidance::Unknown));
}

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use log::debug;
use chalk_ir::{fold::shift::Shift, CanonicalVarKinds, GenericArg};
use chalk_ir::{fold::shift::Shift, CanonicalVarKinds};
use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::{salsa::InternKey, CrateId};
@ -80,7 +80,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
fn impls_for_trait(
&self,
trait_id: TraitId,
parameters: &[GenericArg<Interner>],
parameters: &[chalk_ir::GenericArg<Interner>],
binders: &CanonicalVarKinds<Interner>,
) -> Vec<ImplId> {
debug!("impls_for_trait {:?}", trait_id);
@ -308,7 +308,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
_closure_id: chalk_ir::ClosureId<Interner>,
_substs: &chalk_ir::Substitution<Interner>,
) -> chalk_ir::Substitution<Interner> {
Substitution::empty().to_chalk(self.db)
Substitution::empty(&Interner).to_chalk(self.db)
}
fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
@ -439,7 +439,7 @@ pub(crate) fn trait_datum_query(
lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
let trait_datum = TraitDatum {
id: trait_id,
binders: make_binders(trait_datum_bound, bound_vars.len()),
binders: make_binders(trait_datum_bound, bound_vars.len(&Interner)),
flags,
associated_ty_ids,
well_known,
@ -577,7 +577,7 @@ fn impl_def_datum(
.collect();
debug!("impl_datum: {:?}", impl_datum_bound);
let impl_datum = ImplDatum {
binders: make_binders(impl_datum_bound, bound_vars.len()),
binders: make_binders(impl_datum_bound, bound_vars.len(&Interner)),
impl_type,
polarity,
associated_ty_value_ids,

View file

@ -13,7 +13,7 @@ use crate::{
db::HirDatabase,
primitive::UintTy,
traits::{Canonical, DomainGoal},
AliasTy, CallableDefId, FnPointer, InEnvironment, OpaqueTy, ProjectionTy,
AliasTy, CallableDefId, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy,
QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
};
@ -137,7 +137,7 @@ impl ToChalk for Ty {
db,
substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
);
TyKind::Function(FnPointer { num_args: (substs.len() - 1), sig, substs })
TyKind::Function(FnPointer { num_args: (substs.len(&Interner) - 1), sig, substs })
}
chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown,
@ -216,24 +216,39 @@ fn array_to_chalk(db: &dyn HirDatabase, ty: Ty) -> chalk_ir::Ty<Interner> {
chalk_ir::TyKind::Array(arg, const_).intern(&Interner)
}
impl ToChalk for GenericArg {
type Chalk = chalk_ir::GenericArg<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
match self.interned {
crate::GenericArgData::Ty(ty) => ty.to_chalk(db).cast(&Interner),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
match chalk.interned() {
chalk_ir::GenericArgData::Ty(ty) => Ty::from_chalk(db, ty.clone()).cast(&Interner),
chalk_ir::GenericArgData::Lifetime(_) => unimplemented!(),
chalk_ir::GenericArgData::Const(_) => unimplemented!(),
}
}
}
impl ToChalk for Substitution {
type Chalk = chalk_ir::Substitution<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
chalk_ir::Substitution::from_iter(
&Interner,
self.iter(&Interner).map(|ty| ty.clone().to_chalk(db)),
)
}
fn from_chalk(
db: &dyn HirDatabase,
parameters: chalk_ir::Substitution<Interner>,
) -> Substitution {
let tys = parameters
.iter(&Interner)
.map(|p| match p.ty(&Interner) {
Some(ty) => from_chalk(db, ty.clone()),
None => unimplemented!(),
})
.collect();
let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
Substitution(tys)
}
}
@ -531,7 +546,7 @@ pub(super) fn generic_predicate_to_inline_bound(
// have the expected self type
return None;
}
let args_no_self = trait_ref.substitution[1..]
let args_no_self = trait_ref.substitution.interned(&Interner)[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect();
@ -543,7 +558,7 @@ pub(super) fn generic_predicate_to_inline_bound(
return None;
}
let trait_ = projection_ty.trait_(db);
let args_no_self = projection_ty.substitution[1..]
let args_no_self = projection_ty.substitution.interned(&Interner)[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect();