ronantakizawa/codereview-bench huggingface dataset:
Repository: JuliaLang/julia
File: base/multidimensional.jl (Julia)

Code before:
    end

    @nexprs 4 i -> h = hash_mix_linear(p_i, h)
    return hash_uint(h)
end

"""
    union_split(f, x, ts::Tuple{Vararg{Val}}, args...)

call `f(x, args...)`, union-splitting on all the types specified by `ts`

`union_split(f, x, (Val{T1}(), Val{T2}()), y, z)` is equivalent to

```
if x isa T1
    f(x, y, z)
elseif x isa T2
    f(x, y, z)
else
    f(x, y, z)
end
```
"""
@inline function union_split(f::F, @nospecialize(x), ts::Tuple{Val{T}, Vararg{Any,N}}, args...) where {F, T, N}
    if x isa T
        f(x::T, args...)
    else
        union_split(f, x, Base.tail(ts), args...)
    end
end
@inline union_split(f::F, @nospecialize(x), ::Tuple{}, args...) where F = f(x, args...)

function hash_shaped(A, h0::UInt, eltype_hint=())
    h::UInt = h0
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
    # Instead hash the tuple of firsts and lasts along each dimension
    h = hash(map(first, axes(A)), h)
    h = hash(map(last, axes(A)), h)
    len = length(A)

    if len < 8
        # for the shortest arrays we chain directly
        for elt in A
            h = union_split(hash, elt, eltype_hint, h)
        end
        return h
    elseif len < 32768
        # separate accumulator streams, unrolled
        @nexprs 8 i -> p_i::UInt = h
        n  = 1
        limit = len - 7

Review comment (suggestion):
Pretty sure inference can figure `x isa T` on its own in this branch.

```suggestion
        f(x, args...)
```

Code after:
    if len < 8
        # for the shortest arrays we chain directly
        for elt in A
            h = union_split(hash, elt, eltype_hint, h)
        end
        return h
    elseif len < 32768
        # separate accumulator streams, unrolled
        @nexprs 8 i -> p_i::UInt = h
        n  = 1
        limit = len - 7
        while n <= limit
            @nexprs 8 i -> p_i = union_split(hash, A[n + i - 1], eltype_hint, p_i)
            n += 8
        end
        while n <= len
            p_1 = union_split(hash, A[n], eltype_hint, p_1)
            n += 1
        end
        # fold all streams back together
        @nexprs 8 i -> h = hash_mix_linear(p_i, h)
        return hash_uint(h)
    else
        return _hash_fib(A, h)
    end
end

const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
hash(A::AbstractArray, h::UInt) = hash_shaped(A, h ⊻ hash_abstractarray_seed)
Repository: JuliaLang/julia
File: base/multidimensional.jl (Julia)

Code before:
        keyidx = findprev(!isequal(elt), A, keyidx)
        keyidx === nothing && break
    end

    @nexprs 4 i -> h = hash_mix_linear(p_i, h)
    return hash_uint(h)
end

"""
    union_split(f, x, ts::Tuple{Vararg{Val}}, args...)

call `f(x, args...)`, union-splitting on all the types specified by `ts`

`union_split(f, x, (Val{T1}(), Val{T2}()), y, z)` is equivalent to

```
if x isa T1
    f(x, y, z)
elseif x isa T2
    f(x, y, z)
else
    f(x, y, z)
end
```
"""
@inline function union_split(f, @nospecialize(x), ts::Tuple{Val{T}, Vararg{Any,N}}, args...) where {T, N}
    if x isa T
        f(x, args...)
    else
        union_split(f, x, Base.tail(ts), args...)
    end
end
@inline union_split(f, x, ::Tuple{}, args...) = f(x, args...)

function hash_shaped(A, h0::UInt, eltype_hint=())
    h::UInt = h0
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
    # Instead hash the tuple of firsts and lasts along each dimension
    h = hash(map(first, axes(A)), h)
    h = hash(map(last, axes(A)), h)
    len = length(A)

    if len < 8
        # for the shortest arrays we chain directly
        for elt in A
            h = union_split(hash, elt, eltype_hint, h)
        end
        return h
    elseif len < 32768
        # separate accumulator streams, unrolled
        @nexprs 8 i -> p_i::UInt = h

Review comment (suggestion):
The intention is to only allow `Val` elements in the tuple, right? So the dispatch could be a bit stricter:

```suggestion
@inline function union_split(f, @nospecialize(x), ts::Tuple{Val{T}, Vararg{Val,N}}, args...) where {T, N}
```

Loving `union_split`, BTW!

Code after:
    len = length(A)

    if len < 8
        # for the shortest arrays we chain directly
        for elt in A
            h = union_split(hash, elt, eltype_hint, h)
        end
        return h
    elseif len < 32768
        # separate accumulator streams, unrolled
        @nexprs 8 i -> p_i::UInt = h
        n  = 1
        limit = len - 7
        while n <= limit
            @nexprs 8 i -> p_i = union_split(hash, A[n + i - 1], eltype_hint, p_i)
            n += 8
        end
        while n <= len
            p_1 = union_split(hash, A[n], eltype_hint, p_1)
            n += 1
        end
        # fold all streams back together
        @nexprs 8 i -> h = hash_mix_linear(p_i, h)
        return hash_uint(h)
    else
        return _hash_fib(A, h)
    end
end

const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
hash(A::AbstractArray, h::UInt) = hash_shaped(A, h ⊻ hash_abstractarray_seed)
Repository: JuliaLang/julia
File: base/scopedvalues.jl (Julia)

Code before:
julia> g(x) = a[] + b[] + x;

julia> with(a=>10, b=>20) do
           g(30)
       end
60

julia> with(() -> a[] * b[], a=>3, b=>4)
12
```
"""
function with(f, pair::Pair{<:AbstractScopedValue}, rest::Pair{<:AbstractScopedValue}...)
    @with(pair, rest..., f())
end
with(@nospecialize(f)) = f()

macro enter_scope(scope, expr)
    Expr(:tryfinally, esc(expr), nothing, :(Scope($(esc(scope))::Union{Nothing, Scope})))
end

"""
    ScopedThunk(f)

Create a functor that records the current dynamic scope, i.e. all current
`ScopedValue`s, along with `f`. When the functor is invoked, it runs `f`
in the recorded dynamic scope.
"""
struct ScopedThunk{F}
    f::F
    scope::Union{Nothing, Scope}

    ScopedThunk{F}(f) where {F} = new{F}(f, Core.current_scope())
end
ScopedThunk(f) = ScopedThunk{typeof(f)}(f)
(sf::ScopedThunk)() = @enter_scope sf.scope sf.f()

end # module ScopedValues


Review comment (suggestion):
i suppose we should avoid "functor" here?

I suppose either
```suggestion
Create a function object that records the current dynamic scope, i.e. all current
`ScopedValue`s, along with `f`. When the function object is invoked, it runs `f`
in the recorded dynamic scope.
```


Code after:
julia> with(a=>10, b=>20) do
           g(30)
       end
60

julia> with(() -> a[] * b[], a=>3, b=>4)
12
```
"""
function with(f, pair::Pair{<:AbstractScopedValue}, rest::Pair{<:AbstractScopedValue}...)
    @with(pair, rest..., f())
end
with(@nospecialize(f)) = f()

macro enter_scope(scope, expr)
    Expr(:tryfinally, esc(expr), nothing, :(Scope($(esc(scope))::Union{Nothing, Scope})))
end

"""
    ScopedThunk(f)

