Skip to content

Commit 320dd2f

Browse files
authored
Type checker observability (#85)
2 parents 279553c + d1cd068 commit 320dd2f

File tree

28 files changed

+899
-165
lines changed

28 files changed

+899
-165
lines changed

.claude/skills/type-checker-tests/SKILL.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Use this skill when adding new type checker functions or expanding behavior.
1616
|--------|---------|
1717
| Find next test number | `ls tests-integration/fixtures/checking/ \| tail -5` |
1818
| Run a test or multiple tests | `just tc NNN` or `just tc 101 102` |
19+
| Run with tracing enabled | `just tc --debug NNN` |
1920
| Run all checking tests | `just tc` |
2021
| Accept all pending snapshots | `cargo insta accept` |
2122

@@ -162,6 +163,55 @@ When investigating a potential compiler bug:
162163
```bash
163164
# Focus on single test to reduce noise
164165
just tc NNN
166+
167+
# Enable tracing to see type checker behaviour
168+
just tc --debug NNN
169+
```
170+
171+
### Trace Files
172+
173+
The `--debug` flag emits detailed type checker traces to `target/compiler-tracing/`.
174+
175+
**Trace file naming:** `{test_id}_{module_name}.jsonl`
176+
- Example: `200_int_compare_transitive_Main.jsonl`
177+
178+
**Output format:** JSON Lines (one JSON object per line), containing:
179+
- `timestamp` - when the event occurred
180+
- `level` - DEBUG, INFO, or TRACE
181+
- `fields` - trace data (e.g., types being unified)
182+
- `target` - the module emitting the trace (e.g., `checking::algorithm::unification`)
183+
- `span`/`spans` - current span and span stack
184+
185+
**Example trace line:**
186+
```json
187+
{"timestamp":"...","level":"DEBUG","fields":{"t1":"?0","t2":"Int"},"target":"checking::algorithm::unification","span":{"name":"unify"}}
188+
```
189+
190+
When `--debug` is used, the trace file path is shown alongside pending snapshots:
191+
```
192+
UPDATED tests-integration/fixtures/checking/200_int_compare_transitive/Main.snap
193+
TRACE target/compiler-tracing/200_int_compare_transitive_Main.jsonl
194+
```
195+
196+
### Analysing Traces
197+
198+
Trace files can be large for complex tests. Use sampling and filtering:
199+
200+
```bash
201+
# Check file size and line count
202+
wc -l target/compiler-tracing/NNN_*.jsonl
203+
204+
# Sample random lines to get an overview
205+
shuf -n 20 target/compiler-tracing/NNN_*.jsonl | jq .
206+
207+
# Filter by level
208+
jq 'select(.level == "DEBUG")' target/compiler-tracing/NNN_*.jsonl
209+
210+
# Filter by target module
211+
jq 'select(.target | contains("unification"))' target/compiler-tracing/NNN_*.jsonl
212+
213+
# Extract specific fields
214+
jq '{level, target, fields}' target/compiler-tracing/NNN_*.jsonl
165215
```
166216

167217
You should run `just tc` to check for regressions.

Cargo.lock

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

compiler-bin/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ repository = "https://github.com/purefunctor/purescript-analyzer"
1111
keywords = ["purescript", "language server"]
1212
categories = ["compilers"]
1313

14+
[features]
15+
default = []
16+
no-tracing = ["checking/no-tracing"]
17+
1418
[dependencies]
19+
checking = { version = "0.1.0", path = "../compiler-core/checking" }
1520
analyzer = { version = "0.1.0", path = "../compiler-lsp/analyzer" }
1621
async-lsp = "0.2.2"
1722
clap = { version = "4.5.53", features = ["derive"] }

compiler-bin/src/cli.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ pub struct Config {
2424
default_value("info")
2525
)]
2626
pub lsp_log: LevelFilter,
27+
#[arg(
28+
long,
29+
value_name("LevelFilter"),
30+
help("Log level for the type checker"),
31+
default_value("off")
32+
)]
33+
pub checking_log: LevelFilter,
2734
#[arg(
2835
long,
2936
help("Command to use to get source files"),

compiler-bin/src/logging.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub fn start(config: Arc<cli::Config>) {
5151
let fmt_filter = filter::Targets::new()
5252
.with_target("building::engine", config.query_log)
5353
.with_target("purescript_analyzer::lsp", config.lsp_log)
54+
.with_target("checking", config.checking_log)
5455
.with_default(LevelFilter::INFO);
5556
let fmt = fmt::layer().with_writer(file).with_filter(fmt_filter);
5657

compiler-core/checking/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@ name = "checking"
33
version = "0.1.0"
44
edition = "2024"
55

6+
[features]
7+
default = []
8+
no-tracing = ["tracing/max_level_off"]
9+
610
[dependencies]
11+
tracing = "0.1.44"
712
building-types = { version = "0.1.0", path = "../building-types" }
813
files = { version = "0.1.0", path = "../files" }
914
indexing = { version = "0.1.0", path = "../indexing" }
1015
indexmap = "2.12.1"
1116
interner = { version = "0.1.0", path = "../interner" }
1217
itertools = "0.14.0"
1318
lowering = { version = "0.1.0", path = "../lowering" }
19+
parsing = { version = "0.1.0", path = "../parsing" }
1420
petgraph = "0.8.3"
1521
pretty = "0.12"
1622
resolving = { version = "0.1.0", path = "../resolving" }
1723
rustc-hash = "2.1.1"
1824
smol_str = "0.3.4"
25+
stabilizing = { version = "0.1.0", path = "../stabilizing" }
1926
sugar = { version = "0.1.0", path = "../sugar" }

0 commit comments

Comments
 (0)