Skip to content

Commit 24219f3

Browse files
committed
WIP: Make Vararg not a DataType
Currently `Vararg` is a DataType, but is special cased in a bunch of places to give it special behavior (e.g. in subtyping and of course in tuple construction). However, unlike all other DataTypes, it cannot appear as a type parameter, which caused trouble in PR #38071. Having it be a DataType is a bit of a pun of convenience in the first place - it's a lot more similar to a tvar (which can be considered an implementation detail of UnionAll in the same way Vararg is an implementation detail of Tuple), which has its own non-type object. This PR does the same to Vararg, and moves it from being an abstract DataType with special cased behavior to its own custom type (called `Core.VarargMarker`). The user facing behavior should be mostly unchanged, since `boot.jl` now has: ``` const Vararg{T, N} = VarargMarker{T, N} ``` i.e. we have a handly UnionAll wrapper that looks just like it used to. The biggest difference is probably that VarargMarker does not have `.parameters`, so code that tries to reach into that explicitly will need to be adjusted. We could provide a compatibility `getproperty` method to adapt that, but I'd prefer to see how many packages need updating first, before going that route. This is essentially complete, but a few cleanup items remain.
1 parent 8c11d3c commit 24219f3

File tree

17 files changed

+263
-159
lines changed

17 files changed

+263
-159
lines changed

base/boot.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,23 @@ ccall(:jl_toplevel_eval_in, Any, (Any, Any),
242242
(f::typeof(Typeof))(x) = ($(_expr(:meta,:nospecialize,:x)); isa(x,Type) ? Type{x} : typeof(x))
243243
end)
244244

245-
# let the compiler assume that calling Union{} as a constructor does not need
246-
# to be considered ever (which comes up often as Type{<:T})
247-
Union{}(a...) = throw(MethodError(Union{}, a))
248245

249246
macro nospecialize(x)
250247
_expr(:meta, :nospecialize, x)
251248
end
252249

250+
TypeVar(n::Symbol) = _typevar(n, Union{}, Any)
251+
TypeVar(n::Symbol, @nospecialize(ub)) = _typevar(n, Union{}, ub)
252+
TypeVar(n::Symbol, @nospecialize(lb), @nospecialize(ub)) = _typevar(n, lb, ub)
253+
254+
UnionAll(v::TypeVar, @nospecialize(t)) = ccall(:jl_type_unionall, Any, (Any, Any), v, t)
255+
256+
const Vararg{T, N} = VarargMarker{T, N}
257+
258+
# let the compiler assume that calling Union{} as a constructor does not need
259+
# to be considered ever (which comes up often as Type{<:T})
260+
Union{}(a...) = throw(MethodError(Union{}, a))
261+
253262
Expr(@nospecialize args...) = _expr(args...)
254263

255264
abstract type Exception end
@@ -378,12 +387,6 @@ mutable struct WeakRef
378387
(Ptr{Cvoid}, Any), getptls(), v)
379388
end
380389

381-
TypeVar(n::Symbol) = _typevar(n, Union{}, Any)
382-
TypeVar(n::Symbol, @nospecialize(ub)) = _typevar(n, Union{}, ub)
383-
TypeVar(n::Symbol, @nospecialize(lb), @nospecialize(ub)) = _typevar(n, lb, ub)
384-
385-
UnionAll(v::TypeVar, @nospecialize(t)) = ccall(:jl_type_unionall, Any, (Any, Any), v, t)
386-
387390
Tuple{}() = ()
388391

389392
struct VecElement{T}