Create a callable that records the current dynamic scope, i.e. all current
`ScopedValue`s, along with `f`. When the callable is invoked, it runs `f`
in the recorded dynamic scope.
"""
struct ScopedThunk{F}
    f::F
    scope::Union{Nothing, Scope}

    ScopedThunk{F}(f) where {F} = new{F}(f, Core.current_scope())
end
ScopedThunk(f) = ScopedThunk{typeof(f)}(f)
(sf::ScopedThunk)() = @enter_scope sf.scope sf.f()

end # module ScopedValues
Repository: JuliaLang/julia
File: base/meta.jl (Julia)

Code before:
    Meta.unescape(expr)

Peel away `:escape` expressions and redundant block expressions (see
[`unblock`](@ref)).
"""
function unescape(@nospecialize ex)
    ex = unblock(ex)
    while isexpr(ex, :escape) || isexpr(ex, :var"hygienic-scope")
       ex = unblock(ex.args[1])
    end
    return ex
end

"""
    Meta.reescape(unescaped_expr, original_expr)

Re-wrap `unescaped_expr` with the same level of escaping as `original_expr` had.
This is the inverse operation of [`unescape`](@ref) - if the original expression
was escaped, the unescaped expression is wrapped in `:escape` again.
"""
function reescape(@nospecialize(unescaped_expr), @nospecialize(original_expr))
    if isexpr(original_expr, :escape)
        return reescape(Expr(:escape, unescaped_expr), original_expr.args[1])
    elseif isexpr(original_expr, :var"hygienic-scope")
        next, mod = original_expr.args
        return reescape(Expr(:var"hygienic-scope", unescaped_expr, mod), next)
    else
        return unescaped_expr
    end
end

"""
    Meta.uncurly(expr)

Turn `T{P...}` into just `T`.
"""
uncurly(@nospecialize ex) = isexpr(ex, :curly) ? ex.args[1] : ex

end # module


Review comment (security):
```suggestion
        next, ctx... = original_expr.args
        return reescape(Expr(:var"hygienic-scope", unescaped_expr, ctx...), next)
```
(there is technically a third optional argument of the source location to mark for inlining of the location of the original call to the macro)

Code after:
    Meta.unescape(expr)

Peel away `:escape` expressions and redundant block expressions (see
[`unblock`](@ref)).
"""
function unescape(@nospecialize ex)
    ex = unblock(ex)
    while isexpr(ex, :escape) || isexpr(ex, :var"hygienic-scope")
       ex = unblock(ex.args[1])
    end
    return ex
end

"""
    Meta.reescape(unescaped_expr, original_expr)

Re-wrap `unescaped_expr` with the same level of escaping as `original_expr` had.
This is the inverse operation of [`unescape`](@ref) - if the original expression
was escaped, the unescaped expression is wrapped in `:escape` again.
"""
function reescape(@nospecialize(unescaped_expr), @nospecialize(original_expr))
    if isexpr(original_expr, :escape)
        return reescape(Expr(:escape, unescaped_expr), original_expr.args[1])
    elseif isexpr(original_expr, :var"hygienic-scope")
        next, ctx... = original_expr.args
        return reescape(Expr(:var"hygienic-scope", unescaped_expr, ctx...), next)
    else
        return unescaped_expr
    end
end

"""
    Meta.uncurly(expr)

Turn `T{P...}` into just `T`.
"""
uncurly(@nospecialize ex) = isexpr(ex, :curly) ? ex.args[1] : ex

end # module
Repository: JuliaLang/julia
File: base/cmd.jl (Julia)

Code before:
    if length(parsed) >= 1 && isa(parsed[1], Tuple{Cmd})
        cmd = (parsed[1]::Tuple{Cmd})[1]
        (ignorestatus, flags, env, dir, cpus, uid, gid) = (cmd.ignorestatus, cmd.flags, cmd.env, cmd.dir, cmd.cpus, cmd.uid, cmd.gid)
        append!(args, cmd.exec)
        for arg in tail(parsed)
            append!(args, Base.invokelatest(arg_gen, arg...)::Vector{String})
        end
        return Cmd(Cmd(args), ignorestatus, flags, env, dir, cpus, uid, gid)
    else
        for arg in parsed
            append!(args, arg_gen(arg...)::Vector{String})
        end
        return Cmd(args)
    end
end

@assume_effects :foldable !:consistent function cmd_gen(
    parsed::Tuple{Vararg{Tuple{Vararg{Union{String, SubString{String}}}}}}
)
    return @invoke cmd_gen(parsed::Any)
end

"""
    @cmd str

