# Source location of a method defined by a macro

**URL:** <https://discourse.julialang.org/t/source-location-of-a-method-defined-by-a-macro/111402>\
**Category:** General Usage\
**Created:** [March 9, 2024, 6:02pm UTC](https://discourse.julialang.org/t/source-location-of-a-method-defined-by-a-macro/111402 "2024-03-09T18:02:31Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mark\_Nahabedian](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mark_nahabedian/32/16562_2.png) [@Mark\_Nahabedian](https://discourse.julialang.org/u/Mark_Nahabedian)\
**Post date:** [March 9, 2024, 6:02pm UTC](https://discourse.julialang.org/t/source-location-of-a-method-defined-by-a-macro/111402/1 "2024-03-09T18:02:31Z")

</div>

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:

```julia
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

```

```julia
@unify_equal(AbstractString, ==)

```

Here’s the dump:

```julia
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

```julia
  [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

```julia
            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.
