The ~M sigil from ShorterMaps expands ~M{a, b} => %{a: a, b: b}.
The following ExUnit test fails:
test "that fails" do
assert {:a, ~M{b}} = {:a, %{b: 2}} # LHS expands to {:a, %{b: b}}
assert b == 2 # <= crashing line
end
```
mix test
warning: variable "b" does not exist and is being expanded to "b()", please use parentheses to remove the ambiguity or change the variable name
test/shorter_maps_test.exs:7
warning: variable "b" is unused
test/shorter_maps_test.exs:6
** (CompileError) test/shorter_maps_test.exs:7: undefined function b/0
(stdlib) lists.erl:1338: :lists.foreach/2
(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
and these tests pass:
```elixir
test "passes" do
assert ~M{b} = %{b: 2} # here the sigil is just not wrapped in a tuple
assert b == 2
end
test "another passing test" do
assert {:a, %{b: b}} = {:a, %{b: 2}} # this is the manually expanded LHS
assert b == 2
end
In the failing test, the sigil has been wrapped inside a tuple; the sigil expands and binds properly, note the warning variable "b" is unused.
assert/2 should preserve all created variables in the LHS code block, even if they are in a nested datastructure.
This is an elevation of meyercm/shorter_maps#11 as the issue seems to be in assert.
Thank you @meyercm! Can you please isolate the issue a bit further by providing a minimal macro that introduces the mentioned problems?
Sorry, should have thought to simplify the macro portion of the problem.
defmodule MinimalMacroTest do
use ExUnit.Case
defmodule MinimalMacro do
defmacro sigil_l({:<<>>, _, [string]}, _), do: Code.string_to_quoted!(string, [])
end
test "smaller macro" do
import MinimalMacro
assert ~l(a) = 1 # just the macro
assert a == 1 # this works
assert {~l(b)} = {2} # add a tuple wrapper
assert b == 2 # crashes here
end
end
Most helpful comment
Sorry, should have thought to simplify the macro portion of the problem.