base/compiler/tfuncs.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ function typebound_nothrow(b)
446446
if isType(b)
447447
b = unwrap_unionall(b.parameters[1])
448448
b === Union{} && return true
449-
return !isa(b, DataType) || b.name != _va_typename
449+
return !isa(b, DataType) || !isa(b, Core.VarargMarker)
450450
end
451451
return false
452452
end
@@ -487,7 +487,7 @@ function typeof_concrete_vararg(t::DataType)
487487
p = t.parameters[i]
488488
if i == np && isvarargtype(p)
489489
pp = unwrap_unionall(p)
490-
if isconcretetype(pp.parameters[1]) && pp.parameters[2] isa TypeVar
490+
if isconcretetype(pp.T) && pp.N isa TypeVar
491491
return rewrap_unionall(Type{Tuple{t.parameters[1:np-1]..., pp}}, p)
492492
end
493493
elseif !isconcretetype(p)

base/compiler/typelimits.jl

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ function is_derived_type(@nospecialize(t), @nospecialize(c), mindepth::Int)
4646
# see if it is derived from the body
4747
# also handle the var here, since this construct bounds the mindepth to the smallest possible value
4848
return is_derived_type(t, c.var.ub, mindepth) || is_derived_type(t, c.body, mindepth)
49+
elseif isa(c, Core.VarargMarker)
50+
return is_derived_type(t, c.T, mindepth)
4951
elseif isa(c, DataType)
5052
if mindepth > 0
5153
mindepth -= 1
@@ -85,7 +87,7 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
8587
return t # fast path: unparameterized are always simple
8688
else
8789
ut = unwrap_unionall(t)
88-
if isa(ut, DataType) && ut.name !== _va_typename && isa(c, Type) && c !== Union{} && c <: t
90+
if isa(ut, DataType) && isa(c, Type) && c !== Union{} && c <: t
8991
# TODO: need to check that the UnionAll bounds on t are limited enough too
9092
return t # t is already wider than the comparison in the type lattice
9193
elseif is_derived_type_from_any(ut, sources, depth)
@@ -118,19 +120,20 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
118120
b = _limit_type_size(t.b, c.b, sources, depth, allowed_tuplelen)
119121
return Union{a, b}
120122
end
123+
elseif isa(t, Core.VarargMarker)
124+
isa(c, Core.VarargMarker) || return Vararg
125+
VaT = _limit_type_size(t.T, c.T, sources, depth + 1, 0)
126+
N = t.N
127+
if isa(N, TypeVar) || N === c.N
128+
return Vararg{VaT, N}
129+
end
130+
return Vararg{VaT}
121131
elseif isa(t, DataType)
122132
if isa(c, DataType)
123133
tP = t.parameters
124134
cP = c.parameters
125135
if t.name === c.name && !isempty(cP)
126-
if isvarargtype(t)
127-
VaT = _limit_type_size(tP[1], cP[1], sources, depth + 1, 0)
128-
N = tP[2]
129-
if isa(N, TypeVar) || N === cP[2]
130-
return Vararg{VaT, N}
131-
end
132-
return Vararg{VaT}
133-
elseif t.name === Tuple.name
136+
if t.name === Tuple.name
134137
# for covariant datatypes (Tuple),
135138
# apply type-size limit element-wise
136139
ltP = length(tP)
@@ -155,21 +158,17 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec
155158
end
156159
return Tuple{Q...}
157160
end
158-
elseif isvarargtype(c)
159-
# Tuple{Vararg{T}} --> Tuple{T} is OK
160-
return _limit_type_size(t, cP[1], sources, depth, 0)
161161
end
162+
elseif isa(c, Core.VarargMarker)
163+
# Tuple{Vararg{T}} --> Tuple{T} is OK
164+
return _limit_type_size(t, c.T, sources, depth, 0)
162165
end
163166
if isType(t) # allow taking typeof as Type{...}, but ensure it doesn't start nesting
164167
tt = unwrap_unionall(t.parameters[1])
165168
if isa(tt, DataType) && !isType(tt)
166169
is_derived_type_from_any(tt, sources, depth) && return t
167170
end
168171
end
169-
if isvarargtype(t)
170-
# never replace Vararg with non-Vararg
171-
return Vararg
172-
end
173172
if allowed_tuplelen < 1 && t.name === Tuple.name
174173
return Any
175174
end

base/essentials.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,9 @@ function rename_unionall(@nospecialize(u))
271271
return UnionAll(nv, body{nv})
272272
end
273273

274-
const _va_typename = Vararg.body.body.name
275274
function isvarargtype(@nospecialize(t))
276275
t = unwrap_unionall(t)
277-
return isa(t, DataType) && (t::DataType).name === _va_typename
276+
return isa(t, Core.VarargMarker)
278277
end
279278

280279
function isvatuple(@nospecialize(t))
@@ -289,14 +288,14 @@ end
289288
function unwrapva(@nospecialize(t))
290289
# NOTE: this returns a related type, but it's NOT a subtype of the original tuple
291290
t2 = unwrap_unionall(t)
292-
return isvarargtype(t2) ? rewrap_unionall(t2.parameters[1], t) : t
291+
return isvarargtype(t2) ? rewrap_unionall(t2.T, t) : t
293292
end
294293

295294
function unconstrain_vararg_length(@nospecialize(va))
296295
# construct a new Vararg type where its length is unconstrained,
297296
# but its element type still captures any dependencies the input
298297
# element type may have had on the input length
299-
T = unwrap_unionall(va).parameters[1]
298+
T = unwrap_unionall(va).T
300299
return rewrap_unionall(Vararg{T}, va)
301300
end
302301

base/promotion.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function full_va_len(p)
157157
isempty(p) && return 0, true
158158
last = p[end]
159159
if isvarargtype(last)
160-
N = unwrap_unionall(last).parameters[2]
160+
N = unwrap_unionall(last).N
161161
if isa(N, Int)
162162
return length(p)::Int + N - 1, true
163163
end

base/show.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,14 @@ function show(io::IO, tv::TypeVar)
21922192
nothing
21932193
end
21942194

2195+
function show(io::IO, vm::Core.VarargMarker)
2196+
print(io, "Vararg{")
2197+
show(io, vm.T)
2198+
print(io, ", ")
2199+
show(io, vm.N)
2200+
print(io, "}")
2201+
end
2202+
21952203
module IRShow
21962204
const Compiler = Core.Compiler
21972205
using Core.IR

