diff --git a/base/boot.jl b/base/boot.jl index 54d852ca96416..149b940d5d352 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -242,14 +242,23 @@ ccall(:jl_toplevel_eval_in, Any, (Any, Any), (f::typeof(Typeof))(x) = ($(_expr(:meta,:nospecialize,:x)); isa(x,Type) ? Type{x} : typeof(x)) end) -# let the compiler assume that calling Union{} as a constructor does not need -# to be considered ever (which comes up often as Type{<:T}) -Union{}(a...) = throw(MethodError(Union{}, a)) macro nospecialize(x) _expr(:meta, :nospecialize, x) end +TypeVar(n::Symbol) = _typevar(n, Union{}, Any) +TypeVar(n::Symbol, @nospecialize(ub)) = _typevar(n, Union{}, ub) +TypeVar(n::Symbol, @nospecialize(lb), @nospecialize(ub)) = _typevar(n, lb, ub) + +UnionAll(v::TypeVar, @nospecialize(t)) = ccall(:jl_type_unionall, Any, (Any, Any), v, t) + +const Vararg = ccall(:jl_toplevel_eval_in, Any, (Any, Any), Core, _expr(:new, TypeofVararg)) + +# let the compiler assume that calling Union{} as a constructor does not need +# to be considered ever (which comes up often as Type{<:T}) +Union{}(a...) = throw(MethodError(Union{}, a)) + Expr(@nospecialize args...) = _expr(args...) abstract type Exception end @@ -378,12 +387,6 @@ mutable struct WeakRef (Ptr{Cvoid}, Any), getptls(), v) end -TypeVar(n::Symbol) = _typevar(n, Union{}, Any) -TypeVar(n::Symbol, @nospecialize(ub)) = _typevar(n, Union{}, ub) -TypeVar(n::Symbol, @nospecialize(lb), @nospecialize(ub)) = _typevar(n, lb, ub) - -UnionAll(v::TypeVar, @nospecialize(t)) = ccall(:jl_type_unionall, Any, (Any, Any), v, t) - Tuple{}() = () struct VecElement{T} diff --git a/base/broadcast.jl b/base/broadcast.jl index ca671d67fd365..6cfd4dbb8bf89 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -727,8 +727,7 @@ end ci = U end if i == lr && Core.Compiler.isvarargtype(pi) - N = (Base.unwrap_unionall(pi)::DataType).parameters[2] - c[i] = Base.rewrap_unionall(Vararg{ci, N}, pi) + c[i] = isdefined(pi, :N) ? Vararg{ci, pi.N} : Vararg{ci} else c[i] = ci end diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 9469452735da2..d966065852b3a 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -307,7 +307,7 @@ julia> 2^2 * 3^3 !!! compat "Julia 1.6" The method that accepts a tuple requires Julia 1.6 or later. """ -function nextprod(a::Union{Tuple{Vararg{<:Integer}},AbstractVector{<:Integer}}, x::Real) +function nextprod(a::Union{Tuple{Vararg{Integer}},AbstractVector{<:Integer}}, x::Real) if x > typemax(Int) throw(ArgumentError("unsafe for x > typemax(Int), got $x")) end diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 84a7e18a59b73..4ef63f3cbaae1 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -1057,10 +1057,11 @@ function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool) spsig = linfo.def.sig if isa(spsig, UnionAll) if !isempty(linfo.sparam_vals) - env = pointer_from_objref(linfo.sparam_vals) + sizeof(Ptr{Cvoid}) - T = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), T, spsig, env) + sparam_vals = Any[isa(v, Core.TypeofVararg) ? TypeVar(:N, Union{}, Any) : + v for v in linfo.sparam_vals] + T = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), T, spsig, sparam_vals) isref && isreturn && T === Any && return Bottom # catch invalid return Ref{T} where T = Any - for v in linfo.sparam_vals + for v in sparam_vals if isa(v, TypeVar) T = UnionAll(v, T) end diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 2d5fce04c0454..de41849c2323c 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -192,6 +192,8 @@ function sptypes_from_meth_instance(linfo::MethodInstance) ty = UnionAll(tv, Type{tv}) end end + elseif isa(v, Core.TypeofVararg) + ty = Int else ty = Const(v) end diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index 0e95f812e5eb6..22b905096d85e 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -738,7 +738,7 @@ function analyze_method!(match::MethodMatch, atypes::Vector{Any}, # Bail out if any static parameters are left as TypeVar ok = true for i = 1:length(match.sparams) - isa(match.sparams[i], TypeVar) && return nothing + (isa(match.sparams[i], TypeVar) || isa(match.sparams[i], Core.TypeofVararg)) && return nothing end if !params.inlining diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 7f5d3e42522d7..532798bbd9df8 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -447,9 +447,7 @@ function typebound_nothrow(b) b = widenconst(b) (b ⊑ TypeVar) && return true if isType(b) - b = unwrap_unionall(b.parameters[1]) - b === Union{} && return true - return !isa(b, DataType) || b.name != _va_typename + return true end return false end @@ -489,9 +487,8 @@ function typeof_concrete_vararg(t::DataType) for i = 1:np p = t.parameters[i] if i == np && isvarargtype(p) - pp = unwrap_unionall(p) - if isconcretetype(pp.parameters[1]) && pp.parameters[2] isa TypeVar - return rewrap_unionall(Type{Tuple{t.parameters[1:np-1]..., pp}}, p) + if isdefined(p, :T) && !isdefined(p, :N) && isconcretetype(p.T) + return Type{Tuple{t.parameters[1:np-1]..., Vararg{p.T, N}}} where N end elseif !isconcretetype(p) break @@ -555,15 +552,21 @@ function typeassert_type_instance(@nospecialize(v), @nospecialize(t)) widev = widenconst(v) if widev <: t return v - elseif typeintersect(widev, t) === Bottom + end + ti = typeintersect(widev, t) + if ti === Bottom return Bottom end @assert widev <: Tuple new_fields = Vector{Any}(undef, length(v.fields)) for i = 1:length(new_fields) - new_fields[i] = typeassert_type_instance(v.fields[i], getfield_tfunc(t, Const(i))) - if new_fields[i] === Bottom - return Bottom + if isa(v.fields[i], Core.TypeofVararg) + new_fields[i] = v.fields[i] + else + new_fields[i] = typeassert_type_instance(v.fields[i], getfield_tfunc(t, Const(i))) + if new_fields[i] === Bottom + return Bottom + end end end return tuple_tfunc(new_fields) @@ -1130,10 +1133,10 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...) elseif isconstType(headtypetype) headtype = headtypetype.parameters[1] else - return Type + return Any end if !isempty(args) && isvarargtype(args[end]) - return Type + return isvarargtype(headtype) ? Core.TypeofVararg : Type end largs = length(args) if headtype === Union @@ -1175,8 +1178,8 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...) end return allconst ? Const(ty) : Type{ty} end - istuple = (headtype == Tuple) - if !istuple && !isa(headtype, UnionAll) + istuple = isa(headtype, Type) && (headtype == Tuple) + if !istuple && !isa(headtype, UnionAll) && !isvarargtype(headtype) return Union{} end uw = unwrap_unionall(headtype) @@ -1193,7 +1196,8 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...) aip1 = ai.parameters[1] canconst &= !has_free_typevars(aip1) push!(tparams, aip1) - elseif isa(ai, Const) && (isa(ai.val, Type) || isa(ai.val, TypeVar) || valid_tparam(ai.val)) + elseif isa(ai, Const) && (isa(ai.val, Type) || isa(ai.val, TypeVar) || + valid_tparam(ai.val) || (istuple && isa(ai.val, Core.TypeofVararg))) push!(tparams, ai.val) elseif isa(ai, PartialTypeVar) canconst = false @@ -1259,11 +1263,11 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...) catch ex # type instantiation might fail if one of the type parameters # doesn't match, which could happen if a type estimate is too coarse - return Type{<:headtype} + return isvarargtype(headtype) ? Core.TypeofVararg : Type{<:headtype} end !uncertain && canconst && return Const(appl) - if isvarargtype(headtype) - return Type + if isvarargtype(appl) + return Core.TypeofVararg end if istuple return Type{<:appl} @@ -1315,7 +1319,7 @@ function tuple_tfunc(atypes::Vector{Any}) x = atypes[i] # TODO ignore singleton Const (don't forget to update cache logic if you implement this) if !anyinfo - anyinfo = !isa(x, Type) || isType(x) + anyinfo = (!isa(x, Type) && !isvarargtype(x)) || isType(x) end if isa(x, Const) params[i] = typeof(x.val) diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index 17a444e840b77..1ae1f437a6e71 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -220,6 +220,7 @@ widenconst(c::PartialTypeVar) = TypeVar widenconst(t::PartialStruct) = t.typ widenconst(t::Type) = t widenconst(t::TypeVar) = t +widenconst(t::Core.TypeofVararg) = t issubstate(a::VarState, b::VarState) = (a.typ ⊑ b.typ && a.undef <= b.undef) diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index 22be265287fa5..aa1695569d061 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -46,6 +46,8 @@ function is_derived_type(@nospecialize(t), @nospecialize(c), mindepth::Int) # see if it is derived from the body # also handle the var here, since this construct bounds the mindepth to the smallest possible value return is_derived_type(t, c.var.ub, mindepth) || is_derived_type(t, c.body, mindepth) + elseif isa(c, Core.TypeofVararg) + return is_derived_type(t, unwrapva(c), mindepth) elseif isa(c, DataType) if mindepth > 0 mindepth -= 1 @@ -85,7 +87,7 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec return t # fast path: unparameterized are always simple else ut = unwrap_unionall(t) - if isa(ut, DataType) && ut.name !== _va_typename && isa(c, Type) && c !== Union{} && c <: t + if isa(ut, DataType) && isa(c, Type) && c !== Union{} && c <: t # TODO: need to check that the UnionAll bounds on t are limited enough too return t # t is already wider than the comparison in the type lattice elseif is_derived_type_from_any(ut, sources, depth) @@ -118,19 +120,19 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec b = _limit_type_size(t.b, c.b, sources, depth, allowed_tuplelen) return Union{a, b} end + elseif isa(t, Core.TypeofVararg) + isa(c, Core.TypeofVararg) || return Vararg + VaT = _limit_type_size(unwrapva(t), unwrapva(c), sources, depth + 1, 0) + if isdefined(t, :N) && (isa(t.N, TypeVar) || (isdefined(c, :N) && t.N === c.N)) + return Vararg{VaT, t.N} + end + return Vararg{VaT} elseif isa(t, DataType) if isa(c, DataType) tP = t.parameters cP = c.parameters if t.name === c.name && !isempty(cP) - if isvarargtype(t) - VaT = _limit_type_size(tP[1], cP[1], sources, depth + 1, 0) - N = tP[2] - if isa(N, TypeVar) || N === cP[2] - return Vararg{VaT, N} - end - return Vararg{VaT} - elseif t.name === Tuple.name + if t.name === Tuple.name # for covariant datatypes (Tuple), # apply type-size limit element-wise ltP = length(tP) @@ -155,10 +157,10 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec end return Tuple{Q...} end - elseif isvarargtype(c) - # Tuple{Vararg{T}} --> Tuple{T} is OK - return _limit_type_size(t, cP[1], sources, depth, 0) end + elseif isa(c, Core.TypeofVararg) + # Tuple{Vararg{T}} --> Tuple{T} is OK + return _limit_type_size(t, c.T, sources, depth, 0) end if isType(t) # allow taking typeof as Type{...}, but ensure it doesn't start nesting tt = unwrap_unionall(t.parameters[1]) @@ -166,10 +168,6 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec is_derived_type_from_any(tt, sources, depth) && return t end end - if isvarargtype(t) - # never replace Vararg with non-Vararg - return Vararg - end if allowed_tuplelen < 1 && t.name === Tuple.name return Any end diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index ebf148f428383..98528a8738ca9 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -61,6 +61,17 @@ function valid_tparam(@nospecialize(x)) return isa(x, Symbol) || isbits(x) end +function compatible_vatuple(a::DataType, b::DataType) + vaa = a.parameters[end] + vab = a.parameters[end] + if !(isa(vaa, Core.TypeofVararg) && isa(vab, Core.TypeofVararg)) + return isa(vaa, Core.TypeofVararg) == isa(vab, Core.TypeofVararg) + end + (isdefined(vaa, :N) == isdefined(vab, :N)) || return false + !isdefined(vaa, :N) && return true + return vaa.N === vab.N +end + # return an upper-bound on type `a` with type `b` removed # such that `return <: a` && `Union{return, b} == Union{a, b}` function typesubtract(@nospecialize(a), @nospecialize(b), MAX_UNION_SPLITTING::Int) @@ -80,12 +91,15 @@ function typesubtract(@nospecialize(a), @nospecialize(b), MAX_UNION_SPLITTING::I ta = switchtupleunion(a) return typesubtract(Union{ta...}, b, 0) elseif b isa DataType + if !compatible_vatuple(a, b) + return a + end # if exactly one element is not bottom after calling typesubtract # then the result is all of the elements as normal except that one notbottom = fill(false, length(a.parameters)) for i = 1:length(notbottom) - ap = a.parameters[i] - bp = b.parameters[i] + ap = unwrapva(a.parameters[i]) + bp = unwrapva(b.parameters[i]) notbottom[i] = !(ap <: bp && isnotbrokensubtype(ap, bp)) end let i = findfirst(notbottom) @@ -93,6 +107,7 @@ function typesubtract(@nospecialize(a), @nospecialize(b), MAX_UNION_SPLITTING::I ta = collect(a.parameters) ap = a.parameters[i] bp = b.parameters[i] + (isa(ap, Core.TypeofVararg) || isa(bp, Core.TypeofVararg)) && return a ta[i] = typesubtract(ap, bp, min(2, MAX_UNION_SPLITTING)) return Tuple{ta...} end @@ -196,6 +211,7 @@ function unioncomplexity(t::DataType) return c end unioncomplexity(u::UnionAll) = max(unioncomplexity(u.body), unioncomplexity(u.var.ub)) +unioncomplexity(t::Core.TypeofVararg) = isdefined(t, :T) ? unioncomplexity(t.T) : 0 unioncomplexity(@nospecialize(x)) = 0 function improvable_via_constant_propagation(@nospecialize(t)) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 13a180e6a670c..2465f69f1d970 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2346,7 +2346,7 @@ arguments accepted by varargs methods (see the section on [Varargs Functions](@r # Examples ```jldoctest julia> mytupletype = Tuple{AbstractString, Vararg{Int}} -Tuple{AbstractString, Vararg{Int64, N} where N} +Tuple{AbstractString, Vararg{Int64}} julia> isa(("1",), mytupletype) true diff --git a/base/errorshow.jl b/base/errorshow.jl index d3016deeec218..50325be8354e5 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -423,7 +423,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() # If isvarargtype then it checks whether the rest of the input arguments matches # the varargtype if Base.isvarargtype(sig[i]) - sigstr = (unwrap_unionall(sig[i]).parameters[1], "...") + sigstr = (unwrap_unionall(sig[i]).T, "...") j = length(t_i) else sigstr = (sig[i],) @@ -460,7 +460,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() # It ensures that methods like f(a::AbstractString...) gets the correct # number of right_matches for t in arg_types_param[length(sig):end] - if t <: rewrap_unionall(unwrap_unionall(sig[end]).parameters[1], method.sig) + if t <: rewrap_unionall(unwrap_unionall(sig[end]).T, method.sig) right_matches += 1 end end @@ -473,7 +473,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() for (k, sigtype) in enumerate(sig[length(t_i)+1:end]) sigtype = isvarargtype(sigtype) ? unwrap_unionall(sigtype) : sigtype if Base.isvarargtype(sigtype) - sigstr = ((sigtype::DataType).parameters[1], "...") + sigstr = ((sigtype::Core.TypeofVararg).T, "...") else sigstr = (sigtype,) end diff --git a/base/essentials.jl b/base/essentials.jl index aba10a1a011c6..bbba482b84974 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -255,6 +255,14 @@ function rewrap_unionall(@nospecialize(t), @nospecialize(u)) return UnionAll(u.var, rewrap_unionall(t, u.body)) end +function rewrap_unionall(t::Core.TypeofVararg, @nospecialize(u)) + isdefined(t, :T) || return t + if !isdefined(t, :N) || t.N === u.var + return Vararg{rewrap_unionall(t.T, u)} + end + Vararg{rewrap_unionall(t.T, u), t.N} +end + # replace TypeVars in all enclosing UnionAlls with fresh TypeVars function rename_unionall(@nospecialize(u)) if !isa(u, UnionAll) @@ -271,10 +279,8 @@ function rename_unionall(@nospecialize(u)) return UnionAll(nv, body{nv}) end -const _va_typename = Vararg.body.body.name function isvarargtype(@nospecialize(t)) - t = unwrap_unionall(t) - return isa(t, DataType) && (t::DataType).name === _va_typename + return isa(t, Core.TypeofVararg) end function isvatuple(@nospecialize(t)) @@ -286,18 +292,14 @@ function isvatuple(@nospecialize(t)) return false end -function unwrapva(@nospecialize(t)) - # NOTE: this returns a related type, but it's NOT a subtype of the original tuple - t2 = unwrap_unionall(t) - return isvarargtype(t2) ? rewrap_unionall(t2.parameters[1], t) : t -end +unwrapva(t::Core.TypeofVararg) = isdefined(t, :T) ? t.T : Any +unwrapva(@nospecialize(t)) = t -function unconstrain_vararg_length(@nospecialize(va)) +function unconstrain_vararg_length(va::Core.TypeofVararg) # construct a new Vararg type where its length is unconstrained, # but its element type still captures any dependencies the input # element type may have had on the input length - T = unwrap_unionall(va).parameters[1] - return rewrap_unionall(Vararg{T}, va) + return Vararg{unwrapva(va)} end typename(a) = error("typename does not apply to this type") diff --git a/base/methodshow.jl b/base/methodshow.jl index 2dfab099d9386..0e00fd2725722 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -27,25 +27,14 @@ function argtype_decl(env, n, @nospecialize(sig::DataType), i::Int, nargs, isva: t === Any && return s, "" end if isvarargtype(t) - v1, v2 = nothing, nothing - if isa(t, UnionAll) - v1 = t.var - t = t.body - if isa(t, UnionAll) - v2 = t.var - t = t.body - end - end - ut = unwrap_unionall(t) - tt, tn = ut.parameters[1], ut.parameters[2] - if isa(tn, TypeVar) && (tn === v1 || tn === v2) - if tt === Any || (isa(tt, TypeVar) && (tt === v1 || tt === v2)) + if !isdefined(t, :N) + if unwrapva(t) === Any return string(s, "..."), "" else - return s, string_with_env(env, tt) * "..." + return s, string_with_env(env, unwrapva(t)) * "..." end end - return s, string_with_env(env, "Vararg{", tt, ", ", tn, "}") + return s, string_with_env(env, "Vararg{", t.T, ", ", t.N, "}") end return s, string_with_env(env, t) end diff --git a/base/promotion.jl b/base/promotion.jl index 871ba194cb834..a6e6d8fdcac4e 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -157,9 +157,8 @@ function full_va_len(p) isempty(p) && return 0, true last = p[end] if isvarargtype(last) - N = unwrap_unionall(last).parameters[2] - if isa(N, Int) - return length(p)::Int + N - 1, true + if isdefined(last, :N) && isa(last.N, Int) + return length(p)::Int + last.N - 1, true end return length(p)::Int, false end diff --git a/base/reflection.jl b/base/reflection.jl index 27c7697e37570..345b676d10eff 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -775,6 +775,9 @@ function to_tuple_type(@nospecialize(t)) end if isa(t, Type) && t <: Tuple for p in unwrap_unionall(t).parameters + if isa(p, Core.TypeofVararg) + p = p.T + end if !(isa(p, Type) || isa(p, TypeVar)) error("argument tuple type must contain only types") end diff --git a/base/show.jl b/base/show.jl index c340f82ce4f11..dc27d67582774 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2290,6 +2290,19 @@ function show(io::IO, tv::TypeVar) nothing end +function show(io::IO, vm::Core.TypeofVararg) + print(io, "Vararg") + if isdefined(vm, :T) + print(io, "{") + show(io, vm.T) + if isdefined(vm, :N) + print(io, ", ") + show(io, vm.N) + end + print(io, "}") + end +end + module IRShow const Compiler = Core.Compiler using Core.IR diff --git a/base/strings/util.jl b/base/strings/util.jl index 04e2f159c7066..cb611ce5f0db9 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -const Chars = Union{AbstractChar,Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} +const Chars = Union{AbstractChar,Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} # starts with and ends with predicates @@ -402,7 +402,7 @@ function split(str::T, splitter; limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString} _split(str, splitter, limit, keepempty, T <: SubString ? T[] : SubString{T}[]) end -function split(str::T, splitter::Union{Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; +function split(str::T, splitter::Union{Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString} _split(str, in(splitter), limit, keepempty, T <: SubString ? T[] : SubString{T}[]) end @@ -478,7 +478,7 @@ function rsplit(str::T, splitter; limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString} _rsplit(str, splitter, limit, keepempty, T <: SubString ? T[] : SubString{T}[]) end -function rsplit(str::T, splitter::Union{Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; +function rsplit(str::T, splitter::Union{Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString} _rsplit(str, in(splitter), limit, keepempty, T <: SubString ? T[] : SubString{T}[]) end @@ -513,7 +513,7 @@ _replace(io, repl::Function, str, r, pattern::Function) = replace(str::String, pat_repl::Pair{<:AbstractChar}; count::Integer=typemax(Int)) = replace(str, isequal(first(pat_repl)) => last(pat_repl); count=count) -replace(str::String, pat_repl::Pair{<:Union{Tuple{Vararg{<:AbstractChar}}, +replace(str::String, pat_repl::Pair{<:Union{Tuple{Vararg{AbstractChar}}, AbstractVector{<:AbstractChar},Set{<:AbstractChar}}}; count::Integer=typemax(Int)) = replace(str, in(first(pat_repl)) => last(pat_repl), count=count) @@ -689,7 +689,7 @@ julia> bytes2hex(b) """ function bytes2hex end -function bytes2hex(a::Union{NTuple{<:Any, UInt8}, AbstractArray{UInt8}}) +function bytes2hex(a::Union{Tuple{Vararg{UInt8}}, AbstractArray{UInt8}}) b = Base.StringVector(2*length(a)) @inbounds for (i, x) in enumerate(a) b[2i - 1] = hex_chars[1 + x >> 4] @@ -698,7 +698,7 @@ function bytes2hex(a::Union{NTuple{<:Any, UInt8}, AbstractArray{UInt8}}) return String(b) end -function bytes2hex(io::IO, a::Union{NTuple{<:Any, UInt8}, AbstractArray{UInt8}}) +function bytes2hex(io::IO, a::Union{Tuple{Vararg{UInt8}}, AbstractArray{UInt8}}) for x in a print(io, Char(hex_chars[1 + x >> 4]), Char(hex_chars[1 + x & 0xf])) end diff --git a/base/tuple.jl b/base/tuple.jl index 69cd9ee9f4fb7..5991ad304059d 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -287,9 +287,9 @@ function tuple_type_tail(T::Type) else T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,))) if isvatuple(T) && length(T.parameters) == 1 - va = T.parameters[1] - (isa(va, DataType) && isa(va.parameters[2], Int)) || return T - return Tuple{Vararg{va.parameters[1], va.parameters[2]-1}} + va = unwrap_unionall(T.parameters[1])::Core.TypeofVararg + (isdefined(va, :N) && isa(va.N, Int)) || return T + return Tuple{Vararg{va.T, va.N-1}} end return Tuple{argtail(T.parameters...)...} end diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 2f25a2bb4605a..d60ecc71669ef 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -9,6 +9,7 @@ if !isdefined(Base, :uv_eventloop) end Base.include(@__MODULE__, joinpath(Sys.BINDIR::String, "..", "share", "julia", "test", "testhelpers", "FakePTYs.jl")) import .FakePTYs: open_fake_pty +using Base.Meta CTRL_C = '\x03' UP_ARROW = "\e[A" @@ -275,14 +276,23 @@ function generate_precompile_statements() # println(statement) # The compiler has problem caching signatures with `Vararg{?, N}`. Replacing # N with a large number seems to work around it. - statement = replace(statement, r"Vararg{(.*?), N} where N" => s"Vararg{\1, 100}") + ps = Meta.parse(statement) + if isexpr(ps, :call) + if isexpr(ps.args[end], :curly) + l = ps.args[end] + if length(l.args) == 2 && l.args[1] == :Vararg + push!(l.args, 100) + end + end + end try - Base.include_string(PrecompileStagingArea, statement) + # println(ps) + Core.eval(PrecompileStagingArea, ps) n_succeeded += 1 print("\rExecuting precompile statements... $n_succeeded/$(length(statements))") catch # See #28808 - # @error "Failed to precompile $statement" + @error "Failed to precompile $statement" end end println() diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index 9d92e030877a8..d1a29dc19d160 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -252,7 +252,7 @@ julia> Tuple Tuple julia> Tuple.parameters -svec(Vararg{Any, N} where N) +svec(Vararg{Any}) ``` Unlike other types, tuple types are covariant in their parameters, so this definition permits diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index bb02de735e5f9..3753e00263a09 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -896,12 +896,12 @@ signature (when the signature matches). ### Vararg Tuple Types -The last parameter of a tuple type can be the special type [`Vararg`](@ref), which denotes any number +The last parameter of a tuple type can be the special value [`Vararg`](@ref), which denotes any number of trailing elements: ```jldoctest julia> mytupletype = Tuple{AbstractString,Vararg{Int}} -Tuple{AbstractString, Vararg{Int64, N} where N} +Tuple{AbstractString, Vararg{Int64}} julia> isa(("1",), mytupletype) true diff --git a/src/builtins.c b/src/builtins.c index de5318b59295e..96637080af537 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -170,6 +170,18 @@ static int egal_types(jl_value_t *a, jl_value_t *b, jl_typeenv_t *env) JL_NOTSAF } return 1; } + if (dt == jl_vararg_type) + { + jl_vararg_t *vma = (jl_vararg_t*)a; + jl_vararg_t *vmb = (jl_vararg_t*)b; + jl_value_t *vmaT = vma->T ? vma->T : (jl_value_t*)jl_any_type; + jl_value_t *vmbT = vmb->T ? vmb->T : (jl_value_t*)jl_any_type; + if (!egal_types(vmaT, vmbT, env)) + return 0; + if (vma->N && vmb->N) + return egal_types(vma->N, vmb->N, env); + return !vma->N && !vmb->N; + } return jl_egal(a, b); } @@ -290,6 +302,13 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN } return h; } + if (tv == jl_vararg_type) { + jl_vararg_t *vm = (jl_vararg_t*)v; + jl_value_t *t = vm->T ? vm->T : (jl_value_t*)jl_any_type; + jl_value_t *n = vm->N ? vm->N : jl_nothing; + return bitmix(type_object_id_(t, env), + type_object_id_(n, env)); + } return jl_object_id_((jl_value_t*)tv, v); } @@ -896,7 +915,7 @@ static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow) int nf = jl_svec_len(types); if (nf > 0 && field_index >= nf-1 && st->name == jl_tuple_typename) { jl_value_t *ft = jl_field_type(st, nf-1); - if (jl_is_vararg_type(ft)) + if (jl_is_vararg(ft)) return jl_unwrap_vararg(ft); } if (field_index < 0 || field_index >= nf) { @@ -957,7 +976,7 @@ JL_CALLABLE(jl_f_isdefined) // apply_type ----------------------------------------------------------------- -static int valid_type_param(jl_value_t *v) +int jl_valid_type_param(jl_value_t *v) { if (jl_is_tuple(v)) { // NOTE: tuples of symbols are not currently bits types, but have been @@ -971,7 +990,7 @@ static int valid_type_param(jl_value_t *v) } return 1; } - if (jl_is_vararg_type(v)) + if (jl_is_vararg(v)) return 0; // TODO: maybe more things return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v)); @@ -986,11 +1005,11 @@ JL_CALLABLE(jl_f_apply_type) jl_value_t *pi = args[i]; // TODO: should possibly only allow Types and TypeVars, but see // https://github.com/JuliaLang/julia/commit/85f45974a581ab9af955bac600b90d9ab00f093b#commitcomment-13041922 - if (jl_is_vararg_type(pi)) { + if (jl_is_vararg(pi)) { if (i != nargs-1) jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi); } - else if (!valid_type_param(pi)) { + else if (!jl_valid_type_param(pi)) { jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi); } } @@ -1001,10 +1020,21 @@ JL_CALLABLE(jl_f_apply_type) // substituting typevars (a valid_type_param check here isn't sufficient). return (jl_value_t*)jl_type_union(&args[1], nargs-1); } + else if (jl_is_vararg(args[0])) { + jl_vararg_t *vm = (jl_vararg_t*)args[0]; + if (!vm->T) { + JL_NARGS(apply_type, 2, 3); + return (jl_value_t*)jl_wrap_vararg(args[1], nargs == 3 ? args[2] : NULL); + } + else if (!vm->N) { + JL_NARGS(apply_type, 2, 2); + return (jl_value_t*)jl_wrap_vararg(vm->T, args[1]); + } + } else if (jl_is_unionall(args[0])) { for(i=1; i < nargs; i++) { jl_value_t *pi = args[i]; - if (!valid_type_param(pi)) { + if (!jl_valid_type_param(pi)) { jl_type_error_rt("Type", "parameter", jl_isa(pi, (jl_value_t*)jl_number_type) ? (jl_value_t*)jl_long_type : (jl_value_t*)jl_type_type, @@ -1118,9 +1148,9 @@ JL_CALLABLE(jl_f__expr) // Typevar constructor for internal use JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) { - if ((lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb)) || jl_is_vararg_type(lb)) + if (lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb)) jl_type_error_rt("TypeVar", "lower bound", (jl_value_t *)jl_type_type, lb); - if ((ub != (jl_value_t *)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub)) || jl_is_vararg_type(ub)) + if (ub != (jl_value_t *)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub)) jl_type_error_rt("TypeVar", "upper bound", (jl_value_t *)jl_type_type, ub); jl_ptls_t ptls = jl_get_ptls_states(); jl_tvar_t *tv = (jl_tvar_t *)jl_gc_alloc(ptls, sizeof(jl_tvar_t), jl_tvar_type); @@ -1256,7 +1286,6 @@ static void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || tt->super != NULL || tt->name == ((jl_datatype_t*)super)->name || - jl_subtype(super, (jl_value_t*)jl_vararg_type) || jl_is_tuple_type(super) || jl_is_namedtuple_type(super) || jl_subtype(super, (jl_value_t*)jl_type_type) || @@ -1309,7 +1338,7 @@ JL_CALLABLE(jl_f__typebody) size_t nf = jl_svec_len(ft); for (size_t i = 0; i < nf; i++) { jl_value_t *elt = jl_svecref(ft, i); - if ((!jl_is_type(elt) && !jl_is_typevar(elt)) || jl_is_vararg_type(elt)) { + if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_type_error_rt(jl_symbol_name(dt->name->name), "type definition", (jl_value_t*)jl_type_type, elt); @@ -1576,7 +1605,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("Union", (jl_value_t*)jl_uniontype_type); add_builtin("TypeofBottom", (jl_value_t*)jl_typeofbottom_type); add_builtin("Tuple", (jl_value_t*)jl_anytuple_type); - add_builtin("Vararg", (jl_value_t*)jl_vararg_type); + add_builtin("TypeofVararg", (jl_value_t*)jl_vararg_type); add_builtin("SimpleVector", (jl_value_t*)jl_simplevector_type); add_builtin("Module", (jl_value_t*)jl_module_type); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index af2b8c2274ea8..04522edd9c31c 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -737,13 +737,13 @@ static bool is_tupletype_homogeneous(jl_svec_t *t, bool allow_va = false) if (l > 0) { jl_value_t *t0 = jl_svecref(t, 0); if (!jl_is_concrete_type(t0)) { - if (allow_va && jl_is_vararg_type(t0) && + if (allow_va && jl_is_vararg(t0) && jl_is_concrete_type(jl_unwrap_vararg(t0))) return true; return false; } for (i = 1; i < l; i++) { - if (allow_va && i == l - 1 && jl_is_vararg_type(jl_svecref(t, i))) { + if (allow_va && i == l - 1 && jl_is_vararg(jl_svecref(t, i))) { if (t0 != jl_unwrap_vararg(jl_svecref(t, i))) return false; continue; diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index 43fd8408ba750..e6af4e6647fdc 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -752,6 +752,7 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.endswith_lower("jl_task_t") || Name.endswith_lower("jl_uniontype_t") || Name.endswith_lower("jl_method_match_t") || + Name.endswith_lower("jl_vararg_t") || // Probably not technically true for these, but let's allow // it Name.endswith_lower("typemap_intersection_env") || diff --git a/src/codegen.cpp b/src/codegen.cpp index a4359a50abe6c..0b9dc4aa9deed 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -265,7 +265,7 @@ static bool type_has_unique_rep(jl_value_t *t) return true; if (jl_is_datatype(t)) { jl_datatype_t *dt = (jl_datatype_t*)t; - if (dt->name != jl_tuple_typename && !jl_is_vararg_type(t)) { + if (dt->name != jl_tuple_typename) { for (size_t i = 0; i < jl_nparams(dt); i++) if (!type_has_unique_rep(jl_tparam(dt, i))) return false; @@ -1732,7 +1732,7 @@ static std::pair uses_specsig(jl_method_instance_t *lam, jl_value_t if (jl_nparams(sig) == 0) return std::make_pair(false, false); if (va) { - if (jl_is_vararg_type(jl_tparam(sig, jl_nparams(sig) - 1))) + if (jl_is_vararg(jl_tparam(sig, jl_nparams(sig) - 1))) return std::make_pair(false, false); } // not invalid, consider if specialized signature is worthwhile @@ -2996,7 +2996,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (obj.ispointer()) { // Determine which was the type that was homogenous jl_value_t *jt = jl_tparam0(utt); - if (jl_is_vararg_type(jt)) + if (jl_is_vararg(jt)) jt = jl_unwrap_vararg(jt); Value *vidx = emit_unbox(ctx, T_size, fld, (jl_value_t*)jl_long_type); // This is not necessary for correctness, but allows to omit @@ -5255,7 +5255,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con // some sanity checking and check whether there's a vararg size_t nargt = jl_svec_len(argt); - bool isVa = (nargt > 0 && jl_is_vararg_type(jl_svecref(argt, nargt - 1))); + bool isVa = (nargt > 0 && jl_is_vararg(jl_svecref(argt, nargt - 1))); if (isVa) { emit_error(ctx, "cfunction: Vararg syntax not allowed for argument list"); return jl_cgval_t(); diff --git a/src/dump.c b/src/dump.c index 654d47f35a18a..c2e27fd4dbe30 100644 --- a/src/dump.c +++ b/src/dump.c @@ -2637,7 +2637,8 @@ void jl_init_serializer(void) jl_bool_type, jl_linenumbernode_type, jl_pinode_type, jl_upsilonnode_type, jl_type_type, jl_bottom_type, jl_ref_type, - jl_pointer_type, jl_vararg_type, jl_abstractarray_type, jl_nothing_type, + jl_pointer_type, jl_abstractarray_type, jl_nothing_type, + jl_vararg_type, jl_densearray_type, jl_function_type, jl_typename_type, jl_builtin_type, jl_task_type, jl_uniontype_type, jl_array_any_type, jl_intrinsic_type, diff --git a/src/gf.c b/src/gf.c index eb4bdb3b314d5..aff0d6eca6c0b 100644 --- a/src/gf.c +++ b/src/gf.c @@ -530,7 +530,7 @@ jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i) JL_NOTSAFEPOINT return NULL; if (i < len-1) return jl_tparam(sig, i); - if (jl_is_vararg_type(jl_tparam(sig, len-1))) + if (jl_is_vararg(jl_tparam(sig, len-1))) return jl_unwrap_vararg(jl_tparam(sig, len-1)); if (i == len-1) return jl_tparam(sig, i); @@ -633,6 +633,10 @@ static void jl_compilation_sig( } } + if (jl_is_vararg(elt)) { + continue; + } + if (jl_types_equal(elt, (jl_value_t*)jl_type_type)) { // elt == Type{T} where T // not triggered for isdispatchtuple(tt), this attempts to handle // some cases of adapting a random signature into a compilation signature @@ -738,7 +742,10 @@ static void jl_compilation_sig( size_t j = i; int all_are_subtypes = 1; for (; j < jl_svec_len(*newparams); j++) { - if (!jl_subtype(jl_svecref(*newparams, j), lasttype)) { + jl_value_t *paramj = jl_svecref(*newparams, j); + if (jl_is_vararg(paramj)) + paramj = jl_unwrap_vararg(paramj); + if (!jl_subtype(paramj, lasttype)) { all_are_subtypes = 0; break; } @@ -752,7 +759,7 @@ static void jl_compilation_sig( else { jl_value_t *unw = jl_unwrap_unionall(decl); jl_value_t *lastdeclt = jl_tparam(unw, nargs - 1); - assert(jl_is_vararg_type(lastdeclt) && jl_nparams(unw) == nargs); + assert(jl_is_vararg(lastdeclt) && jl_nparams(unw) == nargs); int nsp = jl_svec_len(sparams); if (nsp > 0 && jl_has_free_typevars(lastdeclt)) { assert(jl_subtype_env_size(decl) == nsp); @@ -813,7 +820,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig( nspec_max = nspec_min; } int isbound = (jl_va_tuple_kind((jl_datatype_t*)decl) == JL_VARARG_UNBOUND); - if (jl_is_vararg_type(jl_tparam(type, np - 1))) { + if (jl_is_vararg(jl_tparam(type, np - 1))) { if (!isbound || np < nspec_min || np > nspec_max) return 0; } @@ -822,7 +829,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig( return 0; } } - else if (np != nargs || jl_is_vararg_type(jl_tparam(type, np - 1))) { + else if (np != nargs || jl_is_vararg(jl_tparam(type, np - 1))) { return 0; } @@ -831,7 +838,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig( jl_value_t *decl_i = jl_nth_slot_type((jl_value_t*)decl, i); size_t i_arg = (i < nargs - 1 ? i : nargs - 1); - if (jl_is_vararg_type(elt)) { + if (jl_is_vararg(elt)) { elt = jl_unwrap_vararg(elt); if (jl_has_free_typevars(decl_i)) { // TODO: in this case, answer semi-conservatively that these varargs are always compilable @@ -955,7 +962,7 @@ static int concretesig_equal(jl_value_t *tt, jl_value_t *simplesig) JL_NOTSAFEPO jl_value_t **sigs = jl_svec_data(((jl_datatype_t*)simplesig)->parameters); size_t i, lensig = jl_nparams(simplesig); assert(lensig == jl_nparams(tt)); - assert(lensig > 0 && !jl_is_vararg_type(jl_tparam(simplesig, lensig - 1))); + assert(lensig > 0 && !jl_is_vararg(jl_tparam(simplesig, lensig - 1))); for (i = 0; i < lensig; i++) { jl_value_t *decl = sigs[i]; jl_value_t *a = types[i]; @@ -1047,7 +1054,8 @@ static jl_method_instance_t *cache_method( jl_svec_t *env = matc->sparams; int k, l; for (k = 0, l = jl_svec_len(env); k < l; k++) { - if (jl_is_typevar(jl_svecref(env, k))) { + jl_value_t *env_k = jl_svecref(env, k); + if (jl_is_typevar(env_k) || jl_is_vararg(env_k)) { unmatched_tvars = 1; break; } @@ -1104,7 +1112,7 @@ static jl_method_instance_t *cache_method( newparams = NULL; for (i = 0; i < np; i++) { jl_value_t *elt = jl_svecref(cachett->parameters, i); - if (jl_is_vararg_type(elt)) { + if (jl_is_vararg(elt)) { } else if (jl_is_type_type(elt)) { // TODO: if (!jl_is_singleton(elt)) ... @@ -1225,7 +1233,7 @@ static jl_value_t *get_intersect_matches(jl_typemap_t *defs, jl_typemap_entry_t jl_value_t *va = NULL; if (l > 0) { va = jl_tparam(ttypes, l - 1); - if (jl_is_vararg_type(va)) + if (jl_is_vararg(va)) va = jl_unwrap_vararg(va); else va = NULL; @@ -2668,7 +2676,7 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, int offs, jl_value_t *va = NULL; if (l > 0) { va = jl_tparam(unw, l - 1); - if (jl_is_vararg_type(va)) + if (jl_is_vararg(va)) va = jl_unwrap_vararg(va); else va = NULL; @@ -3125,7 +3133,7 @@ int jl_has_concrete_subtype(jl_value_t *typ) if (typ == jl_bottom_type) return 0; typ = jl_unwrap_unionall(typ); - if (jl_is_vararg_type(typ)) + if (jl_is_vararg(typ)) typ = jl_unwrap_vararg(typ); if (!jl_is_datatype(typ)) return 1; diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index d36b1e67440ba..ee09992c6a584 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -111,7 +111,6 @@ XX(jl_uniontype_type) \ XX(jl_upsilonnode_type) \ XX(jl_vararg_type) \ - XX(jl_vararg_typename) \ XX(jl_vecelement_typename) \ XX(jl_void_type) \ XX(jl_voidpointer_type) \ diff --git a/src/jltypes.c b/src/jltypes.c index 2599b47f744c1..0166430671bb1 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -43,6 +43,14 @@ static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT if (jl_is_uniontype(v)) return has_free_typevars(((jl_uniontype_t*)v)->a, env) || has_free_typevars(((jl_uniontype_t*)v)->b, env); + if (jl_is_vararg(v)) { + jl_vararg_t *vm = (jl_vararg_t*)v; + if (vm->T) { + if (has_free_typevars(vm->T, env)) + return 1; + return vm->N && has_free_typevars(vm->N, env); + } + } if (jl_is_unionall(v)) { jl_unionall_t *ua = (jl_unionall_t*)v; jl_typeenv_t newenv = { ua->var, NULL, env }; @@ -79,6 +87,15 @@ static void find_free_typevars(jl_value_t *v, jl_typeenv_t *env, jl_array_t *out find_free_typevars(((jl_uniontype_t*)v)->a, env, out); find_free_typevars(((jl_uniontype_t*)v)->b, env, out); } + else if (jl_is_vararg(v)) { + jl_vararg_t *vm = (jl_vararg_t *)v; + if (vm->T) { + find_free_typevars(vm->T, env, out); + if (vm->N) { + find_free_typevars(vm->N, env, out); + } + } + } else if (jl_is_unionall(v)) { jl_unionall_t *ua = (jl_unionall_t*)v; jl_typeenv_t newenv = { ua->var, NULL, env }; @@ -112,6 +129,11 @@ static int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOI if (jl_is_uniontype(v)) return jl_has_bound_typevars(((jl_uniontype_t*)v)->a, env) || jl_has_bound_typevars(((jl_uniontype_t*)v)->b, env); + if (jl_is_vararg(v)) { + jl_vararg_t *vm = (jl_vararg_t *)v; + return vm->T && (jl_has_bound_typevars(vm->T, env) || + (vm->N && jl_has_bound_typevars(vm->N, env))); + } if (jl_is_unionall(v)) { jl_unionall_t *ua = (jl_unionall_t*)v; if (jl_has_bound_typevars(ua->var->lb, env) || jl_has_bound_typevars(ua->var->ub, env)) @@ -359,7 +381,7 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) size_t i; for(i=0; i < n; i++) { jl_value_t *pi = ts[i]; - if (!(jl_is_type(pi) || jl_is_typevar(pi)) || jl_is_vararg_type(pi)) + if (!(jl_is_type(pi) || jl_is_typevar(pi))) jl_type_error("Union", (jl_value_t*)jl_type_type, pi); } if (n == 1) return ts[0]; @@ -407,6 +429,34 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) { + if (jl_is_vararg(body)) { + if (jl_options.depwarn) { + if (jl_options.depwarn == JL_OPTIONS_DEPWARN_ERROR) + jl_error("Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead)."); + jl_printf(JL_STDERR, "WARNING: Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead)."); + } + jl_vararg_t *vm = (jl_vararg_t*)body; + int T_has_tv = vm->T && jl_has_typevar(vm->T, v); + int N_has_tv = vm->N && jl_has_typevar(vm->N, v); + if (!T_has_tv && !N_has_tv) { + return body; + } + if (T_has_tv && N_has_tv) { + jl_error("Wrapping `Vararg` directly in UnionAll is disallowed if the typevar occurs in both `T` and `N`"); + } + if (T_has_tv) { + jl_value_t *wrapped = jl_type_unionall(v, vm->T); + JL_GC_PUSH1(&wrapped); + wrapped = (jl_value_t*)jl_wrap_vararg(wrapped, vm->N); + JL_GC_POP(); + return wrapped; + } + else { + assert(N_has_tv); + assert(vm->N == (jl_value_t*)v); + return (jl_value_t*)jl_wrap_vararg(vm->T, NULL); + } + } if (!jl_is_type(body) && !jl_is_typevar(body)) jl_type_error("UnionAll", (jl_value_t*)jl_type_type, body); // normalize `T where T<:S` => S @@ -579,7 +629,7 @@ static ssize_t lookup_type_idx_linearvalue(jl_svec_t *cache, jl_value_t *key1, j return ~cl; } -static jl_value_t *lookup_type(jl_typename_t *tn, jl_value_t **key, size_t n) +static jl_value_t *lookup_type(jl_typename_t *tn JL_PROPAGATES_ROOT, jl_value_t **key, size_t n) { JL_TIMING(TYPE_CACHE_LOOKUP); unsigned hv = typekey_hash(tn, key, n, 0); @@ -966,6 +1016,15 @@ static unsigned type_hash(jl_value_t *kj, int *failed) JL_NOTSAFEPOINT // ignore var and lb, since those might get normalized out in equality testing return type_hash(((jl_tvar_t*)uw)->ub, failed); } + else if (jl_is_vararg(uw)) { + if (!*failed) { + *failed = 1; + return 0; + } + jl_vararg_t *vm = (jl_vararg_t *)uw; + // 0x064eeaab is just a randomly chosen constant + return bitmix(type_hash(vm->T ? vm->T : (jl_value_t*)jl_any_type, failed), vm->N ? type_hash(vm->N, failed) : 0x064eeaab); + } else if (jl_is_uniontype(uw)) { if (!*failed) { *failed = 1; @@ -1025,8 +1084,6 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) dt->hasfreetypevars = 0; dt->isconcretetype = !dt->abstract; dt->isdispatchtuple = istuple; - if (dt->name == jl_vararg_typename) - dt->isconcretetype = 0; size_t i, l = jl_nparams(dt); for (i = 0; i < l; i++) { jl_value_t *p = jl_tparam(dt, i); @@ -1096,30 +1153,6 @@ static jl_value_t *extract_wrapper(jl_value_t *t JL_PROPAGATES_ROOT) JL_GLOBALLY return NULL; } -// convert `Vararg{X, Y} where T` to `Vararg{X where T, Y}` where T doesn't occur free in Y -static jl_value_t *normalize_vararg(jl_value_t *va) -{ - assert(jl_is_vararg_type(va)); - if (!jl_is_unionall(va)) return va; - jl_value_t *body=NULL; - JL_GC_PUSH2(&va, &body); - jl_unionall_t *ua = (jl_unionall_t*)va; - body = normalize_vararg(ua->body); - jl_value_t *unw = jl_unwrap_unionall(body); - jl_value_t *va0 = jl_tparam0(unw), *va1 = jl_tparam1(unw); - if (jl_has_typevar(va1, ua->var)) { - if (body != ua->body) - va = jl_type_unionall(ua->var, body); - } - else { - va = jl_type_unionall(ua->var, va0); - va = jl_wrap_vararg(va, va1); - va = jl_rewrap_unionall(va, body); - } - JL_GC_POP(); - return va; -} - static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack); static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, @@ -1138,7 +1171,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value continue; if (jl_is_datatype(pi)) continue; - if (jl_is_vararg_type(pi)) { + if (jl_is_vararg(pi)) { pi = jl_unwrap_vararg(pi); if (jl_has_free_typevars(pi)) continue; @@ -1149,7 +1182,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_types_equal(pi, tw)) { // This would require some special handling, but is never used at // the moment. - assert(!jl_is_vararg_type(iparams[i])); + assert(!jl_is_vararg(iparams[i])); iparams[i] = tw; if (p) jl_gc_wb(p, tw); } @@ -1163,20 +1196,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value return stack_lkup; if (!istuple) { - if (jl_is_vararg_type((jl_value_t*)dt) && ntp == 2) { - jl_value_t *lenparam = iparams[1]; - if (jl_is_typevar(lenparam)) { - jl_tvar_t *N = (jl_tvar_t*)lenparam; - if (!(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) - jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); - } - else if (!jl_is_long(lenparam)) { - jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, lenparam); - } - else if (jl_unbox_long(lenparam) < 0) { - jl_errorf("Vararg length is negative: %zd", jl_unbox_long(lenparam)); - } - } // check parameters against bounds in type definition check_datatype_parameters(tn, iparams, ntp); } @@ -1190,29 +1209,17 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value JL_GC_PUSH3(&p, &ndt, &last); int isvatuple = 0; - if (istuple && ntp > 0 && jl_is_vararg_type(last)) { + if (istuple && ntp > 0 && jl_is_vararg(last)) { isvatuple = 1; // normalize Tuple{..., Vararg{Int, 3}} to Tuple{..., Int, Int, Int} jl_value_t *va = jl_unwrap_unionall(last); - jl_value_t *va0 = jl_tparam0(va), *va1 = jl_tparam1(va); + jl_value_t *va0 = jl_unwrap_vararg(va), *va1 = jl_unwrap_vararg_num(va); // return same `Tuple` object for types equal to it - if (ntp == 1 && - (last == (jl_value_t*)jl_vararg_type || // Tuple{Vararg} == Tuple - (va0 == (jl_value_t*)jl_any_type && - jl_is_unionall(last) && va1 == (jl_value_t*)((jl_unionall_t*)last)->var))) { + if (ntp == 1 && va0 == (jl_value_t*)jl_any_type && !va1) { JL_GC_POP(); return (jl_value_t*)jl_anytuple_type; } - int did_normalize = 0; - jl_value_t *last2 = normalize_vararg(last); - assert(!jl_is_unionall(last2) || !jl_is_unionall(((jl_unionall_t*)last2)->body)); - if (last2 != last) { - last = last2; - did_normalize = 1; - va = jl_unwrap_unionall(last); - va0 = jl_tparam0(va); va1 = jl_tparam1(va); - } - if (jl_is_long(va1)) { + if (va1 && jl_is_long(va1)) { ssize_t nt = jl_unbox_long(va1); assert(nt >= 0); if (nt == 0 || !jl_has_free_typevars(va0)) { @@ -1232,12 +1239,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value return ndt; } } - if (did_normalize) { - p = jl_alloc_svec(ntp); - for (size_t i = 0; i < ntp-1; i++) - jl_svecset(p, i, iparams[i]); - jl_svecset(p, ntp-1, last); - } } // move array of instantiated parameters to heap; we need to keep it @@ -1462,8 +1463,8 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ // a fixed-length tuple jl_value_t *T=NULL, *N=NULL; jl_value_t *va = jl_unwrap_unionall(jl_tparam0(tt)); - jl_value_t *ttT = jl_tparam0(va); - jl_value_t *ttN = jl_tparam1(va); + jl_value_t *ttT = jl_unwrap_vararg(va); + jl_value_t *ttN = jl_unwrap_vararg_num(va); jl_typeenv_t *e = env; while (e != NULL) { if ((jl_value_t*)e->var == ttT) @@ -1563,6 +1564,22 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t JL_GC_POP(); return t; } + if (jl_is_vararg(t)) { + jl_vararg_t *v = (jl_vararg_t*)t; + jl_value_t *T = NULL; + jl_value_t *N = NULL; + JL_GC_PUSH2(&T, &N); + if (v->T) { + T = inst_type_w_(v->T, env, stack, check); + if (v->N) + N = inst_type_w_(v->N, env, stack, check); + } + if (T != v->T || N != v->N) { + t = (jl_value_t*)jl_wrap_vararg(T, N); + } + JL_GC_POP(); + return t; + } if (!jl_is_datatype(t)) return t; jl_datatype_t *tt = (jl_datatype_t*)t; @@ -1633,19 +1650,31 @@ jl_datatype_t *jl_wrap_Type(jl_value_t *t) return (jl_datatype_t*)jl_instantiate_unionall(jl_type_type, t); } -jl_value_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) { - if (t == NULL) { - assert(n == NULL); - return (jl_value_t*)jl_vararg_type; + if (n) { + if (jl_is_typevar(n)) { + jl_tvar_t *N = (jl_tvar_t*)n; + if (!(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) + jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); + } + else if (!jl_is_long(n)) { + jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, n); + } + else if (jl_unbox_long(n) < 0) { + jl_errorf("Vararg length is negative: %zd", jl_unbox_long(n)); + } } - jl_value_t *vt = jl_instantiate_unionall(jl_vararg_type, t); - if (n == NULL) - return vt; - JL_GC_PUSH1(&vt); - jl_value_t *vn = jl_instantiate_unionall((jl_unionall_t*)vt, n); - JL_GC_POP(); - return vn; + if (t) { + if (!jl_valid_type_param(t)) { + jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); + } + } + jl_ptls_t ptls = jl_get_ptls_states(); + jl_vararg_t *vm = (jl_vararg_t *)jl_gc_alloc(ptls, sizeof(jl_vararg_t), jl_vararg_type); + vm->T = t; + vm->N = n; + return vm; } JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st JL_PROPAGATES_ROOT, void *stack) @@ -1889,10 +1918,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_svec(2, jl_tvar_type, jl_any_type), 0, 0, 2); - jl_svec_t *tv; - tv = jl_svec2(tvar("T"),tvar("N")); - jl_vararg_type = (jl_unionall_t*)jl_new_abstracttype((jl_value_t*)jl_symbol("Vararg"), core, jl_any_type, tv)->name->wrapper; - jl_vararg_typename = ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_vararg_type))->name; + jl_vararg_type = jl_new_datatype(jl_symbol("TypeofVararg"), core, jl_any_type, jl_emptysvec, + jl_perm_symsvec(2, "T", "N"), + jl_svec(2, jl_any_type, jl_any_type), + 0, 0, 0); jl_svec_t *anytuple_params = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL)); jl_anytuple_type = jl_new_datatype(jl_symbol("Tuple"), core, jl_any_type, anytuple_params, @@ -2014,7 +2043,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_function_type->name->mt = NULL; // subtypes of Function have independent method tables jl_builtin_type->name->mt = NULL; // so they don't share the Any type table - tv = jl_svec2(tvar("T"), tvar("N")); + jl_svec_t *tv = jl_svec2(tvar("T"), tvar("N")); jl_abstractarray_type = (jl_unionall_t*) jl_new_abstracttype((jl_value_t*)jl_symbol("AbstractArray"), core, jl_any_type, tv)->name->wrapper; diff --git a/src/julia.h b/src/julia.h index 63b58b7d3e009..66d32af6c4709 100644 --- a/src/julia.h +++ b/src/julia.h @@ -481,6 +481,12 @@ typedef struct _jl_datatype_t { uint8_t cached_by_hash; // stored in hash-based set cache (instead of linear cache) } jl_datatype_t; +typedef struct _jl_vararg_t { + JL_DATA_TYPE + jl_value_t *T; + jl_value_t *N; +} jl_vararg_t; + typedef struct { JL_DATA_TYPE jl_value_t *value; @@ -621,8 +627,7 @@ extern JL_DLLIMPORT jl_datatype_t *jl_anytuple_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_emptytuple_type JL_GLOBALLY_ROOTED; #define jl_tuple_type jl_anytuple_type extern JL_DLLIMPORT jl_unionall_t *jl_anytuple_type_type JL_GLOBALLY_ROOTED; -extern JL_DLLIMPORT jl_unionall_t *jl_vararg_type JL_GLOBALLY_ROOTED; -extern JL_DLLIMPORT jl_typename_t *jl_vararg_typename JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_vararg_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_function_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_builtin_type JL_GLOBALLY_ROOTED; diff --git a/src/julia_internal.h b/src/julia_internal.h index 21bdbc85ec901..ee60f5f95e389 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -422,6 +422,8 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); void jl_resolve_globals_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, int binding_effects); +int jl_valid_type_param(jl_value_t *v); + JL_DLLEXPORT jl_value_t *jl_apply_2va(jl_value_t *f, jl_value_t **args, uint32_t nargs); void JL_NORETURN jl_method_error(jl_function_t *f, jl_value_t **args, size_t na, size_t world); @@ -482,7 +484,7 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_module_t *module, jl_datatype_t *jl_new_uninitialized_datatype(void); void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable); jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x} -jl_value_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n); +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n); void jl_reinstantiate_inner_types(jl_datatype_t *t); jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type); void jl_cache_type_(jl_datatype_t *type); @@ -541,51 +543,49 @@ typedef enum { JL_VARARG_UNBOUND = 3 } jl_vararg_kind_t; -STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) JL_NOTSAFEPOINT +STATIC_INLINE int jl_is_vararg(jl_value_t *v) JL_NOTSAFEPOINT { - v = jl_unwrap_unionall(v); - return (jl_is_datatype(v) && - ((jl_datatype_t*)(v))->name == jl_vararg_typename); + return jl_typeof(v) == (jl_value_t*)jl_vararg_type; } -STATIC_INLINE jl_value_t *jl_unwrap_vararg(jl_value_t *v) JL_NOTSAFEPOINT +STATIC_INLINE jl_value_t *jl_unwrap_vararg(jl_vararg_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - return jl_tparam0(jl_unwrap_unionall(v)); + assert(jl_is_vararg((jl_value_t*)v)); + jl_value_t *T = ((jl_vararg_t*)v)->T; + return T ? T : (jl_value_t*)jl_any_type; } +#define jl_unwrap_vararg(v) (jl_unwrap_vararg)((jl_vararg_t *)v) + +STATIC_INLINE jl_value_t *jl_unwrap_vararg_num(jl_vararg_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + assert(jl_is_vararg((jl_value_t*)v)); + return ((jl_vararg_t*)v)->N; +} +#define jl_unwrap_vararg_num(v) (jl_unwrap_vararg_num)((jl_vararg_t *)v) STATIC_INLINE jl_vararg_kind_t jl_vararg_kind(jl_value_t *v) JL_NOTSAFEPOINT { - if (!jl_is_vararg_type(v)) + if (!jl_is_vararg(v)) return JL_VARARG_NONE; - jl_tvar_t *v1=NULL, *v2=NULL; - if (jl_is_unionall(v)) { - v1 = ((jl_unionall_t*)v)->var; - v = ((jl_unionall_t*)v)->body; - if (jl_is_unionall(v)) { - v2 = ((jl_unionall_t*)v)->var; - v = ((jl_unionall_t*)v)->body; - } - } - assert(jl_is_datatype(v)); - jl_value_t *lenv = jl_tparam1(v); - if (jl_is_long(lenv)) + jl_vararg_t *vm = (jl_vararg_t *)v; + if (!vm->N) + return JL_VARARG_UNBOUND; + if (jl_is_long(vm->N)) return JL_VARARG_INT; - if (jl_is_typevar(lenv) && lenv != (jl_value_t*)v1 && lenv != (jl_value_t*)v2) - return JL_VARARG_BOUND; - return JL_VARARG_UNBOUND; + return JL_VARARG_BOUND; } STATIC_INLINE int jl_is_va_tuple(jl_datatype_t *t) JL_NOTSAFEPOINT { assert(jl_is_tuple_type(t)); size_t l = jl_svec_len(t->parameters); - return (l>0 && jl_is_vararg_type(jl_tparam(t,l-1))); + return (l>0 && jl_is_vararg(jl_tparam(t,l-1))); } STATIC_INLINE size_t jl_vararg_length(jl_value_t *v) JL_NOTSAFEPOINT { - assert(jl_is_vararg_type(v)); - jl_value_t *len = jl_tparam1(jl_unwrap_unionall(v)); + assert(jl_is_vararg(v)); + jl_value_t *len = jl_unwrap_vararg_num(v); assert(jl_is_long(len)); return jl_unbox_long(len); } diff --git a/src/method.c b/src/method.c index 6ba2600f618b8..6df9a9afdce7c 100644 --- a/src/method.c +++ b/src/method.c @@ -711,7 +711,7 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_svec_t *tvars = (jl_svec_t*)jl_svecref(argdata, 1); jl_value_t *functionloc = jl_svecref(argdata, 2); size_t nargs = jl_svec_len(atypes); - int isva = jl_is_vararg_type(jl_svecref(atypes, nargs - 1)); + int isva = jl_is_vararg(jl_svecref(atypes, nargs - 1)); assert(jl_is_svec(atypes)); assert(nargs > 0); assert(jl_is_svec(tvars)); @@ -780,7 +780,7 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, for (i = 0; i < na; i++) { jl_value_t *elt = jl_svecref(atypes, i); - if (!jl_is_type(elt) && !jl_is_typevar(elt)) { + if (!jl_is_type(elt) && !jl_is_typevar(elt) && !jl_is_vararg(elt)) { jl_sym_t *argname = (jl_sym_t*)jl_array_ptr_ref(f->slotnames, i); if (argname == unused_sym) jl_exceptionf(jl_argumenterror_type, @@ -797,7 +797,7 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_symbol_name(m->file), m->line); } - if (jl_is_vararg_type(elt) && i < na-1) + if (jl_is_vararg(elt) && i < na-1) jl_exceptionf(jl_argumenterror_type, "Vararg on non-final argument in method definition for %s at %s:%d", jl_symbol_name(name), diff --git a/src/rtutils.c b/src/rtutils.c index 5ac68510ae392..77d202c3f4a89 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -734,6 +734,19 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt // avoid printing `typeof(Type)` for `UnionAll`. n += jl_printf(out, "UnionAll"); } + else if (vt == jl_vararg_type) { + jl_vararg_t *vm = (jl_vararg_t*)v; + n += jl_printf(out, "Vararg"); + if (vm->T) { + n += jl_printf(out, "{"); + n += jl_static_show_x(out, vm->T, depth); + if (vm->N) { + n += jl_printf(out, ", "); + n += jl_static_show_x(out, vm->N, depth); + } + n += jl_printf(out, "}"); + } + } else if (vt == jl_datatype_type) { // typeof(v) == DataType, so v is a Type object. // Types are printed as a fully qualified name, with parameters, e.g. @@ -1215,7 +1228,7 @@ JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) JL_N n += jl_printf(s, ", "); } else { - if (jl_is_vararg_type(tp)) { + if (jl_is_vararg(tp)) { n += jl_static_show(s, jl_unwrap_vararg(tp)); n += jl_printf(s, "..."); } diff --git a/src/staticdata.c b/src/staticdata.c index 64a2063fff843..d8d4b50468cdc 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -30,7 +30,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 146 +#define NUM_TAGS 145 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -131,7 +131,6 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_llvmpointer_typename); INSERT_TAG(jl_array_typename); INSERT_TAG(jl_type_typename); - INSERT_TAG(jl_vararg_typename); INSERT_TAG(jl_namedtuple_typename); INSERT_TAG(jl_vecelement_typename); diff --git a/src/subtype.c b/src/subtype.c index 30fdefc5bf20f..eabe0e2a0f1e2 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -222,6 +222,12 @@ static int obviously_egal(jl_value_t *a, jl_value_t *b) return ((jl_unionall_t*)a)->var == ((jl_unionall_t*)b)->var && obviously_egal(((jl_unionall_t*)a)->body, ((jl_unionall_t*)b)->body); } + if (jl_is_vararg(a)) { + jl_vararg_t *vma = (jl_vararg_t *)a; + jl_vararg_t *vmb = (jl_vararg_t *)b; + return obviously_egal(jl_unwrap_vararg(vma), jl_unwrap_vararg(vmb)) && + ((!vma->N && !vmb->N) || (vma->N && vmb->N && obviously_egal(vma->N, vmb->N))); + } if (jl_is_typevar(a)) return 0; return !jl_is_type(a) && jl_egal(a,b); } @@ -719,7 +725,9 @@ static int with_tvar(tvar_callback callback, void *context, jl_unionall_t *u, in // fill variable values into `envout` up to `envsz` if (e->envidx < e->envsz) { jl_value_t *val; - if (!vb.occurs_inv && vb.lb != jl_bottom_type) + if (vb.intvalued && vb.lb == (jl_value_t*)jl_any_type) + val = (jl_value_t*)jl_wrap_vararg(NULL, NULL); + else if (!vb.occurs_inv && vb.lb != jl_bottom_type) val = is_leaf_bound(vb.lb) ? vb.lb : (jl_value_t*)jl_new_typevar(u->var->name, jl_bottom_type, vb.lb); else if (vb.lb == vb.ub) val = vb.lb; @@ -841,26 +849,12 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 return res; } -// unwrap <=1 layers of UnionAlls, leaving the var in *p1 the body -static jl_datatype_t *unwrap_1_unionall(jl_value_t *t, jl_tvar_t **p1) JL_NOTSAFEPOINT -{ - assert(t); - if (jl_is_unionall(t)) { - *p1 = ((jl_unionall_t*)t)->var; - t = ((jl_unionall_t*)t)->body; - } - assert(jl_is_datatype(t)); - return (jl_datatype_t*)t; -} - // check n <: (length of vararg type v) static int check_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e) { - jl_tvar_t *va_p1=NULL; - jl_datatype_t *tail = unwrap_1_unionall(v, &va_p1); - jl_value_t *N = jl_tparam1(tail); + jl_value_t *N = jl_unwrap_vararg_num(v); // only do the check if N is free in the tuple type's last parameter - if (N != (jl_value_t*)va_p1) { + if (N) { jl_value_t *nn = jl_box_long(n); JL_GC_PUSH1(&nn); e->invdepth++; @@ -890,28 +884,25 @@ struct subtype_tuple_env { static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, int param) { - jl_tvar_t *yv1=NULL; - jl_datatype_t *yva = unwrap_1_unionall(env->vty, &yv1); - jl_tvar_t *xv1=NULL; - jl_datatype_t *xva = unwrap_1_unionall(env->vtx, &xv1); - - jl_value_t *xp0 = jl_tparam0(xva); jl_value_t *xp1 = jl_tparam1(xva); - jl_value_t *yp0 = jl_tparam0(yva); jl_value_t *yp1 = jl_tparam1(yva); + jl_value_t *xp0 = jl_unwrap_vararg(env->vtx); jl_value_t *xp1 = jl_unwrap_vararg_num(env->vtx); + jl_value_t *yp0 = jl_unwrap_vararg(env->vty); jl_value_t *yp1 = jl_unwrap_vararg_num(env->vty); - if (!jl_is_datatype(env->vtx)) { - // Unconstrained on the left, constrained on the right + if (!xp1) { jl_value_t *yl = yp1; - if (jl_is_typevar(yl)) { - jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl); - if (ylv) - yl = ylv->lb; - } - if (jl_is_long(yl)) { - return 0; + if (yl) { + // Unconstrained on the left, constrained on the right + if (jl_is_typevar(yl)) { + jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl); + if (ylv) + yl = ylv->lb; + } + if (jl_is_long(yl)) { + return 0; + } } } else { - jl_value_t *xl = jl_tparam1(env->vtx); + jl_value_t *xl = jl_unwrap_vararg_num(env->vtx); if (jl_is_typevar(xl)) { jl_varbinding_t *xlv = lookup(e, (jl_tvar_t*)xl); if (xlv) @@ -922,15 +913,17 @@ static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, i // LHS is exhausted. We're a subtype if the RHS is either // exhausted as well or unbounded (in which case we need to // set it to 0). - if (jl_is_datatype(env->vty)) { - jl_value_t *yl = jl_tparam1(env->vty); - if (jl_is_typevar(yl)) { - jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl); - if (ylv) - yl = ylv->lb; - } - if (jl_is_long(yl)) { - return jl_unbox_long(yl) + 1 == env->vy; + if (jl_is_vararg(env->vty)) { + jl_value_t *yl = jl_unwrap_vararg_num(env->vty); + if (yl) { + if (jl_is_typevar(yl)) { + jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl); + if (ylv) + yl = ylv->lb; + } + if (jl_is_long(yl)) { + return jl_unbox_long(yl) + 1 == env->vy; + } } } else { @@ -950,10 +943,14 @@ static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, i if (!subtype(xp0, yp0, e, 1)) return 0; constrain_length: - if (!jl_is_datatype(env->vtx)) { + if (!yp1) { + return 1; + } + if (!xp1) { jl_value_t *yl = yp1; + jl_varbinding_t *ylv = NULL; if (jl_is_typevar(yl)) { - jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl); + ylv = lookup(e, (jl_tvar_t*)yl); if (ylv) yl = ylv->lb; } @@ -963,13 +960,27 @@ static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, i // as a result of the subtype call above). return 0; } + + if (ylv) { + if (ylv->depth0 != e->invdepth || ylv->occurs_inv) + return 0; + ylv->intvalued = 1; + } + // set lb to Any. Since `intvalued` is set, we'll interpret that + // appropriately. + e->invdepth++; + e->Rinvdepth++; + int ans = subtype((jl_value_t*)jl_any_type, yp1, e, 2); + e->invdepth--; + e->Rinvdepth--; + return ans; } // Vararg{T,N} <: Vararg{T2,N2}; equate N and N2 e->invdepth++; e->Rinvdepth++; JL_GC_PUSH2(&xp1, &yp1); - if (jl_is_long(xp1) && env->vx != 1) + if (xp1 && jl_is_long(xp1) && env->vx != 1) xp1 = jl_box_long(jl_unbox_long(xp1) - env->vx + 1); if (jl_is_long(yp1) && env->vy != 1) yp1 = jl_box_long(jl_unbox_long(yp1) - env->vy + 1); @@ -1050,7 +1061,7 @@ static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_ } if (env->vx) { - xi = jl_tparam0(jl_unwrap_unionall(env->vtx)); + xi = jl_unwrap_vararg(env->vtx); if (env->j >= env->ly) return 1; } @@ -1059,7 +1070,7 @@ static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_ } int x_same = env->lastx && jl_egal(xi, env->lastx); if (env->vy) { - yi = jl_tparam0(jl_unwrap_unionall(env->vty)); + yi = jl_unwrap_vararg(env->vty); if (!env->vvx && yi == (jl_value_t*)jl_any_type) goto done; // if y ends in `Vararg{Any}` skip checking everything // keep track of number of consecutive identical types compared to Vararg @@ -1095,7 +1106,7 @@ static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_ // } (from loop:) done: - if (!env->vy && env->j < env->ly && jl_is_vararg_type(jl_tparam(env->yd, env->j))) + if (!env->vy && env->j < env->ly && jl_is_vararg(jl_tparam(env->yd, env->j))) env->vy += 1; if (env->vy && !env->vx && env->lx+1 >= env->ly) { // in Tuple{...,tn} <: Tuple{...,Vararg{T,N}}, check (lx+1-ly) <: N @@ -1121,7 +1132,7 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in if (env.lx > 0) { env.vvx = jl_vararg_kind(jl_tparam(env.xd, env.lx-1)); if (env.vvx == JL_VARARG_BOUND) - xbb = lookup(e, (jl_tvar_t *)jl_tparam1(jl_tparam(env.xd, env.lx - 1))); + xbb = lookup(e, (jl_tvar_t *)jl_unwrap_vararg_num(jl_tparam(env.xd, env.lx - 1))); } if (env.ly > 0) env.vvy = jl_vararg_kind(jl_tparam(env.yd, env.ly-1)); @@ -1170,24 +1181,6 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in return ans; } -static int subtype_naked_vararg(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, int param) -{ - // Vararg: covariant in first parameter, invariant in second - jl_value_t *xp1=jl_tparam0(xd), *xp2=jl_tparam1(xd), *yp1=jl_tparam0(yd), *yp2=jl_tparam1(yd); - // in Vararg{T1} <: Vararg{T2}, need to check subtype twice to - // simulate the possibility of multiple arguments, which is needed - // to implement the diagonal rule correctly. - if (!subtype(xp1, yp1, e, param)) return 0; - if (!subtype(xp1, yp1, e, 1)) return 0; - e->invdepth++; - e->Rinvdepth++; - // Vararg{T,N} <: Vararg{T2,N2}; equate N and N2 - int ans = forall_exists_equal(xp2, yp2, e); - e->invdepth--; - e->Rinvdepth--; - return ans; -} - // `param` means we are currently looking at a parameter of a type constructor // (as opposed to being outside any type constructor, or comparing variable bounds). // this is used to record the positions where type variables occur for the @@ -1283,6 +1276,7 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) } if (jl_is_unionall(y)) return subtype_unionall(x, (jl_unionall_t*)y, e, 1, param); + assert(!jl_is_vararg(x) && !jl_is_vararg(y)); if (jl_is_datatype(x) && jl_is_datatype(y)) { if (x == y) return 1; if (y == (jl_value_t*)jl_any_type) return 1; @@ -1321,13 +1315,6 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) if (xd == jl_any_type) return 0; if (xd->name == jl_tuple_typename) return subtype_tuple(xd, yd, e, param); - if (xd->name == jl_vararg_typename) { - // N.B.: This case is only used for raw varargs that are not part - // of a tuple (those that are have special handling in subtype_tuple). - // Vararg isn't really a proper type, but it does sometimes show up - // as e.g. Type{Vararg}, so we'd like to handle that correctly. - return subtype_naked_vararg(xd, yd, e, param); - } size_t i, np = jl_nparams(xd); int ans = 1; e->invdepth++; @@ -1510,6 +1497,8 @@ static int concrete_min(jl_value_t *t) return 0; // Type{T} may have the concrete supertype `typeof(T)`, so don't try to handle them here return jl_is_concrete_type(t) ? 1 : 2; } + if (jl_is_vararg(t)) + return 0; if (jl_is_typevar(t)) return 0; // could be 0 or more, since we didn't track if it was unbound if (jl_is_uniontype(t)) { @@ -1538,6 +1527,16 @@ static jl_value_t *find_var_body(jl_value_t *t, jl_tvar_t *v) if (b) return b; return find_var_body(((jl_uniontype_t*)t)->b, v); } + else if (jl_is_vararg(t)) { + jl_vararg_t *vm = (jl_vararg_t *)t; + if (vm->T) { + jl_value_t *b = find_var_body(vm->T, v); + if (b) return b; + if (vm->N) { + return find_var_body(vm->N, v); + } + } + } else if (jl_is_datatype(t)) { size_t i; for (i=0; i < jl_nparams(t); i++) { @@ -1594,6 +1593,13 @@ static int obvious_subtype(jl_value_t *x, jl_value_t *y, jl_value_t *y0, int *su *subtype = 0; return 1; } + if (jl_is_vararg(x)) { + if (!jl_is_vararg(y)) { + *subtype = 0; + return 1; + } + return 0; + } if (!jl_is_type(x) || !jl_is_type(y)) { *subtype = jl_egal(x, y); return 1; @@ -1635,7 +1641,7 @@ static int obvious_subtype(jl_value_t *x, jl_value_t *y, jl_value_t *y0, int *su } if (jl_is_datatype(y)) { int istuple = (((jl_datatype_t*)y)->name == jl_tuple_typename); - int iscov = istuple || (((jl_datatype_t*)y)->name == jl_vararg_typename); + int iscov = istuple; // TODO: this would be a nice fast-path to have, unfortuanately, // datatype allocation fails to correctly hash-cons them // and the subtyping tests include tests for this case @@ -2192,6 +2198,22 @@ static jl_value_t *set_var_to_const(jl_varbinding_t *bb, jl_value_t *v JL_MAYBE_ return v; } +static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_t *e) { + if (!bb) + return (jl_value_t*)tv; + if (bb->depth0 != e->invdepth) + return jl_bottom_type; + record_var_occurrence(bb, e, 2); + if (jl_is_long(bb->lb)) { + if (bb->offset == 0) + return bb->lb; + if (jl_unbox_long(bb->lb) < bb->offset) + return jl_bottom_type; + return jl_box_long(jl_unbox_long(bb->lb) - bb->offset); + } + return (jl_value_t*)tv; +} + static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e, int R, int d) { jl_value_t *root=NULL; jl_savedenv_t se; @@ -2391,13 +2413,19 @@ static int var_occurs_inside(jl_value_t *v, jl_tvar_t *var, int inside, int want return 1; return var_occurs_inside(ua->body, var, inside, want_inv); } + else if (jl_is_vararg(v)) { + jl_vararg_t *vm = (jl_vararg_t*)v; + if (vm->T) { + if (var_occurs_inside(vm->T, var, inside || !want_inv, want_inv)) + return 1; + return vm->N && var_occurs_inside(vm->N, var, 1, want_inv); + } + } else if (jl_is_datatype(v)) { size_t i; int istuple = jl_is_tuple_type(v); - int isva = jl_is_vararg_type(v); for (i=0; i < jl_nparams(v); i++) { - int invar = isva ? i == 1 : !istuple; - int ins_i = inside || !want_inv || invar; + int ins_i = inside || !want_inv || !istuple; if (var_occurs_inside(jl_tparam(v,i), var, ins_i, want_inv)) return 1; } @@ -2652,11 +2680,9 @@ static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_ // check n = (length of vararg type v) static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8_t R) { - jl_tvar_t *va_p1=NULL; - jl_datatype_t *tail = unwrap_1_unionall(v, &va_p1); - jl_value_t *N = jl_tparam1(tail); + jl_value_t *N = jl_unwrap_vararg_num(v); // only do the check if N is free in the tuple type's last parameter - if (jl_is_typevar(N) && N != (jl_value_t*)va_p1) { + if (N && jl_is_typevar(N)) { jl_value_t *len = jl_box_long(n); JL_GC_PUSH1(&len); jl_value_t *il = R ? intersect(len, N, e, 2) : intersect(N, len, e, 2); @@ -2667,13 +2693,61 @@ static int intersect_vararg_length(jl_value_t *v, ssize_t n, jl_stenv_t *e, int8 return 1; } +static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); +static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, jl_stenv_t *e, int param) +{ + // Vararg: covariant in first parameter, invariant in second + jl_value_t *xp1=jl_unwrap_vararg(vmx), *xp2=jl_unwrap_vararg_num(vmx), + *yp1=jl_unwrap_vararg(vmy), *yp2=jl_unwrap_vararg_num(vmy); + // in Vararg{T1} <: Vararg{T2}, need to check subtype twice to + // simulate the possibility of multiple arguments, which is needed + // to implement the diagonal rule correctly. + if (intersect(xp1, yp1, e, param==0 ? 1 : param) == jl_bottom_type) + return jl_bottom_type; + jl_value_t *i2=NULL, *ii = intersect(xp1, yp1, e, 1); + if (ii == jl_bottom_type) return jl_bottom_type; + JL_GC_PUSH2(&ii, &i2); + if (!xp2 && !yp2) { + ii = (jl_value_t*)jl_wrap_vararg(ii, NULL); + JL_GC_POP(); + return ii; + } + if (xp2 && jl_is_typevar(xp2)) { + jl_varbinding_t *xb = lookup(e, (jl_tvar_t*)xp2); + if (xb) xb->intvalued = 1; + if (!yp2) { + i2 = bound_var_below((jl_tvar_t*)xp2, xb, e); + } + } + if (yp2 && jl_is_typevar(yp2)) { + jl_varbinding_t *yb = lookup(e, (jl_tvar_t*)yp2); + if (yb) yb->intvalued = 1; + if (!xp2) { + i2 = bound_var_below((jl_tvar_t*)yp2, yb, e); + } + } + if (xp2 && yp2) { + // Vararg{T,N} <: Vararg{T2,N2}; equate N and N2 + i2 = intersect_invariant(xp2, yp2, e); + if (i2 == NULL || i2 == jl_bottom_type || (jl_is_long(i2) && jl_unbox_long(i2) < 0) || + !((jl_is_typevar(i2) && ((jl_tvar_t*)i2)->lb == jl_bottom_type && + ((jl_tvar_t*)i2)->ub == (jl_value_t*)jl_any_type) || jl_is_long(i2))) { + i2 = jl_bottom_type; + } + } + ii = i2 == jl_bottom_type ? (jl_value_t*)jl_bottom_type : (jl_value_t*)jl_wrap_vararg(ii, i2); + JL_GC_POP(); + return ii; +} + + static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, int param) { size_t lx = jl_nparams(xd), ly = jl_nparams(yd); if (lx == 0 && ly == 0) return (jl_value_t*)yd; - int vx=0, vy=0, vvx = (lx > 0 && jl_is_vararg_type(jl_tparam(xd, lx-1))); - int vvy = (ly > 0 && jl_is_vararg_type(jl_tparam(yd, ly-1))); + int vx=0, vy=0, vvx = (lx > 0 && jl_is_vararg(jl_tparam(xd, lx-1))); + int vvy = (ly > 0 && jl_is_vararg(jl_tparam(yd, ly-1))); if (!vvx && !vvy && lx != ly) return jl_bottom_type; jl_svec_t *params = jl_alloc_svec(lx > ly ? lx : ly); @@ -2682,14 +2756,15 @@ static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_sten size_t i=0, j=0; jl_value_t *xi, *yi; while (1) { + vx = vy = 0; xi = i < lx ? jl_tparam(xd, i) : NULL; yi = j < ly ? jl_tparam(yd, j) : NULL; if (xi == NULL && yi == NULL) { assert(i == j && i == jl_svec_len(params)); break; } - if (xi && jl_is_vararg_type(xi)) vx = 1; - if (yi && jl_is_vararg_type(yi)) vy = 1; + if (xi && jl_is_vararg(xi)) vx = 1; + if (yi && jl_is_vararg(yi)) vy = 1; if (xi == NULL || yi == NULL) { res = jl_bottom_type; if (vx && intersect_vararg_length(xi, ly+1-lx, e, 0)) @@ -2698,29 +2773,34 @@ static jl_value_t *intersect_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_sten res = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(params), i); break; } - if (vx && !vy) - xi = jl_unwrap_vararg(xi); - if (vy && !vx) - yi = jl_unwrap_vararg(yi); jl_varbinding_t *xb=NULL, *yb=NULL; + jl_value_t *ii = NULL; if (vx && vy) { // {A^n...,Vararg{T,N}} ∩ {Vararg{S,M}} = {(A∩S)^n...,Vararg{T∩S,N}} plus N = M-n - jl_value_t *xlen = jl_tparam1(jl_unwrap_unionall(xi)); - if (jl_is_typevar(xlen)) { + jl_value_t *xlen = jl_unwrap_vararg_num(xi); + if (xlen && jl_is_typevar(xlen)) { xb = lookup(e, (jl_tvar_t*)xlen); if (xb) xb->offset = ly-lx; } - jl_value_t *ylen = jl_tparam1(jl_unwrap_unionall(yi)); - if (jl_is_typevar(ylen)) { + jl_value_t *ylen = jl_unwrap_vararg_num(yi); + if (ylen && jl_is_typevar(ylen)) { yb = lookup(e, (jl_tvar_t*)ylen); if (yb) yb->offset = lx-ly; } + ii = intersect_varargs((jl_vararg_t*)xi, + (jl_vararg_t*)yi, + e, param); + if (xb) xb->offset = 0; + if (yb) yb->offset = 0; + } else { + if (vx) + xi = jl_unwrap_vararg(xi); + if (vy) + yi = jl_unwrap_vararg(yi); + ii = intersect(xi, yi, e, param == 0 ? 1 : param); } - jl_value_t *ii = intersect(xi, yi, e, param == 0 ? 1 : param); - if (xb) xb->offset = 0; - if (yb) yb->offset = 0; if (ii == jl_bottom_type) { if (vx && vy) { int len = i > j ? i : j; @@ -3022,7 +3102,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa record_var_occurrence(lookup(e, (jl_tvar_t*)y), e, param); return intersect_var((jl_tvar_t*)y, x, e, 1, param); } - if (!jl_has_free_typevars(x) && !jl_has_free_typevars(y) && !jl_is_vararg_type(x) && !jl_is_vararg_type(y)) { + if (!jl_has_free_typevars(x) && !jl_has_free_typevars(y)) { if (jl_subtype(x, y)) return x; if (jl_subtype(y, x)) return y; } @@ -3073,6 +3153,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa } if (jl_is_unionall(y)) return intersect_unionall(x, (jl_unionall_t*)y, e, 1, param); + assert(!jl_is_vararg(x) && !jl_is_vararg(y)); if (jl_is_datatype(x) && jl_is_datatype(y)) { jl_datatype_t *xd = (jl_datatype_t*)x, *yd = (jl_datatype_t*)y; if (param < 2) { @@ -3087,36 +3168,6 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa if (xd->name == yd->name) { if (jl_is_tuple_type(xd)) return intersect_tuple(xd, yd, e, param); - if (jl_is_vararg_type(x)) { - // Vararg: covariant in first parameter, invariant in second - jl_value_t *xp1=jl_tparam0(xd), *xp2=jl_tparam1(xd), *yp1=jl_tparam0(yd), *yp2=jl_tparam1(yd); - // in Vararg{T1} <: Vararg{T2}, need to check subtype twice to - // simulate the possibility of multiple arguments, which is needed - // to implement the diagonal rule correctly. - if (intersect(xp1, yp1, e, param==0 ? 1 : param) == jl_bottom_type) - return jl_bottom_type; - jl_value_t *i2=NULL, *ii = intersect(xp1, yp1, e, 1); - if (ii == jl_bottom_type) return jl_bottom_type; - JL_GC_PUSH2(&ii, &i2); - if (jl_is_typevar(xp2)) { - jl_varbinding_t *xb = lookup(e, (jl_tvar_t*)xp2); - if (xb) xb->intvalued = 1; - } - if (jl_is_typevar(yp2)) { - jl_varbinding_t *yb = lookup(e, (jl_tvar_t*)yp2); - if (yb) yb->intvalued = 1; - } - // Vararg{T,N} <: Vararg{T2,N2}; equate N and N2 - i2 = intersect_invariant(xp2, yp2, e); - if (i2 == NULL || i2 == jl_bottom_type || (jl_is_long(i2) && jl_unbox_long(i2) < 0) || - !((jl_is_typevar(i2) && ((jl_tvar_t*)i2)->lb == jl_bottom_type && - ((jl_tvar_t*)i2)->ub == (jl_value_t*)jl_any_type) || jl_is_long(i2))) - ii = jl_bottom_type; - else - ii = jl_apply_type2((jl_value_t*)jl_vararg_type, ii, i2); - JL_GC_POP(); - return ii; - } size_t i, np = jl_nparams(xd); jl_value_t **newparams; JL_GC_PUSHARGS(newparams, np); @@ -3340,8 +3391,8 @@ static int might_intersect_concrete(jl_value_t *a) if (jl_is_uniontype(a)) return might_intersect_concrete(((jl_uniontype_t*)a)->a) || might_intersect_concrete(((jl_uniontype_t*)a)->b); - if (jl_is_vararg_type(a)) - return might_intersect_concrete(jl_tparam0(a)); + if (jl_is_vararg(a)) + return might_intersect_concrete(jl_unwrap_vararg(a)); if (jl_is_type_type(a)) return 1; if (jl_is_datatype(a)) { @@ -3539,11 +3590,11 @@ static jl_value_t *nth_tuple_elt(jl_datatype_t *t JL_PROPAGATES_ROOT, size_t i) if (i < len-1) return jl_tparam(t, i); jl_value_t *last = jl_unwrap_unionall(jl_tparam(t, len-1)); - if (jl_is_vararg_type(last)) { - jl_value_t *n = jl_tparam1(last); - if (jl_is_long(n) && i >= len-1+jl_unbox_long(n)) + if (jl_is_vararg(last)) { + jl_value_t *n = jl_unwrap_vararg_num(last); + if (n && jl_is_long(n) && i >= len-1+jl_unbox_long(n)) return NULL; - return jl_tparam0(last); + return jl_unwrap_vararg(last); } if (i == len-1) return jl_tparam(t, i); @@ -3605,7 +3656,7 @@ static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invari C = Tuple{AbstractArray, Int, Array} we need A < B < C and A < C. */ - return some_morespecific && cva && ckind == JL_VARARG_BOUND && num_occurs((jl_tvar_t*)jl_tparam1(jl_unwrap_unionall(clast)), env) > 1; + return some_morespecific && cva && ckind == JL_VARARG_BOUND && num_occurs((jl_tvar_t*)jl_unwrap_vararg_num(clast), env) > 1; } // Tuple{..., T} not more specific than Tuple{..., Vararg{S}} if S is diagonal @@ -3628,8 +3679,8 @@ static size_t tuple_full_length(jl_value_t *t) size_t n = jl_nparams(t); if (n == 0) return 0; jl_value_t *last = jl_unwrap_unionall(jl_tparam(t,n-1)); - if (jl_is_vararg_type(last)) { - jl_value_t *N = jl_tparam1(last); + if (jl_is_vararg(last)) { + jl_value_t *N = jl_unwrap_vararg_num(last); if (jl_is_long(N)) n += jl_unbox_long(N)-1; } @@ -3646,7 +3697,7 @@ static int args_morespecific_fix1(jl_value_t *a, jl_value_t *b, int swap, jl_typ return -1; assert(jl_is_va_tuple((jl_datatype_t*)a)); jl_datatype_t *new_a = NULL; - jl_value_t *e[2] = { jl_tparam1(jl_unwrap_unionall(jl_tparam(a, n-1))), jl_box_long(taillen) }; + jl_value_t *e[2] = { jl_unwrap_vararg_num(jl_unwrap_unionall(jl_tparam(a, n-1))), jl_box_long(taillen) }; JL_GC_PUSH2(&new_a, &e[1]); new_a = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)a, e, 1); int changed = 0; @@ -3683,6 +3734,12 @@ static int count_occurs(jl_value_t *t, jl_tvar_t *v) return 0; return count_occurs(((jl_unionall_t*)t)->body, v); } + if (jl_is_vararg(t)) { + jl_vararg_t *vm = (jl_vararg_t*)t; + if (vm->T) { + return count_occurs(vm->T, v) + (vm->N ? count_occurs(vm->N, v) : 0); + } + } if (jl_is_datatype(t)) { int i, c=0; for(i=0; i < jl_nparams(t); i++) diff --git a/src/typemap.c b/src/typemap.c index 347b2147d9aea..50fb9635ff210 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -27,8 +27,8 @@ static jl_value_t *jl_type_extract_name(jl_value_t *t1 JL_PROPAGATES_ROOT) { if (jl_is_unionall(t1)) t1 = jl_unwrap_unionall(t1); - if (jl_is_vararg_type(t1)) { - return jl_type_extract_name(jl_tparam0(t1)); + if (jl_is_vararg(t1)) { + return jl_type_extract_name(jl_unwrap_vararg(t1)); } else if (jl_is_typevar(t1)) { return jl_type_extract_name(((jl_tvar_t*)t1)->ub); @@ -57,8 +57,8 @@ static int jl_type_extract_name_precise(jl_value_t *t1, int invariant) { if (jl_is_unionall(t1)) t1 = jl_unwrap_unionall(t1); - if (jl_is_vararg_type(t1)) { - return jl_type_extract_name_precise(jl_tparam0(t1), invariant); + if (jl_is_vararg(t1)) { + return jl_type_extract_name_precise(jl_unwrap_vararg(t1), invariant); } else if (jl_is_typevar(t1)) { return jl_type_extract_name_precise(((jl_tvar_t*)t1)->ub, 0); @@ -109,6 +109,8 @@ static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t jl_value_t *decl = jl_tparam(sig, i); jl_value_t *a = types[i]; jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; + if (jl_is_vararg(a)) + return 0; if (jl_is_type_type(unw)) { jl_value_t *tp0 = jl_tparam0(unw); if (jl_is_type_type(a)) { @@ -144,11 +146,14 @@ static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t if (n - i != jl_unbox_long(jl_tparam1(decl))) return 0; } - jl_value_t *t = jl_tparam0(decl); + jl_value_t *t = jl_unwrap_vararg(decl); if (jl_is_typevar(t)) t = ((jl_tvar_t*)t)->ub; for (; i < n; i++) { - if (!jl_subtype(types[i], t)) + jl_value_t *ti = types[i]; + if (i == n - 1 && jl_is_vararg(ti)) + ti = jl_unwrap_vararg(ti); + if (!jl_subtype(ti, t)) return 0; } return 1; @@ -643,14 +648,14 @@ static jl_typemap_entry_t *jl_typemap_entry_assoc_by_type( jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); int isua = jl_is_unionall(types); size_t n = jl_nparams(unw); - int typesisva = n == 0 ? 0 : jl_is_vararg_type(jl_tparam(unw, n-1)); + int typesisva = n == 0 ? 0 : jl_is_vararg(jl_tparam(unw, n-1)); for (; ml != (void*)jl_nothing; ml = jl_atomic_load_relaxed(&ml->next)) { size_t lensig = jl_nparams(jl_unwrap_unionall((jl_value_t*)ml->sig)); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing && !isua) { size_t lensimplesig = jl_nparams(ml->simplesig); - int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); + int isva = lensimplesig > 0 && jl_is_vararg(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(((jl_datatype_t*)types)->parameters), n, ml->simplesig, lensimplesig, isva); @@ -722,8 +727,8 @@ static jl_typemap_entry_t *jl_typemap_entry_lookup_by_type( jl_value_t *b = jl_unwrap_unionall((jl_value_t*)ml->sig); size_t na = jl_nparams(a); size_t nb = jl_nparams(b); - int va_a = na > 0 && jl_is_vararg_type(jl_tparam(a, na - 1)); - int va_b = nb > 0 && jl_is_vararg_type(jl_tparam(b, nb - 1)); + int va_a = na > 0 && jl_is_vararg(jl_tparam(a, na - 1)); + int va_b = nb > 0 && jl_is_vararg(jl_tparam(b, nb - 1)); if (!va_a && !va_b) { if (na != nb) continue; @@ -766,7 +771,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type( // compute the type at offset `offs` into `types`, which may be a Vararg if (l <= offs + 1) { ty = jl_tparam(ttypes, l - 1); - if (jl_is_vararg_type(ty)) { + if (jl_is_vararg(ty)) { ty = jl_unwrap_vararg(ty); isva = 1; } @@ -949,7 +954,7 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu if (lensig == n || (ml->va && lensig <= n+1)) { if (ml->simplesig != (void*)jl_nothing) { size_t lensimplesig = jl_nparams(ml->simplesig); - int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); + int isva = lensimplesig > 0 && jl_is_vararg(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) { if (!sig_match_simple(arg1, args, n, jl_svec_data(ml->simplesig->parameters), isva, lensimplesig)) continue; @@ -1182,7 +1187,7 @@ static void jl_typemap_level_insert_( int isva = 0; if (l <= offs + 1) { t1 = jl_tparam(ttypes, l - 1); - if (jl_is_vararg_type(t1)) { + if (jl_is_vararg(t1)) { isva = 1; t1 = jl_unwrap_vararg(t1); } @@ -1259,7 +1264,7 @@ jl_typemap_entry_t *jl_typemap_alloc( isleafsig = 0; // Type{} may have a higher priority than a kind else if (jl_is_type_type(decl)) isleafsig = 0; // Type{} may need special processing to compute the match - else if (jl_is_vararg_type(decl)) + else if (jl_is_vararg(decl)) isleafsig = 0; // makes iteration easier when the endpoints are the same else if (decl == (jl_value_t*)jl_any_type) isleafsig = 0; // Any needs to go in the general cache diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index ead87cde431f0..94e2222a2355f 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -170,7 +170,7 @@ function methodswith(t::Type, f::Function, meths = Method[]; supertypes::Bool=fa if any(function (x) let x = rewrap_unionall(x, d.sig) (type_close_enough(x, t) || - (supertypes ? (t <: x && (!isa(x,TypeVar) || x.ub != Any)) : + (supertypes ? (isa(x, Type) && t <: x && (!isa(x,TypeVar) || x.ub != Any)) : (isa(x,TypeVar) && x.ub != Any && t == x.ub)) && x != Any) end diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index ac68fc64787c3..9585396d11856 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1581,9 +1581,8 @@ function constrains_param(var::TypeVar, @nospecialize(typ), covariant::Bool) end lastp = typ.parameters[fc] vararg = Base.unwrap_unionall(lastp) - if vararg isa DataType && vararg.name === Base._va_typename - N = vararg.parameters[2] - constrains_param(var, N, covariant) && return true + if vararg isa Core.TypeofVararg && isdefined(vararg, :N) + constrains_param(var, vararg.N, covariant) && return true # T = vararg.parameters[1] doesn't constrain var else constrains_param(var, lastp, covariant) && return true diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b06d2ce6c6ce5..75027f4841209 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -284,7 +284,7 @@ code_llvm(devnull, invoke_g10878, ()) @test isa(code_typed(promote,(Any,Any,Vararg{Any})), Array) find_tvar10930(sig::Type{T}) where {T<:Tuple} = 1 function find_tvar10930(arg) - if arg<:Tuple + if isa(arg, Type) && arg<:Tuple find_tvar10930(arg[random_var_name]) end return 1 @@ -627,7 +627,7 @@ function maybe_vararg_tuple_1() end @test Type{Tuple{Vararg{Int}}} <: Base.return_types(maybe_vararg_tuple_1, ())[1] function maybe_vararg_tuple_2() - x = Type[Vararg{Int}][1] + x = [Vararg{Int}][1] Tuple{x} end @test Type{Tuple{Vararg{Int}}} <: Base.return_types(maybe_vararg_tuple_2, ())[1] @@ -1829,8 +1829,8 @@ end @test Core.Compiler.return_type(Core.apply_type, Tuple{Type{Union},Any,Any}) == Type @test Core.Compiler.return_type(Core.apply_type, Tuple{Type{Union},Int}) == Union{} @test Core.Compiler.return_type(Core.apply_type, Tuple{Type{Union},Any,Int}) == Union{} -@test Core.Compiler.return_type(Core.apply_type, Tuple{Any}) == Type -@test Core.Compiler.return_type(Core.apply_type, Tuple{Any,Any}) == Type +@test Core.Compiler.return_type(Core.apply_type, Tuple{Any}) == Any +@test Core.Compiler.return_type(Core.apply_type, Tuple{Any,Any}) == Any # PR 27351, make sure optimized type intersection for method invalidation handles typevars @@ -2653,7 +2653,10 @@ end @test Core.Compiler.typesubtract(NTuple{3, Union{Int, Char}}, NTuple{3, Char}, 10) == Union{Tuple{Char, Char, Int}, Tuple{Char, Int, Char}, Tuple{Char, Int, Int}, Tuple{Int, Char, Char}, Tuple{Int, Char, Int}, Tuple{Int, Int, Char}, Tuple{Int, Int, Int}} - +# Test that these don't throw +@test Core.Compiler.typesubtract(Tuple{Vararg{Int}}, Tuple{Vararg{Char}}, 0) == Tuple{Vararg{Int}} +@test Core.Compiler.typesubtract(NTuple{3, Real}, NTuple{3, Char}, 0) == NTuple{3, Real} +@test Core.Compiler.typesubtract(NTuple{3, Union{Real, Char}}, NTuple{2, Char}, 0) == NTuple{3, Union{Real, Char}} @test Base.return_types(Issue35566.f) == [Val{:expected}] @@ -2834,9 +2837,9 @@ end @test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Vararg}) == Union{Type, TypeVar} @test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Vararg}) == Union{Type, TypeVar} @test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Any, Vararg}) == Union{} -@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Vararg}) == Type -@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Vararg}) == Type -@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Any, Vararg}) == Type +@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Vararg}) == Any +@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Vararg}) == Any +@test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Any, Vararg}) == Any f_apply_cglobal(args...) = cglobal(args...) @test Core.Compiler.return_type(f_apply_cglobal, Tuple{Vararg{Type{Int}}}) == Ptr @test Core.Compiler.return_type(f_apply_cglobal, Tuple{Any, Vararg{Type{Int}}}) == Ptr @@ -2958,7 +2961,7 @@ end end # issue #37638 -@test !(Core.Compiler.return_type(() -> (nothing, Any[]...)[2], Tuple{}) <: Vararg) +@test isa(Core.Compiler.return_type(() -> (nothing, Any[]...)[2], Tuple{}), Type) # Issue #37943 f37943(x::Any, i::Int) = getfield((x::Pair{false, Int}), i) @@ -2970,3 +2973,9 @@ g37943(i::Int) = fieldtype(Pair{false, T} where T, i) f_partial_struct_constprop(a, b) = (a[1]+b[1], nothing) g_partial_struct_constprop() = Val{f_partial_struct_constprop((1,), (1,))[1]}() @test only(Base.return_types(g_partial_struct_constprop, Tuple{})) === Val{2} + +# N parameter of Vararg is known to be Int +gVarargInt(x::Int) = 1 +gVarargInt(x) = 2 +fVarargInt(::Tuple{Vararg{Int, N}}) where {N} = Val{gVarargInt(N)}() +@test only(Base.return_types(fVarargInt, Tuple{Tuple{Vararg{Int}}})) == Val{1} diff --git a/test/core.jl b/test/core.jl index 28af6b88ceb4d..88b54eb25a90b 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1218,7 +1218,7 @@ end # issue #22842 f22842(x::UnionAll) = UnionAll f22842(x::DataType) = length(x.parameters) -@test f22842(Tuple{Vararg{Int64,N} where N}) == 1 +@test f22842(Tuple{Vararg{Int64}}) == 1 @test f22842(Tuple{Vararg{Int64,N}} where N) === UnionAll # issue #1153 @@ -7009,7 +7009,6 @@ end @test_throws ArgumentError Array{Int, 2}(undef, -1, -1) # issue #28812 -@test Tuple{Vararg{Array{T},3} where T} === Tuple{Array,Array,Array} @test Tuple{Vararg{Array{T} where T,3}} === Tuple{Array,Array,Array} # issue #29145 @@ -7521,3 +7520,11 @@ for _ in 1:5 @test all(x->ismissing(x.i), a) end end + +# Redefining types with Vararg +abstract type RedefineVararg; end +const RedefineVarargN{N} = Tuple{Vararg{RedefineVararg, N}} +const RedefineVarargN{N} = Tuple{Vararg{RedefineVararg, N}} + +# NTuples with non-types +@test NTuple{3, 2} == Tuple{2, 2, 2} diff --git a/test/show.jl b/test/show.jl index ff8946acb1662..3b918c064fcb0 100644 --- a/test/show.jl +++ b/test/show.jl @@ -1671,7 +1671,7 @@ end end # issue #25857 - @test repr([(1,),(1,2),(1,2,3)]) == "Tuple{$Int, Vararg{$Int, N} where N}[(1,), (1, 2), (1, 2, 3)]" + @test repr([(1,),(1,2),(1,2,3)]) == "Tuple{$Int, Vararg{$Int}}[(1,), (1, 2), (1, 2, 3)]" # issues #25466 & #26256 @test replstr([:A => [1]]) == "1-element Vector{Pair{Symbol, Vector{$Int}}}:\n :A => [1]" diff --git a/test/specificity.jl b/test/specificity.jl index a34ed8a15eccb..de65c289be02a 100644 --- a/test/specificity.jl +++ b/test/specificity.jl @@ -62,7 +62,7 @@ _z_z_z_(::Int, c...) = 3 @test args_morespecific(Tuple{Union{Int,String},Type{Pair{A,B} where B}} where A, Tuple{Integer,UnionAll}) # PR #21750 -let A = Tuple{Any, Tuple{Vararg{Integer,N} where N}}, +let A = Tuple{Any, Tuple{Vararg{Integer}}}, B = Tuple{Any, Tuple{Any}}, C = Tuple{Any, Tuple{}} @test args_morespecific(A, B) @@ -111,16 +111,16 @@ f17016(f, t1::Tuple) = 1 @test !args_morespecific(Tuple{Type{Any}, Any}, Tuple{Type{T}, Any} where T<:VecElement) @test !args_morespecific((Tuple{Type{T}, Any} where T<:VecElement), Tuple{Type{Any}, Any}) -@test !args_morespecific(Tuple{Type{T}, Tuple{Any, Vararg{Any, N} where N}} where T<:Tuple{Any, Vararg{Any, N} where N}, +@test !args_morespecific(Tuple{Type{T}, Tuple{Any, Vararg{Any}}} where T<:Tuple{Any, Vararg{Any}}, Tuple{Type{Any}, Any}) -@test !args_morespecific(Tuple{Type{T}, Tuple{Any, Vararg{Any, N} where N}} where T<:Tuple{Any, Vararg{Any, N} where N}, +@test !args_morespecific(Tuple{Type{T}, Tuple{Any, Vararg{Any}}} where T<:Tuple{Any, Vararg{Any}}, Tuple{Type{Tuple}, Tuple}) -@test !args_morespecific(Tuple{Type{T}, T} where T<:Tuple{Any, Vararg{Any, N} where N}, +@test !args_morespecific(Tuple{Type{T}, T} where T<:Tuple{Any, Vararg{Any}}, Tuple{Type{T}, Any} where T<:VecElement) @test args_morespecific(Tuple{Any, Tuple{}, Tuple{}}, Tuple{Any, Tuple{Any}}) @test args_morespecific(Tuple{Any, Tuple{Any}, Tuple{Any}}, Tuple{Any, Tuple{Any, Any}}) -@test args_morespecific(Tuple{Any, Vararg{Tuple{}, N} where N}, Tuple{Any, Tuple{Any}}) +@test args_morespecific(Tuple{Any, Vararg{Tuple{}}}, Tuple{Any, Tuple{Any}}) @test args_morespecific(Tuple{T, T} where T<:AbstractFloat, Tuple{T, T, T} where T<:AbstractFloat) @test args_morespecific(Tuple{T, Real, T} where T<:AbstractFloat, Tuple{T, T} where T<:Real) @@ -137,10 +137,10 @@ f17016(f, t1::Tuple) = 1 Tuple{T, T} where T<:Union{Base.StepRangeLen, Base.LinRange}) @test args_morespecific(Tuple{Type{Tuple}, Any, Any}, - Tuple{Type{Tuple{Vararg{E, N} where N}}, Any, Any} where E) + Tuple{Type{Tuple{Vararg{E}}}, Any, Any} where E) @test args_morespecific(Tuple{Type{Tuple{}}, Tuple{}}, - Tuple{Type{T}, T} where T<:Tuple{Any, Vararg{Any, N} where N}) + Tuple{Type{T}, T} where T<:Tuple{Any, Vararg{Any}}) @test args_morespecific(Tuple{Type{CartesianIndex{N}}} where N, Tuple{Type{CartesianIndex{N}},Vararg{Int,N}} where N) @@ -235,14 +235,14 @@ let N = Tuple{Type{Union{Nothing, T}}, Union{Nothing, T}} where T, end # issue #29528 -@test !args_morespecific(Tuple{Array,Vararg{Int64,N} where N}, Tuple{AbstractArray, Array}) +@test !args_morespecific(Tuple{Array,Vararg{Int64}}, Tuple{AbstractArray, Array}) @test !args_morespecific(Tuple{Array,Vararg{Int64,N}} where N, Tuple{AbstractArray, Array}) @test args_morespecific(Tuple{Array,Int64}, Tuple{Array,Vararg{Int64,N}} where N) -@test args_morespecific(Tuple{Array,Int64}, Tuple{Array,Vararg{Int64,N} where N}) +@test args_morespecific(Tuple{Array,Int64}, Tuple{Array,Vararg{Int64}}) @test !args_morespecific(Tuple{Array,Int64}, Tuple{AbstractArray, Array}) # issue #30114 -let T1 = Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64},N} where N}},CartesianIndices{N,R} where R<:Tuple{Vararg{AbstractUnitRange{Int64},N}}} where N +let T1 = Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64}}}},CartesianIndices{N,R} where R<:Tuple{Vararg{AbstractUnitRange{Int64},N}}} where N T2 = Tuple{Type{T},T} where T<:AbstractArray T3 = Tuple{Type{AbstractArray{T,N} where N},AbstractArray} where T T4 = Tuple{Type{AbstractArray{T,N}},AbstractArray{s57,N} where s57} where N where T @@ -254,7 +254,7 @@ let T1 = Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64},N} where N}},Cartesian end @test !args_morespecific(Tuple{Type{Tuple{Vararg{AbstractUnitRange{Int64},N}}},} where N, - Tuple{Type{Tuple{Vararg{AbstractUnitRange,N} where N}},}) + Tuple{Type{Tuple{Vararg{AbstractUnitRange}}},}) @test args_morespecific(Tuple{Type{SubArray{T,2,P} where T}, Array{T}} where T where P, Tuple{Type{AbstractArray{T,N} where N},AbstractArray} where T) diff --git a/test/subtype.jl b/test/subtype.jl index d82e781fd8336..8e5a08782066b 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -73,15 +73,15 @@ function test_2() @test !issub(Tuple{Tuple{Int,Int},Tuple{Int,}}, Tuple{NTuple{N,Int},NTuple{N,Int}} where N) @test NTuple{0} === Tuple{} - @test !issub(Tuple{Val{3}, Vararg{Val{3}}}, Tuple{Vararg{Val{N}, N} where N}) + @test !issub(Tuple{Val{3}, Vararg{Val{3}}}, Tuple{Vararg{Val{N}, N}} where N) @test issub_strict(Tuple{Int,Int}, Tuple{Int,Int,Vararg{Int,N}} where N) @test issub_strict(Tuple{Int,Int}, Tuple{E,E,Vararg{E,N}} where E where N) @test issub(Type{Tuple{VecElement{Bool}}}, (Type{Tuple{Vararg{VecElement{T},N}}} where T where N)) - @test isequal_type(Type{Tuple{Vararg{Int,N}} where N}, Type{Tuple{Vararg{Int,N} where N}}) - @test Type{Tuple{Vararg{Int,N}} where N} !== Type{Tuple{Vararg{Int,N} where N}} + @test isequal_type(Type{Tuple{Vararg{Int,N}} where N}, Type{Tuple{Vararg{Int}}}) + @test Type{Tuple{Vararg{Int,N}} where N} !== Type{Tuple{Vararg{Int}}} end function test_diagonal() @@ -845,7 +845,7 @@ function test_intersection() @testintersect((@UnionAll N Tuple{Array{Int,N},Vararg{Int,N}}), Tuple{Matrix{Int},Int,Vararg{Float64}}, Bottom) - @testintersect(Tuple{Array{Any,1}, Tuple{Int64, Int64, Vararg{Int64, N} where N}}, + @testintersect(Tuple{Array{Any,1}, Tuple{Int64, Int64, Vararg{Int64}}}, Tuple{Array{T,N}, Tuple{Vararg{Int64,N}}} where N where T, Bottom) @@ -919,7 +919,7 @@ function test_intersection() @testintersect(Tuple{Type{S}, Tuple{Any, Vararg{Any}}} where S<:Tuple{Any, Vararg{Any}}, Tuple{Type{T}, T} where T, - Tuple{Type{S},S} where S<:Tuple{Any,Vararg{Any,N} where N}) + Tuple{Type{S},S} where S<:Tuple{Any,Vararg{Any}}) # part of issue #20450 @testintersect(Tuple{Array{Ref{T}, 1}, Array{Pair{M, V}, 1}} where V where T where M, @@ -940,7 +940,7 @@ function test_intersection() Tuple{Vector{T},Vector{T}} where T>:Vector}) # part of issue #20344 - @testintersect(Tuple{Type{Tuple{Vararg{T, N} where N}}, Tuple} where T, + @testintersect(Tuple{Type{Tuple{Vararg{T}}}, Tuple} where T, Tuple{Type{Tuple{Vararg{T, N}}} where N where T, Any}, Bottom) @testintersect(Type{NTuple{N,UnitRange}} where N, @@ -1043,10 +1043,10 @@ function test_intersection() @testintersect(Tuple{Type{Tuple{Vararg{Integer}}}, Tuple}, Tuple{Type{Tuple{Vararg{V}}}, Tuple{Vararg{V}}} where {V}, - Tuple{Type{Tuple{Vararg{Integer,N} where N}},Tuple{Vararg{Integer,N} where N}}) + Tuple{Type{Tuple{Vararg{Integer}}},Tuple{Vararg{Integer}}}) @testintersect(Tuple{Type{Tuple{Vararg{Union{Int,Symbol}}}}, Tuple}, Tuple{Type{Tuple{Vararg{V}}}, Tuple{Vararg{V}}} where {V}, - Tuple{Type{Tuple{Vararg{Union{Int,Symbol},N} where N}},Tuple{Vararg{Union{Int,Symbol},N} where N}}) + Tuple{Type{Tuple{Vararg{Union{Int,Symbol}}}},Tuple{Vararg{Union{Int,Symbol}}}}) # non types @testintersect(Tuple{1}, Tuple{Any}, Tuple{1}) @@ -1377,10 +1377,10 @@ g25430(t::Vector{Tuple{>:Int}}) = true g24521(::T, ::T) where {T} = T @test_throws MethodError g24521(Tuple{Any}, Tuple{T} where T) @test g24521(Vector, Matrix) == UnionAll -@test [Tuple{Vararg{Int64,N} where N}, Tuple{Vararg{Int64,N}} where N] isa Vector{Type} +@test [Tuple{Vararg{Int64}}, Tuple{Vararg{Int64,N}} where N] isa Vector{Type} f24521(::Type{T}, ::Type{T}) where {T} = T @test f24521(Tuple{Any}, Tuple{T} where T) == Tuple{Any} -@test f24521(Tuple{Vararg{Int64,N} where N}, Tuple{Vararg{Int64,N}} where N) == Tuple{Vararg{Int64,N}} where N +@test f24521(Tuple{Vararg{Int64}}, Tuple{Vararg{Int64,N}} where N) == Tuple{Vararg{Int64,N}} where N # issue #26654 @test !(Ref{Union{Int64, Ref{Number}}} <: Ref{Union{Ref{T}, T}} where T) @@ -1654,7 +1654,7 @@ end # Various nasty varargs let T1 = Tuple{Int, Tuple{T}, Vararg{T, 3}} where T <: Int, T2 = Tuple{Int, Any, Any, Any, Integer}, - T3 = Tuple{Int, Any, Any, Any, Integer, Vararg{Integer, N} where N} + T3 = Tuple{Int, Any, Any, Any, Integer, Vararg{Integer}} @test issub_strict(T1, T2) @test issub_strict(T2, T3) @@ -1663,23 +1663,20 @@ end let A = Tuple{Float64, Vararg{Int64, 2}}, B1 = Tuple{Float64, Vararg{T, 2}} where T <: Int64, B2 = Tuple{Float64, T, T} where T <: Int64, - C = Tuple{Float64, Any, Vararg{Integer, N} where N} + C = Tuple{Float64, Any, Vararg{Integer}} @test A == B1 == B2 @test issub_strict(A, C) @test issub_strict(B1, C) @test issub_strict(B2, C) end -let A = Tuple{Vararg{Val{N}, N} where N}, - B = Tuple{Vararg{Val{N}, N}} where N, +let B = Tuple{Vararg{Val{N}, N}} where N, C = Tuple{Val{2}, Val{2}} - @test isequal_type(A, B) @test issub(C, B) - @test issub(C, A) end @test isequal_type(Tuple{T, Vararg{T, 2}} where T<:Real, Tuple{Vararg{T, 3}} where T<: Real) -@test !issub(Tuple{Vararg{T, 3}} where T<:Real, Tuple{Any, Any, Any, Any, Vararg{Any, N} where N}) +@test !issub(Tuple{Vararg{T, 3}} where T<:Real, Tuple{Any, Any, Any, Any, Vararg{Any}}) @test !issub(Tuple{Vararg{T, 3}} where T<:Real, Tuple{Any, Any, Any, Any, Vararg{Any, N}} where N) @test issub_strict(Ref{Tuple{Int, Vararg{Int, N}}} where N, Ref{Tuple{Vararg{Int, N}}} where N) let T31805 = Tuple{Type{Tuple{}}, Tuple{Vararg{Int8, A}}} where A, @@ -1694,6 +1691,13 @@ end @test !isequal_type(Tuple{Int, Vararg{T, 3}} where T<:Real, Tuple{Int, Real, Vararg{T, 2}} where T<:Integer) +@test !isequal_type(Tuple{Tuple{Vararg{Int}},Tuple{Vararg{Int}}}, + Tuple{Tuple{Vararg{Int, N}}, Tuple{Vararg{Int, N}}} where N) + +let (_, E) = intersection_env(Tuple{Tuple{Vararg{Int}}}, Tuple{Tuple{Vararg{Int,N}}} where N) + @test !isa(E[1], Type) +end + # this is is a timing test, so it would fail on debug builds #let T = Type{Tuple{(Union{Int, Nothing} for i = 1:23)..., Union{String, Nothing}}}, # S = Type{T} where T<:Tuple{E, Vararg{E}} where E @@ -1737,9 +1741,9 @@ c32703(::Type{<:Str{C}}, str::Str{C}) where {C<:CSE} = str # issue #33337 @test !issub(Tuple{Type{T}, T} where T<:NTuple{30, Union{Nothing, Ref}}, - Tuple{Type{Tuple{Vararg{V, N} where N}}, Tuple{Vararg{V, N} where N}} where V) + Tuple{Type{Tuple{Vararg{V}}}, Tuple{Vararg{V}}} where V) @test issub(Tuple{Type{Any}, NTuple{4,Union{Int,Nothing}}}, - Tuple{Type{V}, Tuple{Vararg{V, N} where N}} where V) + Tuple{Type{V}, Tuple{Vararg{V}}} where V) # issue #26065 t26065 = Ref{Tuple{T,Ref{Union{Ref{Tuple{Ref{Union{Ref{Ref{Tuple{Ref{Tuple{Union{Tuple{Ref{Ref{T}},T}, T},T}},T}}}, T}},T}}, Ref{T}, T}}}} where T @@ -1758,7 +1762,7 @@ s26065 = Ref{Tuple{T,Ref{Union{Ref{Tuple{Ref{Union{Ref{Ref{Tuple{Ref{Tuple{Union Union{}) @test !issub(Tuple{Type{T}, T} where T<:Tuple{String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}}, - Tuple{Type{Tuple{Vararg{V, N} where N}}, Tuple{Vararg{V, N} where N}} where V) + Tuple{Type{Tuple{Vararg{V}}}, Tuple{Vararg{V}}} where V) # issue 36100 @test NamedTuple{(:a, :b), Tuple{Missing, Union{}}} == NamedTuple{(:a, :b), Tuple{Missing, Union{}}} diff --git a/test/syntax.jl b/test/syntax.jl index c6a43116a937d..085794b72d859 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1971,8 +1971,12 @@ let a(; b) = b end # issue #33987 -f33987(args::(Vararg{Any, N} where N); kwargs...) = args -@test f33987(1,2,3) === (1,2,3) +@test_deprecated eval(quote + # This syntax is deprecated. This test should be removed when the + # deprecation is. + f33987(args::(Vararg{Any, N} where N); kwargs...) = args + @test f33987(1,2,3) === (1,2,3) +end) macro id_for_kwarg(x); x; end Xo65KdlD = @id_for_kwarg let x = 1 diff --git a/test/tuple.jl b/test/tuple.jl index 7f5f16e68fff3..3720a5005f394 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -504,6 +504,7 @@ end # tuple_type_tail on non-normalized vararg tuple @test Base.tuple_type_tail(Tuple{Vararg{T, 3}} where T<:Real) == Tuple{Vararg{T, 2}} where T<:Real +@test Base.tuple_type_tail(Tuple{Vararg{Int}}) == Tuple{Vararg{Int}} @testset "setindex" begin @test Base.setindex((1, ), 2, 1) === (2, )