Skip to content

Commit 8dd0cf5

Browse files
committed
inference: refine exct information if :nothrow is proven
1 parent d85cb0e commit 8dd0cf5

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 5 additions & 4 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

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)