Skip to content

Type system guard refinement false positive in cond with custom guard #15450

Description

@kidq330

Existing issue

  • I have searched existing issues and could not find a duplicate.

Elixir and Erlang/OTP versions

Erlang/OTP 28 [erts-16.4.0.1] [source] [64-bit] [smp:11:11] [ds:11:11:10] [async-threads:1] [jit]

Elixir 1.20.0 (compiled with Erlang/OTP 28)

Operating system

macOS Tahoe 26.5.1

Current behavior

Hi, congrats on your type system :)

I've bumped Elixir and compiled some of our projects and found something that simplified to this:

defmodule MRE do
  defguard g(x) when is_tuple(x) and tuple_size(x) == 3

  def f(x) do
    cond do
      g(x) -> :a
      is_atom(x) -> :b
    end
  end
end

and getting a false positive:

    warning: this clause in cond will never match:

        is_atom(x)

    since it has type:

        dynamic(false)

    where "x" was given the type:

        # type: dynamic({...})
        # from: mre.exs:6
        {arg1} = {x}

    type warning found at:
    │
  7 │       is_atom(x) -> :b
    │                  ~
    │
    └─ mre.exs:7:18: MRE.f/1

It looks like the guard analysis leaks into the next branch. This doesn't happen if the guard is inline or when using case instead of cond.

Expected behavior

No warning

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions