Elixir: MatchError coverage test with specific macro and typespecs

Created on 30 Oct 2019  Â·  9Comments  Â·  Source: elixir-lang/elixir

Environment

$ asdf current
elixir         1.9.2-otp-22 (set by …)
erlang         22.1.5   (set by …)
$ elixir -v
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Elixir 1.9.2 (compiled with Erlang/OTP 22)

I'm using latest openSUSE Tumbleweed for x64 CPU with KDE/Plasma 5 desktop.

Current behavior

Hi, today I found something really weird. In __using__/1 macro I was generating module String. Of course such name is not good and instead of MyLib.String there should be for example MyLib.StringUtils, but name was only temporary.

In such generated module I placed function/macro (does not matter), added docs and typespecs. That macro was really short, so I immediately started to work on another part without compiling it. Later I noticed really weird error:

Compiling 1 file (.ex)
Cover compiling modules ...
** (exit) an exception was raised:
    ** (MatchError) no match of right hand side value: :error
        cover.erl:1605: :cover.do_compile_beam2/6
        cover.erl:1497: :cover.do_compile_beam/3
        (stdlib) lists.erl:1239: :lists.map/2
        cover.erl:2925: anonymous fn/2 in :cover.pmap_spawn/4
    cover.erl:602: :cover.call/1
    (mix) lib/mix/tasks/test.ex:12: Mix.Tasks.Test.Cover.start/2
    (mix) lib/mix/tasks/test.ex:407: Mix.Tasks.Test.do_run/3
    (mix) lib/mix/task.ex:331: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:79: Mix.CLI.run_task/2

This does not give me any hint, so I was confused for a longer time. Without any idea what's happening I decided for desperate move i.e. comment all of my code part by part and see if something has changed and that's how I found it. :smile:

Here is an example code:

defmodule MyLib.String do
  defmacro __using__(_opts \\ []) do
    quote unquote: false do
      defmodule String do
        @spec example() :: String.t()
        def example, do: "sample"
      end
    end
  end
end

defmodule Example do
  use MyLib.String
end

Of course that was mainly my bad. I don't know what I expected with such way too simple naming, but the problem was that I had no idea why I got this error.

Here is something interesting:

defmodule MyLib.String do
  defmacro __using__(_opts \\ []) do
    quote unquote: false do
      defmodule Elixir.Example.String do
        @spec example() :: String.t()
        def example, do: "sample"
      end
    end
  end
end

defmodule Example do
  use MyLib.String
end

as it would not raise …

The most weird part is that it actually compiles without any warning and this error I can see only in mix test --cover task.

Expected behavior

I'm not sure if it's a bug in typespecs handling, but in normal case no module have auto-alias in its body. If that's not a bug and it was something like using reserved word then maybe it would be possible to handle it or provide a better error message, because other people may be really confused seeing something like that.

Most helpful comment

  1. I opened cover source and found out that the line was failing was compile:forms(...). This means the Erlang AST we emitted was invalid.

  2. I rewrote the code to Erlang and found the root cause

  3. I added the missing verification the Erlang pass had and we didn't

All 9 comments

Can you please follow the format asked in the issues template for bug reports? And don't forget to include Elixir and Erlang/OTP versions, thanks.

Right, sorry I forgot about it.

In my case if not said then you can assume latest. :smiley:

$ asdf current
elixir         1.9.2-otp-22 (set by …)
erlang         22.1.5   (set by …)

@josevalim I have updated my issue. Yesterday I was tired and just created this task fast.

The name of the module generated in this case is Example.String, not String. So there is something else here.

OK, I found the bug. Here is the root cause:

== Compilation error in file lib/foo.ex ==
** (CompileError) lib/foo.ex:13: type t/0 undefined (no such type in Example.String)

@josevalim How did you found it? In my case I do not have any compilation errors, so I'm really curious about it …

  1. I opened cover source and found out that the line was failing was compile:forms(...). This means the Erlang AST we emitted was invalid.

  2. I rewrote the code to Erlang and found the root cause

  3. I added the missing verification the Erlang pass had and we didn't

I know this is a long dead issue, but I figure it wouldn't hurt to ask here.

Do you think that adding the module that is being compiled (and failed) to the :cover.do_compile_beam2/6 error would be a experience improvement? Or is there something I'm missing and it wouldn't be a good idea? It seems like a potential good first commit to BEAM for me if it's a good idea.

I just spent ~2 hours tracking down this same error, and it ended up being a dialyzer module attribute ignoring a function that didn't exist (copy/paste and forgot to rename it). Like @dialyzer {:nowarn_function, execute: 2}

@sb8244 right, they would most likely accept a PR that made it clearer. However, in this case, it is also an Elixir bug, so I filed a separate report too. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eproxus picture eproxus  Â·  3Comments

Irio picture Irio  Â·  3Comments

cmeiklejohn picture cmeiklejohn  Â·  3Comments

sashaafm picture sashaafm  Â·  3Comments

ericmj picture ericmj  Â·  3Comments