Skip to content

Commit

Permalink
inference: fix stupdate for Conditional after slot re-assignment (#25602
Browse files Browse the repository at this point in the history
)

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
  • Loading branch information
vtjnash authored Jan 18, 2018
1 parent 7deac81 commit 4f57e0a
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 13 deletions.
63 changes: 51 additions & 12 deletions base/compiler/typelattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
29 changes: 28 additions & 1 deletion test/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1417,4 +1417,31 @@ for expr25261 in opt25261[i:end]
@test expr25261.args[2].typ === Tuple{Int, Int}
global foundslot = true
end
@test foundslot
@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}}]

0 comments on commit 4f57e0a

Please sign in to comment.