Skip to content

Commit c1869ec

Browse files
committed
lowering: Revert undefined global outlining
This partially reverts #51970, once again allowing throwing GlobalRefs in value position for `CodeInfo`, (but not `IRCode`). The primary motivation for this reversal is that after binding partition the throwiness of a global is world-age dependent and we do not want to have lowering be world-age dependent, because that would require us to rewrite the lowered code upon invalidation (#56649). With respect to the original motivation for this change (being able to use the statement flag in inference), we retain the property that the statement flags apply only to the optimizer version of the statement (i.e. with the GlobalRefs moved out). The only place in inference where we were not doing this, we can rely on `exct` instead. This does assume that `exct` is precise, but we've done a lot of work on that in the past year, so hopefully we can rely on that now. The revert is partial, because we go in the opposite direction in a few places: For `GotoIfNot` cond and `EnterNode` scope operands, we just forbid any `GlobalRef` entirely. Constants are rare in these, so no need to burden inference with the possibility of handling these. We do however, keep (and add appropriate handling code) for GlobalRef arguments to `ReturnNode` to make sure that trivial code remains one statement.
1 parent 18205fb commit c1869ec

File tree

8 files changed

+151
-137
lines changed

8 files changed

+151
-137
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2862,7 +2862,7 @@ function sp_type_rewrap(@nospecialize(T), mi::MethodInstance, isreturn::Bool)
28622862
end
28632863

28642864
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
2865-
f = abstract_eval_value(interp, e.args[2], sstate, sv)
2865+
(f, exct) = abstract_eval_value(interp, e.args[2], sstate, sv)
28662866
# rt = sp_type_rewrap(e.args[3], sv.linfo, true)
28672867
atv = e.args[4]::SimpleVector
28682868
at = Vector{Any}(undef, length(atv) + 1)
@@ -2921,30 +2921,32 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, sv::AbsI
29212921
# @assert false "Unexpected EXPR head in value position"
29222922
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
29232923
end
2924-
return Any
2924+
return Pair{Any, Any}(Any, Any)
29252925
end
29262926

29272927
function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::AbsIntState)
29282928
if isa(e, Expr)
29292929
return abstract_eval_value_expr(interp, e, sv)
29302930
else
2931-
(;rt, effects) = abstract_eval_special_value(interp, e, sstate, sv)
2931+
(;rt, exct, effects) = abstract_eval_special_value(interp, e, sstate, sv)
29322932
merge_effects!(interp, sv, effects)
2933-
return collect_limitations!(rt, sv)
2933+
return Pair{Any, Any}(collect_limitations!(rt, sv), exct)
29342934
end
29352935
end
29362936

29372937
function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, sstate::StatementState, sv::AbsIntState)
29382938
n = length(ea)
29392939
argtypes = Vector{Any}(undef, n)
2940+
exct = Union{}
29402941
@inbounds for i = 1:n
2941-
ai = abstract_eval_value(interp, ea[i], sstate, sv)
2942+
(ai, ei) = abstract_eval_value(interp, ea[i], sstate, sv)
29422943
if ai === Bottom
29432944
return nothing
29442945
end
29452946
argtypes[i] = ai
2947+
exct = Union{exct, ei}
29462948
end
2947-
return argtypes
2949+
return Pair{Vector{Any}, Any}(argtypes, exct)
29482950
end
29492951

