diff --git a/base/boot.jl b/base/boot.jl index f39454059a985..1ab6488471a9b 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -265,6 +265,8 @@ UnionAll(v::TypeVar, t::ANY) = ccall(:jl_type_unionall, Any, (Any, Any), v, t) Void() = nothing +(::Type{Tuple{}})() = () + immutable VecElement{T} value::T VecElement(value::T) = new(value) # disable converting constructor in Core diff --git a/base/essentials.jl b/base/essentials.jl index 359b1f07fa55c..35bee9e961b79 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -51,7 +51,7 @@ tuple_type_head(T::UnionAll) = tuple_type_head(T.body) function tuple_type_head(T::DataType) @_pure_meta T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,))) - return T.parameters[1] + return unwrapva(T.parameters[1]) end tuple_type_tail(T::UnionAll) = tuple_type_tail(T.body) function tuple_type_tail(T::DataType) diff --git a/base/tuple.jl b/base/tuple.jl index 05fdd8bd256a6..3d36fdcff91b9 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -108,8 +108,10 @@ map(f, t::Tuple{Any, Any}) = (f(t[1]), f(t[2])) map(f, t::Tuple{Any, Any, Any}) = (f(t[1]), f(t[2]), f(t[3])) map(f, t::Tuple) = (@_inline_meta; (f(t[1]), map(f,tail(t))...)) # stop inlining after some number of arguments to avoid code blowup -typealias Any16{N} Tuple{Any,Any,Any,Any,Any,Any,Any,Any, - Any,Any,Any,Any,Any,Any,Any,Any,Vararg{Any,N}} +typealias Any16{N} Tuple{Any,Any,Any,Any,Any,Any,Any,Any, + Any,Any,Any,Any,Any,Any,Any,Any,Vararg{Any,N}} +typealias All16{T,N} Tuple{T,T,T,T,T,T,T,T, + T,T,T,T,T,T,T,T,Vararg{T,N}} function map(f, t::Any16) n = length(t) A = Array{Any}(n) @@ -159,6 +161,44 @@ function _ftl{N}(out, val, ::Type{Val{N}}) _ftl((out..., val), val, Val{N}) end +# constructing from an iterator + +# only define these in Base, to avoid overwriting the constructors +if isdefined(Main, :Base) + +(::Type{T}){T<:Tuple}(x::Tuple) = convert(T, x) # still use `convert` for tuples + +function (T::Type{All16{E,N}}){E,N}(itr) + len = N+16 + elts = collect(E, Iterators.take(itr,len)) + if length(elts) != len + _totuple_err(T) + end + (elts...,) +end + +(::Type{T}){T<:Tuple}(itr) = _totuple(T, itr, start(itr)) + +_totuple(::Type{Tuple{}}, itr, s) = () + +function _totuple_err(T::ANY) + @_noinline_meta + throw(ArgumentError("too few elements for tuple type $T")) +end + +function _totuple(T, itr, s) + @_inline_meta + done(itr, s) && _totuple_err(T) + v, s = next(itr, s) + (convert(tuple_type_head(T), v), _totuple(tuple_type_tail(T), itr, s)...) +end + +_totuple{E}(::Type{Tuple{Vararg{E}}}, itr, s) = (collect(E, Iterators.rest(itr,s))...,) + +_totuple(::Type{Tuple}, itr, s) = (collect(Iterators.rest(itr,s))...,) + +end + ## comparison ## function isequal(t1::Tuple, t2::Tuple) diff --git a/test/replutil.jl b/test/replutil.jl index 6d4cbd433887c..189a4f30ebc4d 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -44,7 +44,7 @@ test_have_color(buf, "", "") # matches the implicit constructor -> convert method Base.show_method_candidates(buf, Base.MethodError(Tuple{}, (1, 1, 1))) let mc = String(take!(buf)) - @test contains(mc, "\nClosest candidates are:\n Tuple{}{T}(") + @test contains(mc, "\nClosest candidates are:\n Tuple{}") @test !contains(mc, cfile) end diff --git a/test/tuple.jl b/test/tuple.jl index 49c9c31def663..20de2460f80fe 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -203,3 +203,17 @@ let test_15703() end + +# PR #15516 +@test Tuple{Char,Char}("za") === ('z','a') +@test_throws ArgumentError Tuple{Char,Char}("z") + +@test NTuple{20,Int}(Iterators.countfrom(2)) === (2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +@test NTuple{20,Float64}(Iterators.countfrom(2)) === (2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.,13.,14.,15.,16.,17.,18.,19.,20.,21.) +@test_throws ArgumentError NTuple{20,Int}([1,2]) + +@test Tuple{Vararg{Float32}}(Float64[1,2,3]) === (1.0f0, 2.0f0, 3.0f0) +@test Tuple{Int,Vararg{Float32}}(Float64[1,2,3]) === (1, 2.0f0, 3.0f0) +@test Tuple{Int,Vararg{Any}}(Float64[1,2,3]) === (1, 2.0, 3.0) +@test Tuple(ones(5)) === (1.0,1.0,1.0,1.0,1.0) +@test_throws MethodError convert(Tuple, ones(5))