Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[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`.
  • Loading branch information
staticfloat authored and aviatesk committed Feb 22, 2023
commit 1c22e77aba0c655f0d7c7661a508a31e5902e913
9 changes: 9 additions & 0 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2727,6 +2727,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
empty!(frame.pclimitations)
@goto find_next_bb
end
orig_condt = condt
if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condx, SlotNumber)
# if this non-`Conditional` object is a slot, we form and propagate
# the conditional constraint on it
Expand Down Expand Up @@ -2758,6 +2759,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
handle_control_backedge!(interp, frame, currpc, stmt.dest)
@goto branch
else
if !⊑(𝕃ᵢ, orig_condt, Bool)
merge_effects!(interp, frame, EFFECTS_THROWS)
if !hasintersect(widenconst(orig_condt), Bool)
ssavaluetypes[currpc] = Bottom
@goto find_next_bb
end
end

# We continue with the true branch, but process the false
# branch here.
if isa(condt, Conditional)
Expand Down
19 changes: 6 additions & 13 deletions test/compiler/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -696,16 +696,9 @@ end |> !Core.Compiler.is_consistent
@inbounds x[1]
end |> Core.Compiler.is_total

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