Skip to content

Elixir 1.17 should provide better feedback on dead code #13715

Closed as not planned
@bugnano

Description

@bugnano

Elixir and Erlang/OTP versions

Erlang/OTP 27 [erts-15.0] [source] [64-bit] [smp:6:6] [ds:6:6:10] [async-threads:1] [jit:ns]

Elixir 1.17.1 (compiled with Erlang/OTP 27)

Operating system

Ubuntu 24.04

Current behavior

In our codebase we have a guard defined like so:

  defguardp conn_scope(conn, target)
            when is_atom(target) and is_struct(conn, Conn) and
                   is_atom(conn.assigns.auth_profile.scope) and
                   conn.assigns.auth_profile == target

  defguardp session_scope(session, target)
            when is_atom(target) and is_struct(session, Session) and
                   is_atom(session.scope) and
                   session.scope == target

  defguard auth_scope(conn, target)
           when conn_scope(conn, target) or session_scope(conn, target)

so that we can use the guard auth_scope either with a parameter of type Conn or a parameter of type Session, and you can see that we use is_struct to restrict further guards to access the correct members of the appropriate struct.

With Elixir 1.17 the compiler gives the following warning:

     warning: unknown key .assigns in expression:

         session.assigns

     where "session" was given the type:

         # type: dynamic(%DataLayer.Session{
           acked_server_sequence: term(),
           app_id: term(),
           authenticated: term(),
           default_api_version: term(),
           expires_at: term(),
           expiry_timer: term(),
           external_user_id: term(),
           id: term(),
           permissions: term(),
           protocol_version: term(),
           scope: term(),
           sdk_name: term(),
           server_sequence: term(),
           socket_pid: term(),
           transport: term(),
           user_id: term()
         })
         # from: lib/backend_web/calls/conversation_calls.ex:110
         %DataLayer.Session{app_id: app_id} = session

     typing violation found at:
     │
 112 │       when auth_scope(session, :app) do
     │       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     │
     └─ lib/backend_web/calls/conversation_calls.ex:112: BackendWeb.ConversationCalls.delete/2

because it checks also for the guards of the other data structure.

Expected behavior

No warning being emitted, because is_struct narrows down subsequent guards to only 1 data type.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions