]> git.lizzy.rs Git - rust.git/commitdiff
Upgrade Chalk
authorFlorian Diebold <florian.diebold@freiheit.com>
Fri, 20 Nov 2020 17:00:34 +0000 (18:00 +0100)
committerFlorian Diebold <florian.diebold@freiheit.com>
Mon, 7 Dec 2020 10:48:58 +0000 (11:48 +0100)
Also make overflow depth and max type size configurable through env variables.
This can be helpful at least for debugging.

Fixes #6628.

Cargo.lock
crates/hir_ty/Cargo.toml
crates/hir_ty/src/db.rs
crates/hir_ty/src/tests/regression.rs
crates/hir_ty/src/traits.rs
crates/hir_ty/src/traits/chalk.rs
crates/hir_ty/src/traits/chalk/interner.rs
crates/hir_ty/src/traits/chalk/mapping.rs

index 8dcea6ea4410c05c4bf1e0dc3a8a13157fd49ff3..f1847e7699bb54da1419edc3f568fdcc9e5f2e44 100644 (file)
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.37.0"
+version = "0.43.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "564b529b0d620da43dc7ea46fa95b5c602e783e1870aeb07e8cbb6d7ff71bee6"
+checksum = "e2d9e0c8adcced1ab0fea5cb8a38647922893d5b495e363e1814299fd380469b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -180,9 +180,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.37.0"
+version = "0.43.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e67d29482387f4cbed6d8f1b1f7d24f00ff10612c700c65fe4af220df11e4d24"
+checksum = "c5218266a5709bc4943de997e64d3fab41c9e9f68efd54a898de53135e987bd3"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -190,9 +190,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.37.0"
+version = "0.43.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c52032be6fbdf91b6a7df3cafba3a6683fdabeff88e7ab73eea96e28657d973"
+checksum = "ed8f34f13fd4f30251f9f6f1dc56f80363201390ecbcac2fdfc8e33036cd9c4a"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -203,9 +203,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.37.0"
+version = "0.43.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0378bdfe1547b6fd545f518373b08c1e0c14920f7555a62d049021250a2b89b"
+checksum = "379c9f584488346044709d4c638c38d61a06fe593d4de2ac5f15fd2b0ba4cd9d"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
index cf5c38a23578cca3c262d0556cef52a83018cea1..289e812fe57b6f21ca3c2b54fe7de0f931df1414 100644 (file)
@@ -17,9 +17,9 @@ ena = "0.14.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.37", default-features = false }
-chalk-ir = "0.37"
-chalk-recursive = "0.37"
+chalk-solve = { version = "0.43", default-features = false }
+chalk-ir = "0.43"
+chalk-recursive = "0.43"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 hir_def = { path = "../hir_def", version = "0.0.0" }
index 25cf9eb7f1279099a2e7de51ad08e8b7e5a7add0..66bdb8e88e8df0ea1c0ccd5f6c8807066f8b2e76 100644 (file)
@@ -99,6 +99,12 @@ fn generic_predicates_for_param(
     #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
     fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
 
+    #[salsa::invoke(crate::traits::chalk::fn_def_variance_query)]
+    fn fn_def_variance(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> chalk::Variances;
+
+    #[salsa::invoke(crate::traits::chalk::adt_variance_query)]
+    fn adt_variance(&self, krate: CrateId, adt_id: chalk::AdtId) -> chalk::Variances;
+
     #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
     fn associated_ty_value(
         &self,
index 94d86b0d1f232a292616d933697ddecacbedccc9..8cf4e701240aea3d0b35e5f834d4bdad5359f1e1 100644 (file)
@@ -840,3 +840,46 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn issue_6628() {
+    check_infer(
+        r#"
+        #[lang = "fn_once"]
+        pub trait FnOnce<Args> {
+            type Output;
+        }
+
+        struct S<T>();
+        impl<T> S<T> {
+            fn f(&self, _t: T) {}
+            fn g<F: FnOnce(&T)>(&self, _f: F) {}
+        }
+        fn main() {
+            let s = S();
+            s.g(|_x| {});
+            s.f(10);
+        }
+        "#,
+        expect![[r#"
+            105..109 'self': &S<T>
+            111..113 '_t': T
+            118..120 '{}': ()
+            146..150 'self': &S<T>
+            152..154 '_f': F
+            159..161 '{}': ()
+            174..225 '{     ...10); }': ()
+            184..185 's': S<i32>
+            188..189 'S': S<i32>() -> S<i32>
+            188..191 'S()': S<i32>
+            197..198 's': S<i32>
+            197..209 's.g(|_x| {})': ()
+            201..208 '|_x| {}': |&i32| -> ()
+            202..204 '_x': &i32
+            206..208 '{}': ()
+            215..216 's': S<i32>
+            215..222 's.f(10)': ()
+            219..221 '10': i32
+        "#]],
+    );
+}
index ce1174cbef586cc28c24d1df68be37b3be2b048d..dfa51896b6ad9ee11be10fc22cee5fdcaa85a43f 100644 (file)
@@ -1,4 +1,5 @@
 //! Trait solving using Chalk.
+use std::env::var;
 use std::sync::Arc;
 
 use base_db::CrateId;
 
 pub(crate) mod chalk;
 
-// 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;
 
@@ -31,9 +26,11 @@ struct ChalkContext<'a> {
 }
 
 fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
-    let overflow_depth = 100;
+    let overflow_depth =
+        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(100);
     let caching_enabled = true;
-    chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled)
+    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(30);
+    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, caching_enabled)
 }
 
 /// A set of clauses that we assume to be true. E.g. if we are inside this function:
index 55e2c3a3e9b507343db358a4ee2c44f06a867f48..69eae6f79c9ec85eacab0f189aa3acf6d6603ef9 100644 (file)
@@ -104,7 +104,7 @@ fn binder_kind(
         };
 
         // Note: Since we're using impls_for_trait, only impls where the trait
-        // can be resolved should ever reach Chalk. `impl_datum` relies on that
+        // can be resolved should ever reach Chalk. Symbol’s value as variable is void: impl_datum relies on that
         // and will panic if the trait can't be resolved.
         let in_deps = self.db.trait_impls_in_deps(self.krate);
         let in_self = self.db.trait_impls_in_crate(self.krate);
@@ -206,7 +206,7 @@ fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatu
                         Some((trait_, alias))
                     })
                 {
-                    // Making up `AsyncBlock<T>: Future<Output = T>`
+                    // Making up Symbol’s value as variable is void: AsyncBlock<T>:
                     //
                     // |--------------------OpaqueTyDatum-------------------|
                     //        |-------------OpaqueTyDatumBound--------------|
@@ -242,7 +242,7 @@ fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatu
                     // The opaque type has 1 parameter.
                     make_binders(bound, 1)
                 } else {
-                    // If failed to find `Future::Output`, return empty bounds as fallback.
+                    // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
                     let bound = OpaqueTyDatumBound {
                         bounds: make_binders(vec![], 0),
                         where_clauses: make_binders(vec![], 0),
@@ -343,6 +343,23 @@ fn generator_witness_datum(
         // FIXME
         unimplemented!()
     }
+
+    fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
+        self
+    }
+}
+
+impl<'a> chalk_ir::UnificationDatabase<Interner> for ChalkContext<'a> {
+    fn fn_def_variance(
+        &self,
+        fn_def_id: chalk_ir::FnDefId<Interner>,
+    ) -> chalk_ir::Variances<Interner> {
+        self.db.fn_def_variance(self.krate, fn_def_id)
+    }
+
+    fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
+        self.db.adt_variance(self.krate, adt_id)
+    }
 }
 
 pub(crate) fn program_clauses_for_chalk_env_query(
@@ -644,6 +661,32 @@ pub(crate) fn fn_def_datum_query(
     Arc::new(datum)
 }
 
+pub(crate) fn fn_def_variance_query(
+    db: &dyn HirDatabase,
+    _krate: CrateId,
+    fn_def_id: FnDefId,
+) -> Variances {
+    let callable_def: CallableDefId = from_chalk(db, fn_def_id);
+    let generic_params = generics(db.upcast(), callable_def.into());
+    Variances::from(
+        &Interner,
+        std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
+    )
+}
+
+pub(crate) fn adt_variance_query(
+    db: &dyn HirDatabase,
+    _krate: CrateId,
+    adt_id: AdtId,
+) -> Variances {
+    let adt: crate::AdtId = from_chalk(db, adt_id);
+    let generic_params = generics(db.upcast(), adt.into());
+    Variances::from(
+        &Interner,
+        std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
+    )
+}
+
 impl From<FnDefId> for crate::db::InternedCallableDefId {
     fn from(fn_def_id: FnDefId) -> Self {
         InternKey::from_intern_id(fn_def_id.0)
index 39569e690ef656c22f584e858877ae81c4b12bc6..6a4aa8333ec74cb3b656cc05e5034f003523437e 100644 (file)
@@ -25,6 +25,7 @@
 pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
 pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
 pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
+pub(crate) type Variances = chalk_ir::Variances<Interner>;
 
 impl chalk_ir::interner::Interner for Interner {
     type InternedType = Arc<chalk_ir::TyData<Self>>;
@@ -41,6 +42,7 @@ impl chalk_ir::interner::Interner for Interner {
     type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
     type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
     type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
+    type InternedVariances = Arc<[chalk_ir::Variance]>;
     type DefId = InternId;
     type InternedAdtId = hir_def::AdtId;
     type Identifier = TypeAliasId;
@@ -370,6 +372,20 @@ fn debug_constraints(
     ) -> Option<fmt::Result> {
         None
     }
+
+    fn intern_variances<E>(
+        &self,
+        data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
+    ) -> Result<Self::InternedVariances, E> {
+        data.into_iter().collect()
+    }
+
+    fn variances_data<'a>(
+        &self,
+        variances: &'a Self::InternedVariances,
+    ) -> &'a [chalk_ir::Variance] {
+        &variances
+    }
 }
 
 impl chalk_ir::interner::HasInterner for Interner {
index 86cbc4c7e4194279f0e3c46119e1da07539dabb4..8700d664ee718dc326fb549d55b682eda5ca489d 100644 (file)
@@ -31,7 +31,8 @@ fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
                 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
                 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
                 TypeCtor::FnPtr { num_args: _, is_varargs } => {
-                    let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
+                    let substitution =
+                        chalk_ir::FnSubst(apply_ty.parameters.to_chalk(db).shifted_in(&Interner));
                     chalk_ir::TyKind::Function(chalk_ir::FnPointer {
                         num_binders: 0,
                         sig: chalk_ir::FnSig {
@@ -183,7 +184,7 @@ fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
                 assert_eq!(num_binders, 0);
                 let parameters: Substs = from_chalk(
                     db,
-                    substitution.shifted_out(&Interner).expect("fn ptr should have no binders"),
+                    substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
                 );
                 Ty::Apply(ApplicationTy {
                     ctor: TypeCtor::FnPtr {
@@ -536,6 +537,7 @@ fn from_chalk(
         // we don't produce any where clauses with binders and can't currently deal with them
         match where_clause
             .skip_binders()
+            .clone()
             .shifted_out(&Interner)
             .expect("unexpected bound vars in where clause")
         {
@@ -661,7 +663,12 @@ fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) ->
                     chalk_ir::TyVariableKind::Integer => TyKind::Integer,
                     chalk_ir::TyVariableKind::Float => TyKind::Float,
                 },
-                chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
+                // 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).
+                chalk_ir::VariableKind::Lifetime => TyKind::General,
                 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
             })
             .collect();