Source location of a method defined by a macro

I’m having trouble getting the source location of a method definition to be correct. The method is defined by a macro. I would like for the source location of the method to be the location of the macro call, rather than the line in the macro definition that starts with function.

I’m hoping someone can explain to me how source locations travel from the parser, through macro expansion and compilation to the line and file fields of a Method.

I’m seeing something that is totally confusing. This is in Julia 1.9.3.

Here’s the macro and an invocation:

macro unify_equal(typ, op)
    r = 
        quote
            function Unification.unify(continuation,
                                       thing1::$typ, thing2::$typ,
                                       bindings::AbstractBindings)::Nothing
                if $op(thing1, thing2)
                    return continuation(bindings)
                end
                #=
                @unification_failure(thing1, thing2,
                                     _file = $(__source__.file),
                                     _line = $(__source__.line),
                                     _module = $__module__)
                =#
            end
        end
    # Replace the LineNumberNode that preceeds the function with
    # __source__.  There should be an easier way.
    function sourcify(e)
        if isexpr(e, :block)
            for i in 1:(length(e.args))
                if isexpr(e.args[i], :function)
                    @assert e.args[i - 1] isa LineNumberNode
                    e.args[i - 1] = __source__
                end
            end
            return
        elseif e isa Expr
            for a in e.args
                sourcify(a)
            end
        end
    end
    sourcify(r)
    r = esc(r)
    Meta.dump(r; maxdepth=100)
    r
end
@unify_equal(AbstractString, ==)

Here’s the dump:

Expr
  head: Symbol escape
  args: Array{Any}((1,))
    1: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: LineNumberNode
          line: Int64 235
          file: Symbol c:\Users\Mark Nahabedian\.julia\dev\U2\src\unify.jl
        2: Expr
          head: Symbol function
          args: Array{Any}((2,))
            1: Expr
              head: Symbol ::
              args: Array{Any}((2,))
                1: Expr
                  head: Symbol call
                  args: Array{Any}((5,))
                    1: Expr
                      head: Symbol .
                      args: Array{Any}((2,))
                        1: Symbol Unification
                        2: QuoteNode
                          value: Symbol unify
                    2: Symbol continuation
                    3: Expr
                      head: Symbol ::
                      args: Array{Any}((2,))
                        1: Symbol thing1
                        2: Symbol AbstractString
                    4: Expr
                      head: Symbol ::
                      args: Array{Any}((2,))
                        1: Symbol thing2
                        2: Symbol AbstractString
                    5: Expr
                      head: Symbol ::
                      args: Array{Any}((2,))
                        1: Symbol bindings
                        2: Symbol AbstractBindings
                2: Symbol Nothing
            2: Expr
              head: Symbol block
              args: Array{Any}((3,))
                1: LineNumberNode
                  line: Int64 193
                  file: Symbol c:\Users\Mark Nahabedian\.julia\dev\U2\src\unify.jl
                2: LineNumberNode
                  line: Int64 196
                  file: Symbol c:\Users\Mark Nahabedian\.julia\dev\U2\src\unify.jl
                3: Expr
                  head: Symbol if
                  args: Array{Any}((2,))
                    1: Expr
                      head: Symbol call
                      args: Array{Any}((3,))
                        1: Symbol ==
                        2: Symbol thing1
                        3: Symbol thing2
                    2: Expr
                      head: Symbol block
                      args: Array{Any}((2,))
                        1: LineNumberNode
                          line: Int64 197
                          file: Symbol c:\Users\Mark Nahabedian\.julia\dev\U2\src\unify.jl
                        2: Expr
                          head: Symbol return
                          args: Array{Any}((1,))
                            1: Expr
                              head: Symbol call
                              args: Array{Any}((2,))
                                1: Symbol continuation
                                2: Symbol bindings

The above is correct. Line 233 is where the macro invocation is located.

If I list the methods though, I get

  [9] unify(continuation, thing1::AbstractString, thing2::AbstractString, bindings::AbstractBindings)
     @ c:\Users\Mark Nahabedian\.julia\dev\U2\src\unify.jl:193

Line 193 is this line of the macro though

            function Unification.unify(continuation,

Why is the line number what I want in the dump but not on the actual method’s meta-data?

Also, why is the file path coming out a symbol and not a string?
Poking around in the Julia source, I found Meta.replace_sourceloc! but that only changes the first argument of a nested macrocall Expr. It doesn’t appear to be used anywhere.
Thanks.