From 4f57e0a898cf0dd2c6848418209e775155361a9b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 18 Jan 2018 16:49:16 -0500 Subject: [PATCH] inference: fix stupdate for Conditional after slot re-assignment (#25602) We were neglecting to clear Conditional objects upon assignment to their attached slot (which invalidates their knowledge of the contents of that slot) fixes #25579 --- base/compiler/typelattice.jl | 63 +++++++++++++++++++++++++++++------- test/compiler/compiler.jl | 29 ++++++++++++++++- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index a16b0ea39cddd..f4e3fa962c142 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -28,11 +28,11 @@ end # end # ``` mutable struct Conditional - var::Union{Slot,SSAValue} + var::Slot vtype elsetype function Conditional( - @nospecialize(var), + var, @nospecialize(vtype), @nospecialize(nottype)) return new(var, vtype, nottype) @@ -215,27 +215,55 @@ end @inline tchanged(@nospecialize(n), @nospecialize(o)) = o === NOT_FOUND || (n !== NOT_FOUND && !(n ⊑ o)) @inline schanged(@nospecialize(n), @nospecialize(o)) = (n !== o) && (o === NOT_FOUND || (n !== NOT_FOUND && !issubstate(n, o))) +function widenconditional(typ::Conditional) + if typ.vtype == Union{} + return Const(false) + elseif typ.elsetype == Union{} + return Const(true) + else + return Bool + end +end + function stupdate!(state::Tuple{}, changes::StateUpdate) newst = copy(changes.state) if isa(changes.var, Slot) - newst[slot_id(changes.var::Slot)] = changes.vtype + changeid = slot_id(changes.var::Slot) + newst[changeid] = changes.vtype + # remove any Conditional for this Slot from the vtable + for i = 1:length(newst) + newtype = newst[i] + if isa(newtype, VarState) + newtypetyp = newtype.typ + if isa(newtypetyp, Conditional) && slot_id(newtypetyp.var) == changeid + newst[i] = VarState(widenconditional(newtypetyp), newtype.undef) + end + end + end end return newst end -function stupdate!(state::VarTable, change::StateUpdate) - if !isa(change.var, Slot) - return stupdate!(state, change.state) +function stupdate!(state::VarTable, changes::StateUpdate) + if !isa(changes.var, Slot) + return stupdate!(state, changes.state) end newstate = false - changeid = slot_id(change.var::Slot) + changeid = slot_id(changes.var::Slot) for i = 1:length(state) if i == changeid - newtype = change.vtype + newtype = changes.vtype else - newtype = change.state[i] + newtype = changes.state[i] end oldtype = state[i] + # remove any Conditional for this Slot from the vtable + if isa(newtype, VarState) + newtypetyp = newtype.typ + if isa(newtypetyp, Conditional) && slot_id(newtypetyp.var) == changeid + newtype = VarState(widenconditional(newtypetyp), newtype.undef) + end + end if schanged(newtype, oldtype) newstate = state state[i] = smerge(oldtype, newtype) @@ -265,11 +293,22 @@ function stupdate1!(state::VarTable, change::StateUpdate) if !isa(change.var, Slot) return false end - i = slot_id(change.var::Slot) + changeid = slot_id(change.var::Slot) + # remove any Conditional for this Slot from the catch block vtable + for i = 1:length(state) + oldtype = state[i] + if isa(oldtype, VarState) + oldtypetyp = oldtype.typ + if isa(oldtypetyp, Conditional) && slot_id(oldtypetyp.var) == changeid + state[i] = VarState(widenconditional(oldtypetyp), oldtype.undef) + end + end + end + # and update the type of it newtype = change.vtype - oldtype = state[i] + oldtype = state[changeid] if schanged(newtype, oldtype) - state[i] = smerge(oldtype, newtype) + state[changeid] = smerge(oldtype, newtype) return true end return false diff --git a/test/compiler/compiler.jl b/test/compiler/compiler.jl index 740493bedd93e..a47206059385a 100644 --- a/test/compiler/compiler.jl +++ b/test/compiler/compiler.jl @@ -1417,4 +1417,31 @@ for expr25261 in opt25261[i:end] @test expr25261.args[2].typ === Tuple{Int, Int} global foundslot = true end -@test foundslot \ No newline at end of file +@test foundslot + +function f25579(g) + h = g[] + t = (h === nothing) + h = 3.0 + return t ? typeof(h) : typeof(h) +end +@test @inferred f25579(Ref{Union{Nothing, Int}}(nothing)) == Float64 +@test @inferred f25579(Ref{Union{Nothing, Int}}(1)) == Float64 +function g25579(g) + h = g[] + h = (h === nothing) + return h ? typeof(h) : typeof(h) +end +@test @inferred g25579(Ref{Union{Nothing, Int}}(nothing)) == Bool +@test @inferred g25579(Ref{Union{Nothing, Int}}(1)) == Bool +function h25579(g) + h = g[] + t = (h === nothing) + try + h = -1.25 + error("continue at catch block") + end + return t ? typeof(h) : typeof(h) +end +@test Base.return_types(h25579, (Base.RefValue{Union{Nothing, Int}},)) == + Any[Union{Type{Float64}, Type{Int}, Type{Nothing}}]