29502952
struct RTEffects
@@ -2984,21 +2986,23 @@ function abstract_eval_call(interp::AbstractInterpreter, e::Expr, sstate::Statem
29842986
if argtypes === nothing
29852987
return Future(RTEffects(Bottom, Any, Effects()))
29862988
end
2989+
(argtypes, aexct) = argtypes
29872990
arginfo = ArgInfo(ea, argtypes)
29882991
call = abstract_call(interp, arginfo, sstate, sv)::Future
29892992
return Future{RTEffects}(call, interp, sv) do call, interp, sv
29902993
(; rt, exct, effects, refinements) = call
2991-
return RTEffects(rt, exct, effects, refinements)
2994+
return RTEffects(rt, tmerge(typeinf_lattice(interp), exct, aexct), effects, refinements)
29922995
end
29932996
end
29942997

2995-
2998+
const generic_new_exct = Union{ErrorException, TypeError}
29962999
function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
29973000
sv::AbsIntState)
29983001
𝕃ᵢ = typeinf_lattice(interp)
2999-
rt, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
3002+
(ea1, a1exct) = abstract_eval_value(interp, e.args[1], sstate, sv)
3003+
rt, isexact = instanceof_tfunc(ea1, true)
30003004
ut = unwrap_unionall(rt)
3001-
exct = Union{ErrorException,TypeError}
3005+
nothrow = false
30023006
if isa(ut, DataType) && !isabstracttype(ut)
30033007
ismutable = ismutabletype(ut)
30043008
fcount = datatype_fieldcount(ut)
@@ -3018,12 +3022,15 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::Stateme
30183022
end
30193023
if isconcretedispatch(rt)
30203024
nothrow = true
3025+
exct = Union{}
30213026
@assert fcount !== nothing && fcount nargs "malformed :new expression" # syntactically enforced by the front-end
30223027
ats = Vector{Any}(undef, nargs)
30233028
local anyrefine = false
30243029
local allconst = true
30253030
for i = 1:nargs
3026-
at = widenslotwrapper(abstract_eval_value(interp, e.args[i+1], sstate, sv))
3031+
(atn, aexct) = abstract_eval_value(interp, e.args[i+1], sstate, sv)
3032+
exct = Union{exct, aexct}
3033+
at = widenslotwrapper(atn)
30273034
ft = fieldtype(rt, i)
30283035
nothrow && (nothrow = (𝕃ᵢ, at, ft))
30293036
at = tmeet(𝕃ᵢ, at, ft)
@@ -3039,6 +3046,7 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::Stateme
30393046
end
30403047
ats[i] = at
30413048
end
3049+
nothrow || (exct = Union{exct, TypeError})
30423050
if fcount == nargs && consistent === ALWAYS_TRUE && allconst
30433051
argvals = Vector{Any}(undef, nargs)
30443052
for j in 1:nargs
@@ -3054,24 +3062,26 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::Stateme
30543062
end
30553063
else
30563064
rt = refine_partial_type(rt)
3057-
nothrow = false
3065+
exct = generic_new_exct
30583066
end
30593067
else
30603068
consistent = ALWAYS_FALSE
3061-
nothrow = false
3069+
exct = generic_new_exct
30623070
end
3063-
nothrow && (exct = Union{})
3071+
exct = Union{exct, a1exct}
30643072
effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
30653073
return RTEffects(rt, exct, effects)
30663074
end
30673075

30683076
function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
30693077
sv::AbsIntState)
30703078
𝕃ᵢ = typeinf_lattice(interp)
3071-
rt, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
3079+
(a1, a1exct) = abstract_eval_value(interp, e.args[1], sstate, sv)
3080+
rt, isexact = instanceof_tfunc(a1, true)
30723081
nothrow = false
30733082
if length(e.args) == 2 && isconcretedispatch(rt) && !ismutabletype(rt)
3074-
at = abstract_eval_value(interp, e.args[2], sstate, sv)
3083+
(at, a2exct) = abstract_eval_value(interp, e.args[2], sstate, sv)
3084+
exct = Union{a1exct, a2exct}
30753085
n = fieldcount(rt)
30763086
if (isa(at, Const) && isa(at.val, Tuple) && n == length(at.val::Tuple) &&
30773087
(let t = rt, at = at
@@ -3087,12 +3097,14 @@ function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, sstate::St
30873097
nothrow = isexact
30883098
rt = PartialStruct(𝕃ᵢ, rt, at.fields::Vector{Any})
30893099
end
3100+
nothrow || (exct = Union{exct, generic_new_exct})
30903101
else
30913102
rt = refine_partial_type(rt)
3103+
exct = Any
30923104
end
30933105
consistent = !ismutabletype(rt) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
30943106
effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
3095-
return RTEffects(rt, Any, effects)
3107+
return RTEffects(rt, exct, effects)
30963108
end
30973109

30983110
function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
@@ -3107,6 +3119,7 @@ function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr,
31073119
rt = Bottom
31083120
effects = EFFECTS_THROWS
31093121
else
3122+
(argtypes, _) = argtypes
31103123
mi = frame_instance(sv)
31113124
rt = opaque_closure_tfunc(𝕃ᵢ, argtypes[1], argtypes[2], argtypes[3],
31123125
argtypes[5], argtypes[6:end], mi)
@@ -3134,7 +3147,7 @@ end
31343147
function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
31353148
sv::AbsIntState)
31363149
effects = EFFECTS_UNKNOWN
3137-
rt = abstract_eval_value(interp, e.args[1], sstate, sv)
3150+
(rt, _) = abstract_eval_value(interp, e.args[1], sstate, sv)
31383151
if rt isa Const && rt.val isa Expr
31393152
# `copyast` makes copies of Exprs
31403153
rt = Expr
@@ -3190,7 +3203,7 @@ function abstract_eval_isdefined(interp::AbstractInterpreter, @nospecialize(sym)
31903203
end
31913204

31923205
function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
3193-
condt = abstract_eval_value(interp, e.args[2], sstate, sv)
3206+
(condt, argexct) = abstract_eval_value(interp, e.args[2], sstate, sv)
31943207
condval = maybe_extract_const_bool(condt)
31953208
rt = Nothing
31963209
exct = UndefVarError
@@ -3205,7 +3218,7 @@ function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr,
32053218
elseif !hasintersect(widenconst(condt), Bool)
32063219
rt = Union{}
32073220
end
3208-
return RTEffects(rt, exct, effects)
3221+
return RTEffects(rt, Union{exct, argexct}, effects)
32093222
end
32103223

32113224
function abstract_eval_the_exception(::AbstractInterpreter, sv::InferenceState)
@@ -3275,8 +3288,8 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, ssta
32753288
# N.B.: abstract_eval_value_expr can modify the global effects, but
32763289
# we move out any arguments with effects during SSA construction later
32773290
# and recompute the effects.
3278-
rt = abstract_eval_value_expr(interp, e, sv)
3279-
return RTEffects(rt, Any, EFFECTS_TOTAL)
3291+
(rt, exct) = abstract_eval_value_expr(interp, e, sv)
3292+
return RTEffects(rt, exct, EFFECTS_TOTAL)
32803293
end
32813294

32823295
# refine the result of instantiation of partially-known type `t` if some invariant can be assumed
@@ -3296,12 +3309,14 @@ function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate:
32963309
mi = frame_instance(sv)
32973310
t = sp_type_rewrap(e.args[2], mi, true)
32983311
for i = 3:length(e.args)
3299-
if abstract_eval_value(interp, e.args[i], sstate, sv) === Bottom
3312+
(at, aexct) = abstract_eval_value(interp, e.args[i], sstate, sv)
3313+
if at === Bottom
33003314
return RTEffects(Bottom, Any, EFFECTS_THROWS)
33013315
end
33023316
end
33033317
effects = foreigncall_effects(e) do @nospecialize x
3304-
abstract_eval_value(interp, x, sstate, sv)
3318+
(at, aexct) = abstract_eval_value(interp, x, sstate, sv)
3319+
at
33053320
end
33063321
cconv = e.args[5]
33073322
if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt16}))
@@ -3367,6 +3382,10 @@ end
33673382

