Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix some issues with Vararg #20204

Merged
merged 2 commits into from
Jan 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,11 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...)
#end
uncertain = true
if istuple
push!(tparams, Any)
if i == largs
push!(tparams, Vararg)
else
push!(tparams, Any)
end
else
# TODO: use rewrap_unionall to skip only the unknown parameters
#push!(tparams, headtype.parameters[i-1])
Expand All @@ -896,6 +900,9 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...)
uncertain = true
end
!uncertain && return Const(appl)
if isvarargtype(headtype)
return Type
end
if type_too_complex(appl,0)
return Type{_} where _<:headtype
end
Expand Down Expand Up @@ -1817,8 +1824,17 @@ function ⊑(a::ANY, b::ANY)
end
end

widenconst(c::Const) = isa(c.val, Type) ? Type{c.val} : typeof(c.val)
widenconst(c::Conditional) = Bool
function widenconst(c::Const)
if isa(c.val, Type)
if isvarargtype(c.val)
return Type
end
return Type{c.val}
else
return typeof(c.val)
end
end
widenconst(t::ANY) = t

issubstate(a::VarState, b::VarState) = (a.typ ⊑ b.typ && a.undef <= b.undef)
Expand Down
58 changes: 54 additions & 4 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,13 +1012,63 @@ JL_DLLEXPORT void jl_show(jl_value_t *stream, jl_value_t *v)

// internal functions ---------------------------------------------------------

static int valid_type_param(jl_value_t *v)
{
if (jl_is_tuple(v)) {
// NOTE: tuples of symbols are not currently bits types, but have been
// allowed as type parameters. this is a bit ugly.
jl_value_t *tt = jl_typeof(v);
size_t i, l = jl_nparams(tt);
for(i=0; i < l; i++) {
jl_value_t *pi = jl_tparam(tt,i);
if (!(pi == (jl_value_t*)jl_sym_type || jl_isbits(pi)))
return 0;
}
return 1;
}
if (jl_is_vararg_type(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));
}

JL_CALLABLE(jl_f_apply_type)
{
JL_NARGSV(apply_type, 1);
if (!jl_is_unionall(args[0]) && args[0] != (jl_value_t*)jl_anytuple_type &&
args[0] != (jl_value_t*)jl_uniontype_type)
jl_type_error("Type{...} expression", (jl_value_t*)jl_unionall_type, args[0]);
return jl_apply_type(args[0], &args[1], nargs-1);
int i;
if (args[0] == (jl_value_t*)jl_anytuple_type) {
for(i=1; i < nargs; i++) {
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 (i != nargs-1)
jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi);
}
else if (!valid_type_param(pi)) {
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
}
}
return (jl_value_t*)jl_apply_tuple_type_v(&args[1], nargs-1);
}
else if (args[0] == (jl_value_t*)jl_uniontype_type) {
// Union{} has extra restrictions, so it needs to be checked after
// 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_unionall(args[0])) {
for(i=1; i < nargs; i++) {
jl_value_t *pi = args[i];
if (!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,
pi);
}
}
return jl_apply_type(args[0], &args[1], nargs-1);
}
jl_type_error("Type{...} expression", (jl_value_t*)jl_unionall_type, args[0]);
}

// generic function reflection ------------------------------------------------
Expand Down
51 changes: 5 additions & 46 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,9 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)

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))
if ((lb != jl_bottom_type && !jl_is_type(lb) && !jl_is_typevar(lb)) || jl_is_vararg_type(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))
if ((ub != (jl_value_t*)jl_any_type && !jl_is_type(ub) && !jl_is_typevar(ub)) || jl_is_vararg_type(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);
Expand Down Expand Up @@ -659,25 +659,6 @@ jl_value_t *jl_cache_type_(jl_datatype_t *type)

// type instantiation

static int valid_type_param(jl_value_t *v)
{
if (jl_is_tuple(v)) {
// NOTE: tuples of symbols are not currently bits types, but have been
// allowed as type parameters. this is a bit ugly.
jl_value_t *tt = jl_typeof(v);
size_t i;
size_t l = jl_nparams(tt);
for(i=0; i < l; i++) {
jl_value_t *pi = jl_tparam(tt,i);
if (!(pi == (jl_value_t*)jl_sym_type || jl_isbits(pi)))
return 0;
}
return 1;
}
// TODO: maybe more things
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
}

static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub)
{
jl_value_t *lb = t, *ub = t;
Expand Down Expand Up @@ -708,13 +689,6 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
jl_error("too many parameters for type");
jl_value_t *pi = params[i];

if (!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,
pi);
}

