Skip to content

Regression of inferrability of broadcast code #51129

Closed
@giordano

Description

@giordano

In v1.10.0-beta2 I get

julia> f(v, x) = (1 .- (v ./ x) .^ 2)
f (generic function with 1 method)

julia> code_warntype(f, Tuple{Vector{Float64}, Float64})
MethodInstance for f(::Vector{Float64}, ::Float64)
  from f(v, x) @ Main REPL[1]:1
Arguments
  #self#::Core.Const(f)
  v::Vector{Float64}
  x::Float64
Body::Union{Vector, BitVector}
1 ─ %1 = Main.:-::Core.Const(-)
│   %2 = Main.:^::Core.Const(^)
│   %3 = Base.broadcasted(Main.:/, v, x)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}
│   %4 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│   %5 = (%4)()::Core.Const(Val{2}())
│   %6 = Base.broadcasted(Base.literal_pow, %2, %3, %5)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}
│   %7 = Base.broadcasted(%1, 1, %6)::Core.PartialStruct(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(-), Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}}, Any[Core.Const(Base.Broadcast.DefaultArrayStyle{1}()), Core.Const(-), Core.PartialStruct(Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}, Any[Core.Const(1), Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}]), Nothing])
│   %8 = Base.materialize(%7)::Union{Vector, BitVector}
└──      return %8

Return type of f is inferred as Union{Vector, BitVector}, but I'm missing how this can be a BitVector at all.

Interestingly, if I change the definition of f to f(v, x) = ((v ./ x) .^ 2) and then change back to f(v, x) = (1 .- (v ./ x) .^ 2) then this is inferred correctly as Vector{Float64}:

julia> f(v, x) = ((v ./ x) .^ 2)
f (generic function with 1 method)

julia> code_warntype(f, Tuple{Vector{Float64}, Float64})
MethodInstance for f(::Vector{Float64}, ::Float64)
  from f(v, x) @ Main REPL[5]:1
Arguments
  #self#::Core.Const(f)
  v::Vector{Float64}
  x::Float64
Body::Vector{Float64}
1 ─ %1 = Main.:^::Core.Const(^)
│   %2 = Base.broadcasted(Main.:/, v, x)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}
│   %3 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│   %4 = (%3)()::Core.Const(Val{2}())
│   %5 = Base.broadcasted(Base.literal_pow, %1, %2, %4)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}
│   %6 = Base.materialize(%5)::Vector{Float64}
└──      return %6


julia> f(v, x) = (1 .- (v ./ x) .^ 2)
f (generic function with 1 method)

julia> code_warntype(f, Tuple{Vector{Float64}, Float64})
MethodInstance for f(::Vector{Float64}, ::Float64)
  from f(v, x) @ Main REPL[7]:1
Arguments
  #self#::Core.Const(f)
  v::Vector{Float64}
  x::Float64
Body::Vector{Float64}
1 ─ %1 = Main.:-::Core.Const(-)
│   %2 = Main.:^::Core.Const(^)
│   %3 = Base.broadcasted(Main.:/, v, x)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}
│   %4 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│   %5 = (%4)()::Core.Const(Val{2}())
│   %6 = Base.broadcasted(Base.literal_pow, %2, %3, %5)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}
│   %7 = Base.broadcasted(%1, 1, %6)::Core.PartialStruct(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(-), Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}}, Any[Core.Const(Base.Broadcast.DefaultArrayStyle{1}()), Core.Const(-), Core.PartialStruct(Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}, Any[Core.Const(1), Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}]), Nothing])
│   %8 = Base.materialize(%7)::Vector{Float64}
└──      return %8

The fact that this depends on previous definitions of the function is quite surprising.

In 1.9.3 I get out-of-the-box the return type Vector{Float64}

julia> code_warntype(f, Tuple{Vector{Float64}, Float64})
MethodInstance for f(::Vector{Float64}, ::Float64)
  from f(v, x) @ Main REPL[1]:1
Arguments
  #self#::Core.Const(f)
  v::Vector{Float64}
  x::Float64
Body::Vector{Float64}
1 ─ %1 = Main.:-::Core.Const(-)
│   %2 = Main.:^::Core.Const(^)
│   %3 = Base.broadcasted(Main.:/, v, x)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}
│   %4 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│   %5 = (%4)()::Core.Const(Val{2}())
│   %6 = Base.broadcasted(Base.literal_pow, %2, %3, %5)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}
│   %7 = Base.broadcasted(%1, 1, %6)::Core.PartialStruct(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(-), Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}}, Any[Core.Const(-), Core.PartialStruct(Tuple{Int64, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}}, Any[Core.Const(1), Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.literal_pow), Tuple{Base.RefValue{typeof(^)}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(/), Tuple{Vector{Float64}, Float64}}, Base.RefValue{Val{2}}}}]), Core.Const(nothing)])
│   %8 = Base.materialize(%7)::Vector{Float64}
└──      return %8

as expected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    broadcastApplying a function over a collectioncompiler:inferenceType inferenceregressionRegression in behavior compared to a previous version

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions