Skip to content

Type checker crash in unwrap_domain_tuple/2 with Map.update!/3, remote capture, and empty-map guard #15208

@Gustavo-Ziaugra-Arvo

Description

@Gustavo-Ziaugra-Arvo

Elixir and Erlang/OTP versions

Erlang/OTP 28 [erts-16.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]
Elixir 1.20.0-rc.3 (2db87eb) (compiled with Erlang/OTP 28)

Operating system

macOS (Darwin 25.3.0, arm64)

Current behavior

The type checker crashes with a FunctionClauseError in Module.Types.Descr.unwrap_domain_tuple/2 when all three of the following conditions are met:

  1. A guard narrows a map parameter by excluding the empty map (e.g. when properties == %{} or when map_size(properties) == 0)
  2. A subsequent clause calls Map.update!/3 (not Map.update/4)
  3. The third argument is a remote function capture (&Module.fun/1)

Using a local capture (&fun/1), an anonymous function (fn v -> Module.fun(v) end), or Map.update/4 does not trigger the crash.

Minimal reproduction:

  defmodule Helpers do
    def transform(value), do: String.trim(value)
  end

  defmodule Repro do
    def update(properties) when properties == %{}, do: properties

    def update(properties) do
      Map.update!(properties, "name", &Helpers.transform/1)
    end
  end

$ elixir repro.exs

  ** (RuntimeError) found error while checking types for Repro.update/1:

  ** (FunctionClauseError) no function clause matching in Module.Types.Descr.unwrap_domain_tuple/2

      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:285: Module.Types.Descr.unwrap_domain_tuple(:term, ...)
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:270: Module.Types.Descr.domain_to_args/1
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:278: Module.Types.Descr.domain_to_flat_args/2
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:1421: Module.Types.Descr.fun_apply_with_strategy/3
      (elixir 1.20.0-rc.3) lib/module/types/apply.ex:1457: anonymous fn/3 in Module.Types.Apply.map_update_or_replace_lazy/4
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:3518: anonymous fn/4 in Module.Types.Descr.map_update_fun/5
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:3865: Module.Types.Descr.map_update_put_domain/3
      (elixir 1.20.0-rc.3) lib/module/types/descr.ex:3853: anonymous fn/3 in Module.Types.Descr.map_update_put_domains/3

Expected behavior

Compilation should succeed (possibly with type warnings). The guard narrowing the map to not empty_map() combined with a remote function capture in Map.update!/3 should not cause the type checker to crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions