Skip to content

Commit f252ca5

Browse files
committed
fix some more Vararg issues
- fix #11480, don't use `Type{_} where _<:Vararg` in inference - disallow `Vararg` in type var bounds - disallow `Vararg` as a type parameter in general - move some checks from lower-level functions to apply_type
1 parent c7c1062 commit f252ca5

File tree

5 files changed

+90
-53
lines changed

5 files changed

+90
-53
lines changed

base/inference.jl

+13-1
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,9 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...)
860860
uncertain = true
861861
end
862862
!uncertain && return Const(appl)
863+
if isvarargtype(headtype)
864+
return Type
865+
end
863866
if type_too_complex(appl,0)
864867
return Type{_} where _<:headtype
865868
end
@@ -1686,7 +1689,16 @@ function ⊑(a::ANY, b::ANY)
16861689
end
16871690
end
16881691

1689-
widenconst(c::Const) = isa(c.val, Type) ? Type{c.val} : typeof(c.val)
1692+
function widenconst(c::Const)
1693+
if isa(c.val, Type)
1694+
if isvarargtype(c.val)
1695+
return Type
1696+
end
1697+
return Type{c.val}
1698+
else
1699+
return typeof(c.val)
1700+
end
1701+
end
16901702
widenconst(t::ANY) = t
16911703

16921704
issubstate(a::VarState, b::VarState) = (a.typ b.typ && a.undef <= b.undef)

src/builtins.c

+54-4
Original file line numberDiff line numberDiff line change
@@ -1012,13 +1012,63 @@ JL_DLLEXPORT void jl_show(jl_value_t *stream, jl_value_t *v)
10121012

10131013
// internal functions ---------------------------------------------------------
10141014

1015+
static int valid_type_param(jl_value_t *v)
1016+
{
1017+
if (jl_is_tuple(v)) {
1018+
// NOTE: tuples of symbols are not currently bits types, but have been
1019+
// allowed as type parameters. this is a bit ugly.
1020+
jl_value_t *tt = jl_typeof(v);
1021+
size_t i, l = jl_nparams(tt);
1022+
for(i=0; i < l; i++) {
1023+
jl_value_t *pi = jl_tparam(tt,i);
1024+
if (!(pi == (jl_value_t*)jl_sym_type || jl_isbits(pi)))
1025+
return 0;
1026+
}
1027+
return 1;
1028+
}
1029+
if (jl_is_vararg_type(v))
1030+
return 0;
1031+
// TODO: maybe more things
1032+
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
1033+
}
1034+
10151035
JL_CALLABLE(jl_f_apply_type)
10161036
{
10171037
JL_NARGSV(apply_type, 1);
1018-
if (!jl_is_unionall(args[0]) && args[0] != (jl_value_t*)jl_anytuple_type &&
1019-
args[0] != (jl_value_t*)jl_uniontype_type)
1020-
jl_type_error("Type{...} expression", (jl_value_t*)jl_unionall_type, args[0]);
1021-
return jl_apply_type(args[0], &args[1], nargs-1);
1038+
int i;
1039+
if (args[0] == (jl_value_t*)jl_anytuple_type) {
1040+
for(i=1; i < nargs; i++) {
1041+
jl_value_t *pi = args[i];
1042+
// TODO: should possibly only allow Types and TypeVars, but see
1043+
// https://github.com/JuliaLang/julia/commit/85f45974a581ab9af955bac600b90d9ab00f093b#commitcomment-13041922
1044+
if (jl_is_vararg_type(pi)) {
1045+
if (i != nargs-1)
1046+
jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi);
1047+
}
1048+
else if (!valid_type_param(pi)) {
1049+
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
1050+
}
1051+
}
1052+
return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1);
1053+
}
1054+
else if (args[0] == (jl_value_t*)jl_uniontype_type) {
1055+
// Union{} has extra restrictions, so it needs to be checked after
1056+
// substituting typevars (a valid_type_param check here isn't sufficient).
1057+
return (jl_value_t*)jl_type_union(&args[1], nargs-1);
1058+
}
1059+
else if (jl_is_unionall(args[0])) {
1060+
for(i=1; i < nargs; i++) {
1061+
jl_value_t *pi = args[i];
1062+
if (!valid_type_param(pi)) {
1063+
jl_type_error_rt("Type", "parameter",
1064+
jl_isa(pi, (jl_value_t*)jl_number_type) ?
1065+
(jl_value_t*)jl_long_type : (jl_value_t*)jl_type_type,
1066+
pi);
1067+
}
1068+
}
1069+
return jl_apply_type(args[0], &args[1], nargs-1);
1070+
}
1071+
jl_type_error("Type{...} expression", (jl_value_t*)jl_unionall_type, args[0]);
10221072
}
10231073

10241074
// generic function reflection ------------------------------------------------

src/jltypes.c

+5-47
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,9 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
375375

376376
JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub)
377377
{
378-
if (lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb))
378+
if ((lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb)) || jl_is_vararg_type(lb))
379379
jl_type_error_rt("TypeVar", "lower bound", (jl_value_t*)jl_type_type, lb);
380-
if (ub != (jl_value_t*)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub))
380+
if ((ub != (jl_value_t*)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub)) || jl_is_vararg_type(ub))
381381
jl_type_error_rt("TypeVar", "upper bound", (jl_value_t*)jl_type_type, ub);
382382
jl_ptls_t ptls = jl_get_ptls_states();
383383
jl_tvar_t *tv = (jl_tvar_t*)jl_gc_alloc(ptls, sizeof(jl_tvar_t), jl_tvar_type);
@@ -658,25 +658,6 @@ jl_value_t *jl_cache_type_(jl_datatype_t *type)
658658

659659
// type instantiation
660660

661-
static int valid_type_param(jl_value_t *v)
662-
{
663-
if (jl_is_tuple(v)) {
664-
// NOTE: tuples of symbols are not currently bits types, but have been
665-
// allowed as type parameters. this is a bit ugly.
666-
jl_value_t *tt = jl_typeof(v);
667-
size_t i;
668-
size_t l = jl_nparams(tt);
669-
for(i=0; i < l; i++) {
670-
jl_value_t *pi = jl_tparam(tt,i);
671-
if (!(pi == (jl_value_t*)jl_sym_type || jl_isbits(pi)))
672-
return 0;
673-
}
674-
return 1;
675-
}
676-
// TODO: maybe more things
677-
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
678-
}
679-
680661
static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub)
681662
{
682663
jl_value_t *lb = t, *ub = t;
@@ -705,14 +686,6 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
705686
if (!jl_is_unionall(tc))
706687
jl_error("too many parameters for type");
707688
jl_value_t *pi = params[i];
708-
709-
if (!valid_type_param(pi)) {
710-
jl_type_error_rt("Type", "parameter",
711-
jl_isa(pi, (jl_value_t*)jl_number_type) ?
712-
(jl_value_t*)jl_long_type : (jl_value_t*)jl_type_type,
713-
pi);
714-
}
715-
716689
jl_unionall_t *ua = (jl_unionall_t*)tc;
717690
if (!jl_has_free_typevars(ua->var->lb) && !jl_has_free_typevars(ua->var->ub) &&
718691
!within_typevar(pi, ua->var->lb, ua->var->ub)) {
@@ -1139,23 +1112,11 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11391112
return (jl_value_t*)ndt;
11401113
}
11411114

1142-
static void check_tuple_parameter(jl_value_t *pi, size_t i, size_t np)
1143-
{
1144-
// TODO: should possibly only allow Types and TypeVars, but see
1145-
// https://github.com/JuliaLang/julia/commit/85f45974a581ab9af955bac600b90d9ab00f093b#commitcomment-13041922
1146-
if (!valid_type_param(pi))
1147-
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
1148-
if (i != np-1 && jl_is_vararg_type(pi))
1149-
jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi);
1150-
}
1151-
11521115
static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
11531116
{
11541117
int cacheable = 1;
11551118
for(size_t i=0; i < np; i++) {
1156-
jl_value_t *pi = p[i];
1157-
check_tuple_parameter(pi, i, np);
1158-
if (!jl_is_leaf_type(pi))
1119+
if (!jl_is_leaf_type(p[i]))
11591120
cacheable = 0;
11601121
}
11611122
jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np,
@@ -1235,20 +1196,17 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
12351196
iparams = jl_svec_data(ip_heap);
12361197
}
12371198
int cacheable = 1;
1238-
if (jl_is_va_tuple(tt)) {
1199+
if (jl_is_va_tuple(tt))
12391200
cacheable = 0;
1240-
}
12411201
int i;
12421202
for(i=0; i < ntp; i++) {
12431203
jl_value_t *elt = jl_svecref(tp, i);
12441204
jl_value_t *pi = (jl_value_t*)inst_type_w_(elt, env, stack, 0);
12451205
iparams[i] = pi;
12461206
if (ip_heap)
12471207
jl_gc_wb(ip_heap, pi);
1248-
check_tuple_parameter(pi, i, ntp);
1249-
if (cacheable && !jl_is_leaf_type(pi)) {
1208+
if (cacheable && !jl_is_leaf_type(pi))
12501209
cacheable = 0;
1251-
}
12521210
}
12531211
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable,
12541212
stack, env);

test/core.jl

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ f47{T}(x::Vector{Vector{T}}) = 0
1515
@test_throws TypeError ([T] where T)
1616
@test_throws TypeError (Array{T} where T<:[])
1717
@test_throws TypeError (Array{T} where T>:[])
18+
@test_throws TypeError (Array{T} where T<:Vararg)
19+
@test_throws TypeError (Array{T} where T>:Vararg)
20+
@test_throws TypeError (Array{T} where T<:Vararg{Int})
21+
@test_throws TypeError (Array{T} where T<:Vararg{Int,2})
1822

1923
# issue #8652
2024
args_morespecific(a, b) = ccall(:jl_type_morespecific, Cint, (Any,Any), a, b) != 0
@@ -3086,10 +3090,12 @@ end
30863090

30873091
# don't allow Vararg{} in Union{} type constructor
30883092
@test_throws TypeError Union{Int,Vararg{Int}}
3093+
@test_throws TypeError Union{Vararg{Int}}
30893094

3090-
# don't allow Vararg{} in Tuple{} type constructor in non-trailing position
3095+
# only allow Vararg{} in last position of Tuple{ }
30913096
@test_throws TypeError Tuple{Vararg{Int32},Int64,Float64}
30923097
@test_throws TypeError Tuple{Int64,Vararg{Int32},Float64}
3098+
@test_throws TypeError Array{Vararg}
30933099

30943100
# don't allow non-types in Union
30953101
@test_throws TypeError Union{1}

test/inference.jl

+11
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,17 @@ function maybe_vararg_tuple_2()
478478
end
479479
@test Type{Tuple{Vararg{Int}}} <: Base.return_types(maybe_vararg_tuple_2, ())[1]
480480

481+
# issue #11480
482+
@noinline f11480(x,y) = x
483+
let A = Ref
484+
function h11480(x::A{A{A{A{A{A{A{A{A{Int}}}}}}}}}) # enough for type_too_complex
485+
y :: Tuple{Vararg{typeof(x)}} = (x,) # apply_type(Vararg, too_complex) => TypeVar(_,Vararg)
486+
f(y[1], # fool getfield logic : Tuple{_<:Vararg}[1] => Vararg
487+
1) # make it crash by construction of the signature Tuple{Vararg,Int}
488+
end
489+
@test !Base.isvarargtype(Base.return_types(h11480, (Any,))[1])
490+
end
491+
481492
# Issue 19641
482493
foo19641() = let a = 1.0
483494
Core.Inference.return_type(x -> x + a, Tuple{Float64})

0 commit comments

Comments
 (0)