Skip to content

Commit 36c0b0a

Browse files
committed
remove tuple Type manipulations from convert
1 parent 9c45b5d commit 36c0b0a

File tree

5 files changed

+69
-77
lines changed

5 files changed

+69
-77
lines changed

base/compiler/compiler.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ using .Iterators: zip, enumerate
7575
using .Iterators: Flatten, Filter, product # for generators
7676
include("namedtuple.jl")
7777

78+
ntuple(f, ::Val{0}) = ()
79+
ntuple(f, ::Val{1}) = (@_inline_meta; (f(1),))
80+
ntuple(f, ::Val{2}) = (@_inline_meta; (f(1), f(2)))
81+
ntuple(f, ::Val{3}) = (@_inline_meta; (f(1), f(2), f(3)))
82+
ntuple(f, ::Val{n}) where {n} = ntuple(f, n::Int)
83+
ntuple(f, n) = (Any[f(i) for i = 1:n]...,)
84+
7885
# core docsystem
7986
include("docs/core.jl")
8087

base/essentials.jl

Lines changed: 38 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -201,31 +201,6 @@ ERROR: ArgumentError: Cannot call tail on an empty tuple.
201201
tail(x::Tuple) = argtail(x...)
202202
tail(::Tuple{}) = throw(ArgumentError("Cannot call tail on an empty tuple."))
203203

204-
tuple_type_head(T::Type) = (@_pure_meta; fieldtype(T::Type{<:Tuple}, 1))
205-
206-
function tuple_type_tail(T::Type)
207-
@_pure_meta
208-
if isa(T, UnionAll)
209-
return UnionAll(T.var, tuple_type_tail(T.body))
210-
elseif isa(T, Union)
211-
return Union{tuple_type_tail(T.a), tuple_type_tail(T.b)}
212-
else
213-
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
214-
if isvatuple(T) && length(T.parameters) == 1
215-
va = T.parameters[1]
216-
(isa(va, DataType) && isa(va.parameters[2], Int)) || return T
217-
return Tuple{Vararg{va.parameters[1], va.parameters[2]-1}}
218-
end
219-
return Tuple{argtail(T.parameters...)...}
220-
end
221-
end
222-
223-
tuple_type_cons(::Type, ::Type{Union{}}) = Union{}
224-
function tuple_type_cons(::Type{S}, ::Type{T}) where T<:Tuple where S
225-
@_pure_meta
226-
Tuple{S, T.parameters...}
227-
end
228-
229204
function unwrap_unionall(@nospecialize(a))
230205
while isa(a,UnionAll)
231206
a = a.body
@@ -295,54 +270,45 @@ function typename(a::Union)
295270
end
296271
typename(union::UnionAll) = typename(union.body)
297272

