Skip to content

False undefined warning during incremental compile with --no-debug-info #15159

@akash-akya

Description

@akash-akya

Elixir and Erlang/OTP versions

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

Elixir 1.19.5 (compiled with Erlang/OTP 27)

Operating system

Fedora Linux 42 with Nix

Current behavior

I hit this corner case in our repo after upgrading to Elixir 1.19. I was able to reduce it to a very small repro.

The issue appears only when debug info is disabled. With --no-debug-info (in our case it was elixirc_options: [debug_info: ...]), incremental compilation can emit a false undefined warning for a module/function that exists.

I am attaching incremental_warning_repro.patch, which creates the complete minimal Mix project. The key modules are:

lib/source.ex

defmodule IncrementalWarningRepro.Source do
  # REPRO_EDIT: 1

  def identity(value), do: value
end

lib/dependent.ex

defmodule IncrementalWarningRepro.Dependent do
  def touch_source, do: IncrementalWarningRepro.Source.identity(:ok)
  def run, do: :ok
end

lib/caller.ex

defmodule IncrementalWarningRepro.Caller do
  @compile_time_value IncrementalWarningRepro.Source.identity(:ok)
  def compile_time_value, do: @compile_time_value

  def call_dependent, do: IncrementalWarningRepro.Dependent.run()
end

Reproducing steps:

#  apply the attached patch to create the minimal repro project
git apply incremental_warning_repro.patch

cd incremental_warning_repro

# baseline compile with debug info disabled; this is clean
mix compile --no-debug-info

# change only a comment to trigger incremental recompilation
sed -i 's/# REPRO_EDIT: 1/# REPRO_EDIT: 2/' lib/source.ex

# compile again with debug info still disabled; this prints the warning
mix compile --no-debug-info

The second compile prints:

$ mix compile --no-debug-info
Compiling 2 files (.ex)
    warning: IncrementalWarningRepro.Dependent.run/0 is undefined (module IncrementalWarningRepro.Dependent is not available or is yet to be defined). Did you mean:

          * IncrementalWarningRepro.Dependent.run/0

    │
  5 │   def call_dependent, do: IncrementalWarningRepro.Dependent.run()
    │                                                             ~
    │
    └─ lib/caller.ex:5:61: IncrementalWarningRepro.Caller.call_dependent/0

Generated incremental_warning_repro app

The dependency shape in the repro is:

  • Caller -> Source at compile time via a module attribute
  • Dependent -> Source at runtime
  • Caller -> Dependent at runtime

Changing Source recompiles Caller, does not recompile Dependent, and then the verifier warns that Dependent.run/0 is undefined even though Dependent exists.

Additional context:

  • With debug info enabled, the warning disappears.
  • mix compile --no-debug-info --no-verification is clean.

Possible cause:

Elixir 1.19's incremental verification appears to reconstruct already-compiled dependent modules from BEAM metadata more often. When those modules were compiled with debug_info: false, Module.ParallelChecker seems to treat the dependent module as unavailable instead of falling back to an export-only check, which then surfaces as a false undefined warning in the recompiled caller.

Expected behavior

No undefined warning should be emitted here. The module and function exist, and incremental verification should either succeed or degrade gracefully when compiling with --no-debug-info.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions