Where is source code of `record/2` macro?

Record documentation mentions special record/2 macro for use in typespecs only:

Types can be defined for tuples with the record/2 macro (only available in typespecs).

But I can’t find source code of this macro.
I write Record-like module and I need to write a macro to generate typescpecs.
But I don’t understand how to write a macro that would work in typespecs.

The implementation starts here I think, but it’s not a separate macro: elixir/typespec.ex at master · elixir-lang/elixir · GitHub

Thanks. So actually it’s not a macro. It is sad.

Do you need something like this?

defmodule TypespecMacro.Util do
  defmacro deftype(name, spec) do
    quote do
      @type unquote(name) :: unquote(spec)
    end
  end
end

defmodule TypespecMacro do
  import TypespecMacro.Util

  deftype(type1, any)
  deftype(type2, any)

  @spec foo(type1, type2) :: {type1, type2}
  def foo(arg1, arg2) do
    {arg1, arg2}
  end
end
$ iex -S mix
Erlang/OTP 23 [erts-11.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> h TypespecMacro.foo

                              def foo(arg1, arg2)                               

  @spec foo(type1(), type2()) :: {type1(), type2()}

No. I want something like this:

defmodule TypespecMacro.Util do
  defmacro defspec(fields) do
    quote do
      # generating spec based on fields
    end
  end
end

defmodule TypespecMacro do
  import TypespecMacro.Util

  @type t() :: defspec(field1: integer(), field2: String.t())
end

I already did it in the same way as in your example. Awkward, but works.

Good. But why awkward?

It is just my biased opinion.
For me

@type t() :: defspec(field1: integer(), field2: String.t())

looks better than

deftype(t, field1: integer(), field2: String.t())

Oh… you were referring to that. Actually, your way is the way to go, because you can define types of any arity.

Could you please explain what are

types of any arity

Well, if you wanted to define in my example a type of arity > 0 you wouldn’t have been able to do it.
By arity i mean, that it takes let’s say one argument.
@type my_type(any) :: {:ok, any()}

But doing it your way, it is possible.

You can use additional macro parameter:

defmacro deftype(t, params \\ [], spec) when is_list(params) do
  ...
end
deftype(t1, {:ok, any()})
deftype(t2, [any(), integer()], {:ok, &1, &2})