Skip to content

Commit 84e80f4

Browse files
committed
eliminate Undef and Top types. fixes #8631
thanks to @vtjnash for the test case. It's hard to tell whether this is the real fix for the problem, but it works, and having a type that's not a subtype of Any around was just a huge pain. Things are simpler without it. Inside the compiler, undefinedness is no longer part of a variable's type. Instead there is a bit per variable telling whether it is ever used when undefined. This has the disadvantage of being coarser, since it doesn't give the undefinedness of each variable use. However it has the advantage of giving better type info: if a variable is either a Float64 or undefined, its type is just "Float64" and we can optimize accordingly. This combines well with the future optimization of storing possibly-undefined variables unboxed (#6914). For that we will add a run time 1-bit flag to track definedness, and then LLVM can hopefully eliminate checks along paths where the flag is known to be set, gaining back the previous granularity.
1 parent deada3e commit 84e80f4

15 files changed

+115
-145
lines changed

base/base.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ call{T}(::Type{Array{T}}, m::Integer, n::Integer, o::Integer) =
271271

272272
# TODO: possibly turn these into deprecations
273273
Array{T,N}(::Type{T}, d::NTuple{N,Int}) = Array{T}(d)
274-
Array(T::Type, d::Integer...) = Array{T}(convert((Int...), d))
274+
Array{T}(::Type{T}, d::Integer...) = Array{T}(convert((Int...), d))
275275
Array{T}(::Type{T}, m::Integer) = Array{T}(m)
276276
Array{T}(::Type{T}, m::Integer,n::Integer) = Array{T}(m,n)
277277
Array{T}(::Type{T}, m::Integer,n::Integer,o::Integer) = Array{T}(m,n,o)

base/boot.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ import Core.Intrinsics.ccall
117117

118118
export
119119
# key types
120-
Any, DataType, Vararg, ANY, NTuple, Top,
120+
Any, DataType, Vararg, ANY, NTuple,
121121
Tuple, Type, TypeConstructor, TypeName, TypeVar, Union, UnionType, Void,
122122
AbstractArray, DenseArray,
123123
# special objects

base/inference.jl

+65-62
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type StaticVarInfo
1515
vars::Array{Any,1} # names of args and locals
1616
gensym_types::Array{Any,1} # types of the GenSym's in this function
1717
label_counter::Int # index of the current highest label for this function
18+
fedbackvars::ObjectIdDict
1819
end
1920

2021
type EmptyCallStack
@@ -342,7 +343,7 @@ const getfield_tfunc = function (A, s0, name)
342343
return abstract_eval_constant(eval(A1,fld))
343344
end
344345
if s === Module
345-
return Top
346+
return Any
346347
end
347348
if isType(s0)
348349
sp = s0.parameters[1]
@@ -939,9 +940,6 @@ end
939940

940941
function abstract_eval_arg(a::ANY, vtypes::ANY, sv::StaticVarInfo)
941942
t = abstract_eval(a, vtypes, sv)
942-
if isa(a,Symbol) || isa(a,SymbolNode) || isa(a,GenSym)
943-
t = typeintersect(t,Any) # remove Undef
944-
end
945943
if isa(t,TypeVar) && t.lb == Bottom && isleaftype(t.ub)
946944
t = t.ub
947945
end
@@ -1018,19 +1016,18 @@ function abstract_eval(e::ANY, vtypes, sv::StaticVarInfo)
10181016
abstract_eval(e.args[1], vtypes, sv)
10191017
t = Any
10201018
elseif is(e.head,:static_typeof)
1021-
t0 = abstract_eval(e.args[1], vtypes, sv)
1022-
# intersect with Any to remove Undef
1023-
t = typeintersect(t0, Any)
1019+
var = e.args[1]
1020+
t = t0 = abstract_eval(var, vtypes, sv)
10241021
if isa(t,DataType) && typeseq(t,t.name.primary)
10251022
# remove unnecessary typevars
10261023
t = t.name.primary
10271024
end
1028-
if is(t,Bottom) && Undef<:t0
1029-
# the first time we see this statement the variable will probably
1030-
# be Undef; return Bottom so this doesn't contribute to the type
1031-
# we eventually pick.
1032-
elseif is(t,Bottom)
1033-
t = Type{Bottom}
1025+
if is(t,Bottom)
1026+
# if we haven't gotten fed-back type info yet, return Bottom. otherwise
1027+
# Bottom is the actual type of the variable, so return Type{Bottom}.
1028+
if haskey(sv.fedbackvars, var)
1029+
t = Type{Bottom}
1030+
end
10341031
elseif isleaftype(t)
10351032
t = Type{t}
10361033
elseif isleaftype(inference_stack.types)
@@ -1059,7 +1056,7 @@ function abstract_eval(e::ANY, vtypes, sv::StaticVarInfo)
10591056
else
10601057
t = Any
10611058
end
1062-
if isa(t,TypeVar) && t.lb === Bottom
1059+
if isa(t,TypeVar)
10631060
# no need to use a typevar as the type of an expression
10641061
t = t.ub
10651062
end
@@ -1082,30 +1079,20 @@ function abstract_eval_constant(x::ANY)
10821079
return typeof(x)
10831080
end
10841081

1085-
# Undef is the static type of a value location (e.g. variable) that is
1086-
# undefined. The corresponding run-time type is Bottom, since accessing an
1087-
# undefined location is an error. A non-lvalue expression cannot have
1088-
# type Undef, only Bottom.
1089-
# typealias Top Union(Any,Undef)
1090-
10911082
abstract_eval_global(s::Symbol) =
10921083
abstract_eval_global((inference_stack::CallStack).mod, s)
10931084

10941085
function abstract_eval_global(M, s::Symbol)
10951086
if isconst(M,s)
10961087
return abstract_eval_constant(eval(M,s))
10971088
end
1098-
if !isdefined(M,s)
1099-
return Top
1100-
end
1101-
# TODO: change to Undef if there's a way to clear variables
11021089
return Any
11031090
end
11041091

11051092
function abstract_eval_gensym(s::GenSym, sv::StaticVarInfo)
11061093
typ = sv.gensym_types[s.id+1]
11071094
if typ === NF
1108-
return Undef
1095+
return Bottom
11091096
end
11101097
return typ
11111098
end
@@ -1137,7 +1124,7 @@ function abstract_eval_symbol(s::Symbol, vtypes::ObjectIdDict, sv::StaticVarInfo
11371124
end
11381125
if s in sv.vars
11391126
# local variable use not reached
1140-
return Top
1127+
return Bottom
11411128
end
11421129
# global
11431130
return abstract_eval_global(s)
@@ -1208,18 +1195,10 @@ function type_too_complex(t::ANY, d)
12081195
end
12091196

12101197
function tmerge(typea::ANY, typeb::ANY)
1211-
if is(typea,NF)
1212-
return typeb
1213-
end
1214-
if is(typeb,NF)
1215-
return typea
1216-
end
1217-
if typea <: typeb
1218-
return typeb
1219-
end
1220-
if typeb <: typea
1221-
return typea
1222-
end
1198+
is(typea, NF ) && return typeb
1199+
is(typeb, NF) && return typea
1200+
typea <: typeb && return typeb
1201+
typeb <: typea && return typea
12231202
if isa(typea, Tuple) && isa(typeb, Tuple)
12241203
if length(typea) == length(typeb) && !isvatuple(typea) && !isvatuple(typeb)
12251204
return typejoin(typea, typeb)
@@ -1230,7 +1209,7 @@ function tmerge(typea::ANY, typeb::ANY)
12301209
if length(u.types) > MAX_TYPEUNION_LEN || type_too_complex(u, 0)
12311210
# don't let type unions get too big
12321211
# TODO: something smarter, like a common supertype
1233-
return Undef<:u ? Top : Any
1212+
return Any
12341213
end
12351214
return u
12361215
end
@@ -1252,13 +1231,19 @@ function stupdate(state::ObjectIdDict, changes::Union(StateUpdate,VarTable), var
12521231
state
12531232
end
12541233

1255-
function stchanged(new::Union(StateUpdate,VarTable), old, vars)
1234+
function stchanged(new::Union(StateUpdate,VarTable), old, vinflist)
12561235
if is(old,())
12571236
return true
12581237
end
1259-
for i = 1:length(vars)
1260-
v = vars[i]
1261-
if tchanged(new[v], get(old,v,NF))
1238+
for vi in vinflist
1239+
v = vi[1]
1240+
newtype = new[v]
1241+
oldtype = get(old,v,NF)
1242+
if (newtype === Bottom && oldtype !== NF && oldtype !== Bottom) ||
1243+
(oldtype === Bottom && newtype !== NF && newtype !== Bottom)
1244+
vi[3] |= 32
1245+
end
1246+
if tchanged(newtype, oldtype)
12621247
return true
12631248
end
12641249
end
@@ -1457,7 +1442,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
14571442
# initial types
14581443
s[1] = ObjectIdDict()
14591444
for v in vars
1460-
s[1][v] = Undef
1445+
s[1][v] = Bottom
14611446
end
14621447
if la > 0
14631448
lastarg = ast.args[1][la]
@@ -1507,7 +1492,8 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
15071492
cenv[vname] = vtype
15081493
s[1][vname] = vtype
15091494
end
1510-
for vi = ((ast.args[2][2])::Array{Any,1})
1495+
vinflist = ast.args[2][2]::Array{Any,1}
1496+
for vi in vinflist
15111497
vi::Array{Any,1}
15121498
if (vi[3]&4)!=0
15131499
# variables assigned by inner functions are treated like
@@ -1523,7 +1509,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
15231509
gensym_init = Any[ NF for i = 1:length(gensym_uses) ]
15241510
gensym_types = copy(gensym_init)
15251511

1526-
sv = StaticVarInfo(sparams, cenv, vars, gensym_types, length(labels))
1512+
sv = StaticVarInfo(sparams, cenv, vars, gensym_types, length(labels), ObjectIdDict())
15271513
frame.sv = sv
15281514

15291515
recpts = IntSet() # statements that depend recursively on our value
@@ -1565,7 +1551,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
15651551
if !is(cur_hand,())
15661552
# propagate type info to exception handler
15671553
l = cur_hand[1]::Int
1568-
if stchanged(changes, s[l], vars)
1554+
if stchanged(changes, s[l], vinflist)
15691555
push!(W, l)
15701556
s[l] = stupdate(s[l], changes, vars)
15711557
end
@@ -1598,7 +1584,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
15981584
else
15991585
# general case
16001586
handler_at[l] = cur_hand
1601-
if stchanged(changes, s[l], vars)
1587+
if stchanged(changes, s[l], vinflist)
16021588
push!(W, l)
16031589
s[l] = stupdate(s[l], changes, vars)
16041590
end
@@ -1619,6 +1605,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
16191605
gensym_init[id] = vt
16201606
typegotoredo = true
16211607
end
1608+
sv.fedbackvars[var] = true
16221609
end
16231610
elseif is(hd,:return)
16241611
pc´ = n+1
@@ -1663,7 +1650,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
16631650
end
16641651
end
16651652
if pc´<=n && (handler_at[pc´] = cur_hand; true) &&
1666-
stchanged(changes, s[pc´], vars)
1653+
stchanged(changes, s[pc´], vinflist)
16671654
s[pc´] = stupdate(s[pc´], changes, vars)
16681655
pc = pc´
16691656
elseif pc´ in W
@@ -1752,7 +1739,7 @@ function record_var_type(e::Symbol, t::ANY, decls)
17521739
end
17531740
end
17541741

1755-
function eval_annotate(e::ANY, vtypes::ANY, sv::StaticVarInfo, decls, clo)
1742+
function eval_annotate(e::ANY, vtypes::ANY, sv::StaticVarInfo, decls, clo, undefs)
17561743
if isa(e, Symbol)
17571744
e = e::Symbol
17581745

@@ -1761,13 +1748,19 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::StaticVarInfo, decls, clo)
17611748
return e
17621749
end
17631750
t = abstract_eval(e, vtypes, sv)
1751+
if t === Bottom
1752+
undefs[e] = true
1753+
end
17641754
record_var_type(e, t, decls)
17651755
return (is(t,Any) || is(t,IntrinsicFunction)) ? e : SymbolNode(e, t)
17661756
end
17671757

17681758
if isa(e, SymbolNode)
17691759
e = e::SymbolNode
17701760
curtype = e.typ
1761+
if curtype === Bottom
1762+
undefs[e.name] = true
1763+
end
17711764
t = abstract_eval(e.name, vtypes, sv)
17721765
if !(curtype <: t) || typeseq(curtype, t)
17731766
record_var_type(e.name, t, decls)
@@ -1800,7 +1793,7 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::StaticVarInfo, decls, clo)
18001793
# we don't use types on assignment LHS
18011794
s = s.name
18021795
end
1803-
e.args[2] = eval_annotate(e.args[2], vtypes, sv, decls, clo)
1796+
e.args[2] = eval_annotate(e.args[2], vtypes, sv, decls, clo, undefs)
18041797
if isa(s,Symbol)
18051798
# TODO: if this def does not reach any uses, maybe don't do this
18061799
rhstype = exprtype(e.args[2], sv)
@@ -1814,7 +1807,7 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::StaticVarInfo, decls, clo)
18141807
for i=i0:length(e.args)
18151808
subex = e.args[i]
18161809
if !(isa(subex,Number) || isa(subex,AbstractString))
1817-
e.args[i] = eval_annotate(subex, vtypes, sv, decls, clo)
1810+
e.args[i] = eval_annotate(subex, vtypes, sv, decls, clo, undefs)
18181811
end
18191812
end
18201813
if (head === :call || head === :call1) && isa(e.args[1],LambdaStaticData)
@@ -1832,6 +1825,7 @@ end
18321825
function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY,
18331826
args)
18341827
decls = ObjectIdDict()
1828+
undefs = ObjectIdDict()
18351829
# initialize decls with argument types
18361830
for arg in args
18371831
decls[arg] = states[1][arg]
@@ -1842,7 +1836,7 @@ function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY,
18421836
st_i = states[i]
18431837
if st_i !== ()
18441838
# st_i === () => unreached statement (see issue #7836)
1845-
body[i] = eval_annotate(body[i], st_i, sv, decls, closures)
1839+
body[i] = eval_annotate(body[i], st_i, sv, decls, closures, undefs)
18461840
end
18471841
end
18481842
ast.args[3].typ = rettype
@@ -1852,11 +1846,17 @@ function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY,
18521846
if (vi[3]&4)==0
18531847
vi[2] = get(decls, vi[1], vi[2])
18541848
end
1849+
if haskey(undefs, vi[1])
1850+
vi[3] |= 32
1851+
end
18551852
end
18561853
for vi in ast.args[2][3]::Array{Any,1}
18571854
if (vi[3]&4)==0
18581855
vi[2] = get(decls, vi[1], vi[2])
18591856
end
1857+
if haskey(undefs, vi[1])
1858+
vi[3] |= 32
1859+
end
18601860
end
18611861
ast.args[2][4] = sv.gensym_types
18621862

