Skip to content

Commit 1c22e77

Browse files
staticfloataviatesk
authored andcommitted
[compiler] Teach type inference that GotoIfNot can throw (#48583)
Previously, the effects system would ignore certain cases where `GotoIfNot` nodes would be capable of throwing; this resulted in simple examples such as the following being marked as `nothrow`: ``` julia> foo(x) = x > 0 ? x : 0 Base.infer_effects(foo, (Missing,)) (+c,+e,+n,+t,+s,+m,+i) ``` With this change, we correctly notice when a `GotoIfNot` node is given a non-`Bool` condition, annotate the basic block as possibly throwing, and further end type inference if the condition is provably non-`Bool`.
1 parent 50b8c13 commit 1c22e77

File tree

2 files changed

+15
-13
lines changed

2 files changed

+15
-13
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,6 +2727,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27272727
empty!(frame.pclimitations)
27282728
@goto find_next_bb
27292729
end
2730+
orig_condt = condt
27302731
if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condx, SlotNumber)
27312732
# if this non-`Conditional` object is a slot, we form and propagate
27322733
# the conditional constraint on it
@@ -2758,6 +2759,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27582759
handle_control_backedge!(interp, frame, currpc, stmt.dest)
27592760
@goto branch
27602761
else
2762+
if !(𝕃ᵢ, orig_condt, Bool)
2763+
merge_effects!(interp, frame, EFFECTS_THROWS)
2764+
if !hasintersect(widenconst(orig_condt), Bool)
2765+
ssavaluetypes[currpc] = Bottom
2766+
@goto find_next_bb
2767+
end
2768+
end
2769+
27612770
# We continue with the true branch, but process the false
27622771
# branch here.
27632772
if isa(condt, Conditional)

test/compiler/effects.jl

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -696,16 +696,9 @@ end |> !Core.Compiler.is_consistent
696696
@inbounds x[1]
697697
end |> Core.Compiler.is_total
698698

699-
# unknown :static_parameter should taint :nothrow
700-
# https://github.com/JuliaLang/julia/issues/46771
701-
unknown_sparam_throw(::Union{Nothing, Type{T}}) where T = (T; nothing)
702-
unknown_sparam_nothrow1(x::Ref{T}) where T = (T; nothing)
703-
unknown_sparam_nothrow2(x::Ref{Ref{T}}) where T = (T; nothing)
704-
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type{Int},)))
705-
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type{<:Integer},)))
706-
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type,)))
707-
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Nothing,)))
708-
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Union{Type{Int},Nothing},)))
709-
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Any,)))
710-
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_nothrow1, (Ref,)))
711-
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_nothrow2, (Ref{Ref{T}} where T,)))
699+
# GotoIfNot should properly mark itself as throwing when given a non-Bool
700+
# https://github.com/JuliaLang/julia/pull/48583
701+
gotoifnot_throw_check_48583(x) = x ? x : 0
702+
@test !Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Missing,)))
703+
@test !Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Any,)))
704+
@test Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Bool,)))

0 commit comments

Comments
 (0)