Skip to content

Commit

Permalink
add constant inference of isdefined
Browse files Browse the repository at this point in the history
  • Loading branch information
carnaval authored and JeffBezanson committed Jun 10, 2017
1 parent 0b2f6de commit 2d1d1ae
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 2 deletions.
44 changes: 42 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,47 @@ add_tfunc(===, 2, 2,
end
return Bool
end)
add_tfunc(isdefined, 1, 2, (args...)->Bool)
function isdefined_tfunc(args...)
arg1 = args[1]
if isa(arg1, Const)
a1 = typeof(arg1.val)
else
a1 = widenconst(arg1)
end
if isType(a1)
return Bool
end
a1 = unwrap_unionall(a1)
if isa(a1, DataType) && !a1.abstract
if a1 <: Array # TODO update when deprecation is removed
elseif a1 === Module
length(args) == 2 || return Bottom
sym = args[2]
Symbol <: widenconst(sym) || return Bottom
if isa(sym, Const) && isa(sym.val, Symbol) && isa(arg1, Const) && isdefined(arg1.val, sym.val)
return Const(true)
end
elseif length(args) == 2 && isa(args[2], Const)
val = args[2].val
idx::Int = 0
if isa(val, Symbol)
idx = fieldindex(a1, val, false)
elseif isa(val, Int)
idx = val
else
return Bottom
end
if 1 <= idx <= a1.ninitialized
return Const(true)
elseif idx <= 0 || (idx > nfields(a1) && !isvatuple(a1))
return Const(false)
end
end
end
Bool
end
# TODO change IInf to 2 when deprecation is removed
add_tfunc(isdefined, 1, IInf, isdefined_tfunc)
add_tfunc(Core.sizeof, 1, 1, x->Int)
add_tfunc(nfields, 1, 1,
function (x::ANY)
Expand Down Expand Up @@ -3419,7 +3459,7 @@ end
const _pure_builtins = Any[tuple, svec, fieldtype, apply_type, ===, isa, typeof, UnionAll, nfields]

# known effect-free calls (might not be affect-free)
const _pure_builtins_volatile = Any[getfield, arrayref]
const _pure_builtins_volatile = Any[getfield, arrayref, isdefined]

function is_pure_intrinsic(f::IntrinsicFunction)
return !(f === Intrinsics.pointerref || # this one is volatile
Expand Down
47 changes: 47 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -863,3 +863,50 @@ for i in 1:3
ir = sprint(io->code_llvm(io, f22290, Tuple{}))
@test contains(ir, "julia_f22290")
end

# constant inference of isdefined
let f(x) = isdefined(x, 2) ? 1 : ""
@test Base.return_types(f, (Tuple{Int,Int},)) == Any[Int]
@test Base.return_types(f, (Tuple{Int,},)) == Any[String]
end
let f(x) = isdefined(x, :re) ? 1 : ""
@test Base.return_types(f, (Complex64,)) == Any[Int]
@test Base.return_types(f, (Complex,)) == Any[Int]
end
let f(x) = isdefined(x, :NonExistentField) ? 1 : ""
@test Base.return_types(f, (Complex64,)) == Any[String]
@test Union{Int,String} <: Base.return_types(f, (AbstractArray,))[1]
end
import Core.Inference: Const, isdefined_tfunc,
@test isdefined_tfunc(Complex64, Const(())) === Union{}
@test isdefined_tfunc(Complex64, Const(1)) === Const(true)
@test isdefined_tfunc(Complex64, Const(2)) === Const(true)
@test isdefined_tfunc(Complex64, Const(3)) === Const(false)
@test isdefined_tfunc(Complex64, Const(0)) === Const(false)
mutable struct SometimesDefined
x
function SometimesDefined()
v = new()
if rand(Bool)
v.x = 0
end
return v
end
end
@test isdefined_tfunc(SometimesDefined, Const(:x)) == Bool
@test isdefined_tfunc(SometimesDefined, Const(:y)) === Const(false)
@test isdefined_tfunc(Const(Base), Const(:length)) === Const(true)
@test isdefined_tfunc(Const(Base), Symbol) == Bool
@test isdefined_tfunc(Const(Base), Const(:NotCurrentlyDefinedButWhoKnows)) == Bool
@test isdefined_tfunc(SimpleVector, Const(1)) === Const(true)
@test isdefined_tfunc(SimpleVector, Const(:length)) === Const(true)
@test Const(false) isdefined_tfunc(Const(:x), Symbol)
@test Const(false) isdefined_tfunc(Const(:x), Const(:y))
@test isdefined_tfunc(Vector{Int}, Const(1)) == Bool
@test isdefined_tfunc(Vector{Any}, Const(1)) == Bool
@test isdefined_tfunc(Module, Any, Any) === Union{}
@test isdefined_tfunc(Module, Int) === Union{}
@test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(0)) === Const(false)
@test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(1)) === Const(true)
@test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(2)) === Bool
@test isdefined_tfunc(Tuple{Any,Vararg{Any}}, Const(3)) === Bool

0 comments on commit 2d1d1ae

Please sign in to comment.