Repository: JuliaLang/julia
File: JuliaLowering/src/macro_expansion.jl (Julia)

Code before:
    if kind(ex) === K"toplevel"
        mapchildren(ctx, ex) do e
            @ast ctx ex [K"hygienic-scope" e mod::K"Value" lnn::K"Value"]
        end
    else
        mapchildren(e->fix_toplevel_expansion(ctx, e, mod, lnn), ctx, ex)
    end
end

function expand_macro(ctx, ex)
    @assert kind(ex) == K"macrocall"

    macname = ex[1]
    mctx = MacroContext(ctx.graph, ex, current_layer(ctx), ctx.expr_compat_mode)
    macfunc = eval_macro_name(ctx, mctx, macname)
    raw_args = ex[3:end]
    macro_loc = if kind(ex[2]) === K"Value"
        loc = ex[2].value
        if loc isa LineNumberNode
        # Some macros, e.g. @cmd, don't play nicely with file == nothing
        isnothing(loc.file) ? LineNumberNode(loc.line, :none) : loc
        elseif loc isa Core.MacroSource
            loc.lno
        end
    else
        LineNumberNode(0, :none)
    end
    # We use a specific well defined world age for the next checks and macro
    # expansion invocations. This avoids inconsistencies if the latest world
    # age changes concurrently.
    #
    # TODO: Allow this to be passed in
    # TODO: hasmethod always returns false for our `typemax(UInt)` meaning
    # "latest world," which we shouldn't be using.
    has_new_macro = ctx.macro_world === typemax(UInt) ?
        hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}) :
        hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}; world=ctx.macro_world)

    if has_new_macro
        macro_args = prepare_macro_args(ctx, mctx, raw_args)
        expanded = try
            Base.invoke_in_world(ctx.macro_world, macfunc, macro_args...)
        catch exc
            newexc = exc isa MacroExpansionError ?
                MacroExpansionError(mctx, exc.ex, exc.msg, exc.position, exc.err) :
                MacroExpansionError(mctx, ex, "Error expanding macro", :all, exc)
            # TODO: We can delete this rethrow when we move to AST-based error propagation.
            rethrow(newexc)
        end
        if expanded isa SyntaxTree
            if !is_compatible_graph(ctx, expanded)

Review comment (bug):
```suggestion
        else
            LineNumberNode(0, :none)
        end
```
or an assertion failure, etc.

Code after:
    if kind(ex) === K"toplevel"
        mapchildren(ctx, ex) do e
            @ast ctx ex [K"hygienic-scope" e mod::K"Value" lnn::K"Value"]
        end
    else
        mapchildren(e->fix_toplevel_expansion(ctx, e, mod, lnn), ctx, ex)
    end
end

function expand_macro(ctx, ex)
    @assert kind(ex) == K"macrocall"

    macname = ex[1]
    mctx = MacroContext(ctx.graph, ex, current_layer(ctx), ctx.expr_compat_mode)
    macfunc = eval_macro_name(ctx, mctx, macname)
    raw_args = ex[3:end]
    macro_loc = if kind(ex[2]) === K"Value"
        loc = ex[2].value
        if loc isa LineNumberNode
        # Some macros, e.g. @cmd, don't play nicely with file == nothing
        isnothing(loc.file) ? LineNumberNode(loc.line, :none) : loc
        elseif loc isa Core.MacroSource
            loc.lno
        else
            LineNumberNode(0, :none)
        end
    else
        LineNumberNode(0, :none)
    end
    # We use a specific well defined world age for the next checks and macro
    # expansion invocations. This avoids inconsistencies if the latest world
    # age changes concurrently.
    #
    # TODO: Allow this to be passed in
    # TODO: hasmethod always returns false for our `typemax(UInt)` meaning
    # "latest world," which we shouldn't be using.
    has_new_macro = ctx.macro_world === typemax(UInt) ?
        hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}) :
        hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}; world=ctx.macro_world)

    if has_new_macro
        macro_args = prepare_macro_args(ctx, mctx, raw_args)
        expanded = try
            Base.invoke_in_world(ctx.macro_world, macfunc, macro_args...)
        catch exc
            newexc = exc isa MacroExpansionError ?
                MacroExpansionError(mctx, exc.ex, exc.msg, exc.position, exc.err) :
                MacroExpansionError(mctx, ex, "Error expanding macro", :all, exc)
            # TODO: We can delete this rethrow when we move to AST-based error propagation.
            rethrow(newexc)
        end