Similar to `` `str` ``, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed.
The [`Cmd`](@ref) object can be run as a process and can outlive the spawning julia process (see `Cmd` for more).

# Examples
```jldoctest
julia> cm = @cmd " echo 1 "
`echo 1`

julia> run(cm)
1
Process(`echo 1`, ProcessExited(0))
```
"""
macro cmd(str::String)
    cmd_ex = shell_parse(str, special=shell_special, filename=String(__source__.file))[1]
    return :(cmd_gen($(esc(cmd_ex))))
end


Review comment (suggestion):
```suggestion
Similar to ``` `str` ```, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed.
```

Code after:
    if length(parsed) >= 1 && isa(parsed[1], Tuple{Cmd})
        cmd = (parsed[1]::Tuple{Cmd})[1]
        (ignorestatus, flags, env, dir, cpus, uid, gid) = (cmd.ignorestatus, cmd.flags, cmd.env, cmd.dir, cmd.cpus, cmd.uid, cmd.gid)
        append!(args, cmd.exec)
        for arg in tail(parsed)
            append!(args, Base.invokelatest(arg_gen, arg...)::Vector{String})
        end
        return Cmd(Cmd(args), ignorestatus, flags, env, dir, cpus, uid, gid)
    else
        for arg in parsed
            append!(args, arg_gen(arg...)::Vector{String})
        end
        return Cmd(args)
    end
end

@assume_effects :foldable !:consistent function cmd_gen(
    parsed::Tuple{Vararg{Tuple{Vararg{Union{String, SubString{String}}}}}}
)
    return @invoke cmd_gen(parsed::Any)
end

"""
    @cmd str

Similar to ``` `str` ```, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed.
The [`Cmd`](@ref) object can be run as a process and can outlive the spawning julia process (see `Cmd` for more).

