How can I `def render(assigns)` in a macro? ~H can't see `assigns` variable

I am trying to define a macro that defines a render(assigns) function but the compiler keeps rejecting the sigil, claiming that no assigns variable exists.

~H requires a variable named "assigns" to exist and be set to a map

Here is a reduction of the code:

defmodule X do
  defmacro __using__(opts) do
    quote do
      def render(assigns) do
        ~H"""
        <div>Hello from the macro</div>
        """
      end
    end
  end
end

defmodule Web.Test do
  use Web :live_view
  use X

  @impl true
  def mount(params, _session, socket) do
    {:ok, socket}
  end

  # render provided by macro
end

I assume that perhaps the actual variable name is getting “unique’d” in the macro, so maybe def render(assigns) becomes def render(__safe_no_collide_assigns_1) for example. I tried using Macro.var but couldn’t figure quite how to make it work.

Is this possible to do?

I have to use var!(assigns)

def render(var!(assigns)) do
...
end

I had been trying to unquote and Macro.var, but var! is in the Kernel:

https://hexdocs.pm/elixir/Kernel.html#var!/2

4 Likes