Elixir: Problem with doctesting protocols

Created on 27 Jun 2017  路  5Comments  路  Source: elixir-lang/elixir

Environment

  • Elixir & Erlang versions (elixir --version): At least v1.4.2, v1.4.5, v1.5.0-rc.0 (all tested on OTP 19)
  • Operating system: Linux Mint Serena

Current behavior

To reproduce:

  1. mix new Foo
  2. cd foo
  3. Edit foo/lib/foo.ex to contain the following:
defprotocol Foo do
  @doc """
  ##  Examples

      iex> Foo.bar([])
      :ok
  """
  def bar(elem)
end

defimpl Foo, for: List do
  def bar(elem), do: :ok
end
  1. Run mix test

The output:

Compiling 1 file (.ex)
warning: variable "elem" is unused
  lib/foo.ex:13

Generated foo app
** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1
    (elixir) lib/io.ex:445: IO.chardata_to_string(nil)
    (elixir) lib/path.ex:289: Path.relative_to/2
    test/foo_test.exs:3: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/code.ex:370: Code.require_file/2
    (elixir) lib/kernel/parallel_require.ex:57: anonymous fn/2 in Kernel.ParallelRequire.spawn_requires/5

Expected behavior

I'd expect the doctests to work and mix test to run normally.

Elixir Bug

All 5 comments

I think the problem might be caused here in ExUnit: https://github.com/elixir-lang/elixir/blob/master/lib/ex_unit/lib/ex_unit/doc_test.ex#L197

This attempts to look up the source file where the module is defined by using

mod.__info__(:compile)[:source]

For a normal module, the :source key in mod.__info(:compile) exists, but for a protocol, it does not, and thus nil is returned (And this is where Path.relative_to stumbles over.)

Possibly related to this is what happens when you do r ProtocolName (in the example: r Foo) in IEx. This will look up the module in the same way (but using module.module_info(:compile)[:source] rather than module.__info__(:compile)[:source]):

** (ArgumentError) could not find source for module: Foo
    (iex) lib/iex/helpers.ex:426: IEx.Helpers.do_r/1
    (iex) lib/iex/helpers.ex:415: IEx.Helpers.r/1

This might be caused in some way by the protocol consolidation, or at least by the way protocol modules are compiled.
I think that module.__info__(:compile) ought to contain the :source for things that want to introspect the original source (like the doctests that ExUnit wants to do).

@Qqwy good catch. so it is an issue with protocol consolidation most likely, which is discarding the source. We should also change doctest to not choke on those cases as well.

Indeed, it is a consolidation problem, as setting consolidate_protocols: false in the mix.exs of the project makes the doctests work as intended.

I now set it to consolidate_protocols: Mix.env != :test for the time being as a temporary workaround to allow my libraries to have doctests in their protocols.

Glad to see this reported, I experienced the other day and was convinced I did something wrong, and moved on 馃槀

:heart_eyes: Thank you!

Was this page helpful?
0 / 5 - 0 ratings