Skip to content

Commit 78dd548

Browse files
committed
Upgrade Chalk
Also make overflow depth and max type size configurable through env variables. This can be helpful at least for debugging. Fixes #6628.
1 parent a0fa522 commit 78dd548

File tree

8 files changed

+137
-25
lines changed

8 files changed

+137
-25
lines changed

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir_ty/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ ena = "0.14.0"
1717
log = "0.4.8"
1818
rustc-hash = "1.1.0"
1919
scoped-tls = "1"
20-
chalk-solve = { version = "0.37", default-features = false }
21-
chalk-ir = "0.37"
22-
chalk-recursive = "0.37"
20+
chalk-solve = { version = "0.43", default-features = false }
21+
chalk-ir = "0.43"
22+
chalk-recursive = "0.43"
2323

2424
stdx = { path = "../stdx", version = "0.0.0" }
2525
hir_def = { path = "../hir_def", version = "0.0.0" }

crates/hir_ty/src/db.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
9999
#[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
100100
fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;
101101

102+
#[salsa::invoke(crate::traits::chalk::fn_def_variance_query)]
103+
fn fn_def_variance(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> chalk::Variances;
104+
105+
#[salsa::invoke(crate::traits::chalk::adt_variance_query)]
106+
fn adt_variance(&self, krate: CrateId, adt_id: chalk::AdtId) -> chalk::Variances;
107+
102108
#[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
103109
fn associated_ty_value(
104110
&self,

crates/hir_ty/src/tests/regression.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,3 +840,46 @@ fn issue_4966() {
840840
"#]],
841841
);
842842
}
843+
844+
#[test]
845+
fn issue_6628() {
846+
check_infer(
847+
r#"
848+
#[lang = "fn_once"]
849+
pub trait FnOnce<Args> {
850+
type Output;
851+
}
852+
853+
struct S<T>();
854+
impl<T> S<T> {
855+
fn f(&self, _t: T) {}
856+
fn g<F: FnOnce(&T)>(&self, _f: F) {}
857+
}
858+
fn main() {
859+
let s = S();
860+
s.g(|_x| {});
861+
s.f(10);
862+
}
863+
"#,
864+
expect![[r#"
865+
105..109 'self': &S<T>
866+
111..113 '_t': T
867+
118..120 '{}': ()
868+
146..150 'self': &S<T>
869+
152..154 '_f': F
870+
159..161 '{}': ()
871+
174..225 '{ ...10); }': ()
872+
184..185 's': S<i32>
873+
188..189 'S': S<i32>() -> S<i32>
874+
188..191 'S()': S<i32>
875+
197..198 's': S<i32>
876+
197..209 's.g(|_x| {})': ()
877+
201..208 '|_x| {}': |&i32| -> ()
878+
202..204 '_x': &i32
879+
206..208 '{}': ()
880+
215..216 's': S<i32>
881+
215..222 's.f(10)': ()
882+
219..221 '10': i32
883+
"#]],
884+
);
885+
}

crates/hir_ty/src/traits.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Trait solving using Chalk.
2+
use std::env::var;
23
use std::sync::Arc;
34

45
use base_db::CrateId;
@@ -15,12 +16,6 @@ use self::chalk::{from_chalk, Interner, ToChalk};
1516

1617
pub(crate) mod chalk;
1718

18-
// This controls the maximum size of types Chalk considers. If we set this too
19-
// high, we can run into slow edge cases; if we set it too low, Chalk won't
20-
// find some solutions.
21-
// FIXME this is currently hardcoded in the recursive solver
22-
// const CHALK_SOLVER_MAX_SIZE: usize = 10;
23-
2419
/// This controls how much 'time' we give the Chalk solver before giving up.
2520
const CHALK_SOLVER_FUEL: i32 = 100;
2621

@@ -31,9 +26,11 @@ struct ChalkContext<'a> {
3126
}
3227

3328
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
34-
let overflow_depth = 100;
29+
let overflow_depth =
30+
var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(100);
3531
let caching_enabled = true;
36-
chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled)
32+
let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(30);
33+
chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, caching_enabled)
3734
}
3835

3936
/// A set of clauses that we assume to be true. E.g. if we are inside this function:

crates/hir_ty/src/traits/chalk.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
104104
};
105105

106106
// Note: Since we're using impls_for_trait, only impls where the trait
107-
// can be resolved should ever reach Chalk. `impl_datum` relies on that
107+
// can be resolved should ever reach Chalk. Symbol’s value as variable is void: impl_datum relies on that
108108
// and will panic if the trait can't be resolved.
109109
let in_deps = self.db.trait_impls_in_deps(self.krate);
110110
let in_self = self.db.trait_impls_in_crate(self.krate);
@@ -206,7 +206,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
206206
Some((trait_, alias))
207207
})
208208
{
209-
// Making up `AsyncBlock<T>: Future<Output = T>`
209+
// Making up Symbol’s value as variable is void: AsyncBlock<T>:
210210
//
211211
// |--------------------OpaqueTyDatum-------------------|
212212
// |-------------OpaqueTyDatumBound--------------|
@@ -242,7 +242,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
242242
// The opaque type has 1 parameter.
243243
make_binders(bound, 1)
244244
} else {
245-
// If failed to find `Future::Output`, return empty bounds as fallback.
245+
// If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
246246
let bound = OpaqueTyDatumBound {
247247
bounds: make_binders(vec![], 0),
248248
where_clauses: make_binders(vec![], 0),
@@ -343,6 +343,23 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
343343
// FIXME
344344
unimplemented!()
345345
}
346+
347+
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
348+
self
349+
}
350+
}
351+
352+
impl<'a> chalk_ir::UnificationDatabase<Interner> for ChalkContext<'a> {
353+
fn fn_def_variance(
354+
&self,
355+
fn_def_id: chalk_ir::FnDefId<Interner>,
356+
) -> chalk_ir::Variances<Interner> {
357+
self.db.fn_def_variance(self.krate, fn_def_id)
358+
}
359+
360+
fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
361+
self.db.adt_variance(self.krate, adt_id)
362+
}
346363
}
347364

