Skip to content

Commit b56c04b

Browse files
committed
Implement Chalk's debug methods using TLS
Chalk now panics if we don't implement these methods and run with CHALK_DEBUG, so I thought I'd try to implement them 'properly'. Sadly, it seems impossible to do without transmuting lifetimes somewhere. The problem is that we need a `&dyn HirDatabase` to get names etc., which we can't just put into TLS. I thought I could just use `scoped-tls`, but that doesn't support references to unsized types. So I put the `&dyn` into another struct and put the reference to *that* into the TLS, but I have to transmute the lifetime to 'static for that to work.
1 parent 9527146 commit b56c04b

File tree

6 files changed

+304
-56
lines changed

6 files changed

+304
-56
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir_ty/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ ra_prof = { path = "../ra_prof" }
2323
ra_syntax = { path = "../ra_syntax" }
2424
test_utils = { path = "../test_utils" }
2525

26+
scoped-tls = "1"
27+
2628
chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
2729
chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
2830
chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }

crates/ra_hir_ty/src/display.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,21 @@ impl HirDisplay for ApplicationTy {
239239
}
240240
}
241241
TypeCtor::Closure { .. } => {
242-
let sig = self.parameters[0]
243-
.callable_sig(f.db)
244-
.expect("first closure parameter should contain signature");
245-
let return_type_hint = sig.ret().display(f.db);
246-
if sig.params().is_empty() {
247-
write!(f, "|| -> {}", return_type_hint)?;
248-
} else if f.omit_verbose_types() {
249-
write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
242+
let sig = self.parameters[0].callable_sig(f.db);
243+
if let Some(sig) = sig {
244+
let return_type_hint = sig.ret().display(f.db);
245+
if sig.params().is_empty() {
246+
write!(f, "|| -> {}", return_type_hint)?;
247+
} else if f.omit_verbose_types() {
248+
write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
249+
} else {
250+
write!(f, "|")?;
251+
f.write_joined(sig.params(), ", ")?;
252+
write!(f, "| -> {}", return_type_hint)?;
253+
};
250254
} else {
251-
write!(f, "|")?;
252-
f.write_joined(sig.params(), ", ")?;
253-
write!(f, "| -> {}", return_type_hint)?;
254-
};
255+
write!(f, "{{closure}}")?;
256+
}
255257
}
256258
}
257259
Ok(())

crates/ra_hir_ty/src/traits.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -177,20 +177,29 @@ fn solve(
177177

178178
let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
179179

180-
let solution = solver.solve_limited(&context, goal, || {
180+
let should_continue = || {
181181
context.db.check_canceled();
182182
let remaining = fuel.get();
183183
fuel.set(remaining - 1);
184184
if remaining == 0 {
185185
log::debug!("fuel exhausted");
186186
}
187187
remaining > 0
188-
});
188+
};
189+
let mut solve = || solver.solve_limited(&context, goal, should_continue);
190+
// don't set the TLS for Chalk unless Chalk debugging is active, to make
191+
// extra sure we only use it for debugging
192+
let solution =
193+
if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() };
189194

190195
log::debug!("solve({:?}) => {:?}", goal, solution);
191196
solution
192197
}
193198

199+
fn is_chalk_debug() -> bool {
200+
std::env::var("CHALK_DEBUG").is_ok()
201+
}
202+
194203
fn solution_from_chalk(
195204
db: &dyn HirDatabase,
196205
solution: chalk_solve::Solution<Interner>,

crates/ra_hir_ty/src/traits/chalk.rs

+39-42
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use crate::{
2020
ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
2121
};
2222

23+
pub(super) mod tls;
24+
2325
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
2426
pub struct Interner;
2527

@@ -33,90 +35,85 @@ impl chalk_ir::interner::Interner for Interner {
3335
type Identifier = TypeAliasId;
3436
type DefId = InternId;
3537

36-
// FIXME: implement these
3738
fn debug_struct_id(
38-
_type_kind_id: chalk_ir::StructId<Self>,
39-
_fmt: &mut fmt::Formatter<'_>,
39+
type_kind_id: StructId,
40+
fmt: &mut fmt::Formatter<'_>,
4041
) -> Option<fmt::Result> {
41-
None
42+
tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
4243
}
4344

44-
fn debug_trait_id(
45-
_type_kind_id: chalk_ir::TraitId<Self>,
46-
_fmt: &mut fmt::Formatter<'_>,
47-
) -> Option<fmt::Result> {
48-
None
45+
fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
46+
tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
4947
}
5048

51-
fn debug_assoc_type_id(
52-
_id: chalk_ir::AssocTypeId<Self>,
53-
_fmt: &mut fmt::Formatter<'_>,
54-
) -> Option<fmt::Result> {
55-
None
49+
fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
50+
tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
5651
}
5752

5853
fn debug_alias(
59-
_projection: &chalk_ir::AliasTy<Self>,
60-
_fmt: &mut fmt::Formatter<'_>,
54+
alias: &chalk_ir::AliasTy<Interner>,
55+
fmt: &mut fmt::Formatter<'_>,
6156
) -> Option<fmt::Result> {
62-
None
57+
tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
6358
}
6459

65-
fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
66-
None
60+
fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
61+
tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
6762
}
6863

6964
fn debug_lifetime(
70-
_lifetime: &chalk_ir::Lifetime<Self>,
71-
_fmt: &mut fmt::Formatter<'_>,
65+
lifetime: &chalk_ir::Lifetime<Interner>,
66+
fmt: &mut fmt::Formatter<'_>,
7267
) -> Option<fmt::Result> {
73-
None
68+
tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
7469
}
7570

7671
fn debug_parameter(
77-
_parameter: &Parameter<Self>,
78-
_fmt: &mut fmt::Formatter<'_>,
72+
parameter: &Parameter<Interner>,
73+
fmt: &mut fmt::Formatter<'_>,
7974
) -> Option<fmt::Result> {
80-
None
75+
tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
8176
}
8277

83-
fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
84-
None
78+
fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
79+
tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
8580
}
8681

8782
fn debug_goals(
88-
_goals: &chalk_ir::Goals<Self>,
89-
_fmt: &mut fmt::Formatter<'_>,
83+
goals: &chalk_ir::Goals<Interner>,
84+
fmt: &mut fmt::Formatter<'_>,
9085
) -> Option<fmt::Result> {
91-
None
86+
tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
9287
}
9388

9489
fn debug_program_clause_implication(
95-
_pci: &chalk_ir::ProgramClauseImplication<Self>,
96-
_fmt: &mut fmt::Formatter<'_>,
90+
pci: &chalk_ir::ProgramClauseImplication<Interner>,
91+
fmt: &mut fmt::Formatter<'_>,
9792
) -> Option<fmt::Result> {
98-
None
93+
tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
9994
}
10095

10196
fn debug_application_ty(
102-
_application_ty: &chalk_ir::ApplicationTy<Self>,
103-
_fmt: &mut fmt::Formatter<'_>,
97+
application_ty: &chalk_ir::ApplicationTy<Interner>,
98+
fmt: &mut fmt::Formatter<'_>,
10499
) -> Option<fmt::Result> {
105-
None
100+
tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
106101
}
107102

108103
fn debug_substitution(
109-
_substitution: &chalk_ir::Substitution<Self>,
110-
_fmt: &mut fmt::Formatter<'_>,
104+
substitution: &chalk_ir::Substitution<Interner>,
105+
fmt: &mut fmt::Formatter<'_>,
111106
) -> Option<fmt::Result> {
112-
None
107+
tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
113108
}
114109

115110
fn debug_separator_trait_ref(
116-
_separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>,
117-
_fmt: &mut fmt::Formatter<'_>,
111+
separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
112+
fmt: &mut fmt::Formatter<'_>,
118113
) -> Option<fmt::Result> {
119-
None
114+
tls::with_current_program(|prog| {
115+
Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
116+
})
120117
}
121118

122119
fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {

0 commit comments

Comments
 (0)