Upgrade Chalk again

The big change here is counting binders, not
variables (https://github.com/rust-lang/chalk/pull/360). We have to adapt to the
same scheme for our `Ty::Bound`. It's mostly fine though, even makes some things
more clear.
This commit is contained in:
Florian Diebold 2020-04-05 18:24:18 +02:00
parent 3659502816
commit 952714685a
12 changed files with 197 additions and 114 deletions

12
Cargo.lock generated
View file

@ -114,7 +114,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "chalk-derive" name = "chalk-derive"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -124,7 +124,7 @@ dependencies = [
[[package]] [[package]]
name = "chalk-engine" name = "chalk-engine"
version = "0.9.0" version = "0.9.0"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"chalk-macros", "chalk-macros",
"rustc-hash", "rustc-hash",
@ -133,7 +133,7 @@ dependencies = [
[[package]] [[package]]
name = "chalk-ir" name = "chalk-ir"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"chalk-derive", "chalk-derive",
"chalk-engine", "chalk-engine",
@ -143,7 +143,7 @@ dependencies = [
[[package]] [[package]]
name = "chalk-macros" name = "chalk-macros"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@ -151,7 +151,7 @@ dependencies = [
[[package]] [[package]]
name = "chalk-rust-ir" name = "chalk-rust-ir"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"chalk-derive", "chalk-derive",
"chalk-engine", "chalk-engine",
@ -162,7 +162,7 @@ dependencies = [
[[package]] [[package]]
name = "chalk-solve" name = "chalk-solve"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-lang/chalk.git?rev=d383af7333cc6014e9d9e3e77668b5d5b0a5b40e#d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
dependencies = [ dependencies = [
"chalk-derive", "chalk-derive",
"chalk-engine", "chalk-engine",

View file

@ -23,9 +23,9 @@ ra_prof = { path = "../ra_prof" }
ra_syntax = { path = "../ra_syntax" } ra_syntax = { path = "../ra_syntax" }
test_utils = { path = "../test_utils" } test_utils = { path = "../test_utils" }
chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" } chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" } chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" } chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
[dev-dependencies] [dev-dependencies]
insta = "0.15.0" insta = "0.15.0"

View file

@ -14,7 +14,7 @@ use crate::{
db::HirDatabase, db::HirDatabase,
traits::{InEnvironment, Solution}, traits::{InEnvironment, Solution},
utils::generics, utils::generics,
Canonical, Substs, Ty, TypeWalk, BoundVar, Canonical, DebruijnIndex, Substs, Ty,
}; };
const AUTODEREF_RECURSION_LIMIT: usize = 10; const AUTODEREF_RECURSION_LIMIT: usize = 10;
@ -61,14 +61,13 @@ fn deref_by_trait(
return None; return None;
} }
// FIXME make the Canonical handling nicer // FIXME make the Canonical / bound var handling nicer
let parameters = Substs::build_for_generics(&generic_params) let parameters =
.push(ty.value.value.clone().shift_bound_vars(1)) Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
.build();
let projection = super::traits::ProjectionPredicate { let projection = super::traits::ProjectionPredicate {
ty: Ty::Bound(0), ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
projection_ty: super::ProjectionTy { associated_ty: target, parameters }, projection_ty: super::ProjectionTy { associated_ty: target, parameters },
}; };
@ -93,12 +92,16 @@ fn deref_by_trait(
// we have `impl<T> Deref for Foo<T> { Target = T }`, that should be // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
// the case. // the case.
for i in 1..vars.0.num_vars { for i in 1..vars.0.num_vars {
if vars.0.value[i] != Ty::Bound((i - 1) as u32) { if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
{
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
return None; return None;
} }
} }
Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) Some(Canonical {
value: vars.0.value[vars.0.value.len() - 1].clone(),
num_vars: vars.0.num_vars,
})
} }
Solution::Ambig(_) => { Solution::Ambig(_) => {
info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution);

View file

@ -303,7 +303,7 @@ impl HirDisplay for Ty {
} }
} }
} }
Ty::Bound(idx) => write!(f, "?{}", idx)?, Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
Ty::Dyn(predicates) | Ty::Opaque(predicates) => { Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
match self { match self {
Ty::Dyn(_) => write!(f, "dyn ")?, Ty::Dyn(_) => write!(f, "dyn ")?,

View file

@ -7,7 +7,9 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
use test_utils::tested_by; use test_utils::tested_by;
use super::{InferenceContext, Obligation}; use super::{InferenceContext, Obligation};
use crate::{Canonical, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk}; use crate::{
BoundVar, Canonical, DebruijnIndex, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk,
};
impl<'a> InferenceContext<'a> { impl<'a> InferenceContext<'a> {
pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b> pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b>
@ -47,7 +49,7 @@ where
}) })
} }
fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: usize) -> T { fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T {
t.fold_binders( t.fold_binders(
&mut |ty, binders| match ty { &mut |ty, binders| match ty {
Ty::Infer(tv) => { Ty::Infer(tv) => {
@ -72,7 +74,7 @@ where
InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root),
}; };
let position = self.add(free_var); let position = self.add(free_var);
Ty::Bound((position + binders) as u32) Ty::Bound(BoundVar::new(binders, position))
} }
} }
_ => ty, _ => ty,
@ -89,7 +91,7 @@ where
} }
pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
let result = self.do_canonicalize(ty, 0); let result = self.do_canonicalize(ty, DebruijnIndex::INNERMOST);
self.into_canonicalized(result) self.into_canonicalized(result)
} }
@ -98,8 +100,12 @@ where
obligation: InEnvironment<Obligation>, obligation: InEnvironment<Obligation>,
) -> Canonicalized<InEnvironment<Obligation>> { ) -> Canonicalized<InEnvironment<Obligation>> {
let result = match obligation.value { let result = match obligation.value {
Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize(tr, 0)), Obligation::Trait(tr) => {
Obligation::Projection(pr) => Obligation::Projection(self.do_canonicalize(pr, 0)), Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST))
}
Obligation::Projection(pr) => {
Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST))
}
}; };
self.into_canonicalized(InEnvironment { self.into_canonicalized(InEnvironment {
value: result, value: result,
@ -112,13 +118,13 @@ impl<T> Canonicalized<T> {
pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty { pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty {
ty.walk_mut_binders( ty.walk_mut_binders(
&mut |ty, binders| { &mut |ty, binders| {
if let &mut Ty::Bound(idx) = ty { if let &mut Ty::Bound(bound) = ty {
if idx as usize >= binders && (idx as usize - binders) < self.free_vars.len() { if bound.debruijn >= binders {
*ty = Ty::Infer(self.free_vars[idx as usize - binders]); *ty = Ty::Infer(self.free_vars[bound.index]);
} }
} }
}, },
0, DebruijnIndex::INNERMOST,
); );
ty ty
} }
@ -150,7 +156,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
// (kind of hacky) // (kind of hacky)
for (i, var) in vars.iter().enumerate() { for (i, var) in vars.iter().enumerate() {
if &*table.resolve_ty_shallow(var) == var { if &*table.resolve_ty_shallow(var) == var {
table.unify(var, &Ty::Bound(i as u32)); table.unify(var, &Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i)));
} }
} }
Some( Some(

View file

@ -64,6 +64,8 @@ pub use lower::{
}; };
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
pub use chalk_ir::{BoundVar, DebruijnIndex};
/// A type constructor or type name: this might be something like the primitive /// A type constructor or type name: this might be something like the primitive
/// type `bool`, a struct like `Vec`, or things like function pointers or /// type `bool`, a struct like `Vec`, or things like function pointers or
/// tuples. /// tuples.
@ -265,7 +267,11 @@ impl TypeWalk for ProjectionTy {
self.parameters.walk(f); self.parameters.walk(f);
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.parameters.walk_mut_binders(f, binders); self.parameters.walk_mut_binders(f, binders);
} }
} }
@ -299,7 +305,7 @@ pub enum Ty {
/// parameters get turned into variables; during trait resolution, inference /// parameters get turned into variables; during trait resolution, inference
/// variables get turned into bound variables and back; and in `Dyn` the /// variables get turned into bound variables and back; and in `Dyn` the
/// `Self` type is represented with a bound variable as well. /// `Self` type is represented with a bound variable as well.
Bound(u32), Bound(BoundVar),
/// A type variable used during type checking. /// A type variable used during type checking.
Infer(InferTy), Infer(InferTy),
@ -337,7 +343,11 @@ impl TypeWalk for Substs {
} }
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in make_mut_slice(&mut self.0) { for t in make_mut_slice(&mut self.0) {
t.walk_mut_binders(f, binders); t.walk_mut_binders(f, binders);
} }
@ -381,7 +391,13 @@ impl Substs {
/// Return Substs that replace each parameter by a bound variable. /// Return Substs that replace each parameter by a bound variable.
pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
Substs(generic_params.iter().enumerate().map(|(idx, _)| Ty::Bound(idx as u32)).collect()) Substs(
generic_params
.iter()
.enumerate()
.map(|(idx, _)| Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)))
.collect(),
)
} }
pub fn build_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { pub fn build_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
@ -425,8 +441,8 @@ impl SubstsBuilder {
self.param_count - self.vec.len() self.param_count - self.vec.len()
} }
pub fn fill_with_bound_vars(self, starting_from: u32) -> Self { pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
self.fill((starting_from..).map(Ty::Bound)) self.fill((starting_from..).map(|idx| Ty::Bound(BoundVar::new(debruijn, idx))))
} }
pub fn fill_with_unknown(self) -> Self { pub fn fill_with_unknown(self) -> Self {
@ -507,7 +523,11 @@ impl TypeWalk for TraitRef {
self.substs.walk(f); self.substs.walk(f);
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substs.walk_mut_binders(f, binders); self.substs.walk_mut_binders(f, binders);
} }
} }
@ -558,7 +578,11 @@ impl TypeWalk for GenericPredicate {
} }
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self { match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders), GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
GenericPredicate::Projection(projection_pred) => { GenericPredicate::Projection(projection_pred) => {
@ -616,7 +640,11 @@ impl TypeWalk for FnSig {
} }
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { 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) { for t in make_mut_slice(&mut self.params_and_return) {
t.walk_mut_binders(f, binders); t.walk_mut_binders(f, binders);
} }
@ -755,7 +783,7 @@ impl Ty {
pub trait TypeWalk { pub trait TypeWalk {
fn walk(&self, f: &mut impl FnMut(&Ty)); fn walk(&self, f: &mut impl FnMut(&Ty));
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
self.walk_mut_binders(&mut |ty, _binders| f(ty), 0); self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
} }
/// Walk the type, counting entered binders. /// Walk the type, counting entered binders.
/// ///
@ -767,9 +795,17 @@ pub trait TypeWalk {
/// that. Currently, the only thing that introduces bound variables on our /// that. Currently, the only thing that introduces bound variables on our
/// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound /// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound
/// variable for the self type. /// variable for the self type.
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize); 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, usize) -> Ty, binders: usize) -> Self fn fold_binders(
mut self,
f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
binders: DebruijnIndex,
) -> Self
where where
Self: Sized, Self: Sized,
{ {
@ -795,40 +831,43 @@ pub trait TypeWalk {
} }
/// Substitutes `Ty::Bound` vars with the given substitution. /// Substitutes `Ty::Bound` vars with the given substitution.
fn subst_bound_vars(mut self, substs: &Substs) -> Self fn subst_bound_vars(self, substs: &Substs) -> Self
where
Self: Sized,
{
self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
}
/// Substitutes `Ty::Bound` vars with the given substitution.
fn subst_bound_vars_at_depth(mut self, substs: &Substs, depth: DebruijnIndex) -> Self
where where
Self: Sized, Self: Sized,
{ {
self.walk_mut_binders( self.walk_mut_binders(
&mut |ty, binders| { &mut |ty, binders| {
if let &mut Ty::Bound(idx) = ty { if let &mut Ty::Bound(bound) = ty {
if idx as usize >= binders && (idx as usize - binders) < substs.len() { if bound.debruijn >= binders {
*ty = substs.0[idx as usize - binders].clone(); *ty = substs.0[bound.index].clone();
} else if idx as usize >= binders + substs.len() {
// shift free binders
*ty = Ty::Bound(idx - substs.len() as u32);
} }
} }
}, },
0, depth,
); );
self self
} }
// /// Shifts up debruijn indices of `Ty::Bound` vars by `n`.
/// Shifts up `Ty::Bound` vars by `n`. fn shift_bound_vars(self, n: DebruijnIndex) -> Self
fn shift_bound_vars(self, n: i32) -> Self
where where
Self: Sized, Self: Sized,
{ {
self.fold_binders( self.fold_binders(
&mut |ty, binders| match ty { &mut |ty, binders| match ty {
Ty::Bound(idx) if idx as usize >= binders => { Ty::Bound(bound) if bound.debruijn >= binders => {
assert!(idx as i32 >= -n); Ty::Bound(bound.shifted_in_from(n))
Ty::Bound((idx as i32 + n) as u32)
} }
ty => ty, ty => ty,
}, },
0, DebruijnIndex::INNERMOST,
) )
} }
} }
@ -856,7 +895,11 @@ impl TypeWalk for Ty {
f(self); f(self);
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self { match self {
Ty::Apply(a_ty) => { Ty::Apply(a_ty) => {
a_ty.parameters.walk_mut_binders(f, binders); a_ty.parameters.walk_mut_binders(f, binders);
@ -866,7 +909,7 @@ impl TypeWalk for Ty {
} }
Ty::Dyn(predicates) | Ty::Opaque(predicates) => { Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
for p in make_mut_slice(predicates) { for p in make_mut_slice(predicates) {
p.walk_mut_binders(f, binders + 1); p.walk_mut_binders(f, binders.shifted_in());
} }
} }
Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}

View file

@ -29,8 +29,8 @@ use crate::{
all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
variant_data, variant_data,
}, },
Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
TraitEnvironment, TraitRef, Ty, TypeCtor, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -131,7 +131,7 @@ impl Ty {
Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
} }
TypeRef::DynTrait(bounds) => { TypeRef::DynTrait(bounds) => {
let self_ty = Ty::Bound(0); let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let predicates = bounds let predicates = bounds
.iter() .iter()
.flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
@ -141,7 +141,7 @@ impl Ty {
TypeRef::ImplTrait(bounds) => { TypeRef::ImplTrait(bounds) => {
match ctx.impl_trait_mode { match ctx.impl_trait_mode {
ImplTraitLoweringMode::Opaque => { ImplTraitLoweringMode::Opaque => {
let self_ty = Ty::Bound(0); let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let predicates = bounds let predicates = bounds
.iter() .iter()
.flat_map(|b| { .flat_map(|b| {
@ -177,12 +177,10 @@ impl Ty {
} else { } else {
(0, 0, 0, 0) (0, 0, 0, 0)
}; };
Ty::Bound( Ty::Bound(BoundVar::new(
idx as u32 DebruijnIndex::INNERMOST,
+ parent_params as u32 idx as usize + parent_params + self_params + list_params,
+ self_params as u32 ))
+ list_params as u32,
)
} }
ImplTraitLoweringMode::Disallowed => { ImplTraitLoweringMode::Disallowed => {
// FIXME: report error // FIXME: report error
@ -249,7 +247,11 @@ impl Ty {
let ty = match resolution { let ty = match resolution {
TypeNs::TraitId(trait_) => { TypeNs::TraitId(trait_) => {
// if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there
let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None }; let self_ty = if remaining_segments.len() == 0 {
Some(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
} else {
None
};
let trait_ref = let trait_ref =
TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty);
let ty = if remaining_segments.len() == 1 { let ty = if remaining_segments.len() == 1 {
@ -289,7 +291,7 @@ impl Ty {
TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
TypeParamLoweringMode::Variable => { TypeParamLoweringMode::Variable => {
let idx = generics.param_idx(param_id).expect("matching generics"); let idx = generics.param_idx(param_id).expect("matching generics");
Ty::Bound(idx) Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))
} }
} }
} }
@ -558,7 +560,7 @@ impl GenericPredicate {
TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
TypeParamLoweringMode::Variable => { TypeParamLoweringMode::Variable => {
let idx = generics.param_idx(param_id).expect("matching generics"); let idx = generics.param_idx(param_id).expect("matching generics");
Ty::Bound(idx) Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))
} }
} }
} }

View file

@ -20,7 +20,8 @@ use crate::{
db::HirDatabase, db::HirDatabase,
primitive::{FloatBitness, Uncertain}, primitive::{FloatBitness, Uncertain},
utils::all_super_traits, utils::all_super_traits,
ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty,
TypeCtor, TypeWalk,
}; };
/// This is used as a key for indexing impls. /// This is used as a key for indexing impls.
@ -507,8 +508,9 @@ pub(crate) fn inherent_impl_substs(
) -> Option<Substs> { ) -> Option<Substs> {
// we create a var for each type parameter of the impl; we need to keep in // we create a var for each type parameter of the impl; we need to keep in
// mind here that `self_ty` might have vars of its own // mind here that `self_ty` might have vars of its own
let vars = let vars = Substs::build_for_def(db, impl_id)
Substs::build_for_def(db, impl_id).fill_with_bound_vars(self_ty.num_vars as u32).build(); .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars)
.build();
let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
let self_ty_with_vars = let self_ty_with_vars =
Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars };
@ -526,8 +528,8 @@ pub(crate) fn inherent_impl_substs(
fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs { fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs {
s.fold_binders( s.fold_binders(
&mut |ty, binders| { &mut |ty, binders| {
if let Ty::Bound(idx) = &ty { if let Ty::Bound(bound) = &ty {
if *idx >= binders as u32 { if bound.index >= num_vars_to_keep && bound.debruijn >= binders {
Ty::Unknown Ty::Unknown
} else { } else {
ty ty
@ -536,7 +538,7 @@ fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs {
ty ty
} }
}, },
num_vars_to_keep, DebruijnIndex::INNERMOST,
) )
} }
@ -586,7 +588,7 @@ fn generic_implements_goal(
let num_vars = self_ty.num_vars; let num_vars = self_ty.num_vars;
let substs = super::Substs::build_for_def(db, trait_) let substs = super::Substs::build_for_def(db, trait_)
.push(self_ty.value) .push(self_ty.value)
.fill_with_bound_vars(num_vars as u32) .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars)
.build(); .build();
let num_vars = substs.len() - 1 + self_ty.num_vars; let num_vars = substs.len() - 1 + self_ty.num_vars;
let trait_ref = TraitRef { trait_, substs }; let trait_ref = TraitRef { trait_, substs };

View file

@ -7,7 +7,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
use ra_prof::profile; use ra_prof::profile;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use crate::db::HirDatabase; use crate::{db::HirDatabase, DebruijnIndex};
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
@ -128,7 +128,11 @@ impl TypeWalk for ProjectionPredicate {
self.ty.walk(f); self.ty.walk(f);
} }
fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) { fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.projection_ty.walk_mut_binders(f, binders); self.projection_ty.walk_mut_binders(f, binders);
self.ty.walk_mut_binders(f, binders); self.ty.walk_mut_binders(f, binders);
} }
@ -144,7 +148,7 @@ pub(crate) fn trait_solve_query(
Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(), Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(),
Obligation::Projection(_) => "projection".to_string(), Obligation::Projection(_) => "projection".to_string(),
}); });
log::debug!("trait_solve_query({})", goal.value.value.display(db)); eprintln!("trait_solve_query({})", goal.value.value.display(db));
if let Obligation::Projection(pred) = &goal.value.value { if let Obligation::Projection(pred) = &goal.value.value {
if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {

View file

@ -8,7 +8,8 @@ use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
utils::{all_super_traits, generics}, utils::{all_super_traits, generics},
ApplicationTy, Binders, GenericPredicate, Substs, TraitRef, Ty, TypeCtor, ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
TypeCtor, TypeWalk,
}; };
pub(super) struct BuiltinImplData { pub(super) struct BuiltinImplData {
@ -164,11 +165,15 @@ fn closure_fn_trait_impl_datum(
let arg_ty = Ty::apply( let arg_ty = Ty::apply(
TypeCtor::Tuple { cardinality: num_args }, TypeCtor::Tuple { cardinality: num_args },
Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), Substs::builder(num_args as usize)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build(),
); );
let sig_ty = Ty::apply( let sig_ty = Ty::apply(
TypeCtor::FnPtr { num_args }, TypeCtor::FnPtr { num_args },
Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), Substs::builder(num_args as usize + 1)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build(),
); );
let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
@ -203,7 +208,7 @@ fn closure_fn_trait_output_assoc_ty_value(
} }
}; };
let output_ty = Ty::Bound(num_args.into()); let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into()));
let fn_once_trait = let fn_once_trait =
get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
@ -241,7 +246,7 @@ fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplD
// the existence of the Unsize trait has been checked before // the existence of the Unsize trait has been checked before
.expect("Unsize trait missing"); .expect("Unsize trait missing");
let var = Ty::Bound(0); let var = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let substs = Substs::builder(2) let substs = Substs::builder(2)
.push(Ty::apply_one(TypeCtor::Array, var.clone())) .push(Ty::apply_one(TypeCtor::Array, var.clone()))
.push(Ty::apply_one(TypeCtor::Slice, var)) .push(Ty::apply_one(TypeCtor::Slice, var))
@ -270,19 +275,18 @@ fn trait_object_unsize_impl_datum(
// the existence of the Unsize trait has been checked before // the existence of the Unsize trait has been checked before
.expect("Unsize trait missing"); .expect("Unsize trait missing");
let self_ty = Ty::Bound(0); let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
let target_substs = Substs::build_for_def(db, trait_) let target_substs = Substs::build_for_def(db, trait_)
.push(Ty::Bound(0)) .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
// starting from ^2 because we want to start with ^1 outside of the .fill_with_bound_vars(DebruijnIndex::ONE, 1)
// `dyn`, which is ^2 inside
.fill_with_bound_vars(2)
.build(); .build();
let num_vars = target_substs.len(); let num_vars = target_substs.len();
let target_trait_ref = TraitRef { trait_, substs: target_substs }; let target_trait_ref = TraitRef { trait_, substs: target_substs };
let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)]; let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
let self_substs = Substs::build_for_def(db, trait_).fill_with_bound_vars(0).build(); let self_substs =
Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
let self_trait_ref = TraitRef { trait_, substs: self_substs }; let self_trait_ref = TraitRef { trait_, substs: self_substs };
let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
@ -305,24 +309,26 @@ fn super_trait_object_unsize_impl_datum(
// the existence of the Unsize trait has been checked before // the existence of the Unsize trait has been checked before
.expect("Unsize trait missing"); .expect("Unsize trait missing");
let self_substs = Substs::build_for_def(db, data.trait_).fill_with_bound_vars(0).build(); let self_substs = Substs::build_for_def(db, data.trait_)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build();
let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
let num_vars = self_substs.len() - 1; let num_vars = self_substs.len() - 1;
let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())];
// we need to go from our trait to the super trait, substituting type parameters // we need to go from our trait to the super trait, substituting type parameters
let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait); let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
let mut current_trait_ref = self_trait_ref; let mut current_trait_ref = self_trait_ref.clone();
for t in path.into_iter().skip(1) { for t in path.into_iter().skip(1) {
let bounds = db.generic_predicates(current_trait_ref.trait_.into()); let bounds = db.generic_predicates(current_trait_ref.trait_.into());
let super_trait_ref = bounds let super_trait_ref = bounds
.iter() .iter()
.find_map(|b| match &b.value { .find_map(|b| match &b.value {
GenericPredicate::Implemented(tr) GenericPredicate::Implemented(tr)
if tr.trait_ == t && tr.substs[0] == Ty::Bound(0) => if tr.trait_ == t
&& tr.substs[0]
== Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)) =>
{ {
Some(Binders { value: tr, num_binders: b.num_binders }) Some(Binders { value: tr, num_binders: b.num_binders })
} }
@ -332,7 +338,18 @@ fn super_trait_object_unsize_impl_datum(
current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs); current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs);
} }
let super_bounds = vec![GenericPredicate::Implemented(current_trait_ref)]; // We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
// to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
// from the dyn Trait binder, while the other variables come from the impl.
let new_substs = Substs::builder(num_vars + 1)
.push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
.fill_with_bound_vars(DebruijnIndex::ONE, 0)
.build();
let self_bounds =
vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
let super_bounds =
vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
let substs = Substs::builder(2) let substs = Substs::builder(2)
.push(Ty::Dyn(self_bounds.into())) .push(Ty::Dyn(self_bounds.into()))

View file

@ -3,7 +3,10 @@ use std::{fmt, sync::Arc};
use log::debug; use log::debug;
use chalk_ir::{cast::Cast, Goal, GoalData, Parameter, PlaceholderIndex, TypeName, UniverseIndex}; use chalk_ir::{
cast::Cast, fold::shift::Shift, Goal, GoalData, Parameter, PlaceholderIndex, TypeName,
UniverseIndex,
};
use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId};
use ra_db::{ use ra_db::{
@ -235,7 +238,7 @@ impl ToChalk for Ty {
} }
.to_ty::<Interner>(&Interner) .to_ty::<Interner>(&Interner)
} }
Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(&Interner), Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
Ty::Dyn(predicates) => { Ty::Dyn(predicates) => {
let where_clauses = predicates let where_clauses = predicates
@ -277,7 +280,7 @@ impl ToChalk for Ty {
Ty::Projection(ProjectionTy { associated_ty, parameters }) Ty::Projection(ProjectionTy { associated_ty, parameters })
} }
chalk_ir::TyData::Function(_) => unimplemented!(), chalk_ir::TyData::Function(_) => unimplemented!(),
chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32), chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
chalk_ir::TyData::Dyn(where_clauses) => { chalk_ir::TyData::Dyn(where_clauses) => {
assert_eq!(where_clauses.bounds.binders.len(), 1); assert_eq!(where_clauses.bounds.binders.len(), 1);
@ -407,15 +410,15 @@ impl ToChalk for GenericPredicate {
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> {
match self { match self {
GenericPredicate::Implemented(trait_ref) => { GenericPredicate::Implemented(trait_ref) => {
make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) let chalk_trait_ref = trait_ref.to_chalk(db);
let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
}
GenericPredicate::Projection(projection_pred) => {
let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner);
let alias = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner);
make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
} }
GenericPredicate::Projection(projection_pred) => make_binders(
chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
alias: projection_pred.projection_ty.to_chalk(db),
ty: projection_pred.ty.to_chalk(db),
}),
0,
),
GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
} }
} }
@ -579,7 +582,8 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData {
type Chalk = AssociatedTyValue; type Chalk = AssociatedTyValue;
fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue {
let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) }; let ty = self.value.to_chalk(db);
let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty };
chalk_rust_ir::AssociatedTyValue { chalk_rust_ir::AssociatedTyValue {
associated_ty_id: self.assoc_ty_id.to_chalk(db), associated_ty_id: self.assoc_ty_id.to_chalk(db),
@ -738,11 +742,13 @@ pub(crate) fn trait_datum_query(
let associated_ty_ids = let associated_ty_ids =
trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect();
let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses };
let well_known = None; // FIXME set this (depending on lang items)
let trait_datum = TraitDatum { let trait_datum = TraitDatum {
id: trait_id, id: trait_id,
binders: make_binders(trait_datum_bound, bound_vars.len()), binders: make_binders(trait_datum_bound, bound_vars.len()),
flags, flags,
associated_ty_ids, associated_ty_ids,
well_known,
}; };
Arc::new(trait_datum) Arc::new(trait_datum)
} }

View file

@ -201,11 +201,11 @@ impl Generics {
(parent, self_params, list_params, impl_trait_params) (parent, self_params, list_params, impl_trait_params)
} }
pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<u32> { pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<usize> {
Some(self.find_param(param)?.0) Some(self.find_param(param)?.0)
} }
fn find_param(&self, param: TypeParamId) -> Option<(u32, &TypeParamData)> { fn find_param(&self, param: TypeParamId) -> Option<(usize, &TypeParamData)> {
if param.parent == self.def { if param.parent == self.def {
let (idx, (_local_id, data)) = self let (idx, (_local_id, data)) = self
.params .params
@ -215,7 +215,7 @@ impl Generics {
.find(|(_, (idx, _))| *idx == param.local_id) .find(|(_, (idx, _))| *idx == param.local_id)
.unwrap(); .unwrap();
let (_total, parent_len, _child) = self.len_split(); let (_total, parent_len, _child) = self.len_split();
Some(((parent_len + idx) as u32, data)) Some((parent_len + idx, data))
} else { } else {
self.parent_generics.as_ref().and_then(|g| g.find_param(param)) self.parent_generics.as_ref().and_then(|g| g.find_param(param))
} }