Skip to content

Method parameter type annotation Union{Function, Nothing} causes incorrect specialization on concrete Function type #59326

@NHDaly

Description

@NHDaly

The julia documentation says (https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing):

As a heuristic, Julia avoids automatically specializing on argument type parameters in three specific cases: Type, Function, and Vararg. Julia will always specialize when the argument is used within the method, but not if the argument is just passed through to another function.

Surprisingly, this behavior seems to change if we give that method parameter a declared type of ::Union{Function, Nothing}:

$ julia --trace-compile=stderr -e '@noinline f1(f, x) = Any[f, x];  f2(x) = f1(+, Any[x][1]); f2(1)'
precompile(Tuple{typeof(Main.f2), Int64})
precompile(Tuple{typeof(Main.f1), Function, Int64})

$ julia --trace-compile=stderr -e '@noinline f1(f::Function, x) = Any[f, x];  f2(x) = f1(+, Any[x][1]); f2(1)'
precompile(Tuple{typeof(Main.f2), Int64})
precompile(Tuple{typeof(Main.f1), Function, Int64})

$ julia --trace-compile=stderr -e '@noinline f1(f::Union{Function, Nothing}, x) = Any[f, x];  f2(x) = f1(+, Any[x][1]); f2(1)'
precompile(Tuple{typeof(Main.f2), Int64})
precompile(Tuple{typeof(Main.f1), typeof(Base.:(+)), Int64})

As you can see, this is extra surprising because it works as described with no type restrictions at all: f1(f::Any, x) = works fine, but f1(f::Union{Function, Nothing}, x) does not.

This is a bug, right?

I confirmed this same behavior on both julia 1.10 and julia nightly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIndicates an unexpected problem or unintended behaviorcompiler:codegenGeneration of LLVM IR and native code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions