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

NTuples made me sad (so I nixed them) #11242

Merged
merged 16 commits into from
May 5, 2016
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
9 changes: 8 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ New language features
However note that the argument types refer to the syntax tree representation, and not
to the types of run time values.

* Varargs functions like `foo{T}(x::T...)` may now restrict the number
of such arguments using `foo{T,N}(x::Vararg{T,N})` ([#11242]).

* `x ∈ X` is now a synonym for `x in X` in `for` loops and comprehensions,
as it already was in comparisons ([#13824]).

Expand Down Expand Up @@ -42,6 +45,9 @@ Language changes

* The `if` keyword cannot be followed immediately by a line break ([#15763]).

* The built-in `NTuple` type has been removed; `NTuple{N,T}` is now
implemented internally as `Tuple{Vararg{T,N}}` ([#11242]).

Command-line option changes
---------------------------

Expand Down Expand Up @@ -175,11 +181,13 @@ Deprecated or removed
<!--- generated by NEWS-update.jl: -->
[#4163]: https://github.com/JuliaLang/julia/issues/4163
[#4211]: https://github.com/JuliaLang/julia/issues/4211
[#6190]: https://github.com/JuliaLang/julia/issues/6190
[#8036]: https://github.com/JuliaLang/julia/issues/8036
[#8846]: https://github.com/JuliaLang/julia/issues/8846
[#9503]: https://github.com/JuliaLang/julia/issues/9503
[#9627]: https://github.com/JuliaLang/julia/issues/9627
[#11196]: https://github.com/JuliaLang/julia/issues/11196
[#11242]: https://github.com/JuliaLang/julia/issues/11242
[#13062]: https://github.com/JuliaLang/julia/issues/13062
[#13232]: https://github.com/JuliaLang/julia/issues/13232
[#13338]: https://github.com/JuliaLang/julia/issues/13338
Expand Down Expand Up @@ -211,4 +219,3 @@ Deprecated or removed
[#15550]: https://github.com/JuliaLang/julia/issues/15550
[#15609]: https://github.com/JuliaLang/julia/issues/15609
[#15763]: https://github.com/JuliaLang/julia/issues/15763
[#6190]: https://github.com/JuliaLang/julia/issues/6190
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
26 changes: 14 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 All @@ -593,6 +590,9 @@ add_tfunc(apply_type, 1, IInf, apply_type_tfunc)
end

function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState)
if !isleaftype(Type{types})
return Any
end
argtype = typeintersect(types,limit_tuple_type(argtype))
if is(argtype,Bottom)
return Bottom
Expand Down Expand Up @@ -861,7 +861,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 +875,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 +1123,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
32 changes: 28 additions & 4 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,41 @@ function argtype_decl(env, n, t) # -> (argname, argtype)
return s, ""
end
if isvarargtype(t)
if t.parameters[1] === Any
return string(s, "..."), ""
else
return s, string_with_env(env, t.parameters[1]) * "..."
tt, tn = t.parameters[1], t.parameters[2]
if isa(tn, TypeVar) && !tn.bound
if tt === Any || (isa(tt, TypeVar) && !tt.bound)
return string(s, "..."), ""
else
return s, string_with_env(env, tt) * "..."
end
end
return s, string_with_env(env, "Vararg{", tt, ",", tn, "}")
elseif t == String
return s, "String"
end
return s, string_with_env(env, t)
end

function argtype_decl_vararg(env, n, t)
if isa(n, Expr)
s = string(n.args[1])
if n.args[2].head == :...
# x... or x::T... declaration
if t.parameters[1] === Any
return string(s, "..."), ""
else
return s, string_with_env(env, t.parameters[1]) * "..."
end
elseif t == String
return s, "String"
end
end
# x::Vararg, x::Vararg{T}, or x::Vararg{T,N} declaration
s, length(n.args[2].args) < 4 ?
string_with_env(env, "Vararg{", t.parameters[1], "}") :
string_with_env(env, "Vararg{", t.parameters[1], ",", t.parameters[2], "}")
end

function arg_decl_parts(m::Method)
tv = m.tvars
if !isa(tv,SimpleVector)
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
2 changes: 2 additions & 0 deletions doc/manual/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ the zero or more values passed to ``bar`` after its first two arguments:
In all these cases, ``x`` is bound to a tuple of the trailing values
passed to ``bar``.

It is possible to constrain the number of values passed as a variable argument; this will be discussed later in :ref:`man-vararg-fixedlen`.

On the flip side, it is often handy to "splice" the values contained in
an iterable collection into a function call as individual arguments. To
do this, one also uses ``...`` but in the function call instead:
Expand Down
26 changes: 26 additions & 0 deletions doc/manual/methods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,32 @@ can also constrain type parameters of methods::
The ``same_type_numeric`` function behaves much like the ``same_type``
function defined above, but is only defined for pairs of numbers.

.. _man-vararg-fixedlen:

Parametrically-constrained Varargs methods
------------------------------------------

Function parameters can also be used to constrain the number of arguments that may be supplied to a "varargs" function (:ref:`man-varargs-functions`). The notation ``Vararg{T,N}`` is used to indicate such a constraint. For example:

.. doctest::

julia> bar(a,b,x::Vararg{Any,2}) = (a,b,x)

julia> bar(1,2,3)
ERROR: MethodError: `bar` has no matching method bar(::Int, ::Int, ::Int)

julia> bar(1,2,3,4)
(1,2,(3,4))

julia> bar(1,2,3,4,5)
ERROR: MethodError: `bar` has no method matching bar(::Int, ::Int, ::Int, ::Int, ::Int)

More usefully, it is possible to constrain varargs methods by a parameter. For example::

function getindex{T,N}(A::AbstractArray{T,N}, indexes::Vararg{Number,N})

would be called only when the number of ``indexes`` matches the dimensionality of the array.

.. _man-note-on-optional-and-keyword-arguments:

Note on Optional and keyword Arguments
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