# Examples
```jldoctest
julia> cm = @cmd " echo 1 "
`echo 1`

julia> run(cm)
1
Process(`echo 1`, ProcessExited(0))
```
"""
macro cmd(str::String)
    cmd_ex = shell_parse(str, special=shell_special, filename=String(__source__.file))[1]
    return :(cmd_gen($(esc(cmd_ex))))
end
Repository: JuliaLang/julia
File: src/init.c (C)

Code before:
    jl_init_threading();
    jl_init_threadinginfra();
    if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
        jl_install_default_signal_handlers();

    jl_gc_init();

    arraylist_new(&jl_linkage_blobs, 0);
    arraylist_new(&jl_image_relocs, 0);
    arraylist_new(&jl_top_mods, 0);
    arraylist_new(&eytzinger_image_tree, 0);
    arraylist_new(&eytzinger_idxs, 0);
    arraylist_push(&eytzinger_idxs, (void*)0);
    arraylist_push(&eytzinger_image_tree, (void*)1); // outside image

    jl_ptls_t ptls = jl_init_threadtls(0);
#pragma GCC diagnostic push
#if defined(_COMPILER_GCC_) && __GNUC__ >= 12
#pragma GCC diagnostic ignored "-Wdangling-pointer"
#endif
    if (jl_options.task_metrics == JL_OPTIONS_TASK_METRICS_ON) {
        // enable before creating the root task so it gets timings too.
        jl_atomic_fetch_add(&jl_task_metrics_enabled, 1);
    }
    // warning: this changes `jl_current_task`, so be careful not to call that from this function
    jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi);
    // Initialize constant objects
    jl_nothing = jl_gc_permobj(0, jl_nothing_type, 0);
    jl_set_typetagof(jl_nothing, jl_nothing_tag, GC_OLD_MARKED);
    jl_init_box_caches();
    jl_init_common_symbols();
#pragma GCC diagnostic pop
    JL_GC_PROMISE_ROOTED(ct);
    _finish_jl_init_(sysimage, ptls, ct);
}

#ifdef __cplusplus
}
#endif


Review comment (suggestion):
The ordering before seems quite intentional since `jl_init_root_task` uses `jl_nothing`. 

So now the root task is storing an uninitialized pointer in places and later we use pointer identity checks "val == jl_nothing".

Code after:
    jl_init_threading();
    jl_init_threadinginfra();
    if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
        jl_install_default_signal_handlers();

    jl_gc_init();

    arraylist_new(&jl_linkage_blobs, 0);
    arraylist_new(&jl_image_relocs, 0);
    arraylist_new(&jl_top_mods, 0);
    arraylist_new(&eytzinger_image_tree, 0);
    arraylist_new(&eytzinger_idxs, 0);
    arraylist_push(&eytzinger_idxs, (void*)0);
    arraylist_push(&eytzinger_image_tree, (void*)1); // outside image

    jl_ptls_t ptls = jl_init_threadtls(0);
#pragma GCC diagnostic push
#if defined(_COMPILER_GCC_) && __GNUC__ >= 12
#pragma GCC diagnostic ignored "-Wdangling-pointer"
#endif
    if (jl_options.task_metrics == JL_OPTIONS_TASK_METRICS_ON) {
        // enable before creating the root task so it gets timings too.
        jl_atomic_fetch_add(&jl_task_metrics_enabled, 1);
    }
    // Initialize constant objects
    jl_nothing = jl_gc_permobj(ptls, 0, jl_nothing_type, 0);
    jl_set_typetagof(jl_nothing, jl_nothing_tag, GC_OLD_MARKED);
    // warning: this changes `jl_current_task`, so be careful not to call that from this function
    jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi);
    jl_init_box_caches();
    jl_init_common_symbols();
#pragma GCC diagnostic pop
    JL_GC_PROMISE_ROOTED(ct);
    _finish_jl_init_(sysimage, ptls, ct);
}

#ifdef __cplusplus
}
#endif
Repository: JuliaLang/julia
File: test/llvmpasses/memoryref-addrspace.jl (Julia)

Code before:
# This file is a part of Julia. License is MIT: https://julialang.org/license
# RUN: julia --startup-file=no --check-bounds=yes %s %t -O
# RUN: cat %t/* | FileCheck %s

include(joinpath("..", "testhelpers", "llvmpasses.jl"))

# Test for GenericMemoryRef address space bug
# Issue: stores incorrectly use addrspace(10) instead of addrspace(11)
# in bounds checking code, causing LLVM assertion failures
function bf(i, x)
    x[i] *= x[i]
    nothing
end

# CHECK-LABEL: @julia_bf
# CHECK: oob:
# CHECK: store {{.*}} addrspace(11) {{.*}}GenericMemoryRef
# CHECK-NOT: store {{.*}} addrspace(10) {{.*}}GenericMemoryRef
# CHECK: call void @ijl_bounds_error_int

emit(bf, Tuple{Int, Vector{Float64}})


Review comment (suggestion):
```suggestion
emit(bf, Int, Vector{Float64})
```

Code after:
# This file is a part of Julia. License is MIT: https://julialang.org/license
# RUN: julia --startup-file=no --check-bounds=yes %s %t -O
# RUN: cat %t/* | FileCheck %s

include(joinpath("..", "testhelpers", "llvmpasses.jl"))

# Test for GenericMemoryRef address space bug
# Issue: stores incorrectly use addrspace(10) instead of addrspace(11)
# in bounds checking code, causing LLVM assertion failures
function bf(i, x)
    x[i] *= x[i]
    nothing
end

# CHECK-LABEL: @julia_bf
# CHECK: oob:
# CHECK: store ptr {{.*}}, ptr %"box::GenericMemoryRef"
# CHECK-NOT: store {{.*}} addrspace(10) {{.*}}GenericMemoryRef
# CHECK: call void @ijl_bounds_error_int

emit(bf, Int, Vector{Float64})
Repository: JuliaLang/julia
File: base/operators.jl (Julia)

Code before:
    x::T

    function Fix{N}(f::F, x) where {N,F}
        if !(N isa Int)
            throw(ArgumentError(LazyString("expected type parameter in `Fix` to be `Int`, but got `", N, "::", typeof(N), "`")))
        elseif N < 1
            throw(ArgumentError(LazyString("expected `N` in `Fix{N}` to be integer greater than 0, but got ", N)))
        end
        new{N,_stable_typeof(f),_stable_typeof(x)}(f, x)
    end
end

function (f::Fix{N})(args::Vararg{Any,M}; kws...) where {N,M}
    M < N-1 && throw(ArgumentError(LazyString("expected at least ", N-1, " arguments to `Fix{", N, "}`, but got ", M)))
    return f.f(args[begin:begin+(N-2)]..., f.x, args[begin+(N-1):end]...; kws...)
end

# Special cases for improved constant propagation
(f::Fix{1})(arg; kws...) = f.f(f.x, arg; kws...)
(f::Fix{2})(arg; kws...) = f.f(arg, f.x; kws...)

function Base.show(io::IO, fix::Fix)
    function get_n(::Fix{N}) where {N}
        N
    end
    constr = Fix{get_n(fix)}
    callable = fix.f
    fixed_argument = fix.x
    show(io, constr)
    print(io, '(')
    show(io, callable)
    print(io, ',')
    print(io, ' ')
    show(io, fixed_argument)
    print(io, ')')
end

"""
Alias for `Fix{1}`. See [`Fix`](@ref Base.Fix).
"""
const Fix1{F,T} = Fix{1,F,T}

"""
Alias for `Fix{2}`. See [`Fix`](@ref Base.Fix).
"""
const Fix2{F,T} = Fix{2,F,T}


"""
    isequal(x)


