mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Upgrade Chalk
Also make overflow depth and max type size configurable through env variables. This can be helpful at least for debugging. Fixes #6628.
This commit is contained in:
parent
a0fa522fda
commit
78dd548243
8 changed files with 137 additions and 25 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -99,6 +99,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[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,
|
||||
|
|
|
@ -840,3 +840,46 @@ fn issue_4966() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[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
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! Trait solving using Chalk.
|
||||
use std::env::var;
|
||||
use std::sync::Arc;
|
||||
|
||||
use base_db::CrateId;
|
||||
|
@ -15,12 +16,6 @@ use self::chalk::{from_chalk, Interner, ToChalk};
|
|||
|
||||
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:
|
||||
|
|
|
@ -104,7 +104,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
};
|
||||
|
||||
// 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 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
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 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
// 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 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
// 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)
|
||||
|
|
|
@ -25,6 +25,7 @@ pub(crate) type FnDefId = chalk_ir::FnDefId<Interner>;
|
|||
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 @@ impl chalk_ir::interner::Interner for Interner {
|
|||
) -> 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 {
|
||||
|
|
|
@ -31,7 +31,8 @@ impl ToChalk for Ty {
|
|||
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 @@ impl ToChalk for Ty {
|
|||
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 @@ impl ToChalk for GenericPredicate {
|
|||
// 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 @@ where
|
|||
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();
|
||||
|
|
Loading…
Reference in a new issue