348365
pub(crate) fn program_clauses_for_chalk_env_query(
@@ -644,6 +661,32 @@ pub(crate) fn fn_def_datum_query(
644661
Arc::new(datum)
645662
}
646663

664+
pub(crate) fn fn_def_variance_query(
665+
db: &dyn HirDatabase,
666+
_krate: CrateId,
667+
fn_def_id: FnDefId,
668+
) -> Variances {
669+
let callable_def: CallableDefId = from_chalk(db, fn_def_id);
670+
let generic_params = generics(db.upcast(), callable_def.into());
671+
Variances::from(
672+
&Interner,
673+
std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
674+
)
675+
}
676+
677+
pub(crate) fn adt_variance_query(
678+
db: &dyn HirDatabase,
679+
_krate: CrateId,
680+
adt_id: AdtId,
681+
) -> Variances {
682+
let adt: crate::AdtId = from_chalk(db, adt_id);
683+
let generic_params = generics(db.upcast(), adt.into());
684+
Variances::from(
685+
&Interner,
686+
std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
687+
)
688+
}
689+
647690
impl From<FnDefId> for crate::db::InternedCallableDefId {
648691
fn from(fn_def_id: FnDefId) -> Self {
649692
InternKey::from_intern_id(fn_def_id.0)

crates/hir_ty/src/traits/chalk/interner.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub(crate) type FnDefId = chalk_ir::FnDefId<Interner>;
2525
pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
2626
pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
2727
pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
28+
pub(crate) type Variances = chalk_ir::Variances<Interner>;
2829

2930
impl chalk_ir::interner::Interner for Interner {
3031
type InternedType = Arc<chalk_ir::TyData<Self>>;
@@ -41,6 +42,7 @@ impl chalk_ir::interner::Interner for Interner {
4142
type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
4243
type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
4344
type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
45+
type InternedVariances = Arc<[chalk_ir::Variance]>;
4446
type DefId = InternId;
4547
type InternedAdtId = hir_def::AdtId;
4648
type Identifier = TypeAliasId;
@@ -370,6 +372,20 @@ impl chalk_ir::interner::Interner for Interner {
370372
) -> Option<fmt::Result> {
371373
None
372374
}
375+
376+
fn intern_variances<E>(
377+
&self,
378+
data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
379+
) -> Result<Self::InternedVariances, E> {
380+
data.into_iter().collect()
381+
}
382+
383+
fn variances_data<'a>(
384+
&self,
385+
variances: &'a Self::InternedVariances,
386+
) -> &'a [chalk_ir::Variance] {
387+
&variances
388+
}
373389
}
374390

375391
impl chalk_ir::interner::HasInterner for Interner {

crates/hir_ty/src/traits/chalk/mapping.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ impl ToChalk for Ty {
3131
TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
3232
TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
3333
TypeCtor::FnPtr { num_args: _, is_varargs } => {
34-
let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
34+
let substitution =
35+
chalk_ir::FnSubst(apply_ty.parameters.to_chalk(db).shifted_in(&Interner));
3536
chalk_ir::TyKind::Function(chalk_ir::FnPointer {
3637
num_binders: 0,
3738
sig: chalk_ir::FnSig {
@@ -183,7 +184,7 @@ impl ToChalk for Ty {
183184
assert_eq!(num_binders, 0);
184185
let parameters: Substs = from_chalk(
185186
db,
186-
substitution.shifted_out(&Interner).expect("fn ptr should have no binders"),
187+
substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
187188
);
188189
Ty::Apply(ApplicationTy {
189190
ctor: TypeCtor::FnPtr {
@@ -536,6 +537,7 @@ impl ToChalk for GenericPredicate {
536537
// we don't produce any where clauses with binders and can't currently deal with them
537538
match where_clause
538539
.skip_binders()
540+
.clone()
539541
.shifted_out(&Interner)
540542
.expect("unexpected bound vars in where clause")
541543
{
@@ -661,7 +663,12 @@ where
661663
chalk_ir::TyVariableKind::Integer => TyKind::Integer,
662664
chalk_ir::TyVariableKind::Float => TyKind::Float,
663665
},
664-
chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
666+
// HACK: Chalk can sometimes return new lifetime variables. We
667+
// want to just skip them, but to not mess up the indices of
668+
// other variables, we'll just create a new type variable in
669+
// their place instead. This should not matter (we never see the
670+
// actual *uses* of the lifetime variable).
671+
chalk_ir::VariableKind::Lifetime => TyKind::General,
665672
chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
666673
})
667674
.collect();

0 commit comments

Comments
 (0)