Skip to content

Commit

Permalink
implement Vararg{T,N} type rules
Browse files Browse the repository at this point in the history
This commit includes the following changes:

Add new jl_tuple_subtype_ algorithm

Test jl_subtype_le more thoroughly, return "new" result

This also makes tweaks to the algorithm to prevent matches like
Array{Tuple{Int}} <: Array{NTuple}

Update jl_type_morespecific

Update type_match for new va tuples

Implement jl_type_intersect for new Vararg tuples

Update typejoin for new Varargs

Instantiate Tuple{Vararg{Int,3}} as Tuple{Int,Int,Int}

Make NTuple{N,T} a typealias for Tuple{Vararg{T,N}}

Don't wrap V<:Vararg in TypeVar(:_, V)
  • Loading branch information
timholy committed May 5, 2016
1 parent c4f54d1 commit add7a23
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 440 deletions.
2 changes: 2 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ convert{T}(::Type{T}, x::T) = x
cconvert{T}(::Type{T}, x) = convert(T, x)
unsafe_convert{T}(::Type{T}, x::T) = x

typealias NTuple{N,T} Tuple{Vararg{T,N}}

# primitive array constructors
(::Type{Array{T,N}}){T,N}(d::NTuple{N,Int}) =
ccall(:jl_new_array, Array{T,N}, (Any,Any), Array{T,N}, d)
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export
Irrational,
Matrix,
MergeSort,
NTuple,
Nullable,
ObjectIdDict,
OrdinalRange,
Expand Down
23 changes: 11 additions & 12 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ function istopfunction(topmod, f::ANY, sym)
return false
end

isknownlength(t::DataType) = !isvatuple(t) && !(t.name===NTuple.name && !isa(t.parameters[1],Int))
isknownlength(t::DataType) = !isvatuple(t) || (length(t.parameters) == 1 && isa(t.parameters[1].parameters[2],Int))

# t[n:end]
tupletype_tail(t::ANY, n) = Tuple{t.parameters[n:end]...}
Expand Down Expand Up @@ -303,7 +303,7 @@ function typeof_tfunc(t::ANY)
Type{typeof(t)}
end
elseif isa(t,DataType)
if isleaftype(t)
if isleaftype(t) || isvarargtype(t)
Type{t}
elseif t === Any
DataType
Expand Down Expand Up @@ -397,7 +397,7 @@ function limit_type_depth(t::ANY, d::Int, cov::Bool, vars)
else
return t
end
if inexact
if inexact && !isvarargtype(R)
R = TypeVar(:_,R)
push!(vars, R)
end
Expand Down Expand Up @@ -428,9 +428,6 @@ function getfield_tfunc(s0::ANY, name)
return reduce(tmerge, Bottom, map(t->getfield_tfunc(t, name)[1], s.types)), false
end
if isa(s,DataType)
if is(s.name,NTuple.name)
return (name Symbol ? Bottom : s.parameters[2]), true
end
if s.abstract
return Any, false
end
Expand Down Expand Up @@ -501,7 +498,7 @@ function fieldtype_tfunc(s::ANY, name)
if is(t,Bottom)
return t
end
Type{exact || isleaftype(t) || isa(t,TypeVar) ? t : TypeVar(:_, t)}
Type{exact || isleaftype(t) || isa(t,TypeVar) || isvarargtype(t) ? t : TypeVar(:_, t)}
end
add_tfunc(fieldtype, 2, 2, fieldtype_tfunc)

Expand Down Expand Up @@ -581,7 +578,7 @@ function apply_type_tfunc(args...)
if type_too_complex(appl,0)
return Type{TypeVar(:_,headtype)}
end
!isa(appl,TypeVar) ? Type{TypeVar(:_,appl)} : Type{appl}
!(isa(appl,TypeVar) || isvarargtype(appl)) ? Type{TypeVar(:_,appl)} : Type{appl}
end
add_tfunc(apply_type, 1, IInf, apply_type_tfunc)

Expand Down Expand Up @@ -861,7 +858,9 @@ function precise_container_types(args, types, vtypes::VarTable, sv)
assert(n == length(types))
result = cell(n)
for i = 1:n
ai = args[i]; ti = types[i]; tti = widenconst(ti)
ai = args[i]
ti = types[i]
tti = widenconst(ti)
if isa(ai,Expr) && ai.head === :call && (abstract_evals_to_constant(ai.args[1], svec, vtypes, sv) ||
abstract_evals_to_constant(ai.args[1], tuple, vtypes, sv))
aa = ai.args
Expand All @@ -873,8 +872,8 @@ function precise_container_types(args, types, vtypes::VarTable, sv)
return nothing
elseif ti Tuple
if i == n
if tti.name === NTuple.name
result[i] = Any[Vararg{tti.parameters[2]}]
if isvatuple(tti) && length(tti.parameters) == 1
result[i] = Any[Vararg{tti.parameters[1].parameters[1]}]
else
result[i] = tti.parameters
end
Expand Down Expand Up @@ -1121,7 +1120,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
# abstract types yield Type{<:T} instead of Type{T}.
# this doesn't really model the situation perfectly, but
# "isleaftype(inference_stack.types)" should be good enough.
if isa(t,TypeVar)
if isa(t,TypeVar) || isvarargtype(t)
t = Type{t}
else
t = Type{TypeVar(:_,t)}
Expand Down
62 changes: 40 additions & 22 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,40 @@ function typejoin(a::ANY, b::ANY)
return Any
end
ap, bp = a.parameters, b.parameters
la = length(ap)::Int; lb = length(bp)::Int
if la==0 || lb==0
lar = length(ap)::Int; lbr = length(bp)::Int
laf, afixed = full_va_len(ap)
lbf, bfixed = full_va_len(bp)
if lar==0 || lbr==0
return Tuple
end
if la < lb
if isvarargtype(ap[la])
c = cell(la)
c[la] = Vararg{typejoin(ap[la].parameters[1], tailjoin(bp,la))}
n = la-1
if laf < lbf
if isvarargtype(ap[lar]) && !afixed
c = cell(laf)
c[laf] = Vararg{typejoin(ap[lar].parameters[1], tailjoin(bp,laf))}
n = laf-1
else
c = cell(la+1)
c[la+1] = Vararg{tailjoin(bp,la+1)}
n = la
c = cell(laf+1)
c[laf+1] = Vararg{tailjoin(bp,laf+1)}
n = laf
end
elseif lb < la
if isvarargtype(bp[lb])
c = cell(lb)
c[lb] = Vararg{typejoin(bp[lb].parameters[1], tailjoin(ap,lb))}
n = lb-1
elseif lbf < laf
if isvarargtype(bp[lbr]) && !bfixed
c = cell(lbf)
c[lbf] = Vararg{typejoin(bp[lbr].parameters[1], tailjoin(ap,lbf))}
n = lbf-1
else
c = cell(lb+1)
c[lb+1] = Vararg{tailjoin(ap,lb+1)}
n = lb
c = cell(lbf+1)
c[lbf+1] = Vararg{tailjoin(ap,lbf+1)}
n = lbf
end
else
c = cell(la)
n = la
c = cell(laf)
n = laf
end
for i = 1:n
ai = ap[i]; bi = bp[i]
ai = ap[min(i,lar)]; bi = bp[min(i,lbr)]
ci = typejoin(unwrapva(ai),unwrapva(bi))
c[i] = isvarargtype(ai) || isvarargtype(bi) ? Vararg{ci} : ci
c[i] = i == length(c) && (isvarargtype(ai) || isvarargtype(bi)) ? Vararg{ci} : ci
end
return Tuple{c...}
elseif b <: Tuple
Expand Down Expand Up @@ -92,8 +94,24 @@ function typejoin(a::ANY, b::ANY)
return Any
end

# Returns length, isfixed
function full_va_len(p)
isempty(p) && return 0, true
if isvarargtype(p[end])
N = p[end].parameters[2]
if isa(N, Integer)
return (length(p) + N - 1)::Int, true
end
return length(p)::Int, false
end
return length(p)::Int, true
end

