简体   繁体   中英

Elixir dynamic generated mod with macro created function,problems on resolving the context

I want to generate a module which using a macro created function, everything works as expected but except for the context on unquote(block) seems works out of expectation. The testing code are the following.

    defmodule A do
      defmacro wrap(head,opts \\[],do: block) do
        {name,args} = case head do
          name when is_atom(name) ->
          {name,[]}
          h ->
          Macro.decompose_call h
        end
        quote do
          def unquote(name)(unquote_splicing(args)) do
            IO.inspect __ENV__
            unquote(block)
          end
        end
      end
    end

    defmodule B do
      import A,only: [wrap: 2]
      alias B.C
      wrap test do
        C.test2
      end
    end

    defmodule C do
      def test do
        quote do
          import A,only: [wrap: 2]
          alias B.C
          wrap test do
            IO.inspect __ENV__
            C.test2
          end
        end
      end
    end

    defmodule B.C do
      def test2 do
        "good"
      end
    end
Module.create D,C.test,__ENV__

module B should be identical to D,except for D is a dynamically generated module and B is a predefined module. When calling B.test, it correctly resolves C to BC and returning back "good" as result. But when calling D.test, it raised out exception where C cannot being found((UndefinedFunctionError) undefined function C.test2/0)

Is there anyone who have some insights on the root of the problem here? Any help would be real appreciated. Thx in advance for the help ;)

Update

Confirmed as a bug and is fixed

Essentially, the quote block is not properly resolving the alias BC . If you directly refer to it inside of the block, the problem evaporates. I'm not exactly sure why this is the behavior. It is possible that the alias with the same current module name makes the call ambiguous. Either way, you can fix it by rewriting your C module to the following:

defmodule C do
  def test do
    quote do
      import A, only: [wrap: 2]
      wrap test do
        IO.inspect __ENV__
        B.C.test2
      end
    end
  end
end

Here's the result:

iex(1)> D.test
"good"

** Update:

This alias issue does appear to be a bug. With the alias inserted, the macro printout shows that both C and BC are listed as aliases and yet it still doesn't work. I also verified that the current module name was not causing a collision issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM