Skip to content

Commit

Permalink
better updates for jb/subtype
Browse files Browse the repository at this point in the history
this uses a unique syntax for 'where' so that parsing it is backwards compatible
with v0.5, and also passes the tests
  • Loading branch information
vtjnash committed Jan 5, 2017
1 parent 7ef6040 commit 94af823
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 48 deletions.
113 changes: 79 additions & 34 deletions src/JLD.jl
Original file line number Diff line number Diff line change
Expand Up @@ -873,12 +873,55 @@ writeas(gr::GlobalRef) = GlobalRefSerializer(gr)

### Converting attribute strings to Julia types

const _where_macrocall = Symbol("@where")
function expand_where_macro(e::Expr)
if TYPESYSTEM_06
e.head = :where
shift!(e.args)
else
e.head = :let
tv = e.args[2]
if isa(tv, Symbol)
sym = tv
tv = :(TypeVar($sym))
elseif isa(tv, Expr)
if tv.head === :comparison
lb = tv.args[1]
sym = tv.args[3]
ub = tv.args[5]
tv = :(TypeVar($sym, $lb, $ub))
elseif tv.head === :(<:)
sym = tv.args[1]
ub = tv.args[2]
tv = :(TypeVar($sym, $ub))
else
return false
end
else
return false
end
e.args[2] = Expr(:(=), sym, tv)
end
return true
end

is_valid_type_ex(s::Symbol) = true
is_valid_type_ex(s::QuoteNode) = true
is_valid_type_ex{T}(::T) = isbits(T)
is_valid_type_ex(e::Expr) = (((e.head == :curly || e.head == :tuple || e.head == :.) && all(is_valid_type_ex, e.args)) ||
(e.head == :where && is_valid_type_ex(e.args[1])) ||
(e.head == :call && (e.args[1] == :Union || e.args[1] == :TypeVar || e.args[1] == :symbol)))
function is_valid_type_ex(e::Expr)
if e.head === :curly || e.head == :tuple || e.head == :.
return all(is_valid_type_ex, e.args)
elseif e.head === :where
return is_valid_type_ex(e.args[1])
elseif e.head === :let && length(e.args) == 2
return is_valid_type_ex(e.args[1]) &&
is_valid_type_ex(e.args[2].args[2])
elseif e.head == :call
f = e.args[1]
return f === :Union || f === :TypeVar || f === :symbol
end
return false
end

const typemap_Core = Dict(
:Uint8 => :UInt8,
Expand All @@ -891,45 +934,44 @@ const typemap_Core = Dict(
const _typedict = Dict{Compat.UTF8String,Type}()

fixtypes(typ) = typ
@eval begin
function fixtypes(typ::Expr)
if typ.head == :.
if length(typ.args) == 2 && typ.args[1] == :Core
arg = typ.args[2].value
return Expr(:., :Core, QuoteNode(get(typemap_Core, arg, arg)))
else
return typ
end
elseif typ == :(Core.Type{TypeVar(:T,Union(Core.Any,Core.Undef))}) || typ == :(Core.Type{TypeVar(:T)})
# Work around https://github.com/JuliaLang/julia/issues/8226 and the removal of Top
return :(Core.Type)
function fixtypes(typ::Expr)
if typ.head === :macrocall && typ.args[1] === _where_macrocall
expand_where_macro(typ)
end
if typ.head === :.
if length(typ.args) == 2 && typ.args[1] === :Core
arg = typ.args[2].value
return Expr(:., :Core, QuoteNode(get(typemap_Core, arg, arg)))
else
return typ
end
elseif typ == :(Core.Type{TypeVar(:T,Union(Core.Any,Core.Undef))}) || typ == :(Core.Type{TypeVar(:T)})
# Work around https://github.com/JuliaLang/julia/issues/8226 and the removal of Top
return :(Core.Type)
end

for i = 1:length(typ.args)
typ.args[i] = fixtypes(typ.args[i])
end
for i = 1:length(typ.args)
typ.args[i] = fixtypes(typ.args[i])
end

if (typ.head == :call && !isempty(typ.args) &&
typ.args[1] == :Union)
return Expr(:curly, typ.args...)
end
if (typ.head === :call && !isempty(typ.args) &&
typ.args[1] === :Union)
return Expr(:curly, typ.args...)
end

if typ.head == :tuple
return Expr(:curly, :Tuple, typ.args...)
end
typ
if typ.head === :tuple
return Expr(:curly, :Tuple, typ.args...)
end
return typ
end

function _julia_type(s::AbstractString)
typ = get(_typedict, s, UnconvertedType)
if typ == UnconvertedType
local sp
try
sp = parse(s)
catch err
sp = parse(s, raise=false)
if (isa(sp, Expr) && (sp.head == :error || sp.head == :continue || sp.head == :incomplete))
println("error parsing type string ", s)
rethrow(err)
eval(sp)
end
typ = julia_type(fixtypes(sp))
if typ != UnsupportedType
Expand Down Expand Up @@ -975,12 +1017,14 @@ function full_typename(io::IO, file::JldFile, x::Core.BottomType)
print(io, "Union()")
end
function full_typename(io::IO, file::JldFile, x::UnionAll)
x == Type && return print(io, "Type")
print(io, "@where(")
full_typename(io, file, x.body)
print(io, " where ")
print(io, ',')
tv = x.var
if is(tv.lb, Union{}) && is(tv.ub, Any)
if tv.lb === Union{} && tv.ub === Any
print(io, tv.name)
elseif is(tv.lb, Union{})
elseif tv.lb === Union{}
print(io, tv.name)
print(io, "<:")
full_typename(io, file, tv.ub)
Expand All @@ -991,6 +1035,7 @@ function full_typename(io::IO, file::JldFile, x::UnionAll)
print(io, "<:")
full_typename(io, file, tv.ub)
end
print(io, ')')
end
function full_typename(io::IO, file::JldFile, tv::TypeVar)
print(io, tv.name)
Expand Down
34 changes: 20 additions & 14 deletions test/jldtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ end
objwithpointer = ObjWithPointer(0)
# Custom BitsType (#99)
bitstype 64 MyBT
bt = reinterpret(MyBT, @compat Int64(55))
bt = reinterpret(MyBT, Int64(55))
# Symbol arrays (#100)
sa_asc = [:a, :b]
sa_utf8 = [, ]
# SubArray (to test tuple type params)
subarray = view([1:5;], 1:5)
# Array of empty tuples (to test tuple type params)
arr_empty_tuple = (@compat Tuple{})[]
arr_empty_tuple = (Tuple{})[]
immutable EmptyImmutable end
emptyimmutable = EmptyImmutable()
arr_emptyimmutable = [emptyimmutable]
Expand Down Expand Up @@ -155,17 +155,23 @@ immutable Vague
end
vague = Vague(7)
# Immutable with a union of BitsTypes
@compat immutable BitsUnion
immutable BitsUnion
x::Union{Int64, Float64}
end
bitsunion = BitsUnion(5.0)
# Immutable with a union of Types
@compat immutable TypeUnionField
x::Union{Type{Int64}, Type{Float64}}
let UT = if JLD.TYPESYSTEM_06
eval(parse("Type{T} where T <: Union{Int64, Float64}"))
else
Union{Type{Int64}, Type{Float64}}
end
@eval immutable TypeUnionField
x::$UT
end
end
typeunionfield = TypeUnionField(Int64)
# Generic union type field
@compat immutable GenericUnionField
immutable GenericUnionField
x::Union{Vector{Int},Int}
end
genericunionfield = GenericUnionField(1)
Expand Down Expand Up @@ -199,11 +205,11 @@ bigdata = [1:10000;]
bigints = big(3).^(1:100)
bigfloats = big(3.2).^(1:100)
# None
@compat none = Union{}
@compat nonearr = Array(Union{}, 5)
none = Union{}
nonearr = Array(Union{}, 5)
# nothing/Void
scalar_nothing = nothing
@compat vector_nothing = Union{Int,Void}[1,nothing]
vector_nothing = Union{Int,Void}[1,nothing]

# some data big enough to ensure that compression is used:
Abig = kron(eye(10), rand(20,20))
Expand All @@ -217,7 +223,7 @@ bitsparambool = BitsParams{true}()
bitsparamsymbol = BitsParams{:x}()
bitsparamint = BitsParams{1}()
bitsparamuint = BitsParams{0x01}()
bitsparamint16 = BitsParams{@compat Int16(1)}()
bitsparamint16 = BitsParams{Int16(1)}()

# Tuple of tuples
tuple_of_tuples = (1, 2, (3, 4, [5, 6]), [7, 8])
Expand All @@ -237,7 +243,7 @@ natyperef = Any[NALikeType(), NALikeType()]
iseq(x,y) = isequal(x,y)
iseq(x::MyStruct, y::MyStruct) = (x.len == y.len && x.data == y.data)
iseq(x::MyImmutable, y::MyImmutable) = (isequal(x.x, y.x) && isequal(x.y, y.y) && isequal(x.z, y.z))
@compat iseq(x::Union{EmptyTI, EmptyTT}, y::Union{EmptyTI, EmptyTT}) = isequal(x.x, y.x)
iseq(x::Union{EmptyTI, EmptyTT}, y::Union{EmptyTI, EmptyTT}) = isequal(x.x, y.x)
iseq(c1::Array{Base.Sys.CPUinfo}, c2::Array{Base.Sys.CPUinfo}) = length(c1) == length(c2) && all([iseq(c1[i], c2[i]) for i = 1:length(c1)])
function iseq(c1::Base.Sys.CPUinfo, c2::Base.Sys.CPUinfo)
for n in fieldnames(Base.Sys.CPUinfo)
Expand All @@ -248,7 +254,7 @@ function iseq(c1::Base.Sys.CPUinfo, c2::Base.Sys.CPUinfo)
true
end
iseq(x::MyUnicodeStruct☺, y::MyUnicodeStruct☺) = (x.α == y.α && x.∂ₓα == y.∂ₓα)
@compat iseq(x::Array{Union{}}, y::Array{Union{}}) = size(x) == size(y)
iseq(x::Array{Union{}}, y::Array{Union{}}) = size(x) == size(y)
macro check(fid, sym)
ex = quote
let tmp
Expand Down Expand Up @@ -712,9 +718,9 @@ for compatible in (false, true), compress in (false, true)
end

# Issue #106
save(fn, "i106", Mod106.typ(@compat(Int64(1)), Mod106.UnexportedT), compress=compress)
save(fn, "i106", Mod106.typ(Int64(1), Mod106.UnexportedT), compress=compress)
i106 = load(fn, "i106")
@assert i106 == Mod106.typ(@compat(Int64(1)), Mod106.UnexportedT)
@assert i106 == Mod106.typ(Int64(1), Mod106.UnexportedT)

# bracket syntax for datasets
jldopen(fn, "w", compatible=compatible, compress=compress) do file
Expand Down

0 comments on commit 94af823

Please sign in to comment.