Elixir v1.20.0-rc.0 (and rc.1) released: type inference of all constructs

I just finished upgrading a rather big project to 1.19.5 and resolving all warnings. After setting the elixir version to 1.20.0-rc.1 and running mix.compile the compiler revealed many new warnings

  • Found a lot of unused required modules. Mostly Logger and Ecto.Query (TIL you don’t need to require the Logger to make use of Logger.metadata)

  • Possible false positive or future deprecation? This warning was emitted, but pinning the variable here has no effect aside from removing the warning

    warning: the variable "chunk_size" is accessed inside size(...) of a bitstring but it was defined outside of the match. You must precede it with the pin operator
        │
    118 │     <<chunk::binary-size(chunk_size), rest::binary>> = binary
    
  • It found a couple of interesting, unused function clauses, similar to the cases below. In this particular case it was fine, but there are some cases where I cannot figure out the reason. Still a great addition to the compiler :+1:

    current = Enum.at(search_results, current_index)
    highlight_term(current.sentence_text, current)}
    
         warning: this clause of defp highlight_term/2 is never used
         │
     194 │   defp highlight_term(text, nil), do: text
    
  • In this particular case it didn’t complain about the fact that we (accidentally) assumed that uri.query is a map, but we’re trying to pass a map to URI.decode_query. Still a great find :+1:

         warning: incompatible types given to URI.decode_query/1:
    
             URI.decode_query(query)
    
         given types:
    
             dynamic(map())
    
         but expected one of:
    
             binary()
    
         where "query" was given the type:
    
             # type: dynamic(map())
             # from: my_code.ex:187:33
             is_map(query)
    
         typing violation found at:
         │
     188 │            %{"latency" => latency_raw} <- URI.decode_query(query),
    
        uri = URI.parse(url)
    
        latency =
          with %{query: query} when is_map(query) <- uri,
               %{"latency" => latency_raw} <- URI.decode_query(query),
               {latency, ""} <- Integer.parse(latency_raw) do
    
    

I’ve also measured the performance of the compilation of this project a bit. ~190 dependencies and +800 files. Overall very happy with the results and MIX_OS_DEPS_COMPILE_PARTITION_COUNT is a blessing for sure
deps = mix deps.compile
project = mix compile

elixir_version stage partitions seconds
1.18.4-otp-28 deps unset 73.95
1.18.4-otp-28 project 11.57
1.19.3-otp-28 deps unset 68.80
1.19.3-otp-28 deps 2 41.78
1.19.3-otp-28 deps 4 31.60
1.19.3-otp-28 project 13.65
1.19.5-otp-28 deps unset 68.00
1.19.5-otp-28 deps 2 41.60
1.19.5-otp-28 deps 4 31.72
1.19.5-otp-28 project 12.88
1.20.0-rc.1-otp-28 deps unset 69.54
1.20.0-rc.1-otp-28 deps 2 41.56
1.20.0-rc.1-otp-28 deps 4 32.22
1.20.0-rc.1-otp-28 project 13.25
12 Likes