Skip to content

Commit c037dc0

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 0f3a598 commit c037dc0

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
@@ -21,6 +21,8 @@ ra_prof = { path = "../ra_prof" }
2121
ra_syntax = { path = "../ra_syntax" }
2222
test_utils = { path = "../test_utils" }
2323

24+
scoped-tls = "1"
25+
2426
chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" }
2527
chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" }
2628
chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "d383af7333cc6014e9d9e3e77668b5d5b0a5b40e" }

crates/ra_hir_ty/src/display.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -248,19 +248,21 @@ impl HirDisplay for ApplicationTy {
248248
}
249249
}
250250
TypeCtor::Closure { .. } => {
251-
let sig = self.parameters[0]
252-
.callable_sig(f.db)
253-
.expect("first closure parameter should contain signature");
254-
let return_type_hint = sig.ret().display(f.db);
255-
if sig.params().is_empty() {
256-
write!(f, "|| -> {}", return_type_hint)?;
257-
} else if f.omit_verbose_types() {
258-
write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
251+
let sig = self.parameters[0].callable_sig(f.db);
252+
if let Some(sig) = sig {
253+
let return_type_hint = sig.ret().display(f.db);
254+
if sig.params().is_empty() {
255+
write!(f, "|| -> {}", return_type_hint)?;
256+
} else if f.omit_verbose_types() {
257+
write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
258+
} else {
259+
write!(f, "|")?;
260+
f.write_joined(sig.params(), ", ")?;
261+
write!(f, "| -> {}", return_type_hint)?;
262+
};
259263
} else {
260-
write!(f, "|")?;
261-
f.write_joined(sig.params(), ", ")?;
262-
write!(f, "| -> {}", return_type_hint)?;
263-
};
264+
write!(f, "{{closure}}")?;
265+
}
264266
}
265267
}
266268
Ok(())

crates/ra_hir_ty/src/traits.rs

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

174174
let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
175175

176-
let solution = solver.solve_limited(&context, goal, || {
176+
let should_continue = || {
177177
context.db.check_canceled();
178178
let remaining = fuel.get();
179179
fuel.set(remaining - 1);
180180
if remaining == 0 {
181181
log::debug!("fuel exhausted");
182182
}
183183
remaining > 0
184-
});
184+
};
185+
let mut solve = || solver.solve_limited(&context, goal, should_continue);
186+
// don't set the TLS for Chalk unless Chalk debugging is active, to make
187+
// extra sure we only use it for debugging
188+
let solution =
189+
if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() };
185190

186191
log::debug!("solve({:?}) => {:?}", goal, solution);
187192
solution
188193
}
189194

195+
fn is_chalk_debug() -> bool {
196+
std::env::var("CHALK_DEBUG").is_ok()
197+
}
198+
190199
fn solution_from_chalk(
191200
db: &dyn HirDatabase,
192201
solution: chalk_solve::Solution<Interner>,

crates/ra_hir_ty/src/traits/chalk.rs

+39-42
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use crate::{
1717
ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
1818
};
1919

20+
pub(super) mod tls;
21+
2022
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
2123
pub struct Interner;
2224

@@ -30,90 +32,85 @@ impl chalk_ir::interner::Interner for Interner {
3032
type Identifier = TypeAliasId;
3133
type DefId = InternId;
3234

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

41-
fn debug_trait_id(
42-
_type_kind_id: chalk_ir::TraitId<Self>,
43-
_fmt: &mut fmt::Formatter<'_>,
44-
) -> Option<fmt::Result> {
45-
None
42+
fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
43+
tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
4644
}
4745

48-
fn debug_assoc_type_id(
49-
_id: chalk_ir::AssocTypeId<Self>,
50-
_fmt: &mut fmt::Formatter<'_>,
51-
) -> Option<fmt::Result> {
52-
None
46+
fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
47+
tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
5348
}
5449

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

62-
fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
63-
None
57+
fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
58+
tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
6459
}
6560

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

7368
fn debug_parameter(
74-
_parameter: &Parameter<Self>,
75-
_fmt: &mut fmt::Formatter<'_>,
69+
parameter: &Parameter<Interner>,
70+
fmt: &mut fmt::Formatter<'_>,
7671
) -> Option<fmt::Result> {
77-
None
72+
tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
7873
}
7974

80-
fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
81-
None
75+
fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
76+
tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
8277
}
8378

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

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

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

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

112107
fn debug_separator_trait_ref(
113-
_separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>,
114-
_fmt: &mut fmt::Formatter<'_>,
108+
separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
109+
fmt: &mut fmt::Formatter<'_>,
115110
) -> Option<fmt::Result> {
116-
None
111+
tls::with_current_program(|prog| {
112+
Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
113+
})
117114
}
118115

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

0 commit comments

Comments
 (0)