Skip to content

Commit 9482961

Browse files
committed
improve exct modeling for invoke calls
1 parent f87d164 commit 9482961

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
9898
add_remark!(interp, sv, "[constprop] Discarded because the result was wider than inference")
9999
end
100100
if const_call_result.exct exct
101-
exct = const_call_result.exct
102-
(; const_result, edge) = const_call_result
101+
(; exct, const_result, edge) = const_call_result
103102
else
104103
add_remark!(interp, sv, "[constprop] Discarded exception type because result was wider than inference")
105104
end
@@ -2135,12 +2134,13 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
21352134
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
21362135
isexact || return CallMeta(Any, Any, Effects(), NoCallInfo())
21372136
unwrapped = unwrap_unionall(types)
2138-
if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name
2139-
return CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())
2137+
types === Bottom && return CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())
2138+
if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
2139+
return CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())
21402140
end
21412141
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
21422142
nargtype = typeintersect(types, argtype)
2143-
nargtype === Bottom && return CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())
2143+
nargtype === Bottom && return CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())
21442144
nargtype isa DataType || return CallMeta(Any, Any, Effects(), NoCallInfo()) # other cases are not implemented below
21452145
isdispatchelem(ft) || return CallMeta(Any, Any, Effects(), NoCallInfo()) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
21462146
ft = ft::DataType
@@ -2154,7 +2154,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
21542154
tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
21552155
ti = tienv[1]; env = tienv[2]::SimpleVector
21562156
result = abstract_call_method(interp, method, ti, env, false, si, sv)
2157-
(; rt, edge, effects, volatile_inf_result) = result
2157+
(; rt, exct, edge, effects, volatile_inf_result) = result
21582158
match = MethodMatch(ti, env, method, argtype <: method.sig)
21592159
res = nothing
21602160
sig = match.spec_types
@@ -2168,23 +2168,28 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
21682168
# argtypes′[i] = t ⊑ a ? t : a
21692169
# end
21702170
𝕃ₚ = ipo_lattice(interp)
2171+
, , = partialorder(𝕃ₚ), strictneqpartialorder(𝕃ₚ), join(𝕃ₚ)
21712172
f = singleton_type(ft′)
21722173
invokecall = InvokeCall(types, lookupsig)
21732174
const_call_result = abstract_call_method_with_const_args(interp,
21742175
result, f, arginfo, si, match, sv, invokecall)
21752176
const_result = volatile_inf_result
21762177
if const_call_result !== nothing
2177-
if (𝕃ₚ, const_call_result.rt, rt)
2178+
if const_call_result.rt rt
21782179
(; rt, effects, const_result, edge) = const_call_result
21792180
end
2181+
if const_call_result.exct exct
2182+
(; exct, const_result, edge) = const_call_result
2183+
end
21802184
end
21812185
rt = from_interprocedural!(interp, rt, sv, arginfo, sig)
21822186
info = InvokeCallInfo(match, const_result)
21832187
edge !== nothing && add_invoke_backedge!(sv, lookupsig, edge)
21842188
if !match.fully_covers
21852189
effects = Effects(effects; nothrow=false)
2190+
exct = exct TypeError
21862191
end
2187-
return CallMeta(rt, Any, effects, info)
2192+
return CallMeta(rt, exct, effects, info)
21882193
end
21892194

21902195
function invoke_rewrite(xs::Vector{Any})
@@ -2205,16 +2210,16 @@ end
22052210