Review comment (suggestion):
```suggestion
function Base.show(io::IO, fix::Fix{N}) where {N}
    constr = Fix{N}
```

Code after:
    x::T

    function Fix{N}(f::F, x) where {N,F}
        if !(N isa Int)
            throw(ArgumentError(LazyString("expected type parameter in `Fix` to be `Int`, but got `", N, "::", typeof(N), "`")))
        elseif N < 1
            throw(ArgumentError(LazyString("expected `N` in `Fix{N}` to be integer greater than 0, but got ", N)))
        end
        new{N,_stable_typeof(f),_stable_typeof(x)}(f, x)
    end
end

function (f::Fix{N})(args::Vararg{Any,M}; kws...) where {N,M}
    M < N-1 && throw(ArgumentError(LazyString("expected at least ", N-1, " arguments to `Fix{", N, "}`, but got ", M)))
    (left, right) = _split_tuple(args, N-1)
    return f.f(left..., f.x, right...; kws...)
end

# Special cases for improved constant propagation
(f::Fix{1})(arg; kws...) = f.f(f.x, arg; kws...)
(f::Fix{2})(arg; kws...) = f.f(arg, f.x; kws...)

function Base.show(io::IO, fix::Fix{N}) where {N}
    constr = Fix{N}
    callable = fix.f
    fixed_argument = fix.x
    show(io, constr)
    print(io, '(')
    show(io, callable)
    print(io, ',')
    print(io, ' ')
    show(io, fixed_argument)
    print(io, ')')
end

"""
Alias for `Fix{1}`. See [`Fix`](@ref Base.Fix).
"""
const Fix1{F,T} = Fix{1,F,T}

"""
Alias for `Fix{2}`. See [`Fix`](@ref Base.Fix).
"""
const Fix2{F,T} = Fix{2,F,T}


