Skip to content

Commit bf2787d

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 bf4b429 commit bf2787d

File tree

5 files changed

+90
-52
lines changed

5 files changed

+90
-52
lines changed

base/inference.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,9 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...)
900900
uncertain = true
901901
end
902902
!uncertain && return Const(appl)
903+
if isvarargtype(headtype)
904+
return Type
905+
end
903906
if type_too_complex(appl,0)
904907
return Type{_} where _<:headtype
905908
end
@@ -1821,8 +1824,17 @@ function ⊑(a::ANY, b::ANY)
18211824
end
18221825
end
18231826

1824-
widenconst(c::Const) = isa(c.val, Type) ? Type{c.val} : typeof(c.val)
18251827
widenconst(c::Conditional) = Bool
1828+
function widenconst(c::Const)
1829+
if isa(c.val, Type)
1830+
if isvarargtype(c.val)
1831+
return Type
1832+
end
1833+
return Type{c.val}
1834+
else
1835+
return typeof(c.val)
1836+
end
1837+
end
18261838
widenconst(t::ANY) = t
18271839

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

src/builtins.c

Lines changed: 54 additions & 4 deletions
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

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,9 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
376376

377377
JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub)
378378
{
379-
if (lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb))
379+
if ((lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb)) || jl_is_vararg_type(lb))
380380
jl_type_error_rt("TypeVar", "lower bound", (jl_value_t*)jl_type_type, lb);
381-
if (ub != (jl_value_t*)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub))
381+
if ((ub != (jl_value_t*)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub)) || jl_is_vararg_type(ub))
382382
jl_type_error_rt("TypeVar", "upper bound", (jl_value_t*)jl_type_type, ub);
383383
jl_ptls_t ptls = jl_get_ptls_states();
384384
jl_tvar_t *tv = (jl_tvar_t*)jl_gc_alloc(ptls, sizeof(jl_tvar_t), jl_tvar_type);
@@ -659,25 +659,6 @@ jl_value_t *jl_cache_type_(jl_datatype_t *type)
659659

660660
// type instantiation
661661

662-
static int valid_type_param(jl_value_t *v)
663-
{
664-
if (jl_is_tuple(v)) {
665-
// NOTE: tuples of symbols are not currently bits types, but have been
666-
// allowed as type parameters. this is a bit ugly.
667-
jl_value_t *tt = jl_typeof(v);
668-
size_t i;
669-
size_t l = jl_nparams(tt);
670-
for(i=0; i < l; i++) {
671-
jl_value_t *pi = jl_tparam(tt,i);
672-
if (!(pi == (jl_value_t*)jl_sym_type || jl_isbits(pi)))
673-
return 0;
674-
}
675-
return 1;
676-
}
677-
// TODO: maybe more things
678-
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
679-
}
680-
681662
static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub)
682663
{
683664
jl_value_t *lb = t, *ub = t;
@@ -708,13 +689,6 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
708689
jl_error("too many parameters for type");
709690
jl_value_t *pi = params[i];
710691

711-
if (!valid_type_param(pi)) {
712-
jl_type_error_rt("Type", "parameter",
713-
jl_isa(pi, (jl_value_t*)jl_number_type) ?
714-
(jl_value_t*)jl_long_type : (jl_value_t*)jl_type_type,
715-
pi);
716-
}
717-
718692
tc0 = ((jl_unionall_t*)tc0)->body;
719693
// doing a substitution can cause later UnionAlls to be dropped,
720694
// as in `NTuple{0,T} where T` => `Tuple{}`. allow values to be
@@ -1150,23 +1124,11 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11501124
return (jl_value_t*)ndt;
11511125
}
11521126

1153-
static void check_tuple_parameter(jl_value_t *pi, size_t i, size_t np)
1154-
{
1155-
// TODO: should possibly only allow Types and TypeVars, but see
1156-
// https://github.com/JuliaLang/julia/commit/85f45974a581ab9af955bac600b90d9ab00f093b#commitcomment-13041922
1157-
if (!valid_type_param(pi))
1158-
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
1159-
if (i != np-1 && jl_is_vararg_type(pi))
1160-
jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi);
1161-
}
1162-
11631127
static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
11641128
{
11651129
int cacheable = 1;
11661130
for(size_t i=0; i < np; i++) {
1167-
jl_value_t *pi = p[i];
1168-
check_tuple_parameter(pi, i, np);
1169-
if (!jl_is_leaf_type(pi))
1131+
if (!jl_is_leaf_type(p[i]))
11701132
cacheable = 0;
11711133
}
11721134
jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np,
@@ -1246,20 +1208,17 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
12461208
iparams = jl_svec_data(ip_heap);
12471209
}
12481210
int cacheable = 1;
1249-
if (jl_is_va_tuple(tt)) {
1211+
if (jl_is_va_tuple(tt))
12501212
cacheable = 0;
1251-
}
12521213
int i;
12531214
for(i=0; i < ntp; i++) {
12541215
jl_value_t *elt = jl_svecref(tp, i);
12551216
jl_value_t *pi = (jl_value_t*)inst_type_w_(elt, env, stack, 0);
12561217
iparams[i] = pi;
12571218
if (ip_heap)
12581219
jl_gc_wb(ip_heap, pi);
1259-
check_tuple_parameter(pi, i, ntp);
1260-
if (cacheable && !jl_is_leaf_type(pi)) {
1220+
if (cacheable && !jl_is_leaf_type(pi))
12611221
cacheable = 0;
1262-
}
12631222
}
12641223
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable,
12651224
stack, env);

test/core.jl

Lines changed: 7 additions & 1 deletion
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

Lines changed: 11 additions & 0 deletions
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)