@@ -2350,7 +2350,6 @@ function inlineable(f::ANY, e::Expr, atypes::Tuple, sv::StaticVarInfo, enclosing
23502350
for i = 1:numarg
23512351
name = newnames[i]
23522352
argtype = exprtype(argexprs[i],sv)
2353-
argtype = typeintersect(argtype,Any) # remove Undef
23542353
push!(locals, Any[name,argtype,0])
23552354
push!(newcall.args, argtype===Any ? name : SymbolNode(name, argtype))
23562355
end
@@ -3044,7 +3043,7 @@ function remove_redundant_temp_vars(ast, sa)
30443043
# this transformation is not valid for vars used before def.
30453044
# we need to preserve the point of assignment to know where to
30463045
# throw errors (issue #4645).
3047-
if !occurs_undef(v, ast.args[3])
3046+
if !occurs_undef(v, ast.args[3], varinfo)
30483047

30493048
# the transformation is not ideal if the assignment
30503049
# is present for the auto-unbox functionality
@@ -3063,18 +3062,22 @@ end
30633062

30643063
function local_typeof(v, varinfo)
30653064
for (v2, typ, info) in varinfo
3066-
if v === v2
3067-
return typ
3068-
end
3065+
v === v2 && return typ
3066+
end
3067+
@assert false "v not in varinfo"
3068+
end
3069+
function var_infobits(v, varinfo)
3070+
for (v2, typ, info) in varinfo
3071+
v === v2 && return info
30693072
end
30703073
@assert false "v not in varinfo"
30713074
end
30723075

3073-
occurs_undef(var::GenSym, expr) = false
3076+
occurs_undef(var::GenSym, expr, varinfo) = false
30743077

3075-
occurs_undef(var, expr) =
3076-
occurs_more(expr,
3077-
e->(isa(e,SymbolNode) && symequal(var,e) && issubtype(Undef,e.typ)), 0)>0
3078+
occurs_undef(var, expr, varinfo) =
3079+
occurs_more(expr, e->(isa(e,SymbolNode) && symequal(var,e) &&
3080+
((var_infobits(e.name,varinfo)&32)!=0)), 0)>0
30783081

30793082
# compute set of vars assigned once
30803083
function find_sa_vars(ast)

base/serialize.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ let i = 2
2222
UTF16String, UTF32String, Float16,
2323
:reserved9, :reserved10, :reserved11, :reserved12,
2424

25-
(), Bool, Any, :Any, Bottom, Top, Undef, Type,
25+
(), Bool, Any, :Any, Bottom, :reserved21, :reserved22, Type,
2626
:Array, :TypeVar, :Box,
2727
:lambda, :body, :return, :call, symbol("::"),
2828
:(=), :null, :gotoifnot, :A, :B, :C, :M, :N, :T, :S, :X, :Y,

base/show.jl

+1-7
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,7 @@ function show(io::IO, x::IntrinsicFunction)
6666
print(io, "(intrinsic function #", box(Int32,unbox(IntrinsicFunction,x)), ")")
6767
end
6868

69-
function show(io::IO, x::UnionType)
70-
if is(x,Top)
71-
print(io, "Top")
72-
else
73-
print(io, "Union", x.types)
74-
end
75-
end
69+
show(io::IO, x::UnionType) = print(io, "Union", x.types)
7670

7771
show(io::IO, x::TypeConstructor) = show(io, x.body)
7872

0 commit comments

Comments
 (0)