22062211
function abstract_throw(interp::AbstractInterpreter, argtypes::Vector{Any}, ::AbsIntState)
22072212
na = length(argtypes)
2208-
𝕃ᵢ = typeinf_lattice(interp)
2213+
= join(typeinf_lattice(interp))
22092214
if na == 2
22102215
argtype2 = argtypes[2]
22112216
if isvarargtype(argtype2)
2212-
exct = tmerge(𝕃ᵢ, unwrapva(argtype2), ArgumentError)
2217+
exct = unwrapva(argtype2) ArgumentError
22132218
else
22142219
exct = argtype2
22152220
end
22162221
elseif na == 3 && isvarargtype(argtypes[3])
2217-
exct = tmerge(𝕃ᵢ, argtypes[2], ArgumentError)
2222+
exct = argtypes[2] ArgumentError
22182223
else
22192224
exct = ArgumentError
22202225
end
@@ -2348,26 +2353,26 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter,
23482353
(; rt, exct, edge, effects, volatile_inf_result) = result
23492354
match = MethodMatch(sig, Core.svec(), ocmethod, sig <: ocsig)
23502355
𝕃ₚ = ipo_lattice(interp)
2351-
, = partialorder(𝕃ₚ), strictneqpartialorder(𝕃ₚ)
2356+
, , = partialorder(𝕃ₚ), strictneqpartialorder(𝕃ₚ), join(𝕃ₚ)
23522357
const_result = volatile_inf_result
23532358
if !result.edgecycle
23542359
const_call_result = abstract_call_method_with_const_args(interp, result,
23552360
nothing, arginfo, si, match, sv)
23562361
if const_call_result !== nothing
2357-
if const_call_result.rt rt
2362+
if const_call_result.rt rt
23582363
(; rt, effects, const_result, edge) = const_call_result
23592364
end
2360-
if const_call_result.exct exct
2365+
if const_call_result.exct exct
23612366
(; exct, const_result, edge) = const_call_result
23622367
end
23632368
end
23642369
end
23652370
if check # analyze implicit type asserts on argument and return type
23662371
rty = (unwrap_unionall(tt)::DataType).parameters[2]
23672372
rty = rewrap_unionall(rty isa TypeVar ? rty.ub : rty, tt)
2368-
if !(rt rty && sig ocsig)
2373+
if !(rt rty && sig ocsig)
23692374
effects = Effects(effects; nothrow=false)
2370-
exct = tmerge(𝕃ₚ, exct, TypeError)
2375+
exct = exct TypeError
23712376
end
23722377
end
23732378
rt = from_interprocedural!(interp, rt, sv, arginfo, match.spec_types)

test/compiler/inference.jl

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6078,9 +6078,7 @@ gcondvarargs(a, x...) = return fcondvarargs(a, x...) ? isa(a, Int64) : !isa(a, I
60786078
@test Core.Compiler.return_type(gcondvarargs, Tuple{Vararg{Any}}) === Bool
60796079

60806080
# JuliaLang/julia#55627: argtypes check in `abstract_call_opaque_closure`
6081-
issue55627_some_method(x) = 2x
6082-
issue55627_make_oc() = Base.Experimental.@opaque (x::Int)->issue55627_some_method(x)
6083-
6081+
issue55627_make_oc() = Base.Experimental.@opaque (x::Int) -> 2x
60846082
@test Base.infer_return_type() do
60856083
f = issue55627_make_oc()
60866084
return f(1), f()
@@ -6099,9 +6097,7 @@ end >: MethodError
60996097
end >: TypeError
61006098

61016099
# `exct` modeling for opaque closure
6102-
oc_exct_1() = Base.Experimental.@opaque function (x)
6103-
return x < 0 ? throw(x) : x
6104-
end
6100+
oc_exct_1() = Base.Experimental.@opaque (x) -> x < 0 ? throw(x) : x
61056101
@test Base.infer_exception_type((Int,)) do x
61066102
oc_exct_1()(x)
61076103
end == Int
@@ -6116,6 +6112,28 @@ f_invoke_nothrow(::Int) = :int
61166112
@test Base.infer_effects((Int,)) do x
61176113
@invoke f_invoke_nothrow(x::Number)
61186114
end |> Core.Compiler.is_nothrow
6115+
@test Base.infer_effects((Char,)) do x
6116+
@invoke f_invoke_nothrow(x::Number)
6117+
end |> !Core.Compiler.is_nothrow
61196118
@test Base.infer_effects((Union{Nothing,Int},)) do x
61206119
@invoke f_invoke_nothrow(x::Number)
61216120
end |> !Core.Compiler.is_nothrow
6121+
6122+
# `exct` modeling for `invoke` calls
6123+
f_invoke_exct(x::Number) = x < 0 ? throw(x) : x
6124+
f_invoke_exct(x::Int) = x
6125+
@test Base.infer_exception_type((Int,)) do x
6126+
@invoke f_invoke_exct(x::Number)
6127+
end == Int
6128+
@test Base.infer_exception_type() do
6129+
@invoke f_invoke_exct(42::Number)
6130+
end == Union{}
6131+
@test Base.infer_exception_type((Union{Nothing,Int},)) do x
6132+
@invoke f_invoke_exct(x::Number)
6133+
end == Union{Int,TypeError}
6134+
@test Base.infer_exception_type((Int,)) do x
6135+
invoke(f_invoke_exct, Number, x)
6136+
end == TypeError
6137+
@test Base.infer_exception_type((Char,)) do x
6138+
invoke(f_invoke_exct, Tuple{Number}, x)
6139+
end == TypeError

0 commit comments

Comments
 (0)