33683383
function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact}, retry_after_resolve::Bool=true)
33693384
worlds = world_range(src)
3385+
abstract_eval_globalref_type(g, worlds, retry_after_resolve)
3386+
end
3387+
3388+
function abstract_eval_globalref_type(g::GlobalRef, worlds::WorldRange, retry_after_resolve::Bool=true)
33703389
partition = lookup_binding_partition(min_world(worlds), g)
33713390
partition.max_world < max_world(worlds) && return Any
33723391
while is_some_imported(binding_kind(partition))
@@ -3380,7 +3399,7 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode,
33803399
# the binding unless necessary - doing so triggers an additional lookup, which though
33813400
# not super expensive is hot enough to show up in benchmarks.
33823401
force_binding_resolution!(g)
3383-
return abstract_eval_globalref_type(g, src, false)
3402+
return abstract_eval_globalref_type(g, worlds, false)
33843403
end
33853404
# return Union{}
33863405
return Any
@@ -3391,6 +3410,11 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode,
33913410
return partition_restriction(partition)
33923411
end
33933412

3413+
function is_global_nothrow_const_in_all_worlds(g::GlobalRef, worlds::WorldRange, retry_after_resolve::Bool=true)
3414+
# TODO: We may be fine if there's two different partitions with different constants
3415+
return isa(abstract_eval_globalref_type(g, worlds, retry_after_resolve), Const)
3416+
end
3417+
33943418
function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
33953419
force_binding_resolution!(g)
33963420
partition = lookup_binding_partition(get_inference_world(interp), g)
@@ -3821,7 +3845,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
38213845
elseif isa(stmt, GotoIfNot)
38223846
condx = stmt.cond
38233847
condslot = ssa_def_slot(condx, frame)
3824-
condt = abstract_eval_value(interp, condx, StatementState(currstate, currsaw_latestworld), frame)
3848+
condt, aexct = abstract_eval_value(interp, condx, StatementState(currstate, currsaw_latestworld), frame)
3849+
@assert aexct === Bottom # Guaranteed in lowering
38253850
if condt === Bottom
38263851
ssavaluetypes[currpc] = Bottom
38273852
empty!(frame.pclimitations)
@@ -3908,7 +3933,11 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
39083933
@goto fallthrough
39093934
end
39103935
elseif isa(stmt, ReturnNode)
3911-
rt = abstract_eval_value(interp, stmt.val, StatementState(currstate, currsaw_latestworld), frame)
3936+
rt, rexct = abstract_eval_value(interp, stmt.val, StatementState(currstate, currsaw_latestworld), frame)
3937+
if rexct !== Union{}
3938+
update_exc_bestguess!(interp, rexct, frame)
3939+
propagate_to_error_handler!(currstate, currsaw_latestworld, frame, 𝕃ᵢ)
3940+
end
39123941
if update_bestguess!(interp, frame, currstate, rt)
39133942
update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
39143943
# no reason to revisit if that call-site doesn't affect the final result
@@ -3921,7 +3950,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
39213950
ssavaluetypes[currpc] = Any
39223951
add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
39233952
if isdefined(stmt, :scope)
3924-
scopet = abstract_eval_value(interp, stmt.scope, StatementState(currstate, currsaw_latestworld), frame)
3953+
scopet, sexct = abstract_eval_value(interp, stmt.scope, StatementState(currstate, currsaw_latestworld), frame)
3954+
@assert sexct === Bottom # Guaranteed in lowering
39253955
handler = gethandler(frame, currpc + 1)::TryCatchFrame
39263956
@assert handler.scopet !== nothing
39273957
if !(𝕃ᵢ, scopet, handler.scopet)
@@ -4023,13 +4053,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
40234053
changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
40244054
end
40254055
end
4026-
if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
4027-
if exct !== Union{}
4028-
update_exc_bestguess!(interp, exct, frame)
4029-
# TODO: assert that these conditions match. For now, we assume the `nothrow` flag
4030-
# to be correct, but allow the exct to be an over-approximation.
4031-
end
4056+
if exct !== Union{}
4057+
update_exc_bestguess!(interp, exct, frame)
40324058
propagate_to_error_handler!(currstate, currsaw_latestworld, frame, 𝕃ᵢ)
4059+
# TODO: assert that these conditions match. For now, we assume the `nothrow` flag
4060+
# to be correct, but allow the exct to be an over-approximation.
4061+
else
4062+
has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
40334063
end
40344064
if rt === Bottom
40354065
ssavaluetypes[currpc] = Bottom

0 commit comments

Comments
 (0)