The goal of this project funded by Clojurists Together is to
improve static type error messages in Typed Clojure,
specifically to replace expanded code in error messages with surface-level syntax.
In the first half of the project (last update), I concentrated on three main areas:
- Increase direct support for problematic clojure.core macros
- Improve error messages for inlining functions
- Identify classes of implementation quirks in core Clojure macros to prepare for potential typing rules
In the second half (this update), I:
- Improved the experience of mixing clojure.spec and Typed Clojure
- Typed Clojure no longer complains about the expansion of
s/def
s/fdef
- Approach: implemented custom typing rules for both macros that ignores the body
- Commit
- Trimmed error messages
- Some hints in error messages have become irrelevant noise.
- Commit
- Created a proof-of-concept cljs.analyzer variant that can partially macroexpand
- inspired by the inlining work from the first half of this project
- Problem: CLJS uses lots of macros. Typed Clojure errors are even worse in CLJS.
- eg., (+ 1 2) => (js* "(~{})" 1)
- we want to pass (+ 1 2) to the type checker, not (js* "(~{})" 1)
- but + is a macro call... not representable by cljs.analyzer
- Solution: make partially expanded forms representable to the type checker
- Type checker uses tools.analyzer-style AST's to analyze code
- I created typed.clj.analyzer to add an :unanalyzed form for partially expanded forms
- but I didn't know how to port to cljs
- Promising early results
- unit tests for pausing the expansion of the children of each AST :op
- Next: integrate into cljs checker (which was on pause for several years and needs a lot of other updates)
- Commit