Repository: JuliaLang/julia
File: stdlib/InteractiveUtils/src/macros.jl (Julia)

Code before:
                              PairSymAny(:(.), Base.getproperty),
                              PairSymAny(:vect, Base.vect),
                              PairSymAny(Symbol("'"), Base.adjoint),
                              PairSymAny(:typed_hcat, Base.typed_hcat),
                              PairSymAny(:string, string))
                if ex0.head === head
                    return Expr(:call, fcn, f, typesof_expr(ex0.args, where_params), kws...)
                end
            end
        end
    end
    if isa(ex0, Expr) && ex0.head === :macrocall # Make @edit @time 1+2 edit the macro by using the types of the *expressions*
        return Expr(:call, fcn, esc(ex0.args[1]), Tuple{#=__source__=#LineNumberNode, #=__module__=#Module, Any[ Core.Typeof(ex0.args[i]) for i in 3:length(ex0.args) ]...}, kws...)
    end

    ex = Meta.lower(__module__, ex0)
    if !isa(ex, Expr)
        return Expr(:call, :error, "expression is not a function call or symbol")
    end

    exret = Expr(:none)
    if ex.head === :call
        if any(@nospecialize(x) -> isexpr(x, :...), ex0.args) &&
            (ex.args[1] === GlobalRef(Core,:_apply_iterate) ||
             ex.args[1] === GlobalRef(Base,:_apply_iterate))
            # check for splatting
            exret = Expr(:call, ex.args[2], fcn,
                        Expr(:tuple, extract_farg(ex.args[3]), typesof_expr(ex.args[4:end], where_params)))
        else
            exret = Expr(:call, fcn, extract_farg(ex.args[1]), typesof_expr(ex.args[2:end], where_params), kws...)
        end
    end
    if ex.head === :thunk || exret.head === :none
        exret = Expr(:call, :error, "expression is not a function call, \
                                    or is too complex for @$fcn to analyze; \
                                    break it down to simpler parts if possible. \
                                    In some cases, you may want to use Meta.@lower.")
    end
    return exret
end

"""
Same behaviour as `gen_call_with_extracted_types` except that keyword arguments
of the form "foo=bar" are passed on to the called function as well.
The keyword arguments must be given before the mandatory argument.
"""
function gen_call_with_extracted_types_and_kwargs(__module__, fcn, ex0; is_source_reflection = !is_code_macro(fcn), supports_binding_reflection = false)
    kws = Expr[]
    arg = ex0[end] # Mandatory argument
    for i in 1:length(ex0)-1
        x = ex0[i]

Review comment (suggestion):
Did this get deleted by accident? I don't see why you are still calling `Meta.lower` if you unconditionally ignore the result now (and I'm also not entirely certain what this part of the code did before either).

Code after:
to the type constructor.
To remove the ambiguity, `code_typed` must support an implementation that directly accepts a function type. This implementation
is assumed to be the method for `fcn(sigt::Type{<:Tuple})`.
"""
function gen_call_with_extracted_types(__module__, fcn, ex0, kws = Expr[]; is_source_reflection = !is_code_macro(fcn), supports_binding_reflection = false, use_signature_tuple = false)
    # Ignore assignments (e.g. `@edit a = f(x)` gets turned into `@edit f(x)`)
    if isa(ex0, Expr) && ex0.head === :(=) && isa(ex0.args[1], Symbol)
        return gen_call_with_extracted_types(__module__, fcn, ex0.args[2], kws; is_source_reflection, supports_binding_reflection, use_signature_tuple)
    end
    where_params = nothing
    if isa(ex0, Expr)
        ex0, where_params = extract_where_parameters(ex0)
    end
    if isa(ex0, Expr)
        if ex0.head === :do && isexpr(get(ex0.args, 1, nothing), :call)
            # Normalize `f(args...) do ... end` calls to `f(do_anonymous_function, args...)`
            if length(ex0.args) != 2
                return Expr(:call, :error, "ill-formed do call")
            end
            i = findlast(@nospecialize(a)->(isexpr(a, :kw) || isexpr(a, :parameters)), ex0.args[1].args)
            args = copy(ex0.args[1].args)
            insert!(args, (isnothing(i) ? 2 : 1+i::Int), ex0.args[2])
            ex0 = Expr(:call, args...)
        end
        if is_broadcasting_expr(ex0) && !is_source_reflection
            # Manually wrap top-level broadcasts in a function.
            # We don't do that if `fcn` reflects into the source,
            # because that destroys provenance information.
            args = Any[]
            ex, i = recursive_dotcalls!(copy(ex0), args)
            xargs = [Symbol('x', j) for j in 1:i-1]
            dotfuncname = gensym("dotfunction")
            call = gen_call(fcn, Any[dotfuncname, args...], where_params, kws; use_signature_tuple)
            return quote
                let $(esc(:($dotfuncname($(xargs...)) = $ex)))
                    $call
                end
            end
        elseif isexpr(ex0, :.) && is_source_reflection
            # If `ex0` has the form A.B (or some chain A.B.C.D) and `fcn` reflects into the source,
            # `A` (or `A.B.C`) may be a module, in which case `fcn` is probably more interested in
            # the binding rather than the `getproperty` call.
            # If binding reflection is not supported, we generate an error; `getproperty(::Module, field)`
            # is not going to be interesting to reflect into, so best to allow future non-breaking support
            # for binding reflection in case the macro may eventually support that.
            fully_qualified_symbol = true
            ex1 = ex0
            while ex1 isa Expr && ex1.head === :.
                fully_qualified_symbol = (length(ex1.args) == 2 &&
                                            ex1.args[2] isa QuoteNode &&
                                            ex1.args[2].value isa Symbol)