Skip to content

Commit fa93097

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. I think this is sound, but I still don't really want to do it this way...
1 parent 0f3a598 commit fa93097

File tree

6 files changed

+299
-54
lines changed

6 files changed

+299
-54
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

+86-11
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,78 @@ impl HirDisplay for &Ty {
107107
}
108108
}
109109

110+
impl HirDisplay for TypeCtor {
111+
fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
112+
match *self {
113+
TypeCtor::Bool => write!(f, "bool")?,
114+
TypeCtor::Char => write!(f, "char")?,
115+
TypeCtor::Int(t) => write!(f, "{}", t)?,
116+
TypeCtor::Float(t) => write!(f, "{}", t)?,
117+
TypeCtor::Str => write!(f, "str")?,
118+
TypeCtor::Slice => write!(f, "[?]")?,
119+
TypeCtor::Array => write!(f, "[?; _]")?,
120+
TypeCtor::RawPtr(m) => write!(f, "*{} ?", m.as_keyword_for_ptr())?,
121+
TypeCtor::Ref(m) => write!(f, "&{} ?", m.as_keyword_for_ref())?,
122+
TypeCtor::Never => write!(f, "!")?,
123+
TypeCtor::Tuple { cardinality } => {
124+
if cardinality == 1 {
125+
write!(f, "(?,)")?;
126+
} else {
127+
write!(f, "(")?;
128+
for _ in 0..cardinality {
129+
write!(f, "?,")?;
130+
}
131+
write!(f, ")")?;
132+
}
133+
}
134+
TypeCtor::FnPtr { num_args } => {
135+
write!(f, "fn(")?;
136+
for _ in 0..num_args {
137+
write!(f, "?,")?;
138+
}
139+
write!(f, ") -> ?")?;
140+
}
141+
TypeCtor::FnDef(def) => {
142+
let name = match def {
143+
CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(),
144+
CallableDef::StructId(s) => f.db.struct_data(s).name.clone(),
145+
CallableDef::EnumVariantId(e) => {
146+
let enum_data = f.db.enum_data(e.parent);
147+
enum_data.variants[e.local_id].name.clone()
148+
}
149+
};
150+
match def {
151+
CallableDef::FunctionId(_) => write!(f, "fn {}", name)?,
152+
CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
153+
write!(f, "{}", name)?
154+
}
155+
}
156+
}
157+
TypeCtor::Adt(def_id) => {
158+
let name = match def_id {
159+
AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
160+
AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
161+
AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
162+
};
163+
write!(f, "{}", name)?;
164+
}
165+
TypeCtor::AssociatedType(type_alias) => {
166+
let trait_ = match type_alias.lookup(f.db.upcast()).container {
167+
AssocContainerId::TraitId(it) => it,
168+
_ => panic!("not an associated type"),
169+
};
170+
let trait_name = f.db.trait_data(trait_).name.clone();
171+
let name = f.db.type_alias_data(type_alias).name.clone();
172+
write!(f, "{}::{}", trait_name, name)?;
173+
}
174+
TypeCtor::Closure { def, expr } => {
175+
write!(f, "{{closure {:?} in {:?}}}", expr, def)?;
176+
}
177+
}
178+
Ok(())
179+
}
180+
}
181+
110182
impl HirDisplay for ApplicationTy {
111183
fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
112184
if f.should_truncate() {
@@ -249,18 +321,21 @@ impl HirDisplay for ApplicationTy {
249321
}
250322
TypeCtor::Closure { .. } => {
251323
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)?;
324+
.callable_sig(f.db);
325+
if let Some(sig) = sig {
326+
let return_type_hint = sig.ret().display(f.db);
327+
if sig.params().is_empty() {
328+
write!(f, "|| -> {}", return_type_hint)?;
329+
} else if f.omit_verbose_types() {
330+
write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
331+
} else {
332+
write!(f, "|")?;
333+
f.write_joined(sig.params(), ", ")?;
334+
write!(f, "| -> {}", return_type_hint)?;
335+
};
259336
} else {
260-
write!(f, "|")?;
261-
f.write_joined(sig.params(), ", ")?;
262-
write!(f, "| -> {}", return_type_hint)?;
263-
};
337+
self.ctor.hir_fmt(f)?;
338+
}
264339
}
265340
}
266341
Ok(())

crates/ra_hir_ty/src/traits.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,17 @@ 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+
};
185+
let solution = chalk::tls::set_current_program(db, || {
186+
solver.solve_limited(&context, goal, should_continue)
184187
});
185188

186189
log::debug!("solve({:?}) => {:?}", goal, solution);

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

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

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

55-
fn debug_alias(
56-
_projection: &chalk_ir::AliasTy<Self>,
57-
_fmt: &mut fmt::Formatter<'_>,
58-
) -> Option<fmt::Result> {
59-
None
56+
fn debug_alias(alias: &chalk_ir::AliasTy<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
57+
tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
6058
}
6159

62-
fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
63-
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)))
6462
}
6563

6664
fn debug_lifetime(
67-
_lifetime: &chalk_ir::Lifetime<Self>,
68-
_fmt: &mut fmt::Formatter<'_>,
65+
lifetime: &chalk_ir::Lifetime<Interner>,
66+
fmt: &mut fmt::Formatter<'_>,
6967
) -> Option<fmt::Result> {
70-
None
68+
tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
7169
}
7270

7371
fn debug_parameter(
74-
_parameter: &Parameter<Self>,
75-
_fmt: &mut fmt::Formatter<'_>,
72+
parameter: &Parameter<Interner>,
73+
fmt: &mut fmt::Formatter<'_>,
7674
) -> Option<fmt::Result> {
77-
None
75+
tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
7876
}
7977

80-
fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
81-
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)))
8280
}
8381

84-
fn debug_goals(
85-
_goals: &chalk_ir::Goals<Self>,
86-
_fmt: &mut fmt::Formatter<'_>,
87-
) -> Option<fmt::Result> {
88-
None
82+
fn debug_goals(goals: &chalk_ir::Goals<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
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)