# reduce typejoin over A[i:end]
function tailjoin(A, i)
if i > length(A)
return unwrapva(A[end])
end
t = Bottom
for j = i:length(A)
t = typejoin(t, unwrapva(A[j]))
Expand Down
1 change: 0 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ FLAGS += -Wall -Wno-strict-aliasing -fno-omit-frame-pointer -fvisibility=hidden
override CFLAGS += -Wold-style-definition -Wstrict-prototypes -Wc++-compat
endif


SRCS := \
jltypes gf typemap ast builtins module interpreter \
alloc dlload sys init task array dump toplevel jl_uv jlapi signal-handling \
Expand Down
14 changes: 0 additions & 14 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,6 @@ typedef struct {
// Note that this function updates len
static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)
{
if (jl_is_ntuple_type(dt)) {
jl_value_t *lenvar = jl_tparam0(dt);
jl_value_t *elty = jl_tparam1(dt);
assert(jl_is_datatype(elty));
size_t alignment = ((jl_datatype_t*)elty)->alignment;
*len = LLT_ALIGN((*len), alignment);
assert(jl_is_long(lenvar));
size_t l = jl_unbox_long(lenvar);
size_t nb = l*LLT_ALIGN(jl_datatype_size(elty), alignment);
jl_value_t *v = (jl_value_t*)newobj(dt, NWORDS(nb));
memcpy(jl_data_ptr(v), data, nb);
return v;
}

assert(jl_is_datatype(dt));
jl_datatype_t *bt = (jl_datatype_t*)dt;
size_t nb = jl_datatype_size(bt);
Expand Down
3 changes: 1 addition & 2 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,6 @@ void jl_init_primitives(void)
add_builtin("TypeName", (jl_value_t*)jl_typename_type);
add_builtin("TypeConstructor", (jl_value_t*)jl_typector_type);
add_builtin("Tuple", (jl_value_t*)jl_anytuple_type);
add_builtin("NTuple", (jl_value_t*)jl_ntuple_type);
add_builtin("Vararg", (jl_value_t*)jl_vararg_type);
add_builtin("Type", (jl_value_t*)jl_type_type);
add_builtin("DataType", (jl_value_t*)jl_datatype_type);
Expand Down Expand Up @@ -1580,7 +1579,7 @@ JL_DLLEXPORT void jl_(void *jl_value)

JL_DLLEXPORT void jl_breakpoint(jl_value_t *v)
{
// put a breakpoint in you debugger here
// put a breakpoint in your debugger here
}

#ifdef __cplusplus
Expand Down
4 changes: 2 additions & 2 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -2444,7 +2444,7 @@ void jl_init_serializer(void)
jl_labelnode_type, jl_linenumbernode_type,
jl_gotonode_type, jl_quotenode_type, jl_topnode_type,
jl_type_type, jl_bottom_type, jl_ref_type, jl_pointer_type,
jl_vararg_type, jl_ntuple_type, jl_abstractarray_type,
jl_vararg_type, jl_abstractarray_type,
jl_densearray_type, jl_void_type, jl_function_type,
jl_typector_type, jl_typename_type, jl_builtin_type,
jl_task_type, jl_uniontype_type, jl_typetype_type, jl_typetype_tvar,
Expand All @@ -2458,7 +2458,7 @@ void jl_init_serializer(void)
jl_datatype_type->name, jl_uniontype_type->name, jl_array_type->name,
jl_expr_type->name, jl_typename_type->name, jl_type_type->name,
jl_methtable_type->name, jl_typemap_level_type->name, jl_typemap_entry_type->name, jl_tvar_type->name,
jl_ntuple_type->name, jl_abstractarray_type->name, jl_vararg_type->name,
jl_abstractarray_type->name, jl_vararg_type->name,
jl_densearray_type->name, jl_void_type->name, jl_lambda_info_type->name, jl_method_type->name,
jl_module_type->name, jl_function_type->name, jl_typedslot_type->name,
jl_abstractslot_type->name, jl_slotnumber_type->name,
Expand Down
Loading

0 comments on commit add7a23

Please sign in to comment.