
type-checker-tests
by purefunctor
Compiler frontend for PureScript in Rust
SKILL.md
name: type-checker-tests description: Add integration tests for type checker inference and checking functions allowed-tools: Bash(mkdir:*)
Type Checker Integration Tests
Use this skill when adding new type checker functions or expanding behavior.
Language: Test fixtures use PureScript syntax, not Haskell.
Quick Reference
| Action | Command |
|---|---|
| Find next test number | ls tests-integration/fixtures/checking/ | tail -5 |
| Run a test or multiple tests | just tc NNN or just tc 101 102 |
| Run with tracing enabled | just tc --debug NNN |
| Run all checking tests | just tc |
| Accept all pending snapshots | cargo insta accept |
Use just tc --help for all options.
Creating a Test
1. Create fixture directory
mkdir tests-integration/fixtures/checking/{NNN_descriptive_name}
Tests are auto-discovered by build.rs - no manual registration needed.
2. Write Main.purs
Standard pattern - pair typed (checking) and untyped (inference) variants:
module Main where
-- Checking mode: explicit signature constrains type checker
test :: Array Int -> Int
test [x] = x
-- Inference mode: type checker infers unconstrained
test' [x] = x
Guidelines:
- Test ONE specific behavior per fixture
- Name tests descriptively:
test,test',test2,test2', etc. - Include edge cases relevant to the behavior being tested
3. Generate and review snapshot
just tc NNN
This outputs:
CREATED path(green) with numbered lines showing full contentUPDATED path(yellow) with chunked diff (2 lines context, line numbers)
Multi-File Tests
For testing imports, re-exports, or cross-module behavior, add multiple .purs files
to the same fixture directory. The type checker loads all .purs files in the folder.
Example structure:
tests-integration/fixtures/checking/NNN_import_test/
├── Main.purs # The test file (snapshot generated for Main)
├── Lib.purs # Supporting module
└── Main.snap # Generated snapshot
Lib.purs:
module Lib where
life :: Int
life = 42
data Maybe a = Just a | Nothing
Main.purs:
module Main where
import Lib (life, Maybe(..))
test :: Maybe Int
test = Just life
Key points:
- Module name must match filename (
Lib.purs->module Lib where) - Only
Main.pursgenerates a snapshot (the test runs againstMain) - Use standard PureScript import syntax
Reviewing Snapshots
Snapshots have this structure:
Terms
functionName :: InferredOrCheckedType
...
Types
TypeName :: Kind
...
Errors
ErrorKind { details } at [location]
Acceptance Criteria
Before accepting, verify:
-
Types are correct - Check that inferred types match expectations
test :: Array Int -> Int- explicit signature preservedtest' :: forall t. Array t -> t- polymorphism inferred correctly
-
No unexpected
???- This indicates inference failuretest :: ???- STOP: the term failed to type checkCannotUnify { ??? -> ???, Int }- OK in error tests, shows unresolved unification variables
-
Errors appear where expected - For tests validating error behavior
- Confirm error kind matches expectations (e.g.,
NoInstanceFound,CannotUnify) - Verify error location points to the correct declaration
- Confirm error kind matches expectations (e.g.,
-
Polymorphism is appropriate
- Check type variable names (
t6,a, etc.) are scoped correctly - Verify constraints propagate as expected
- Check type variable names (
Common Issues
| Symptom | Likely Cause |
|---|---|
test :: ??? | Test code has syntax error or uses undefined names |
| Unexpected monomorphism | Missing polymorphic context or over-constrained signature |
| Wrong error location | Check binder/expression placement in source |
| Missing types in snapshot | Module header or imports incorrect |
Accept and Verify
# Accept only after thorough review
cargo insta accept
# Verify all checking tests pass
just tc
Debugging
When investigating a potential compiler bug:
# Focus on single test to reduce noise
just tc NNN
# Enable tracing to see type checker behaviour
just tc --debug NNN
Trace Files
The --debug flag emits detailed type checker traces to target/compiler-tracing/.
Trace file naming: {test_id}_{module_name}.jsonl
- Example:
200_int_compare_transitive_Main.jsonl
Output format: JSON Lines (one JSON object per line), containing:
timestamp- when the event occurredlevel- DEBUG, INFO, or TRACEfields- trace data (e.g., types being unified)target- the module emitting the trace (e.g.,checking::algorithm::unification)span/spans- current span and span stack
Example trace line:
{"timestamp":"...","level":"DEBUG","fields":{"t1":"?0","t2":"Int"},"target":"checking::algorithm::unification","span":{"name":"unify"}}
When --debug is used, the trace file path is shown alongside pending snapshots:
UPDATED tests-integration/fixtures/checking/200_int_compare_transitive/Main.snap
TRACE target/compiler-tracing/200_int_compare_transitive_Main.jsonl
Analysing Traces
Trace files can be large for complex tests. Use sampling and filtering:
# Check file size and line count
wc -l target/compiler-tracing/NNN_*.jsonl
# Sample random lines to get an overview
shuf -n 20 target/compiler-tracing/NNN_*.jsonl | jq .
# Filter by level
jq 'select(.level == "DEBUG")' target/compiler-tracing/NNN_*.jsonl
# Filter by target module
jq 'select(.target | contains("unification"))' target/compiler-tracing/NNN_*.jsonl
# Extract specific fields
jq '{level, target, fields}' target/compiler-tracing/NNN_*.jsonl
You should run just tc to check for regressions.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon



