diff --git a/README.md b/README.md index 812c7dbad..99b3e7f03 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ Currently, the `@compat` macro supports the following syntaxes: * `@compat Array{<:Real}` and similar uses of `<:T` to define a set of parameterized types ([#20414]). In 0.4 and 0.5, this only works for non-nested usages (e.g. you can't define `Array{<:Array{<:Real}}`). +* `@compat abstract type T end` and `@compat primitive type T 8 end` + to declare abstract and primitive types. [#20418] + This only work when `@compat` is applied directly on the declaration. + ## Type Aliases * In 0.5, `ASCIIString` and `ByteString` were deprecated, and `UTF8String` was renamed to the (now concrete) type `String`. diff --git a/src/Compat.jl b/src/Compat.jl index 01c06a981..88411f2ef 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -746,8 +746,53 @@ function _compat(ex::Symbol) end _compat(ex) = ex -macro compat(ex) - esc(_compat(ex)) +function _get_typebody(ex::Expr) + args = ex.args + if ex.head !== :type || length(args) != 3 || args[1] !== true + throw(ArgumentError("Invalid usage of @compat: $ex")) + end + name = args[2] + if !isexpr(args[3], :block) + throw(ArgumentError("Invalid type declaration: $ex")) + end + body = (args[3]::Expr).args + filter!(body) do e + if isa(e, LineNumberNode) || isexpr(e, :line) + return false + end + return true + end + return name, body +end + +function _compat_primitive(typedecl) + name, body = _get_typebody(typedecl) + if length(body) != 1 + throw(ArgumentError("Invalid primitive type declaration: $typedecl")) + end + return Expr(:bitstype, body[1], name) +end + +function _compat_abstract(typedecl) + name, body = _get_typebody(typedecl) + if length(body) != 0 + throw(ArgumentError("Invalid abstract type declaration: $typedecl")) + end + return Expr(:abstract, name) +end + +macro compat(ex...) + if VERSION < v"0.6.0-dev.2746" && length(ex) == 2 && ex[1] === :primitive + return esc(_compat_primitive(ex[2])) + elseif length(ex) != 1 + throw(ArgumentError("@compat called with wrong number of arguments: $ex")) + elseif (VERSION < v"0.6.0-dev.2746" && isexpr(ex[1], :abstract) && + length(ex[1].args) == 1 && isexpr(ex[1].args[1], :type)) + # This can in principle be handled in nested case but we do not + # do that to be consistent with primitive types. + return esc(_compat_abstract(ex[1].args[1])) + end + esc(_compat(ex[1])) end export @compat, @inline, @noinline diff --git a/test/runtests.jl b/test/runtests.jl index 97b9ddead..963216515 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -742,7 +742,7 @@ mktempdir() do dir verbose && println("$name read...") - @test @compat read(io()) == UInt8[convert(UInt8, _) for _ in text] + @test @compat read(io()) == UInt8[convert(UInt8, x) for x in text] @test read(io()) == read(filename) @@ -843,7 +843,7 @@ mktempdir() do dir @test readstring("$filename.to") == text verbose && println("$name write(::IOBuffer, ...)") - @compat to = IOBuffer(UInt8[convert(UInt8, _) for _ in text], false, true) + @compat to = IOBuffer(UInt8[convert(UInt8, x) for x in text], false, true) write(to, io()) @test String(take!(to)) == text @@ -1353,8 +1353,10 @@ end end @test do_boundscheck() == true -@test Compat.promote_eltype_op(@functorize(+), ones(2,2), 1) === Float64 -@test Compat.promote_eltype_op(@functorize(*), ones(Int, 2), zeros(Int16,2)) === Int +if VERSION < v"0.6.0-dev.1886" + @test Compat.promote_eltype_op(@functorize(+), ones(2,2), 1) === Float64 + @test Compat.promote_eltype_op(@functorize(*), ones(Int, 2), zeros(Int16,2)) === Int +end #Add test for Base.normalize and Base.normalize! let @@ -1622,7 +1624,7 @@ for x in (3.1, -17, 3//4, big(111.1), Inf) end # julia#20006 -abstract AbstractFoo20006 +@compat abstract type AbstractFoo20006 end immutable ConcreteFoo20006{T<:Int} <: AbstractFoo20006 end immutable ConcreteFoo20006N{T<:Int,N} <: AbstractFoo20006 end typealias ConcreteFoo200061{T<:Int} ConcreteFoo20006N{T,1} @@ -1751,4 +1753,12 @@ end let x = [1,2,3] @dotcompat f(x) = x^2 @test f(x) == [1,4,9] -end \ No newline at end of file +end + +# PR #20418 +@compat abstract type Abstract20418{T} <: Ref{T} end +@test Compat.TypeUtils.isabstract(Abstract20418) +@compat primitive type Primitive20418{T} <: Ref{T} 16 end +@test !Compat.TypeUtils.isabstract(Primitive20418) +@test isbits(Primitive20418{Int}) +@test sizeof(Primitive20418{Int}) == 2