tc0 = ((jl_unionall_t*)tc0)->body;
// doing a substitution can cause later UnionAlls to be dropped,
// as in `NTuple{0,T} where T` => `Tuple{}`. allow values to be
Expand Down Expand Up @@ -1150,23 +1124,11 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
return (jl_value_t*)ndt;
}

static void check_tuple_parameter(jl_value_t *pi, size_t i, size_t np)
{
// TODO: should possibly only allow Types and TypeVars, but see
// https://github.com/JuliaLang/julia/commit/85f45974a581ab9af955bac600b90d9ab00f093b#commitcomment-13041922
if (!valid_type_param(pi))
jl_type_error_rt("Tuple", "parameter", (jl_value_t*)jl_type_type, pi);
if (i != np-1 && jl_is_vararg_type(pi))
jl_type_error_rt("Tuple", "non-final parameter", (jl_value_t*)jl_type_type, pi);
}

static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params)
{
int cacheable = 1;
for(size_t i=0; i < np; i++) {
jl_value_t *pi = p[i];
check_tuple_parameter(pi, i, np);
if (!jl_is_leaf_type(pi))
if (!jl_is_leaf_type(p[i]))
cacheable = 0;
}
jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np,
Expand Down Expand Up @@ -1246,20 +1208,17 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
iparams = jl_svec_data(ip_heap);
}
int cacheable = 1;
if (jl_is_va_tuple(tt)) {
if (jl_is_va_tuple(tt))
cacheable = 0;
}
int i;
for(i=0; i < ntp; i++) {
jl_value_t *elt = jl_svecref(tp, i);
jl_value_t *pi = (jl_value_t*)inst_type_w_(elt, env, stack, 0);
iparams[i] = pi;
if (ip_heap)
jl_gc_wb(ip_heap, pi);
check_tuple_parameter(pi, i, ntp);
if (cacheable && !jl_is_leaf_type(pi)) {
if (cacheable && !jl_is_leaf_type(pi))
cacheable = 0;
}
}
jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable,
stack, env);
Expand Down
8 changes: 7 additions & 1 deletion test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ f47{T}(x::Vector{Vector{T}}) = 0
@test_throws TypeError ([T] where T)
@test_throws TypeError (Array{T} where T<:[])
@test_throws TypeError (Array{T} where T>:[])
@test_throws TypeError (Array{T} where T<:Vararg)
@test_throws TypeError (Array{T} where T>:Vararg)
@test_throws TypeError (Array{T} where T<:Vararg{Int})
@test_throws TypeError (Array{T} where T<:Vararg{Int,2})

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

# don't allow Vararg{} in Union{} type constructor
@test_throws TypeError Union{Int,Vararg{Int}}
@test_throws TypeError Union{Vararg{Int}}

# don't allow Vararg{} in Tuple{} type constructor in non-trailing position
# only allow Vararg{} in last position of Tuple{ }
@test_throws TypeError Tuple{Vararg{Int32},Int64,Float64}
@test_throws TypeError Tuple{Int64,Vararg{Int32},Float64}
@test_throws TypeError Array{Vararg}

# don't allow non-types in Union
@test_throws TypeError Union{1}
Expand Down
23 changes: 23 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,29 @@ function g19348(x)
end
test_inferred_static(@code_typed g19348((1, 2.0)))

# make sure Tuple{unknown} handles the possibility that `unknown` is a Vararg
function maybe_vararg_tuple_1()
x = Any[Vararg{Int}][1]
Tuple{x}
end
@test Type{Tuple{Vararg{Int}}} <: Base.return_types(maybe_vararg_tuple_1, ())[1]
function maybe_vararg_tuple_2()
x = Type[Vararg{Int}][1]
Tuple{x}
end
@test Type{Tuple{Vararg{Int}}} <: Base.return_types(maybe_vararg_tuple_2, ())[1]

# issue #11480
@noinline f11480(x,y) = x
let A = Ref
function h11480(x::A{A{A{A{A{A{A{A{A{Int}}}}}}}}}) # enough for type_too_complex
y :: Tuple{Vararg{typeof(x)}} = (x,) # apply_type(Vararg, too_complex) => TypeVar(_,Vararg)
f(y[1], # fool getfield logic : Tuple{_<:Vararg}[1] => Vararg
1) # make it crash by construction of the signature Tuple{Vararg,Int}
end
@test !Base.isvarargtype(Base.return_types(h11480, (Any,))[1])
end

# Issue 19641
foo19641() = let a = 1.0
Core.Inference.return_type(x -> x + a, Tuple{Float64})
Expand Down