2016-06-14 55 views
1

Elixir 1.3.0-rc1編譯器無法編譯我的一個宏。 在Elixir 1.2.6中沒問題。Elixir 1.3中的宏和模塊屬性

defmodule M do 
    defmacro ifa(a, exp) do 
    if (Macro.expand_once(a, __ENV__)), do: exp 
    end 
end 

defmodule Foo do 
    @flag true 

    require M 
    def main do 
    M.ifa (@flag), do: IO.puts 123 
    end 
end 

Foo.main 

編譯器抱怨屬性。

% /tmp/elixir-1.3.0-rc1/bin/elixir foobar.exs 
** (ArgumentError) could not call get_attribute on module M because it was already compiled 
    (elixir) lib/module.ex:1144: Module.assert_not_compiled!/2 
    (elixir) lib/module.ex:1066: Module.get_attribute/3 
    (elixir) lib/kernel.ex:2360: Kernel.do_at/4 
    (elixir) expanding macro: [email protected]/1 
    foobar.exs:12: M.ifa/2 
    expanding macro: M.ifa/2 
    foobar.exs:12: Foo.main/0 


% /tmp/elixir-1.2.6/bin/elixir foobar.exs 
123 

我想知道爲什麼Foo在擴展宏之前編譯。 1.3有什麼變化?

+1

從現在開始,我可以用1.2.6和1.3分支上的最新提交重現相同的行爲。如果您在這裏沒有得到答案,我會建議在IRC頻道(freenode上的#elixir-lang)或官方Google Group上提問。這可能是一個錯誤,因爲它破壞了在1.2中正常工作的代碼。 – Dogbert

回答

3

Elixir在您的代碼中實際發現了一個錯誤! :D

在您的宏中,當您使用__ENV__時,您將在定義宏的模塊的上下文中擴展用戶引用的表達式,而不是在調用方的上下文中。該解決方案是使用__CALLER__確保@flag兩種藥劑V1.2和V1.3使用Foo的情況下被適當擴大:

defmodule M do 
    defmacro ifa(a, exp) do 
    if (Macro.expand_once(a, __CALLER__)), do: exp 
    end 
end 

感謝您嘗試藥劑V1.3-RC!