Type Checker
Erie now has a very basic type checker. It supports simple builtin types like Integer
and String
, and the slightly more complex polymorphic list and tuple types. User-defined types are not supported yet.
Testing
The type checker has provided a pretty amazing opportunity for test-driven development. The type checker code has so many paths and branches that having a complete test suite helps prevent me from introducing regression bugs.
I have also found assert_raise
to be indespensible. A proper type checker would collect errors and print them all at the end of compilation, but for now, it raise
s errors when the type checker finds a mismatch.
test "literal list type fails with mismatched types" do
code = """
(sig one [] [Integer])
(def one []
[1 2 "3" 4])
"""
{:ok, forms} = Parser.parse(code)
translator = Translator.from_parsed(forms, {:Core, 1}, false)
assert_raise RuntimeError, fn ->
TypeChecker.check(translator)
end
end
Error Messages
When writing a type checker, one should aspire to the level of detail and helpfulness in Elm type checker messages. The errors raise
d by the Erie type checker right now are just good enough to help me debug any example Erie code I write, but definitely not good enough to live in the compiler long-term.
def expression_type({:var, _, name}, bindings, _signatures) do
bindings
|> Enum.find(fn {n, _} -> n == name end)
|> case do
nil -> raise "Returning a binding `#{name}` that isn't a function parameter"
{_, type} -> type
end
end
As much as I’d like to add great error messages now, that’s a major project in and of itself.