Skip to content

Commit 53bb7fb

Browse files
authored
allow nested combinations of (named)tuples, symbols, and bits as type parameters (#46300)
1 parent 1ece3f6 commit 53bb7fb

File tree

5 files changed

+38
-28
lines changed

5 files changed

+38
-28
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ New language features
99
handled via `Base.split_rest`. ([#42902])
1010
* Character literals now support the same syntax allowed in string literals; i.e. the syntax can
1111
represent invalid UTF-8 sequences as allowed by the `Char` type ([#44989]).
12+
* Nested combinations of tuples and named tuples of symbols are now allowed as type parameters ([#46300]).
1213

1314
Language changes
1415
----------------

base/compiler/tfuncs.jl

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,18 +1351,7 @@ end
13511351
add_tfunc(fieldtype, 2, 3, fieldtype_tfunc, 0)
13521352

13531353
# Like `valid_tparam`, but in the type domain.
1354-
function valid_tparam_type(T::DataType)
1355-
T === Symbol && return true
1356-
isbitstype(T) && return true
1357-
if T <: Tuple
1358-
isconcretetype(T) || return false
1359-
for P in T.parameters
1360-
(P === Symbol || isbitstype(P)) || return false
1361-
end
1362-
return true
1363-
end
1364-
return false
1365-
end
1354+
valid_tparam_type(T::DataType) = valid_typeof_tparam(T)
13661355
valid_tparam_type(U::Union) = valid_tparam_type(U.a) && valid_tparam_type(U.b)
13671356
valid_tparam_type(U::UnionAll) = valid_tparam_type(unwrap_unionall(U))
13681357

base/compiler/typeutils.jl

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,26 @@ function valid_as_lattice(@nospecialize(x))
103103
return false
104104
end
105105

106-
# test if non-Type, non-TypeVar `x` can be used to parameterize a type
107-
function valid_tparam(@nospecialize(x))
108-
if isa(x, Tuple)
109-
for t in x
110-
isa(t, Symbol) || isbits(t) || return false
106+
function valid_typeof_tparam(@nospecialize(t))
107+
if t === Symbol || isbitstype(t)
108+
return true
109+
end
110+
isconcretetype(t) || return false
111+
if t <: NamedTuple
112+
t = t.parameters[2]
113+
end
114+
if t <: Tuple
115+
for p in t.parameters
116+
valid_typeof_tparam(p) || return false
111117
end
112118
return true
113119
end
114-
return isa(x, Symbol) || isbits(x)
120+
return false
115121
end
116122

123+
# test if non-Type, non-TypeVar `x` can be used to parameterize a type
124+
valid_tparam(@nospecialize(x)) = valid_typeof_tparam(typeof(x))
125+
117126
function compatible_vatuple(a::DataType, b::DataType)
118127
vaa = a.parameters[end]
119128
vab = a.parameters[end]

src/builtins.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,20 +1258,28 @@ JL_CALLABLE(jl_f_set_binding_type)
12581258

12591259
// apply_type -----------------------------------------------------------------
12601260

1261-
int jl_valid_type_param(jl_value_t *v)
1261+
static int is_nestable_type_param(jl_value_t *t)
12621262
{
1263-
if (jl_is_tuple(v)) {
1263+
if (jl_is_namedtuple_type(t))
1264+
t = jl_tparam1(t);
1265+
if (jl_is_tuple_type(t)) {
12641266
// NOTE: tuples of symbols are not currently bits types, but have been
12651267
// allowed as type parameters. this is a bit ugly.
1266-
jl_value_t *tt = jl_typeof(v);
1267-
size_t i, l = jl_nparams(tt);
1268-
for(i=0; i < l; i++) {
1269-
jl_value_t *pi = jl_tparam(tt,i);
1270-
if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi)))
1268+
size_t i, l = jl_nparams(t);
1269+
for (i = 0; i < l; i++) {
1270+
jl_value_t *pi = jl_tparam(t, i);
1271+
if (!(pi == (jl_value_t*)jl_symbol_type || jl_isbits(pi) || is_nestable_type_param(pi)))
12711272
return 0;
12721273
}
12731274
return 1;
12741275
}
1276+
return 0;
1277+
}
1278+
1279+
int jl_valid_type_param(jl_value_t *v)
1280+
{
1281+
if (jl_is_tuple(v) || jl_is_namedtuple(v))
1282+
return is_nestable_type_param(jl_typeof(v));
12751283
if (jl_is_vararg(v))
12761284
return 0;
12771285
// TODO: maybe more things

test/core.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,9 +1987,8 @@ mutable struct TupleParam{P}
19871987
x::Bool
19881988
end
19891989

1990-
function tupledispatch(a::TupleParam{(1,:a)})
1991-
a.x
1992-
end
1990+
tupledispatch(a::TupleParam{(1,:a)}) = a.x
1991+
tupledispatch(a::TupleParam{(1,(:a,))}) = 42
19931992

19941993
# tuples can be used as type params
19951994
let t1 = TupleParam{(1,:a)}(true),
@@ -2001,6 +2000,10 @@ let t1 = TupleParam{(1,:a)}(true),
20012000
# dispatch works properly
20022001
@test tupledispatch(t1) == true
20032002
@test_throws MethodError tupledispatch(t2)
2003+
2004+
@test tupledispatch(TupleParam{(1,(:a,))}(true)) === 42
2005+
@test_throws TypeError TupleParam{NamedTuple{(:a,), Tuple{Any}}((1,))}
2006+
@test_throws TypeError Val{NamedTuple{(:a,), Tuple{NamedTuple{<:Any,Tuple{Int}}}}(((x=2,),))}
20042007
end
20052008

20062009
# issue #5254

0 commit comments

Comments
 (0)