"""
    isequal(x)

Create a function that compares its argument to `x` using [`isequal`](@ref), i.e.
a function equivalent to `y -> isequal(y, x)`.
Repository: JuliaLang/julia
File: base/operators.jl (Julia)

Code before:
    end
end

function (f::Fix{N})(args::Vararg{Any,M}; kws...) where {N,M}
    M < N-1 && throw(ArgumentError(LazyString("expected at least ", N-1, " arguments to `Fix{", N, "}`, but got ", M)))
    return f.f(args[begin:begin+(N-2)]..., f.x, args[begin+(N-1):end]...; kws...)
end

# Special cases for improved constant propagation
(f::Fix{1})(arg; kws...) = f.f(f.x, arg; kws...)
(f::Fix{2})(arg; kws...) = f.f(arg, f.x; kws...)

function Base.show(io::IO, fix::Fix{N}) where {N}
    constr = Fix{N}
    callable = fix.f
    fixed_argument = fix.x
    show(io, constr)
    print(io, '(')
    show(io, callable)
    print(io, ',')
    print(io, ' ')
    show(io, fixed_argument)
    print(io, ')')
end

"""
Alias for `Fix{1}`. See [`Fix`](@ref Base.Fix).
"""
const Fix1{F,T} = Fix{1,F,T}

"""
Alias for `Fix{2}`. See [`Fix`](@ref Base.Fix).
"""
const Fix2{F,T} = Fix{2,F,T}


"""
    isequal(x)

Create a function that compares its argument to `x` using [`isequal`](@ref), i.e.
a function equivalent to `y -> isequal(y, x)`.

The returned function is of type `Base.Fix2{typeof(isequal)}`, which can be
used to implement specialized methods.
"""
isequal(x) = Fix2(isequal, x)

"""
    ==(x)

Create a function that compares its argument to `x` using [`==`](@ref), i.e.

Review comment (suggestion):
Might it be cleaner just to redirect from `show(::Function)` back to show_default, so we don't need to write out an explicit hand-written copy of `show_default`, and also perhaps to define `showarg`?
```suggestion
show(io::IO, fix::Fix) = show_default(io, fix)
function showarg(io::IO, fix::Fix{N}, toplevel) where {N}
    print(io, "Fix{", N, "}(")
    showarg(io, fix.f, false)
    showarg(io, fix.x, false)
    print(io, ")")
end
```

Code after:
    end
end

function (f::Fix{N})(args::Vararg{Any,M}; kws...) where {N,M}
    M < N-1 && throw(ArgumentError(LazyString("expected at least ", N-1, " arguments to `Fix{", N, "}`, but got ", M)))
    (left, right) = _split_tuple(args, N-1)
    return f.f(left..., f.x, right...; kws...)
end

# Special cases for improved constant propagation
(f::Fix{1})(arg; kws...) = f.f(f.x, arg; kws...)
(f::Fix{2})(arg; kws...) = f.f(arg, f.x; kws...)

function Base.show(io::IO, fix::Fix{N}) where {N}
    constr = Fix{N}
    callable = fix.f
    fixed_argument = fix.x
    show(io, constr)
    print(io, '(')
    show(io, callable)
    print(io, ',')
    print(io, ' ')
    show(io, fixed_argument)
    print(io, ')')
end

"""
Alias for `Fix{1}`. See [`Fix`](@ref Base.Fix).
"""
const Fix1{F,T} = Fix{1,F,T}

"""
Alias for `Fix{2}`. See [`Fix`](@ref Base.Fix).
"""
const Fix2{F,T} = Fix{2,F,T}


"""
    isequal(x)

Create a function that compares its argument to `x` using [`isequal`](@ref), i.e.
a function equivalent to `y -> isequal(y, x)`.

The returned function is of type `Base.Fix2{typeof(isequal)}`, which can be
used to implement specialized methods.
"""
isequal(x) = Fix2(isequal, x)

"""
    ==(x)