298-
const AtLeast1 = Tuple{Any, Vararg{Any}}
299-
300-
# converting to empty tuple type
301-
convert(::Type{Tuple{}}, ::Tuple{}) = ()
302-
convert(::Type{Tuple{}}, x::AtLeast1) = throw(MethodError(convert, (Tuple{}, x)))
303-
304-
# converting to tuple types with at least one element
305-
convert(::Type{T}, x::T) where {T<:AtLeast1} = x
306-
convert(::Type{T}, x::AtLeast1) where {T<:AtLeast1} =
307-
(convert(tuple_type_head(T), x[1]), convert(tuple_type_tail(T), tail(x))...)
308-
309-
# converting to Vararg tuple types
310-
convert(::Type{Tuple{Vararg{V}}}, x::Tuple{Vararg{V}}) where {V} = x
311-
convert(T::Type{Tuple{Vararg{V}}}, x::Tuple) where {V} =
312-
(convert(tuple_type_head(T), x[1]), convert(T, tail(x))...)
313-
314-
# TODO: the following definitions are equivalent (behaviorally) to the above method
315-
# I think they may be faster / more efficient for inference,
316-
# if we could enable them, but are they?
317-
# TODO: These currently can't be used (#21026, #23017) since with
318-
# z(::Type{<:Tuple{Vararg{T}}}) where {T} = T
319-
# calling
320-
# z(Tuple{Val{T}} where T)
321-
# fails, even though `Type{Tuple{Val}} == Type{Tuple{Val{S}} where S}`
322-
# and so T should be `Val` (aka `Val{S} where S`)
323-
#convert(_::Type{Tuple{S}}, x::Tuple{S}) where {S} = x
324-
#convert(_::Type{Tuple{S}}, x::Tuple{Any}) where {S} = (convert(S, x[1]),)
325-
#convert(_::Type{T}, x::T) where {S, N, T<:Tuple{S, Vararg{S, N}}} = x
326-
#convert(_::Type{Tuple{S, Vararg{S, N}}},
327-
# x::Tuple{Any, Vararg{Any, N}}) where
328-
# {S, N} = cnvt_all(S, x...)
329-
#convert(_::Type{Tuple{Vararg{S, N}}},
330-
# x::Tuple{Vararg{Any, N}}) where
331-
# {S, N} = cnvt_all(S, x...)
332-
# TODO: These currently can't be used since
333-
# Type{NTuple} <: (Type{Tuple{Vararg{S}}} where S) is true
334-
# even though the value S doesn't exist
335-
#convert(_::Type{Tuple{Vararg{S}}},
336-
# x::Tuple{Any, Vararg{Any}}) where
337-
# {S} = cnvt_all(S, x...)
338-
#convert(_::Type{Tuple{Vararg{S}}},
339-
# x::Tuple{Vararg{Any}}) where
340-
# {S} = cnvt_all(S, x...)
341-
#cnvt_all(T) = ()
342-
#cnvt_all(T, x, rest...) = (convert(T, x), cnvt_all(T, rest...)...)
343-
# TODO: These may be necessary if the above are enabled
273+
_tuple_error(T::Type, x) = (@_noinline_meta; throw(MethodError(convert, (T, x))))
274+
275+
convert(::Type{T}, x::T) where {T<:Tuple} = x
276+
function convert(::Type{T}, x::NTuple{N,Any}) where {N, T<:Tuple}
277+
NTuple{N,Union{}} <: T || _tuple_error(T, x)
278+
cvt1(n) = (@_inline_meta; convert(fieldtype(T, n), Core.getfield(x, n, #=boundscheck=#false)))
279+
return ntuple(cvt1, Val(N))
280+
end
281+
282+
# optimizations?
283+
# converting to tuple types of fixed length
284+
#convert(::Type{T}, x::T) where {N, T<:NTuple{N,Any}} = x
285+
#convert(::Type{T}, x::NTuple{N,Any}) where {N, T<:NTuple{N,Any}} =
286+
# ntuple(n -> convert(fieldtype(T, n), x[n]), Val(N))
287+
#convert(::Type{T}, x::Tuple{Vararg{Any}}) where {N, T<:NTuple{N,Any}} =
288+
# throw(MethodError(convert, (T, x)))
289+
# converting to tuple types of indefinite length
290+
#convert(::Type{Tuple{Vararg{V}}}, x::Tuple{Vararg{V}}) where {V} = x
291+
#convert(::Type{NTuple{N, V}}, x::NTuple{N, V}) where {N, V} = x
292+
#function convert(T::Type{Tuple{Vararg{V}}}, x::Tuple) where {V}
293+
# @isdefined(V) || (V = fieldtype(T, 1))
294+
# return map(t -> convert(V, t), x)
295+
#end
296+
#function convert(T::Type{NTuple{N, V}}, x::NTuple{N, Any}) where {N, V}
297+
# @isdefined(V) || (V = fieldtype(T, 1))
298+
# return map(t -> convert(V, t), x)
299+
#end
300+
# short tuples
344301
#convert(::Type{Tuple{}}, ::Tuple{}) = ()
345-
#convert(::Type{Tuple{Vararg{S}}} where S, ::Tuple{}) = ()
302+
#convert(::Type{Tuple{S}}, x::Tuple{S}) where {S} = x
303+
#convert(::Type{Tuple{S, T}}, x::Tuple{S, T}) where {S, T} = x
304+
#convert(::Type{Tuple{S, T, U}}, x::Tuple{S, T, U}) where {S, T, U} = x
305+
#convert(::Type{Tuple{S}}, x::Tuple{Any}) where {S} = (convert(S, x[1]),)
306+
#convert(::Type{Tuple{S, T}}, x::Tuple{Any, Any}) where {S, T} = (convert(S, x[1]), convert(T, x[2]),)
307+
#convert(::Type{Tuple{S, T, U}}, x::Tuple{Any, Any, Any}) where {S, T, U} = (convert(S, x[1]), convert(T, x[2]), convert(U, x[3]))
308+
#convert(::Type{Tuple{}}, x::Tuple) = _tuple_error(Tuple{}, x)
309+
#convert(::Type{Tuple{S}}, x::Tuple) = _tuple_error(Tuple{S}, x)
310+
#convert(::Type{Tuple{S, T}}, x::Tuple{Any, Any}) where {S, T} =_tuple_error(Tuple{S, T}, x)
311+
#convert(::Type{Tuple{S, T, U}}, x::Tuple{Any, Any, Any}) where {S, T, U} = _tuple_error(Tuple{S, T, U}, x)
346312

347313
"""
348314
oftype(x, y)

base/tuple.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,23 @@ fill_to_length(t::Tuple{}, val, ::Val{2}) = (val, val)
220220
# NOTE: this means this constructor must be avoided in Core.Compiler!
221221
if nameof(@__MODULE__) === :Base
222222

223+
function tuple_type_tail(T::Type)
224+
@_pure_meta # TODO: this method is wrong (and not @pure)
225+
if isa(T, UnionAll)
226+
return UnionAll(T.var, tuple_type_tail(T.body))
227+
elseif isa(T, Union)
228+
return Union{tuple_type_tail(T.a), tuple_type_tail(T.b)}
229+
else
230+
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
231+
if isvatuple(T) && length(T.parameters) == 1
232+
va = T.parameters[1]
233+
(isa(va, DataType) && isa(va.parameters[2], Int)) || return T
234+
return Tuple{Vararg{va.parameters[1], va.parameters[2]-1}}
235+
end
236+
return Tuple{argtail(T.parameters...)...}
237+
end
238+
end
239+
223240
(::Type{T})(x::Tuple) where {T<:Tuple} = convert(T, x) # still use `convert` for tuples
224241

225242
(::Type{T})(itr) where {T<:Tuple} = _totuple(T, itr)
@@ -235,7 +252,7 @@ function _totuple(T, itr, s...)
235252
@_inline_meta
236253
y = iterate(itr, s...)
237254
y === nothing && _totuple_err(T)
238-
(convert(tuple_type_head(T), y[1]), _totuple(tuple_type_tail(T), itr, y[2])...)
255+
return (convert(fieldtype(T, 1), y[1]), _totuple(tuple_type_tail(T), itr, y[2])...)
239256
end
240257

241258
# use iterative algorithm for long tuples

test/ambiguous.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,6 @@ end
269269
@test_broken need_to_handle_undef_sparam == Set()
270270
pop!(need_to_handle_undef_sparam, which(Core.Compiler._cat, Tuple{Any, AbstractArray}))
271271
pop!(need_to_handle_undef_sparam, first(methods(Core.Compiler.same_names)))
272-
pop!(need_to_handle_undef_sparam, which(Core.Compiler.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{}}))
273-
pop!(need_to_handle_undef_sparam, which(Core.Compiler.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{Int8}}))
274272
@test need_to_handle_undef_sparam == Set()
275273
end
276274
let need_to_handle_undef_sparam =
@@ -292,8 +290,6 @@ end
292290
pop!(need_to_handle_undef_sparam, which(Base.oneunit, Tuple{Type{Union{Missing, T}} where T}))
293291
pop!(need_to_handle_undef_sparam, which(Base.convert, (Type{Union{Some{T}, Nothing}} where T, Some)))
294292
pop!(need_to_handle_undef_sparam, which(Base.convert, (Type{Union{T, Nothing}} where T, Some)))
295-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{}}))
296-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{Int8}}))
297293
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Nothing,T}},Union{Nothing,T}} where T))
298294
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Missing,T}},Union{Missing,T}} where T))
299295
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Missing,Nothing,T}},Union{Missing,Nothing,T}} where T))

test/tuple.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ end
3636
@test convert(NTuple{3, Int}, (1.0, 2, 0x3)) === (1, 2, 3)
3737
@test convert(Tuple{Int, Int, Float64}, (1.0, 2, 0x3)) === (1, 2, 3.0)
3838

39+
@test convert(Tuple{Vararg{AbstractFloat}}, (2,)) == (2.0,)
40+
@test convert(Tuple{Int, Vararg{AbstractFloat}}, (-9.0+0im, 2,)) == (-9, 2.0,)
41+
let x = @inferred(convert(Tuple{Integer, UInt8, UInt16, UInt32, Int, Vararg{Real}}, (2.0, 3, 5, 6.0, 42, 3.0+0im)))
42+
@test x == (2, 0x03, 0x0005, 0x00000006, 42, 3.0)
43+
end
44+
3945
@test_throws MethodError convert(Tuple{Int}, ())
4046
@test_throws MethodError convert(Tuple{Any}, ())
4147
@test_throws MethodError convert(Tuple{Int, Vararg{Int}}, ())

0 commit comments

Comments
 (0)