Skip to content

Commit 0a891d1

Browse files
Merge #3748
3748: Implement Chalk's debug methods using TLS r=matklad a=flodiebold 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. I think this is sound, but I still don't really want to do it this way... Having names in the Chalk debug output is very nice, but maybe IDs will have to suffice 😞 Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
2 parents 176f7f6 + a0a80a4 commit 0a891d1

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
@@ -24,6 +24,8 @@ ra_prof = { path = "../ra_prof" }
2424
ra_syntax = { path = "../ra_syntax" }
2525
test_utils = { path = "../test_utils" }
2626

27+
scoped-tls = "1"
28+
2729
chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
2830
chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
2931
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
@@ -247,19 +247,21 @@ impl HirDisplay for ApplicationTy {
247247
}
248248
}
249249
TypeCtor::Closure { .. } => {
250-
let sig = self.parameters[0]
251-
.callable_sig(f.db)
252-
.expect("first closure parameter should contain signature");
253-
if sig.params().is_empty() {
254-
write!(f, "||")?;
255-
} else if f.omit_verbose_types() {
256-
write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
250+
let sig = self.parameters[0].callable_sig(f.db);
251+
if let Some(sig) = sig {
252+
if sig.params().is_empty() {
253+
write!(f, "||")?;
254+
} else if f.omit_verbose_types() {
255+
write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
256+
} else {
257+
write!(f, "|")?;
258+
f.write_joined(sig.params(), ", ")?;
259+
write!(f, "|")?;
260+
};
261+
write!(f, " -> {}", sig.ret().display(f.db))?;
257262
} else {
258-
write!(f, "|")?;
259-
f.write_joined(sig.params(), ", ")?;
260-
write!(f, "|")?;
261-
};
262-
write!(f, " -> {}", sig.ret().display(f.db))?;
263+
write!(f, "{{closure}}")?;
264+
}
263265
}
264266
}
265267
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)