diff --git a/base/array.jl b/base/array.jl index f1f8a3958acc03..520eb11b030bee 100644 --- a/base/array.jl +++ b/base/array.jl @@ -26,22 +26,50 @@ call(::Type{Matrix}) = Array{Any}(0, 0) function call{P<:Ptr,T<:Ptr}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array{T<:Ptr}) return RefArray(a) # effectively a no-op end -function call{P<:Ptr,T}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) + +## Replacing this if-else with traitfns: +# function call{P<:Ptr,T}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) +# if (!isbits(T) && T <: eltype(P)) +# # this Array already has the right memory layout for the requested Ref +# return RefArray(a,1,false) # root something, so that this function is type-stable +# else +# ptrs = Array(P, length(a)+1) +# roots = Array(Any, length(a)) +# for i = 1:length(a) +# root = cconvert(P, a[i]) +# ptrs[i] = unsafe_convert(P, root)::P +# roots[i] = root +# end +# ptrs[length(a)+1] = C_NULL +# return RefArray(ptrs,1,roots) +# end +# end + +"Make a trait custom trait (just for illustration)" +@traitdef IsJustRight{P,T} +@generated function trait{P,T}(::Type{IsJustRight{P,T}}) if (!isbits(T) && T <: eltype(P)) - # this Array already has the right memory layout for the requested Ref - return RefArray(a,1,false) # root something, so that this function is type-stable + return :(IsJustRight{P,T}) else - ptrs = Array(P, length(a)+1) - roots = Array(Any, length(a)) - for i = 1:length(a) - root = cconvert(P, a[i]) - ptrs[i] = unsafe_convert(P, root)::P - roots[i] = root - end - ptrs[length(a)+1] = C_NULL - return RefArray(ptrs,1,roots) + return :(Not{IsJustRight{P,T}}) end end +@traitfn function call{P<:Ptr,T; IsJustRight{P,T}}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) + # this Array already has the right memory layout for the requested Ref + return RefArray(a,1,false) # root something, so that this function is type-stable +end +@traitfn function call{P<:Ptr,T; !IsJustRight{P,T}}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) + ptrs = Array(P, length(a)+1) + roots = Array(Any, length(a)) + for i = 1:length(a) + root = cconvert(P, a[i]) + ptrs[i] = unsafe_convert(P, root)::P + roots[i] = root + end + ptrs[length(a)+1] = C_NULL + return RefArray(ptrs,1,roots) +end + cconvert{P<:Ptr,T<:Ptr}(::Union{Type{Ptr{P}},Type{Ref{P}}}, a::Array{T}) = a cconvert{P<:Ptr}(::Union{Type{Ptr{P}},Type{Ref{P}}}, a::Array) = Ref{P}(a) @@ -54,7 +82,9 @@ asize_from(a::Array, n) = n > ndims(a) ? () : (arraysize(a,n), asize_from(a, n+1 size{_,N}(a::Array{_,N}) = asize_from(a, 1)::NTuple{N,Int} length(a::Array) = arraylen(a) -elsize{T}(a::Array{T}) = isbits(T) ? sizeof(T) : sizeof(Ptr) +#elsize{T}(a::Array{T}) = isbits(T) ? sizeof(T) : sizeof(Ptr) +@traitfn elsize{T; IsBits{T}}(a::Array{T}) = sizeof(T) +@traitfn elsize{T; !IsBits{T}}(a::Array{T}) = sizeof(Ptr) sizeof(a::Array) = elsize(a) * length(a) strides{T}(a::Array{T,1}) = (1,) @@ -75,13 +105,24 @@ function unsafe_copy!{T}(dest::Ptr{T}, src::Ptr{T}, n) return dest end -function unsafe_copy!{T}(dest::Array{T}, doffs, src::Array{T}, soffs, n) - if isbits(T) - unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n) - else - for i=0:n-1 - @inbounds arrayset(dest, src[i+soffs], i+doffs) - end +# function unsafe_copy!{T}(dest::Array{T}, doffs, src::Array{T}, soffs, n) +# if isbits(T) +# unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n) +# else +# for i=0:n-1 +# @inbounds arrayset(dest, src[i+soffs], i+doffs) +# end +# end +# return dest +# end + +@traitfn function unsafe_copy!{T; IsBits{T}}(dest::Array{T}, doffs, src::Array{T}, soffs, n) + unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n) + return dest +end +@traitfn function unsafe_copy!{T; !IsBits{T}}(dest::Array{T}, doffs, src::Array{T}, soffs, n) + for i=0:n-1 + @inbounds arrayset(dest, src[i+soffs], i+doffs) end return dest end diff --git a/base/coreimg.jl b/base/coreimg.jl index b22250647327b5..9f85ede8f20077 100644 --- a/base/coreimg.jl +++ b/base/coreimg.jl @@ -44,7 +44,7 @@ include("pointer.jl") # traits getindex(A::Array, i1::Real) = arrayref(A, to_index(i1)) include("traits.jl") -include("traits-bootstrap-tests.jl") +#include("traits-bootstrap-tests.jl") # core array operations include("abstractarray.jl") diff --git a/base/sysimg.jl b/base/sysimg.jl index cfd042c1432f9a..07b4b4635056b1 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -15,7 +15,7 @@ eval(m,x) = Core.eval(m,x) include("exports.jl") -if true +if false # simple print definitions for debugging. enable these if something # goes wrong during bootstrap before printing code is available. show(x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any), @@ -51,7 +51,7 @@ include("functors.jl") # traits include("traits.jl") -include("traits-bootstrap-tests.jl") +#include("traits-bootstrap-tests.jl") # also activate the printing above # array structures include("abstractarray.jl") diff --git a/base/traits-bootstrap-tests.jl b/base/traits-bootstrap-tests.jl new file mode 100644 index 00000000000000..f0777746442ed3 --- /dev/null +++ b/base/traits-bootstrap-tests.jl @@ -0,0 +1,94 @@ +# Tests which can be run during bootstrap. Essentially the same as in test/traits.jl + +println("--------------------trait-----------------") +println("Running traits tests:") +### tests +@traitdef Tr{X} +@traitimpl Tr{Int} +@traitfn ff985{X; Tr{X}}(x::X) = x +a = ff985(5) +# println("Running traitfn:") +# println(ff985(5)) + +## run tests + +macro assert_(ex) + :($(esc(ex)) ? $(nothing) : (print("------------- Error in: "); println($(esc(ex)))) ) +end + +@traitdef Tr1{X} +@assert_ trait(Tr1{Int})==Not{Tr1{Int}} +@assert_ !istrait(Tr1{Int}) +@traitimpl Tr1{Integer} +@assert_ trait(Tr1{Int})==Tr1{Int} +@assert_ istrait(Tr1{Int}) +@assert_ trait(Tr1{Bool})==Tr1{Bool} + +# Logic. trait(Tr) returns the same trait Tr if it is fulfilled and +# Not{Tr} otherwise. This is a bit confusing. +@assert_ trait(Tr1{AbstractString})==Not{Tr1{AbstractString}} +@assert_ istrait(Tr1{AbstractString})==false +@assert_ trait(Not{Tr1{AbstractString}})==Not{Tr1{AbstractString}} +@assert_ istrait(Not{Tr1{AbstractString}})==true +@assert_ trait(Not{Not{Tr1{AbstractString}}})==Not{Tr1{AbstractString}} +@assert_ istrait(Not{Not{Tr1{AbstractString}}})==false +@assert_ trait(Not{Not{Not{Tr1{AbstractString}}}})==Not{Tr1{AbstractString}} +@assert_ istrait(Not{Not{Not{Tr1{AbstractString}}}})==true + +@assert_ trait(Not{Tr1{Integer}})==Tr1{Integer} +@assert_ istrait(Not{Tr1{Integer}})==false +@assert_ trait(Not{Not{Tr1{Integer}}})==Tr1{Integer} +@assert_ istrait(Not{Not{Tr1{Integer}}})==true +@assert_ trait(Not{Not{Not{Tr1{Integer}}}})==Tr1{Integer} +@assert_ istrait(Not{Not{Not{Tr1{Integer}}}})==false + +@traitdef Tr2{X,Y} +@assert_ trait(Tr2{Int,AbstractFloat})==Not{Tr2{Int,AbstractFloat}} +@traitimpl Tr2{Integer, Float64} +@assert_ trait(Tr2{Int, Float64})==Tr2{Int, Float64} +@assert_ trait(Tr2{Int, Float32})==Not{Tr2{Int, Float32}} + +# trait functions +@traitfn f985{X; Tr1{X}}(x::X) = 1 # def 1 +@traitfn f985{X; !Tr1{X}}(x::X) = 2 +@assert_ f985(5)==1 +@assert_ f985(5.)==2 + + +@traitfn f985{X,Y; Tr2{X,Y}}(x::X,y::Y,z) = 1 +@assert_ f985(5,5., "a")==1 +@traitfn f985{X,Y; !Tr2{X,Y}}(x::X,y::Y,z) = 2 +@assert_ f985(5,5, "a")==2 +# This will overwrite the definition def1 above +@traitfn f985{X; !Tr2{X,X}}(x::X) = 10 +@traitfn f985{X; Tr2{X,X}}(x::X) = 100 +@assert_ f985(5)==10 +@assert_ f985(5.)==10 +@traitimpl Tr2{Integer, Integer} +@assert_ f985(5.)==10 +println("This fails on the first round of coreimg.jl:") +@assert_ f985(5)==10 +println("end of failure") +# need to update method cache to make above right: +@traitfn f985{X; Tr2{X,X}}(x::X) = 100 +@assert_ f985(5)==100 +@assert_ f985(5.)==10 + +# VarArg +@traitfn g{X; Tr1{X}}(x::X, y...) = y +@assert_ g(5, 7, 8)==((7,8),) +### @assert_ g(5.0, 7, 8)==((7,8),) # hangs because of https://github.com/JuliaLang/julia/issues/13183 +## With macros +@traitfn @generated ggg{X; Tr1{X}}(x::X) = ( x<:Array ? :(x[1]+1) : :(x)) +#@traitfn @generated ggg{X; Tr1{X}}(x::X) = ( println(x); x<:Array ? :(x[1]+1) : :(x)) +@assert_ ggg(5)==5 +@traitimpl Tr1{AbstractArray} +a = Array(Any,1) # Array(Int,1) does not work yet!? +a[1] = 5 +@assert_ ggg(a)==6 + +# traitfn with Type +@traitfn ggt{X; Tr1{X}}(::Type{X}, y) = (X,y) +@assert_ ggt(Array, 5)==(Array, 5) + +println("Traits tests done") diff --git a/base/traits.jl b/base/traits.jl index 7fa9b4068f0546..2961825c93cec7 100644 --- a/base/traits.jl +++ b/base/traits.jl @@ -278,20 +278,20 @@ typealias IsNothing{X} Not{IsAnything{X}} end end -# "Trait of all isbits-types" -# @traitdef IsBits{X} -# @generated function trait{X}(::Type{IsBits{X}}) -# isbits(X) ? :(IsBits{X}) : :(Not{IsBits{X}}) -# end +"Trait of all isbits-types" +@traitdef IsBits{X} +@generated function trait{X}(::Type{IsBits{X}}) + isbits(X) ? :(IsBits{X}) : :(Not{IsBits{X}}) +end -# "Trait of all immutable types" -# @traitdef IsImmutable{X} -# @generated function trait{X}(::Type{IsImmutable{X}}) -# X.mutable ? :(Not{IsImmutable{X}}) : :(IsImmutable{X}) -# end +"Trait of all immutable types" +@traitdef IsImmutable{X} +@generated function trait{X}(::Type{IsImmutable{X}}) + X.mutable ? :(Not{IsImmutable{X}}) : :(IsImmutable{X}) +end -# "Trait of all leaf types types" -# @traitdef IsLeafType{X} -# @generated function trait{X}(::Type{IsLeafType{X}}) -# X.mutable ? :(Not{IsLeafType{X}}) : :(IsLeafType{X}) -# end +"Trait of all leaf types types" +@traitdef IsLeafType{X} +@generated function trait{X}(::Type{IsLeafType{X}}) + X.mutable ? :(Not{IsLeafType{X}}) : :(IsLeafType{X}) +end diff --git a/test/traits.jl b/test/traits.jl index 1bf49a616746a4..95f2431d472184 100644 --- a/test/traits.jl +++ b/test/traits.jl @@ -72,6 +72,19 @@ using Base.Test @traitfn g{X; !Tr1{X}}(x::X, y...) = 99 @test g(5.0, 7, 8)==99 +## With macros +@traitfn @generated ggg{X; Tr1{X}}(x::X) = ( x<:Array ? :(x[1]+1) : :(x)) +#@traitfn @generated ggg{X; Tr1{X}}(x::X) = ( println(x); x<:Array ? :(x[1]+1) : :(x)) +@test ggg(5)==5 +@traitimpl Tr1{AbstractArray} +a = Array(Any,1) # Array(Int,1) does not work yet!? +a[1] = 5 +@test ggg(a)==6 + +# traitfn with Type +@traitfn ggt{X; Tr1{X}}(::Type{X}, y) = (X,y) +@test ggt(Array, 5)==(Array, 5) + ###### # Other tests #####