Typle - Expression-level type query library for Elixir 1.20+

I know I put the cart before the horse, but AI providers started this race, not me.

Welcome Typle, the library that leverages a modern Elixir type system to discover types given the bunch of Elixir code.

The real application is my credo add-ons. In our team there are people who sometimes get lazy and use Access everywhere like: container[:key] no matter what container is. Also there are assistants who always use Access, because container.key is less fancy, or who knows why. I personally find this quite disturbing. Let alone Access is slower, it absolutely does not belong here.

So I started to implement a credo check for that, and I realized I should issue a warning if and only if the container is a map (and a key is an atom literal, but that’s a no-brainer.)

That’s how Typle was born. It’s just a baby-lib, but it might be already quite useful for those linting their code.

iex|🌢|1 ▶ {:ok, type} = Typle.Inference.infer_file("test/support/sample_module.ex")
{:ok,
 %{
   exprs: %{
     {6, 11} => "a",
     {6, 14} => "b",
     {7, 5} => "a",
     {7, 7} => ":erlang.+(a, b)",
     {7, 9} => "b",
     {10, 13} => "name",
     {11, 0} => "<<\"Hello, \", name::binary>>",
     {14, 19} => "input",
     {15, 5} => "case Integer.parse(input) do\n  {num, _rest} -> {:ok, num}\n  :error -> {:error, :invalid}\nend",
     {15, 17} => "Integer.parse(input)",
     {15, 24} => "input",
     {16, 8} => "num",
     {16, 13} => "_rest",
     {16, 29} => "num",
     {21, 22} => "x",
     {21, 30} => "x",
     {22, 16} => "x",
     {22, 24} => "x"
   },
   types: %{
     {6, 11} => #Typle.Type<dynamic()>,
     {6, 14} => #Typle.Type<dynamic()>,
     {7, 5} => #Typle.Type<integer()>,
     {7, 7} => #Typle.Type<dynamic(float() or integer())>,
     {7, 9} => #Typle.Type<integer()>,
     {10, 13} => #Typle.Type<dynamic()>,
     {11, 0} => #Typle.Type<binary()>,
     {14, 19} => #Typle.Type<dynamic()>,
     {15, 5} => #Typle.Type<{:error, :invalid} or {:ok, dynamic(integer())}>,
     {15, 17} => #Typle.Type<dynamic(:error or {integer(), binary()})>,
     {15, 24} => #Typle.Type<dynamic()>,
     {16, 8} => #Typle.Type<dynamic(integer())>,
     {16, 13} => #Typle.Type<dynamic(binary())>,
     {16, 29} => #Typle.Type<dynamic(integer())>,
     ...
   }
 }}

mix tasks included.

Enjoy!

10 Likes

Ooooo, this is nice! Everything you build is gold. This will be useful for a lean-of-elixir toy-project i’m playing with.

1 Like

:person_bowing: