]> git.lizzy.rs Git - rust.git/commitdiff
Switch Chalk to recursive solver
authorFlorian Diebold <flodiebold@gmail.com>
Fri, 10 Apr 2020 15:44:43 +0000 (17:44 +0200)
committerFlorian Diebold <flodiebold@gmail.com>
Thu, 16 Apr 2020 11:06:23 +0000 (13:06 +0200)
 + various fixes related to that.

crates/ra_hir_ty/src/autoderef.rs
crates/ra_hir_ty/src/infer/unify.rs
crates/ra_hir_ty/src/tests/traits.rs
crates/ra_hir_ty/src/traits.rs
crates/ra_hir_ty/src/traits/chalk.rs

index d91c21e24cce7a31e64a5000358d01535d4098d1..1b0f84c5c752eb3b890827dfdf4a3f5994e67090 100644 (file)
@@ -14,7 +14,7 @@
     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))
                 {
index ac25f8a80577f5397531c99a20dc9782f098ec7a..5f6cea8d318e13863f8c33d4aff81128ed08783a 100644 (file)
@@ -32,6 +32,7 @@ pub(super) struct Canonicalizer<'a, 'b>
     var_stack: Vec<TypeVarId>,
 }
 
+#[derive(Debug)]
 pub(super) struct Canonicalized<T> {
     pub value: Canonical<T>,
     free_vars: Vec<InferTy>,
index b3a2fc4395dfae992bd9819827b9f4ada3c35f9f..0e4fd7bfd16041764d00c7490e30dd1a3f769326 100644 (file)
@@ -349,7 +349,6 @@ fn bar(&self) -> {
 
 #[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 @@ impl<T: Iterator> IntoIterator for T {
 
 #[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]
index 44fbdb19701594c3eefd87876d44338b42a559f5..05791a84868fdef628434a2e11d17e772191a6bc 100644 (file)
 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()
 }
 
index b43e2a539ee67ca4a647eabfbce2cd5b11af0f68..60d70d18e89d031612e196e4fc177ef66587daa8 100644 (file)
@@ -511,13 +511,13 @@ fn from_chalk(
 }
 
 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!()
     }
 }