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

Code before:
        end
    elseif old_k === new_k
        (new_k === :global || new_k === :local) && return bid
        throw(LoweringError(ex, "function $(_var_str(new_k)) name not unique"))
    # See note in test/scopes.jl: "globals may overlap args or sparams"
    # elseif new_k === :global && old_k in (:argument, :static_parameter)
    #     declare_in_scope!(ctx, scope, ex, :global)
    else
        throw(LoweringError(ex, """
        $(_var_str(new_k)) name `$(NameKey(ex).name)` conflicts with an \
        existing $(_var_str(old_k)) from the same scope"""))
    end
end

# globals are added to both `scope` and the top scope
function declare_in_scope!(ctx, scope::ScopeInfo, ex, bk::Symbol; kws...)
    nk = NameKey(ex)
    if bk === :global
        declaration_scope = top_scope(ctx)
        mod = ctx.scope_layers[ex.scope_layer].mod
    else
        declaration_scope = scope
        mod = nothing
    end
    b = _new_binding(ctx, ex, nk.name, bk;
                     mod, is_internal=getmeta(ex, :is_internal, false), kws...)
    declaration_scope.vars[nk] = b.id
    scope.vars[nk] = b.id
    add_lambda_local!(ctx, scope, b)
    return b.id
end

function add_lambda_local!(ctx, scope::ScopeInfo, b)
    if b.kind === :global || b.is_ssa
        return
    end
    lam = scope.is_lifted ? top_scope(ctx) : enclosing_lambda(ctx, scope)
    @assert !haskey(lam.locals_capt, b.id)
    lam.locals_capt[b.id] = false
    b.lambda_id = lam.id
    nothing
end

function ensure_captured!(ctx, scope::ScopeInfo, b)
    if b.kind === :global || b.is_ssa
        return
    end
    lam = enclosing_lambda(ctx, scope)
    if !haskey(lam.locals_capt, b.id)
        b.is_captured = true
        lam.locals_capt[b.id] = true

Review comment (suggestion):
Looks reasonable. It could also be ok or maybe good to have an extra flag on `ScopeLayer` for `is_internal`. A bit like a "light" version of `BindingInfo`.

Code after:
    elseif old_k === new_k
        (new_k === :global || new_k === :local) && return bid
        throw(LoweringError(ex, "function $(_var_str(new_k)) name not unique"))
    # See note in test/scopes.jl: "globals may overlap args or sparams"
    # elseif new_k === :global && old_k in (:argument, :static_parameter)
    #     declare_in_scope!(ctx, scope, ex, :global)
    else
        throw(LoweringError(ex, """
        $(_var_str(new_k)) name `$(NameKey(ex).name)` conflicts with an \
        existing $(_var_str(old_k)) from the same scope"""))
    end
end

# globals are added to both `scope` and the top scope
function declare_in_scope!(ctx, scope::ScopeInfo, ex, bk::Symbol; kws...)
    nk = NameKey(ex)
    if bk === :global
        declaration_scope = top_scope(ctx)
        mod = ctx.scope_layers[ex.scope_layer].mod
    else
        declaration_scope = scope
        mod = nothing
    end
    is_internal = ctx.scope_layers[nk.layer].is_internal || getmeta(ex, :is_internal, false)
    b = _new_binding(ctx, ex, nk.name, bk; mod, is_internal, kws...)
    declaration_scope.vars[nk] = b.id
    scope.vars[nk] = b.id
    add_lambda_local!(ctx, scope, b)
    return b.id
end

function add_lambda_local!(ctx, scope::ScopeInfo, b)
    if b.kind === :global || b.is_ssa
        return
    end
    lam = scope.is_lifted ? top_scope(ctx) : enclosing_lambda(ctx, scope)
    @assert !haskey(lam.locals_capt, b.id)
    lam.locals_capt[b.id] = false
    b.lambda_id = lam.id
    nothing
end

function ensure_captured!(ctx, scope::ScopeInfo, b)
    if b.kind === :global || b.is_ssa
        return
    end
    lam = enclosing_lambda(ctx, scope)
    if !haskey(lam.locals_capt, b.id)
        b.is_captured = true
        lam.locals_capt[b.id] = true
        s2 = parent(ctx, lam)