src/builtins.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,10 @@ JL_CALLABLE(jl_f_apply_type)
10021002
// substituting typevars (a valid_type_param check here isn't sufficient).
10031003
return (jl_value_t*)jl_type_union(&args[1], nargs-1);
10041004
}
1005+
else if (args[0] == (jl_value_t*)jl_vararg_marker_type) {
1006+
JL_NARGS(apply_type, 3, 3);
1007+
return jl_wrap_vararg(args[1], args[2]);
1008+
}
10051009
else if (jl_is_unionall(args[0])) {
10061010
for(i=1; i < nargs; i++) {
10071011
jl_value_t *pi = args[i];
@@ -1257,7 +1261,6 @@ static void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super)
12571261
if (!jl_is_datatype(super) || !jl_is_abstracttype(super) ||
12581262
tt->super != NULL ||
12591263
tt->name == ((jl_datatype_t*)super)->name ||
1260-
jl_subtype(super, (jl_value_t*)jl_vararg_type) ||
12611264
jl_is_tuple_type(super) ||
12621265
jl_is_namedtuple_type(super) ||
12631266
jl_subtype(super, (jl_value_t*)jl_type_type) ||
@@ -1577,7 +1580,7 @@ void jl_init_primitives(void) JL_GC_DISABLED
15771580
add_builtin("Union", (jl_value_t*)jl_uniontype_type);
15781581
add_builtin("TypeofBottom", (jl_value_t*)jl_typeofbottom_type);
15791582
add_builtin("Tuple", (jl_value_t*)jl_anytuple_type);
1580-
add_builtin("Vararg", (jl_value_t*)jl_vararg_type);
1583+
add_builtin("VarargMarker", (jl_value_t*)jl_vararg_marker_type);
15811584
add_builtin("SimpleVector", (jl_value_t*)jl_simplevector_type);
15821585

15831586
add_builtin("Module", (jl_value_t*)jl_module_type);

src/dump.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,11 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
567567
jl_serialize_value(s, ((jl_tvar_t*)v)->lb);
568568
jl_serialize_value(s, ((jl_tvar_t*)v)->ub);
569569
}
570+
else if (jl_is_vararg_marker(v)) {
571+
write_uint8(s->s, TAG_VARARG);
572+
jl_serialize_value(s, ((jl_vararg_marker_t*)v)->T);
573+
jl_serialize_value(s, ((jl_vararg_marker_t*)v)->N);
574+
}
570575
else if (jl_is_method(v)) {
571576
write_uint8(s->s, TAG_METHOD);
572577
jl_method_t *m = (jl_method_t*)v;
@@ -1747,6 +1752,15 @@ static jl_value_t *jl_deserialize_value(jl_serializer_state *s, jl_value_t **loc
17471752
tv->ub = jl_deserialize_value(s, &tv->ub);
17481753
jl_gc_wb(tv, tv->ub);
17491754
return (jl_value_t*)tv;
1755+
case TAG_VARARG:
1756+
v = jl_gc_alloc(s->ptls, sizeof(jl_vararg_marker_t), jl_vararg_marker_type);
1757+
jl_vararg_marker_t *vm = (jl_vararg_marker_t*)v;
1758+
arraylist_push(&backref_list, vm);
1759+
vm->T = (jl_sym_t*)jl_deserialize_value(s, NULL);
1760+
jl_gc_wb(vm, vm->T);
1761+
vm->N = jl_deserialize_value(s, &vm->N);
1762+
jl_gc_wb(vm, vm->N);
1763+
return (jl_value_t*)vm;
17501764
case TAG_METHOD:
17511765
return jl_deserialize_value_method(s, loc);
17521766
case TAG_METHOD_INSTANCE:
@@ -2580,7 +2594,8 @@ void jl_init_serializer(void)
25802594

25812595
jl_bool_type, jl_linenumbernode_type, jl_pinode_type,
25822596
jl_upsilonnode_type, jl_type_type, jl_bottom_type, jl_ref_type,
2583-
jl_pointer_type, jl_vararg_type, jl_abstractarray_type, jl_nothing_type,
2597+
jl_pointer_type, jl_abstractarray_type, jl_nothing_type,
2598+
jl_vararg_marker_type,
25842599
jl_densearray_type, jl_function_type, jl_typename_type,
25852600
jl_builtin_type, jl_task_type, jl_uniontype_type,
25862601
jl_array_any_type, jl_intrinsic_type,
@@ -2629,6 +2644,7 @@ void jl_init_serializer(void)
26292644
deser_tag[TAG_GOTOIFNOT] = (jl_value_t*)jl_gotoifnot_type;
26302645
deser_tag[TAG_RETURNNODE] = (jl_value_t*)jl_returnnode_type;
26312646
deser_tag[TAG_ARGUMENT] = (jl_value_t*)jl_argument_type;
2647+
deser_tag[TAG_VARARG] = (jl_value_t*)jl_vararg_marker_type;
26322648

26332649
intptr_t i = 0;
26342650
while (vals[i] != NULL) {
@@ -2658,7 +2674,6 @@ void jl_init_serializer(void)
26582674
arraylist_push(&builtin_typenames, ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_abstractarray_type))->name);
26592675
arraylist_push(&builtin_typenames, ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_densearray_type))->name);
26602676
arraylist_push(&builtin_typenames, jl_tuple_typename);
2661-
arraylist_push(&builtin_typenames, jl_vararg_typename);
26622677
arraylist_push(&builtin_typenames, jl_namedtuple_typename);
26632678
}
26642679

0 commit comments

Comments
 (0)