@@ -393,18 +393,26 @@ let f(x) = (x...,)
393393 @test code_typed (f, Tuple{Union{Int64, CartesianIndex{1 }, CartesianIndex{3 }}})[1 ][2 ] == Tuple{Int64}
394394end
395395
396- # check if `x` is a statically-resolved call of a function whose name is `sym`
397- isinvoke (@nospecialize (x), sym:: Symbol ) = isinvoke (x, mi-> mi. def. name=== sym)
398- function isinvoke (@nospecialize (x), pred)
399- if Meta. isexpr (x, :invoke )
400- return pred (x. args[1 ]:: Core.MethodInstance )
396+ import Core. Compiler: argextype, singleton_type
397+ const EMPTY_SPTYPES = Core. Compiler. EMPTY_SLOTTYPES
398+
399+ code_typed1 (args... ; kwargs... ) = first (only (code_typed (args... ; kwargs... ))):: Core.CodeInfo
400+ get_code (args... ; kwargs... ) = code_typed1 (args... ; kwargs... ). code
401+
402+ # check if `x` is a dynamic call of a given function
403+ function iscall ((src, f):: Tuple{Core.CodeInfo,Function} , @nospecialize (x))
404+ return iscall (x) do @nospecialize x
405+ singleton_type (argextype (x, src, EMPTY_SPTYPES)) === f
401406 end
402- return false
403407end
404- code_typed1 (args... ; kwargs... ) = (first (only (code_typed (args... ; kwargs... ))):: Core.CodeInfo ). code
408+ iscall (pred, @nospecialize (x)) = Meta. isexpr (x, :call ) && pred (x. args[1 ])
409+
410+ # check if `x` is a statically-resolved call of a function whose name is `sym`
411+ isinvoke (sym:: Symbol , @nospecialize (x)) = isinvoke (mi-> mi. def. name=== sym, x)
412+ isinvoke (pred, @nospecialize (x)) = Meta. isexpr (x, :invoke ) && pred (x. args[1 ]:: Core.MethodInstance )
405413
406414# https://github.com/JuliaLang/julia/issues/42754
407- # inline union-split constant-prop'ed sources
415+ # inline union-split constant-prop'ed results
408416mutable struct X42754
409417 # NOTE in order to confuse `fieldtype_tfunc`, we need to have at least two fields with different types
410418 a:: Union{Nothing, Int}
430438
431439import Base: @constprop
432440
441+ # test union-split callsite with successful and unsuccessful constant-prop' results
442+ @constprop :aggressive @inline f42840 (xs, a:: Int ) = xs[a] # should be successful, and inlined
443+ @constprop :none @noinline f42840 (xs:: AbstractVector , a:: Int ) = xs[a] # should be unsuccessful, but still statically resolved
444+ let src = code_typed ((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
445+ f42840 (xs, 2 )
446+ end |> only |> first
447+ @test count (src. code) do @nospecialize x
448+ iscall ((src, getfield), x) # `(xs::Tuple{Int,Int,Int})[a::Const(2)]` => `getfield(xs, 2)`
449+ end == 1
450+ @test count (src. code) do @nospecialize x
451+ isinvoke (:f42840 , x)
452+ end == 1
453+ end
454+ # a bit weird, but should handle this kind of case as well
455+ @constprop :aggressive @noinline g42840 (xs, a:: Int ) = xs[a] # should be successful, but only statically resolved
456+ @constprop :none @inline g42840 (xs:: AbstractVector , a:: Int ) = xs[a] # should be unsuccessful, still inlined
457+ let src = code_typed ((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
458+ g42840 (xs, 2 )
459+ end |> only |> first
460+ @test count (src. code) do @nospecialize x
461+ iscall ((src, Base. arrayref), x) # `(xs::Vector{Int})[a::Const(2)]` => `Base.arrayref(true, xs, 2)`
462+ end == 1
463+ @test count (src. code) do @nospecialize x
464+ isinvoke (:g42840 , x)
465+ end == 1
466+ end
467+
433468# test single, non-dispatchtuple callsite inlining
434469
435470@constprop :none @inline test_single_nondispatchtuple (@nospecialize (t)) =
0 commit comments