Switch Chalk to recursive solver

+ various fixes related to that.
This commit is contained in:
Florian Diebold 2020-04-10 17:44:43 +02:00
parent 364415b7d6
commit 14570df015
5 changed files with 53 additions and 40 deletions

View File

@ -14,7 +14,7 @@ use crate::{
db::HirDatabase,
traits::{InEnvironment, Solution},
utils::generics,
BoundVar, Canonical, DebruijnIndex, Substs, Ty,
BoundVar, Canonical, DebruijnIndex, Obligation, Substs, TraitRef, Ty,
};
const AUTODEREF_RECURSION_LIMIT: usize = 10;
@ -66,6 +66,20 @@ fn deref_by_trait(
let parameters =
Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
// Check that the type implements Deref at all
let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
let implements_goal = super::Canonical {
num_vars: ty.value.num_vars,
value: InEnvironment {
value: Obligation::Trait(trait_ref),
environment: ty.environment.clone(),
},
};
if db.trait_solve(krate, implements_goal).is_none() {
return None;
}
// Now do the assoc type projection
let projection = super::traits::ProjectionPredicate {
ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
@ -91,6 +105,11 @@ fn deref_by_trait(
// they're just being 'passed through'. In the 'standard' case where
// we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
// the case.
// FIXME: if the trait solver decides to truncate the type, these
// assumptions will be broken. We would need to properly introduce
// new variables in that case
for i in 1..vars.0.num_vars {
if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
{

View File

@ -32,6 +32,7 @@ where
var_stack: Vec<TypeVarId>,
}
#[derive(Debug)]
pub(super) struct Canonicalized<T> {
pub value: Canonical<T>,
free_vars: Vec<InferTy>,

View File

@ -349,7 +349,6 @@ trait Trait: SuperTrait {
#[test]
fn infer_project_associated_type() {
// y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
assert_snapshot!(
infer(r#"
trait Iterable {
@ -368,12 +367,12 @@ fn test<T: Iterable>() {
[108; 261) '{ ...ter; }': ()
[118; 119) 'x': u32
[145; 146) '1': u32
[156; 157) 'y': {unknown}
[183; 192) 'no_matter': {unknown}
[202; 203) 'z': {unknown}
[215; 224) 'no_matter': {unknown}
[234; 235) 'a': {unknown}
[249; 258) 'no_matter': {unknown}
[156; 157) 'y': Iterable::Item<T>
[183; 192) 'no_matter': Iterable::Item<T>
[202; 203) 'z': Iterable::Item<T>
[215; 224) 'no_matter': Iterable::Item<T>
[234; 235) 'a': Iterable::Item<T>
[249; 258) 'no_matter': Iterable::Item<T>
"###
);
}
@ -433,8 +432,8 @@ fn test<T: Iterable<Item=u32>>() {
"#),
@r###"
[67; 100) '{ ...own; }': ()
[77; 78) 'y': {unknown}
[90; 97) 'unknown': {unknown}
[77; 78) 'y': u32
[90; 97) 'unknown': u32
"###
);
}
@ -549,7 +548,7 @@ impl std::ops::Index<u32> for Bar {
fn test() {
let a = Bar;
let b = a[1];
let b = a[1u32];
b<|>;
}
@ -574,7 +573,7 @@ fn infer_ops_index_autoderef() {
//- /main.rs crate:main deps:std
fn test() {
let a = &[1u32, 2, 3];
let b = a[1];
let b = a[1u32];
b<|>;
}
@ -916,11 +915,7 @@ fn test<T: ApplyL>(t: T) {
}
"#,
);
// FIXME here Chalk doesn't normalize the type to a placeholder. I think we
// need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
// to the trait env ourselves here; probably Chalk can't do this by itself.
// assert_eq!(t, "ApplyL::Out<[missing name]>");
assert_eq!(t, "{unknown}");
assert_eq!(t, "ApplyL::Out<T>");
}
#[test]
@ -1329,16 +1324,16 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
[263; 264) 'y': impl Trait<Type = i64>
[290; 398) '{ ...r>); }': ()
[296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
[296; 302) 'get(x)': {unknown}
[296; 302) 'get(x)': u32
[300; 301) 'x': T
[308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown}
[308; 315) 'get2(x)': {unknown}
[308; 312) 'get2': fn get2<u32, T>(T) -> u32
[308; 315) 'get2(x)': u32
[313; 314) 'x': T
[321; 324) 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
[321; 327) 'get(y)': {unknown}
[321; 327) 'get(y)': i64
[325; 326) 'y': impl Trait<Type = i64>
[333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> {unknown}
[333; 340) 'get2(y)': {unknown}
[333; 337) 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
[333; 340) 'get2(y)': i64
[338; 339) 'y': impl Trait<Type = i64>
[346; 349) 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
[346; 357) 'get(set(S))': u64
@ -1402,7 +1397,6 @@ mod iter {
#[test]
fn projection_eq_within_chalk() {
// std::env::set_var("CHALK_DEBUG", "1");
assert_snapshot!(
infer(r#"
trait Trait1 {
@ -1422,7 +1416,7 @@ fn test<T: Trait1<Type = u32>>(x: T) {
[164; 165) 'x': T
[170; 186) '{ ...o(); }': ()
[176; 177) 'x': T
[176; 183) 'x.foo()': {unknown}
[176; 183) 'x.foo()': u32
"###
);
}
@ -1578,7 +1572,7 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
[150; 151) 'f': F
[156; 184) '{ ...2)); }': ()
[162; 163) 'f': F
[162; 181) 'f.call...1, 2))': {unknown}
[162; 181) 'f.call...1, 2))': u128
[174; 180) '(1, 2)': (u32, u64)
[175; 176) '1': u32
[178; 179) '2': u64
@ -1829,7 +1823,7 @@ impl Trait for S2 {
"#,
), @r###"
[54; 58) 'self': &Self
[60; 61) 'x': {unknown}
[60; 61) 'x': Trait::Item<Self>
[140; 144) 'self': &S
[146; 147) 'x': u32
[161; 175) '{ let y = x; }': ()
@ -1989,9 +1983,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
}
"#,
);
// assert_eq!(t, "u32");
// doesn't currently work, Chalk #234
assert_eq!(t, "{unknown}");
assert_eq!(t, "u32");
}
#[test]

View File

@ -16,10 +16,12 @@ use self::chalk::{from_chalk, Interner, ToChalk};
pub(crate) mod chalk;
mod builtin;
/// This controls the maximum size of types Chalk considers. If we set this too
/// high, we can run into slow edge cases; if we set it too low, Chalk won't
/// find some solutions.
const CHALK_SOLVER_MAX_SIZE: usize = 10;
// This controls the maximum size of types Chalk considers. If we set this too
// high, we can run into slow edge cases; if we set it too low, Chalk won't
// find some solutions.
// FIXME this is currently hardcoded in the recursive solver
// const CHALK_SOLVER_MAX_SIZE: usize = 10;
/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;
@ -30,8 +32,7 @@ struct ChalkContext<'a> {
}
fn create_chalk_solver() -> chalk_solve::Solver<Interner> {
let solver_choice =
chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None };
let solver_choice = chalk_solve::SolverChoice::recursive();
solver_choice.into_solver()
}

View File

@ -511,13 +511,13 @@ impl ToChalk for ProjectionTy {
}
impl ToChalk for super::ProjectionPredicate {
type Chalk = chalk_ir::Normalize<Interner>;
type Chalk = chalk_ir::AliasEq<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Normalize<Interner> {
chalk_ir::Normalize { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) }
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
chalk_ir::AliasEq { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) }
}
fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::Normalize<Interner>) -> Self {
fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self {
unimplemented!()
}
}