Skip to content

Commit 0402c78

Browse files
authored
inference: followups for #51754 (#52241)
Composed of: - typeinf_local: factor into `update_cycle_worklists!` utility (78f7b4e) - inference: fix exception type of `typename` call (fac36d8) - add missing type annotations (7ce140e) - inference: refine exct information if `:nothrow` is proven (76143d3) - ~~improve exception type inference for core math functions (525bd6c)~~ Separated into another PR
2 parents 527af66 + 8dd0cf5 commit 0402c78

File tree

4 files changed

+64
-21
lines changed

4 files changed

+64
-21
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,13 +1196,14 @@ function semi_concrete_eval_call(interp::AbstractInterpreter,
11961196
# state = InliningState(interp)
11971197
# ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
11981198
effects = result.effects
1199-
if !is_nothrow(effects)
1200-
effects = Effects(effects; nothrow)
1199+
if nothrow
1200+
effects = Effects(effects; nothrow=true)
12011201
end
12021202
if noub
1203-
effects = Effects(effects; noub = ALWAYS_TRUE)
1203+
effects = Effects(effects; noub=ALWAYS_TRUE)
12041204
end
1205-
return ConstCallResults(rt, result.exct, SemiConcreteResult(mi, ir, effects), effects, mi)
1205+
exct = refine_exception_type(result.exct, effects)
1206+
return ConstCallResults(rt, exct, SemiConcreteResult(mi, ir, effects), effects, mi)
12061207
end
12071208
end
12081209
end
@@ -2136,7 +2137,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
21362137
argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
21372138
return abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods)
21382139
elseif la == 2 && istopfunction(f, :typename)
2139-
return CallMeta(typename_static(argtypes[2]), Any, EFFECTS_TOTAL, MethodResultPure())
2140+
return CallMeta(typename_static(argtypes[2]), Bottom, EFFECTS_TOTAL, MethodResultPure())
21402141
elseif f === Core._hasmethod
21412142
return _hasmethod_tfunc(interp, argtypes, sv)
21422143
end
@@ -3086,6 +3087,14 @@ function propagate_to_error_handler!(frame::InferenceState, currpc::Int, W::BitS
30863087
end
30873088
end
30883089

3090+
function update_cycle_worklists!(callback, frame::InferenceState)
3091+
for (caller, caller_pc) in frame.cycle_backedges
3092+
if callback(caller, caller_pc)
3093+
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
3094+
end
3095+
end
3096+
end
3097+
30893098
# make as much progress on `frame` as possible (without handling cycles)
30903099
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
30913100
@assert !is_inferred(frame)
@@ -3204,11 +3213,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
32043213
elseif isa(stmt, ReturnNode)
32053214
rt = abstract_eval_value(interp, stmt.val, currstate, frame)
32063215
if update_bestguess!(interp, frame, currstate, rt)
3207-
for (caller, caller_pc) in frame.cycle_backedges
3208-
if caller.ssavaluetypes[caller_pc] !== Any
3209-
# no reason to revisit if that call-site doesn't affect the final result
3210-
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
3211-
end
3216+
update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
3217+
# no reason to revisit if that call-site doesn't affect the final result
3218+
return caller.ssavaluetypes[caller_pc] !== Any
32123219
end
32133220
end
32143221
ssavaluetypes[frame.currpc] = Any
@@ -3231,11 +3238,11 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
32313238
if cur_hand == 0
32323239
if !(𝕃ₚ, exct, frame.exc_bestguess)
32333240
frame.exc_bestguess = tmerge(𝕃ₚ, frame.exc_bestguess, exct)
3234-
for (caller, caller_pc) in frame.cycle_backedges
3235-
handler = caller.handler_at[caller_pc][1]
3236-
if (handler == 0 ? caller.exc_bestguess : caller.handlers[handler].exct) !== Any
3237-
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
3238-
end
3241+
update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
3242+
caller_handler = caller.handler_at[caller_pc][1]
3243+
caller_exct = caller_handler == 0 ?
3244+
caller.exc_bestguess : caller.handlers[caller_handler].exct
3245+
return caller_exct !== Any
32393246
end
32403247
end
32413248
else

base/compiler/ssair/irinterp.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, irsv::IRIn
5151
return RTEffects(rt, exct, effects)
5252
end
5353

54-
function kill_block!(ir, bb)
54+
function kill_block!(ir::IRCode, bb::Int)
5555
# Kill the entire block
5656
stmts = ir.cfg.blocks[bb].stmts
5757
for bidx = stmts
@@ -64,7 +64,6 @@ function kill_block!(ir, bb)
6464
return
6565
end
6666

67-
6867
function update_phi!(irsv::IRInterpretationState, from::Int, to::Int)
6968
ir = irsv.ir
7069
if length(ir.cfg.blocks[to].preds) == 0

base/compiler/typeinfer.jl

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,11 @@ function adjust_effects(sv::InferenceState)
503503
return ipo_effects
504504
end
505505

506+
function refine_exception_type(@nospecialize(exc_bestguess), ipo_effects::Effects)
507+
ipo_effects.nothrow && return Bottom
508+
return exc_bestguess
509+
end
510+
506511
# inference completed on `me`
507512
# update the MethodInstance
508513
function finish(me::InferenceState, interp::AbstractInterpreter)
@@ -539,8 +544,8 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
539544
end
540545
me.result.valid_worlds = me.valid_worlds
541546
me.result.result = bestguess
542-
me.result.ipo_effects = me.ipo_effects = adjust_effects(me)
543-
me.result.exc_result = exc_bestguess
547+
ipo_effects = me.result.ipo_effects = me.ipo_effects = adjust_effects(me)
548+
me.result.exc_result = me.exc_bestguess = refine_exception_type(me.exc_bestguess, ipo_effects)
544549

545550
if limited_ret
546551
# a parent may be cached still, but not this intermediate work:
@@ -862,20 +867,23 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
862867
isinferred = is_inferred(frame)
863868
edge = isinferred ? mi : nothing
864869
effects = isinferred ? frame.result.ipo_effects : adjust_effects(Effects(), method) # effects are adjusted already within `finish` for ipo_effects
870+
exc_bestguess = refine_exception_type(frame.exc_bestguess, effects)
865871
# propagate newly inferred source to the inliner, allowing efficient inlining w/o deserialization:
866872
# note that this result is cached globally exclusively, we can use this local result destructively
867873
volatile_inf_result = isinferred && let inferred_src = result.src
868874
isa(inferred_src, CodeInfo) && (is_inlineable(inferred_src) || force_inline)
869875
end ? VolatileInferenceResult(result) : nothing
870-
return EdgeCallResult(frame.bestguess, frame.exc_bestguess, edge, effects, volatile_inf_result)
876+
return EdgeCallResult(frame.bestguess, exc_bestguess, edge, effects, volatile_inf_result)
871877
elseif frame === true
872878
# unresolvable cycle
873879
return EdgeCallResult(Any, Any, nothing, Effects())
874880
end
875881
# return the current knowledge about this cycle
876882
frame = frame::InferenceState
877883
update_valid_age!(caller, frame.valid_worlds)
878-
return EdgeCallResult(frame.bestguess, frame.exc_bestguess, nothing, adjust_effects(Effects(), method))
884+
effects = adjust_effects(Effects(), method)
885+
exc_bestguess = refine_exception_type(frame.exc_bestguess, effects)
886+
return EdgeCallResult(frame.bestguess, exc_bestguess, nothing, effects)
879887
end
880888

881889
function cached_return_type(code::CodeInstance)

test/compiler/inference.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5558,3 +5558,32 @@ function foo_typed_throw_metherr()
55585558
return 1
55595559
end
55605560
@test Base.return_types(foo_typed_throw_metherr) |> only === Float64
5561+
5562+
# using `exct` information if `:nothrow` is proven
5563+
Base.@assume_effects :nothrow function sin_nothrow(x::Float64)
5564+
x == Inf && return zero(x)
5565+
return sin(x)
5566+
end
5567+
@test Base.infer_exception_type(sin_nothrow, (Float64,)) == Union{}
5568+
@test Base.return_types((Float64,)) do x
5569+
try
5570+
return sin_nothrow(x)
5571+
catch err
5572+
return err
5573+
end
5574+
end |> only === Float64
5575+
# for semi-concrete interpretation result too
5576+
Base.@constprop :aggressive function sin_maythrow(x::Float64, maythrow::Bool)
5577+
if maythrow
5578+
return sin(x)
5579+
else
5580+
return @noinline sin_nothrow(x)
5581+
end
5582+
end
5583+
@test Base.return_types((Float64,)) do x
5584+
try
5585+
return sin_maythrow(x, false)
5586+
catch err
5587+
return err
5588+
end
5589+
end |> only === Float64

0 commit comments

Comments
 (0)