Skip to content

False-positive runtime dispatch reports on Julia 1.13-rc1 for concrete Base broadcast/view/CartesianIndex code (clean on 1.12) #839

Description

@ChrisRackauckas-Claude

On Julia 1.13.0-rc1, @report_opt produces runtime-dispatch reports for straightforward, fully-concrete Base code paths (broadcast, view, CartesianIndex construction, mightalias) that are reported clean on Julia 1.12.6 with the same JET version (0.11.5). Native inference of every flagged frame is concrete and dispatch-free on both versions, so these appear to be false positives in JET's analysis layer on 1.13 rather than Base inference regressions or real dispatches.

Found via ForwardDiff.jl's QA testset (JET.@test_opt over gradient/jacobian/hessian), which fails on all "Julia pre" CI jobs; reduced to the self-contained MWEs below.

MWEs (clean on 1.12.6, flagged on 1.13.0-rc1; JET 0.11.5 in both cases)

using JET

# 1. Type-constructor broadcast with a Ref argument — 1 report on 1.13-rc1
struct P{N,V}; v::NTuple{N,V}; end
struct D{T,V,N}; val::V; p::P{N,V}; end
seedlike!(d, x, p) = (d .= D{Nothing,Float64,1}.(x, Ref(p)); d)
@report_opt seedlike!(Vector{D{Nothing,Float64,1}}(undef, 3), rand(3), P{1,Float64}((1.0,)))
# runtime dispatch in Broadcast.preprocess (broadcast.jl:977):
#   Broadcasted(nothing, …, %2::Tuple{Union{RefValue{…}, Extruded{…}}, RefValue{P{…}}}, …)
# (native inference of preprocess with these argtypes gives the concrete
#  Tuple{Extruded{Vector{Float64},…}, RefValue{P{1,Float64}}} on both versions)

# 2. CartesianIndex from Int + CartesianIndex — 3 reports on 1.13-rc1
ci2(i, c) = CartesianIndex(i, c)
@report_opt ci2(1, CartesianIndex(2))
# flatten (multidimensional.jl:92): Tuple(%1::Union{Int64, CartesianIndex{1}})::Tuple
# Val(x::Int64) dispatch; CartesianIndex(%1::Tuple)::Any
# Also triggered by plain `@simd for I in CartesianIndices(::Matrix)` loops.

# 3. view with a Colon and a range — 2 reports on 1.13-rc1
viewmwe(A, r) = view(A, :, r)
@report_opt viewmwe(rand(3, 3), 1:2)
# SubArray(…, %1::Tuple{Union{Slice{…}, UnitRange{…}}, …}) at subarray.jl:28,
# including a union-split into the impossible argument order
# unsafe_view(::Matrix, ::UnitRange, ::Slice)

# 4. dotview + broadcast assignment (hits 3. plus mightalias/_isdisjoint/_in_tuple) —
#    10 reports on 1.13-rc1
dotviewmwe!(A, r, y) = (A[:, r] .= y .* transpose(y); A)
@report_opt dotviewmwe!(rand(3, 3), 1:2, rand(3))

Full suite: 23 reports on 1.13.0-rc1, 0 on 1.12.6.

Evidence these are analysis false positives, not real dispatches

  • Base.infer_return_type / code_typed with the exact argtypes from the reports is concrete and identical on 1.12.6 and 1.13.0-rc1, e.g. on rc1:
    • Base.infer_return_type(Base.IteratorsMD.flatten, (Tuple{Int,CartesianIndex{1}},)) == Tuple{Int, Int}
    • Base.infer_return_type(view, (Matrix{Float64}, Colon, UnitRange{Int})) is the concrete SubArray{Float64, 2, Matrix{Float64}, Tuple{Slice{OneTo{Int}}, UnitRange{Int}}, true}
    • Base.Broadcast.preprocess for MWE 1's broadcast infers the concrete Broadcasted{Nothing, …, Tuple{Extruded{…}, RefValue{…}}}
  • Cache-cold inference through a minimal custom AbstractInterpreter with a fresh cache_owner is equally concrete on rc1 (rules out warm-sysimage-cache masking).
  • Runtime: the MWE kernels are 0-allocation on both versions (e.g. @allocated seedlike!(…) == 0 on rc1), so no dynamic dispatch exists in the compiled code.
  • _in_tuple (flagged as a leaf in pattern 4) is not new 1.13 code — it exists verbatim in 1.12.6 operators.jl, where JET is silent about it.

The unifying shape seems to be that in nested frames, call-site type/constant refinement is lost, so tuple element access degrades to the union over all element types (t::Tuple{Int, CartesianIndex{1}}; t[i]::Union{Int, CartesianIndex{1}}) and Val(x) is no longer const-propagated. Shallow versions of the same operations (e.g. a direct ensure_indexable call, or a hand-written recursive tuple map) are still analyzed precisely.

Not fixed by #815

Re-running the full MWE suite with PatrickHaecker/JET.jl#julia-1.13-compat (PR #815) on 1.13.0-rc1 gives identical reports, so this seems to be a distinct problem from what that PR addresses. Possibly related to the constprop issues in #819 (typeassert InferenceState, got IRInterpretationState in const_prop_call on JET#master), but these reports are silent mis-analysis rather than a crash.

Versions: Julia 1.13.0-rc1 (official binaries via juliaup), JET 0.11.5 (also reproduced with 0.11.4 in ForwardDiff CI), Linux x86_64.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions