From c9fe08697893c44ec26910a4367bf92bea7ad916 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 May 2015 08:27:14 -0500 Subject: [PATCH 01/32] Add a length parameter N to Vararg, Vararg{T,N} This also: - adds an enum classification of Vararg types - implements a few convenience functions - switches some checks from jl_is_va_tuple to jl_va_tuple_kind(t) == JL_VARARG_UNBOUND - updates jl_wrap_vararg to take two inputs - displays such Varargs properly in the REPL --- base/methodshow.jl | 16 ++++++++++++-- src/gf.c | 7 +++--- src/jltypes.c | 28 +++++++++++++++--------- src/julia.h | 52 ++++++++++++++++++++++++++++++++++---------- src/julia_internal.h | 2 +- src/typemap.c | 4 ++-- test/show.jl | 25 +++++++++++++++++++++ 7 files changed, 104 insertions(+), 30 deletions(-) diff --git a/base/methodshow.jl b/base/methodshow.jl index 3ba293809e43d..6dd20826e3f31 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -10,6 +10,9 @@ function get_lambda(m::TypeMapEntry) end function argtype_decl(env, n, t) # -> (argname, argtype) + if isvarargtype(t) + return argtype_decl_vararg(env, n, t) + end if isa(n,Expr) n = n.args[1] # handle n::T in arg list end @@ -21,7 +24,13 @@ function argtype_decl(env, n, t) # -> (argname, argtype) if t === Any && !isempty(s) return s, "" end - if isvarargtype(t) + return s, string(t) +end + +function argtype_decl_vararg(env, n, t) + s = string(n.args[1]) + if n.args[2].head == :... + # x... or x::T... declaration if t.parameters[1] === Any return string(s, "..."), "" else @@ -30,7 +39,10 @@ function argtype_decl(env, n, t) # -> (argname, argtype) elseif t == ByteString return s, "ByteString" end - return s, string_with_env(env, t) + # 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::TypeMapEntry) diff --git a/src/gf.c b/src/gf.c index e52121ca97116..ca0e785969250 100644 --- a/src/gf.c +++ b/src/gf.c @@ -487,7 +487,8 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca // in general, here we want to find the biggest type that's not a // supertype of any other method signatures. so far we are conservative // and the types we find should be bigger. - if (!isstaged && jl_nparams(type) > mt->max_args && jl_is_va_tuple(decl)) { + if (!isstaged && jl_nparams(type) > mt->max_args + && jl_va_tuple_kind(decl) == JL_VARARG_UNBOUND) { size_t nspec = mt->max_args + 2; limited = jl_alloc_svec(nspec); temp3 = (jl_value_t*)limited; @@ -519,7 +520,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca // avoid Type{Type{...}}... if (jl_is_type_type(lasttype) && jl_is_type_type(jl_tparam0(lasttype))) lasttype = (jl_value_t*)jl_type_type; - jl_svecset(limited, i, jl_wrap_vararg(lasttype)); + jl_svecset(limited, i, jl_wrap_vararg(lasttype, (jl_value_t*)NULL)); } else { jl_value_t *lastdeclt = jl_tparam(decl,jl_nparams(decl)-1); @@ -868,7 +869,7 @@ static void invalidate_conflicting(union jl_typemap_t *pml, jl_value_t *type, jl static void update_max_args(jl_methtable_t *mt, jl_tupletype_t *type) { size_t na = jl_nparams(type); - if (jl_is_va_tuple(type)) + if (jl_va_tuple_kind(type) == JL_VARARG_UNBOUND) na--; if (na > mt->max_args) mt->max_args = na; diff --git a/src/jltypes.c b/src/jltypes.c index 89fa755777e5d..34e13a9d23b73 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -433,12 +433,20 @@ static size_t tuple_intersect_size(jl_svec_t *a, jl_svec_t *b, int *bot) return 0; } -jl_datatype_t *jl_wrap_vararg(jl_value_t *t) +jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) { - jl_value_t *env[2]; + if (n == NULL) { + jl_value_t *env[2]; + env[0] = jl_tparam0(jl_vararg_type); + env[1] = t; + return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, env, 1); + } + jl_value_t *env[4]; env[0] = jl_tparam0(jl_vararg_type); env[1] = t; - return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, env, 1); + env[2] = jl_tparam1(jl_vararg_type); + env[3] = n; + return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, env, 2); } static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, @@ -490,7 +498,7 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, return (jl_value_t*)jl_bottom_type; } if (aseq && bseq) - ce = (jl_value_t*)jl_wrap_vararg(ce); + ce = (jl_value_t*)jl_wrap_vararg(ce, (jl_value_t*) NULL); jl_svecset(tc, ci, ce); } done_intersect_tuple: @@ -865,7 +873,7 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, // the length of the other tuple if (jl_is_va_tuple((jl_datatype_t*)a)) { temp = (jl_value_t*)jl_svec_copy(((jl_datatype_t*)b)->parameters); - jl_svecset(temp, alen-1, jl_wrap_vararg(elty)); + jl_svecset(temp, alen-1, jl_wrap_vararg(elty, (jl_value_t*)NULL)); b = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)temp); if (jl_is_typevar(lenvar)) { // store "at least N" constraints in the <: env @@ -3045,7 +3053,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, else { return jl_false; } - jl_value_t *p_seq = (jl_value_t*)jl_wrap_vararg(jl_svecref(tp,1)); + jl_value_t *p_seq = (jl_value_t*)jl_wrap_vararg(jl_svecref(tp,1), (jl_value_t*)NULL); JL_GC_PUSH1(&p_seq); p_seq = (jl_value_t*)jl_svec1(p_seq); p_seq = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)p_seq); @@ -3317,16 +3325,16 @@ void jl_init_types(void) jl_type_type, jl_any_type), 0, 1, 3); - jl_svec_t *tv; - tv = jl_svec1(tvar("T")); - jl_vararg_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Vararg"), jl_any_type, tv); vararg_sym = jl_symbol("Vararg"); + jl_svec_t *tv; + tv = jl_svec2(tvar("T"),tvar("N")); + jl_vararg_type = jl_new_abstracttype((jl_value_t*)vararg_sym, jl_any_type, tv); jl_anytuple_type = jl_new_datatype(jl_symbol("Tuple"), jl_any_type, jl_emptysvec, jl_emptysvec, jl_emptysvec, 0, 0, 0); jl_tuple_typename = jl_anytuple_type->name; jl_anytuple_type->uid = 0; - jl_anytuple_type->parameters = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type)); + jl_anytuple_type->parameters = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL)); jl_anytuple_type->types = jl_anytuple_type->parameters; jl_anytuple_type->nfields = 1; diff --git a/src/julia.h b/src/julia.h index 2d204df89aba3..1f4293d9180f4 100644 --- a/src/julia.h +++ b/src/julia.h @@ -940,18 +940,6 @@ STATIC_INLINE int jl_is_tuple_type(void *t) ((jl_datatype_t*)(t))->name == jl_tuple_typename); } -STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) -{ - return (jl_is_datatype(v) && - ((jl_datatype_t*)(v))->name == jl_vararg_type->name); -} - -STATIC_INLINE int jl_is_va_tuple(jl_datatype_t *t) -{ - size_t l = jl_svec_len(t->parameters); - return (l>0 && jl_is_vararg_type(jl_tparam(t,l-1))); -} - STATIC_INLINE int jl_is_ntuple_type(jl_value_t *v) { return (jl_is_datatype(v) && @@ -1075,6 +1063,46 @@ JL_DLLEXPORT int jl_get_size(jl_value_t *val, size_t *pnt); #define jl_long_type jl_int32_type #endif +typedef enum { + JL_VARARG_NONE = 0, + JL_VARARG_INT = 1, + JL_VARARG_BOUND = 2, + JL_VARARG_UNBOUND = 3 +} JL_VARARG_KIND; + +STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) +{ + return (jl_is_datatype(v) && + ((jl_datatype_t*)(v))->name == jl_vararg_type->name); +} + +STATIC_INLINE JL_VARARG_KIND jl_vararg_kind(jl_value_t *v) +{ + if (!jl_is_vararg_type(v)) + return JL_VARARG_NONE; + jl_value_t *lenv = jl_tparam1(v); + if (jl_is_long(lenv)) + return JL_VARARG_INT; + assert(jl_is_typevar(lenv)); + return ((jl_tvar_t*)lenv)->bound ? JL_VARARG_BOUND : JL_VARARG_UNBOUND; +} + +STATIC_INLINE int jl_is_va_tuple(jl_datatype_t *t) +{ + assert(jl_is_tuple_type(t)); + size_t l = jl_svec_len(t->parameters); + return (l>0 && jl_is_vararg_type(jl_tparam(t,l-1))); +} + +STATIC_INLINE JL_VARARG_KIND jl_va_tuple_kind(jl_datatype_t *t) +{ + assert(jl_is_tuple_type(t)); + size_t l = jl_svec_len(t->parameters); + if (l == 0) + return JL_VARARG_NONE; + return jl_vararg_kind(jl_tparam(t,l-1)); +} + // structs JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err); JL_DLLEXPORT jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i); diff --git a/src/julia_internal.h b/src/julia_internal.h index 8f828a4927a16..8510ad6a6a026 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -190,7 +190,7 @@ jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_datatype_t *super, jl_svec_t *parameters); jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x} -jl_datatype_t *jl_wrap_vararg(jl_value_t *t); +jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n); void jl_assign_bits(void *dest, jl_value_t *bits); jl_expr_t *jl_exprn(jl_sym_t *head, size_t n); jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module); diff --git a/src/typemap.c b/src/typemap.c index c23e69f2cf5ab..e311b075f45e3 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -841,7 +841,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par jl_gc_wb(ml, ml->simplesig); ml->tvars = tvars; jl_gc_wb(ml, ml->tvars); - ml->va = jl_is_va_tuple(type); + ml->va = jl_va_tuple_kind(type) == JL_VARARG_UNBOUND; // TODO: `l->func` or `l->func->roots` might need to be rooted ml->func.value = newvalue; if (newvalue) @@ -861,7 +861,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par newrec->guardsigs = guardsigs; newrec->next = (jl_typemap_entry_t*)jl_nothing; // compute the complexity of this type signature - newrec->va = jl_is_va_tuple(type); + newrec->va = jl_va_tuple_kind(type) == JL_VARARG_UNBOUND; newrec->issimplesig = (tvars == jl_emptysvec); // a TypeVar environment needs an complex matching test newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted JL_GC_PUSH1(&newrec); diff --git a/test/show.jl b/test/show.jl index 250dc2e3668d2..71eda1f714c52 100644 --- a/test/show.jl +++ b/test/show.jl @@ -392,6 +392,31 @@ A = reshape(1:16,4,4) @test replstr(UpperTriangular(copy(A))) == "4×4 UpperTriangular{$Int,Array{$Int,2}}:\n 1 5 9 13\n ⋅ 6 10 14\n ⋅ ⋅ 11 15\n ⋅ ⋅ ⋅ 16" @test replstr(LowerTriangular(copy(A))) == "4×4 LowerTriangular{$Int,Array{$Int,2}}:\n 1 ⋅ ⋅ ⋅\n 2 6 ⋅ ⋅\n 3 7 11 ⋅\n 4 8 12 16" +# Vararg methods in method tables +function test_mt(f, str) + mt = methods(f) + @test length(mt) == 1 + defs = mt.defs + io = IOBuffer() + show(io, defs) + strio = takebuf_string(io) + @test strio[1:length(str)] == str +end +begin + local f1, f2, f3, f4, f5 + f1(x...) = [x...] + f2(x::Vararg{Any}) = [x...] + f3(x::Vararg) = [x...] + f4(x::Vararg{Any,3}) = [x...] + f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{Int,N}) = [indexes...] + test_mt(f1, "f1(x...)") + test_mt(f2, "f2(x::Vararg{Any})") + test_mt(f3, "f3(x::Vararg{T<:Any})") # FIXME? better as x::Vararg? + test_mt(f4, "f4(x::Vararg{Any,3})") + intstr = string(Int) + test_mt(f5, "f5{T,N}(A::AbstractArray{T,N},indexes::Vararg{$intstr,N})") +end + # Issue #15525, printing of vcat @test sprint(show, :([a;])) == ":([a;])" @test sprint(show, :([a;b])) == ":([a;b])" From cde289a5aea9ef098e4853e4105885758a2ef717 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 May 2015 12:16:30 -0500 Subject: [PATCH 02/32] Add NTuple translation utilities --- src/jltypes.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/jltypes.c b/src/jltypes.c index 34e13a9d23b73..17e0f214a1a5d 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -308,6 +308,111 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_svec_t *types) return jl_type_union_v(jl_svec_data(types), jl_svec_len(types)); } +// On-the-fly translation of NTuple{N,T} into Tuple{Vararg{T,N}} +// In terms of GC behavior, these are defensive--- +// who knows where these will be called from? +static jl_datatype_t *ntuple_translate_tuple(jl_datatype_t *tt); +static int needs_translation_tuple(jl_datatype_t *tt); + +static int needs_translation(jl_value_t *v) +{ + if (jl_is_tuple_type(v)) return needs_translation_tuple((jl_datatype_t*)v); + if (jl_is_typevar(v)) return needs_translation(((jl_tvar_t*)v)->ub) || needs_translation(((jl_tvar_t*)v)->lb); + return jl_is_ntuple_type(v); +} + +static int needs_translation_data(jl_value_t **data, int n) +{ + int i; + for (i = 0; i < n; i++) + if (needs_translation(data[i])) + return 1; + return 0; +} + +static int needs_translation_svec(jl_svec_t *sv) +{ + return needs_translation_data(jl_svec_data(sv), jl_svec_len(sv)); +} + +static int needs_translation_tuple(jl_datatype_t *tt) +{ + return needs_translation_svec(tt->parameters); +} + +static jl_value_t *ntuple_translate(jl_value_t *v) +{ + jl_value_t *tva = NULL, *result = NULL, *temp = NULL; + JL_GC_PUSH4(&v, &tva, &result, &temp); + if (jl_is_tuple_type(v)) { + result = (jl_value_t*)ntuple_translate_tuple((jl_datatype_t*)v); + JL_GC_POP(); + return result; + } + if (jl_is_typevar(v)) { + jl_tvar_t *tv = (jl_tvar_t*) v; + tva = (jl_value_t*)ntuple_translate(tv->lb); + temp = (jl_value_t*)ntuple_translate(tv->ub); + result = (jl_value_t*)jl_new_typevar(tv->name, tva, temp); + ((jl_tvar_t*)result)->bound = tv->bound; + JL_GC_POP(); + return result; + } + if (!jl_is_ntuple_type(v)) { + JL_GC_POP(); + return v; + } + tva = (jl_value_t*) jl_wrap_vararg(jl_tparam1(v), jl_tparam0(v)); + result = (jl_value_t*)jl_tupletype_fill(1, tva); + JL_GC_POP(); + return result; +} + +static jl_svec_t *ntuple_translate_data(jl_value_t **data, int n) +{ + int i; + jl_value_t **gcprotected; + JL_GC_PUSHARGS(gcprotected, 2*n+1); + for (i = 0; i < n; i++) { + gcprotected[i] = data[i]; + gcprotected[i+n] = NULL; // just in case + } + gcprotected[2*n] = NULL; + jl_svec_t *snew = jl_alloc_svec(n); + gcprotected[2*n] = (jl_value_t*) snew; + for (i = 0; i < n; i++) + gcprotected[i+n] = jl_svecref(snew, i); + assert(jl_is_svec(snew)); + for (i = 0; i < n; i++) { + assert(jl_is_svec(snew)); + jl_value_t *translated = ntuple_translate(data[i]); + assert(jl_is_svec(snew)); + jl_svecset(snew, i, translated); + } + JL_GC_POP(); + return snew; +} + +static jl_svec_t *ntuple_translate_svec(jl_svec_t *sv) +{ + jl_svec_t *result=NULL; + JL_GC_PUSH2(&sv, &result); + result = ntuple_translate_data(jl_svec_data(sv), jl_svec_len(sv)); + JL_GC_POP(); + return result; +} + +static jl_datatype_t *ntuple_translate_tuple(jl_datatype_t *tt) +{ + assert(jl_is_tuple_type(tt)); + jl_svec_t *snew = NULL; + JL_GC_PUSH2(&tt, &snew); + snew = ntuple_translate_svec(tt->parameters); + jl_datatype_t *result = jl_apply_tuple_type(snew); + JL_GC_POP(); + return result; +} + // --- type intersection --- typedef enum {invariant, covariant} variance_t; From 458cdde5d7f687e8066eb28bb5a205a7c1d743cb Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 May 2015 12:17:07 -0500 Subject: [PATCH 03/32] Add flexible Vararg info utilities --- src/jltypes.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/jltypes.c b/src/jltypes.c index 17e0f214a1a5d..dd50bead6a918 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -512,6 +512,57 @@ static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, return tu; } +/* +Simplification of varargs tuple types: + JL_TUPLE_FIXED: tuples of known length (JL_VARARG_NONE or JL_VARARG_INT) + JL_TUPLE_VAR: tuples of unknown length (JL_VARARG_BOUND or JL_VARARG_UNBOUND) + +In some cases, JL_VARARG_BOUND tuples get described as JL_TUPLE_FIXED, +if the constraints on length are already known. +*/ +typedef enum { + JL_TUPLE_FIXED = 0, + JL_TUPLE_VAR = 1 +} JL_TUPLE_LENKIND; + +// Set the parameters for a single tuple +// returns lenf, sets kind and lenkind +static size_t data_vararg_params(jl_value_t **data, size_t lenr, cenv_t *eqc, JL_VARARG_KIND *kind, JL_TUPLE_LENKIND *lenkind) +{ + size_t lenf = lenr; + int i; + if (lenr == 0) { + *kind = JL_VARARG_NONE; + *lenkind = JL_TUPLE_FIXED; + return lenf; + } + *lenkind = JL_TUPLE_VAR; + *kind = jl_vararg_kind(data[lenr-1]); + if (*kind == JL_VARARG_NONE || *kind == JL_VARARG_INT) + *lenkind = JL_TUPLE_FIXED; + if (*kind == JL_VARARG_INT || *kind == JL_VARARG_BOUND) { + // try to set N from eqc parameters + jl_value_t *N = jl_tparam1(data[lenr-1]); + if (!jl_is_long(N) && eqc != NULL) { + for (i = 0; i < eqc->n; i+=2) + if (eqc->data[i] == N && jl_is_long(eqc->data[i+1])) { + N = eqc->data[i+1]; + break; + } + } + if (jl_is_long(N)) { + lenf += jl_unbox_long(N)-1; + *lenkind = JL_TUPLE_FIXED; + } + } + return lenf; +} + +static size_t tuple_vararg_params(jl_svec_t *a, cenv_t *eqc, JL_VARARG_KIND *kind, JL_TUPLE_LENKIND *lenkind) +{ + return data_vararg_params(jl_svec_data(a), jl_svec_len(a), eqc, kind, lenkind); +} + // if returns with *bot!=0, then intersection is Union{} static size_t tuple_intersect_size(jl_svec_t *a, jl_svec_t *b, int *bot) { From 0b53e36568e0125ee5aafaa055d1891a0e34a584 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 4 May 2015 07:15:18 -0500 Subject: [PATCH 04/32] Add new jl_tuple_subtype_ algorithm This leaves the old one in place and compares the results of the two. This way we can catch bugs immediately, rather than trying to deduce what went wrong from the indirect consequences. --- src/jltypes.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++---- test/core.jl | 11 ++ 2 files changed, 260 insertions(+), 21 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index dd50bead6a918..be1014a29a5ae 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2536,7 +2536,7 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant); -static int jl_tuple_subtype_(jl_value_t **child, size_t cl, +static int jl_tuple_subtype_old(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta, int invariant) { size_t pl = jl_nparams(pdt); @@ -2566,6 +2566,82 @@ static int jl_tuple_subtype_(jl_value_t **child, size_t cl, return 0; } +static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, + jl_datatype_t *pdt, int ta, int invariant) +{ + size_t plenr = jl_nparams(pdt); + jl_value_t **parent = jl_svec_data(pdt->parameters); + size_t plenf, clenf; + JL_VARARG_KIND ckind, pkind; + JL_TUPLE_LENKIND clenkind, plenkind; + int bottom = 0; + // Stage 1 + clenf = data_vararg_params(child, clenr, NULL, &ckind, &clenkind); + plenf = tuple_vararg_params(pdt->parameters, NULL, &pkind, &plenkind); + // Stage 2 + if (clenkind == JL_TUPLE_FIXED && plenkind == JL_TUPLE_FIXED) { + bottom = clenf != plenf; + } + else if (clenkind == JL_TUPLE_FIXED && plenkind == JL_TUPLE_VAR) { + bottom = clenf+1 < plenf; + } + if (plenr == 0 && clenr > 0) + bottom = 1; + if (bottom) return 0; + size_t ci=0, pi=0; + jl_value_t *ce=NULL, *pe=NULL; + int cseq=0, pseq=0; + // Stage 3 + while (1) { + if (!cseq) + cseq = !ta && ci= clenf) + return pi>=plenf || (pseq && (!invariant || parent[plenr-1] != (jl_value_t*)jl_vararg_type)); // Note: may need equivalent of || jl_subtype_le_((jl_value_t*)jl_anytuple_type, a, 0, 1), but tests pass without it + if (pi >= plenf && !pseq) + return 0; + if (ci < clenr) { + ce = child[ci]; + if (jl_is_vararg_type(ce)) ce = jl_tparam0(ce); + } + if (pi < plenr) { + pe = parent[pi]; + if (jl_is_vararg_type(pe)) pe = jl_tparam0(pe); + } + + if (!jl_subtype_le(ce, pe, ta, invariant)) + return 0; + + if (cseq && pseq) return 1; + ci++; + pi++; + } +} + +static int jl_tuple_subtype_(jl_value_t **child, size_t cl, + jl_datatype_t *pdt, int ta, int invariant) +{ + int retold = jl_tuple_subtype_old(child, cl, pdt, ta, invariant); + if (!needs_translation_data(child, cl) && !needs_translation((jl_value_t*)pdt)) + return retold; + jl_svec_t *newchilds=NULL; + jl_datatype_t *newpdt=NULL; + JL_GC_PUSH2(&newchilds, &newpdt); + newchilds = ntuple_translate_data(child, cl); + newpdt = (jl_datatype_t*) ntuple_translate((jl_value_t*)pdt); + int retnew = jl_tuple_subtype_new(jl_svec_data(newchilds), cl, newpdt, ta, invariant); + if (retnew != retold) { + jl_printf(JL_STDOUT, "Disagree jl_tuple_subtype_ with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); + jl_(newchilds); + jl_(newpdt); + } + JL_GC_POP(); + return retold; +} + int jl_tuple_subtype(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta) { return jl_tuple_subtype_(child, cl, pdt, ta, 0); @@ -2585,13 +2661,13 @@ static int tuple_all_subtype(jl_datatype_t *t, jl_value_t *super, int ta, int in } // ta specifies whether typeof() should be implicitly applied to a. -static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) +static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant) { if (!ta&&jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; if (ta) { if (jl_is_type_type(b)) { - return jl_is_type(a) && jl_subtype_le(a, jl_tparam0(b), 0, 1); + return jl_is_type(a) && jl_subtype_le_old(a, jl_tparam0(b), 0, 1); } } else if (a == b) { @@ -2604,10 +2680,10 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) jl_svec_t *ap = ((jl_uniontype_t*)a)->types; size_t l_ap = jl_svec_len(ap); if (invariant && !jl_is_typevar(b)) { - return jl_subtype_le(a,b,0,0) && jl_subtype_le(b,a,0,0); + return jl_subtype_le_old(a,b,0,0) && jl_subtype_le_old(b,a,0,0); } for(i=0; i < l_ap; i++) { - if (!jl_subtype_le(jl_svecref(ap,i), b, 0, invariant)) + if (!jl_subtype_le_old(jl_svecref(ap,i), b, 0, invariant)) return 0; } return 1; @@ -2618,14 +2694,14 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(tp0a)) { jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; - if (jl_subtype_le(ub, b, 1, 0) && - !jl_subtype_le((jl_value_t*)jl_any_type, ub, 0, 0)) { - if (jl_subtype_le(lb, b, 1, 0)) + if (jl_subtype_le_old(ub, b, 1, 0) && + !jl_subtype_le_old((jl_value_t*)jl_any_type, ub, 0, 0)) { + if (jl_subtype_le_old(lb, b, 1, 0)) return 1; } } else { - if (jl_subtype_le(tp0a, b, 1, 0)) + if (jl_subtype_le_old(tp0a, b, 1, 0)) return 1; } } @@ -2635,7 +2711,7 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_subtype_le(a, jl_svecref(bp,i), ta, invariant)) + if (jl_subtype_le_old(a, jl_svecref(bp,i), ta, invariant)) return 1; } if (!ta && jl_is_typevar(a) && ((jl_tvar_t*)a)->ub == jl_bottom_type) @@ -2652,7 +2728,7 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (tuple_all_subtype((jl_datatype_t*)a, tp, 0, invariant)) { if (invariant) { return (jl_datatype_t*)b != jl_ntuple_type || - jl_subtype_le((jl_value_t*)jl_anytuple_type, a, 0, 1); + jl_subtype_le_old((jl_value_t*)jl_anytuple_type, a, 0, 1); } return 1; } @@ -2660,7 +2736,7 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) } } if (jl_is_tuple_type(b)) { - return jl_tuple_subtype_(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), + return jl_tuple_subtype_old(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), (jl_datatype_t*)b, 0, invariant); } } @@ -2674,7 +2750,7 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) // only ((T>:S)...,) can be a supertype of NTuple{N,S} jl_value_t *ntp = jl_tparam1(a); if (jl_nparams(b) == 1 && jl_is_va_tuple((jl_datatype_t*)b)) { - return jl_subtype_le(ntp, jl_tparam0(jl_tparam0(b)), 0, invariant); + return jl_subtype_le_old(ntp, jl_tparam0(jl_tparam0(b)), 0, invariant); } } return 0; @@ -2689,10 +2765,10 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (tta->name == ttb->name) { if (tta->name == jl_ntuple_typename) { // NTuple must be covariant - return jl_subtype_le(jl_tparam(tta,1), jl_tparam(ttb,1), 0, invariant); + return jl_subtype_le_old(jl_tparam(tta,1), jl_tparam(ttb,1), 0, invariant); } if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_subtype_le(a, jl_tparam0(b), 0, 1)) + if (jl_subtype_le_old(a, jl_tparam0(b), 0, 1)) return 1; } assert(jl_nparams(tta) == jl_nparams(ttb)); @@ -2706,7 +2782,7 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) return 0; } } - if (!jl_subtype_le(apara, bpara, 0, 1)) + if (!jl_subtype_le_old(apara, bpara, 0, 1)) return 0; } return 1; @@ -2723,25 +2799,177 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); } if (invariant) { return 0; } - return jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + return jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); } if (jl_is_typevar(b)) { - return jl_subtype_le(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + return jl_subtype_le_old(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); } if ((jl_datatype_t*)a == jl_any_type) return 0; return jl_egal(a, b); } +int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) +{ + if (!ta&&jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; + if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; + if (ta) { + if (jl_is_type_type(b)) { + return jl_is_type(a) && jl_subtype_le_new(a, jl_tparam0(b), 0, 1); + } + } + else if (a == b) { + // Union() <: Union() + return 1; + } + + size_t i; + if (!ta && jl_is_uniontype(a)) { + jl_svec_t *ap = ((jl_uniontype_t*)a)->types; + size_t l_ap = jl_svec_len(ap); + if (invariant && !jl_is_typevar(b)) { + return jl_subtype_le_new(a,b,0,0) && jl_subtype_le_new(b,a,0,0); + } + for(i=0; i < l_ap; i++) { + if (!jl_subtype_le_new(jl_svecref(ap,i), b, 0, invariant)) + return 0; + } + return 1; + } + + if (!ta && jl_is_type_type(a) && !invariant) { + jl_value_t *tp0a = jl_tparam0(a); + if (jl_is_typevar(tp0a)) { + jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; + jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; + if (jl_subtype_le_new(ub, b, 1, 0) && + !jl_subtype_le_new((jl_value_t*)jl_any_type, ub, 0, 0)) { + if (jl_subtype_le_new(lb, b, 1, 0)) + return 1; + } + } + else { + if (jl_subtype_le_new(tp0a, b, 1, 0)) + return 1; + } + } + + if (jl_is_uniontype(b)) { + if (invariant) + return 0; + jl_svec_t *bp = ((jl_uniontype_t*)b)->types; + for(i=0; i < jl_svec_len(bp); i++) { + if (jl_subtype_le_new(a, jl_svecref(bp,i), ta, invariant)) + return 1; + } + return 0; + } + + if (ta) a = (jl_value_t*)jl_typeof(a); + + if (jl_is_tuple_type(a)) { + if (jl_is_tuple_type(b)) { + return jl_tuple_subtype_new(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), + (jl_datatype_t*)b, 0, invariant); + } + } + + if (a == b) return 1; + if (!invariant && (jl_datatype_t*)b == jl_any_type) return 1; + + if (jl_is_datatype(a) && jl_is_datatype(b)) { + if ((jl_datatype_t*)a == jl_any_type) return 0; + jl_datatype_t *tta = (jl_datatype_t*)a; + jl_datatype_t *ttb = (jl_datatype_t*)b; + int super=0; + while (tta != (jl_datatype_t*)jl_any_type) { + if (tta->name == ttb->name) { + if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { + if (jl_subtype_le_new(a, jl_tparam0(b), 0, 1)) + return 1; + } + if (invariant && ttb == (jl_datatype_t*)ttb->name->primary) + return 0; + assert(jl_nparams(tta) == jl_nparams(ttb)); + size_t l = jl_nparams(tta); + for(i=0; i < l; i++) { + jl_value_t *apara = jl_tparam(tta,i); + jl_value_t *bpara = jl_tparam(ttb,i); + if (invariant && jl_is_typevar(bpara) && + !((jl_tvar_t*)bpara)->bound) { + if (!jl_is_typevar(apara)) + return 0; + } + if (!jl_subtype_le_new(apara, bpara, 0, 1)) + return 0; + } + return 1; + } + else if (invariant) { + return 0; + } + tta = tta->super; super = 1; + } + assert(!invariant); + return 0; + } + + if (jl_is_typevar(a)) { + if (jl_is_typevar(b)) { + return + jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)a)->ub, + (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)b)->lb, + (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); + } + if (invariant) { + return 0; + } + return jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + } + if (jl_is_typevar(b)) { + return jl_subtype_le_new(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + } + if ((jl_datatype_t*)a == jl_any_type) return 0; + + return jl_egal(a, b); +} + +static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) +{ + int retold = jl_subtype_le_old(a, b, ta, invariant); + if (!needs_translation(a) && !needs_translation(b)) + return retold; + jl_value_t *newa=NULL, *newb=NULL; + JL_GC_PUSH2(&newa, &newb); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + int retnew = jl_subtype_le_new(newa, newb, ta, invariant); + if (retnew != retold) { + jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); + jl_(a); + jl_(b); + } + JL_GC_POP(); + return retnew; +} + JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) { return jl_subtype_le(a, b, ta, 0); diff --git a/test/core.jl b/test/core.jl index 7c3b65a9b86dd..c80d7960e7bc4 100644 --- a/test/core.jl +++ b/test/core.jl @@ -136,6 +136,17 @@ end @test () != Type{Tuple{}} +let N = TypeVar(:N,true), V = TypeVar(:V, NTuple{N,Int}), T = TypeVar(:T,true) + @test Tuple{} <: NTuple{N,Int} + @test Tuple{} <: NTuple{N,T} + @test Array{Tuple{}} <: Array{NTuple{N,Int}} + @test Array{Tuple{}} <: Array{NTuple{N,T}} + @test Tuple{Type{Int8}, Tuple{}} <: Tuple{Type{Int8}, NTuple{N,Int}} + @test Tuple{Type{Int8}, Tuple{Int,Int}} <: Tuple{Type{Int8}, NTuple{N,Int}} + @test V <: NTuple + # @test !(V <: Tuple{Vararg}) # current behavior, but this conflicts with the above +end + # issue #6561 @test issubtype(Array{Tuple}, Array{NTuple}) @test issubtype(Array{Tuple{Vararg{Any}}}, Array{NTuple}) From 4acbe56c38603d890f887ea0fccbf1fd1e7bcb6d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 9 May 2015 08:13:00 -0500 Subject: [PATCH 05/32] 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} --- src/Makefile | 3 +- src/jltypes.c | 115 ++++++++++++++++++++++++++++++++++------------- src/warnonce.cpp | 27 +++++++++++ test/core.jl | 33 +++++++++----- 4 files changed, 135 insertions(+), 43 deletions(-) create mode 100644 src/warnonce.cpp diff --git a/src/Makefile b/src/Makefile index 214da1d85a1a7..4784b0ff3160c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -24,12 +24,11 @@ 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 \ simplevector APInt-C runtime_intrinsics runtime_ccall \ - threadgroup threading stackwalk gc + threadgroup threading stackwalk gc warnonce ifeq ($(JULIACODEGEN),LLVM) SRCS += codegen disasm debuginfo llvm-simdloop llvm-gcroot diff --git a/src/jltypes.c b/src/jltypes.c index be1014a29a5ae..dbf43ad1b5e9e 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -362,8 +362,12 @@ static jl_value_t *ntuple_translate(jl_value_t *v) JL_GC_POP(); return v; } - tva = (jl_value_t*) jl_wrap_vararg(jl_tparam1(v), jl_tparam0(v)); - result = (jl_value_t*)jl_tupletype_fill(1, tva); + if (v == (jl_value_t*)jl_ntuple_type) + result = (jl_value_t*)jl_anytuple_type; + else { + tva = (jl_value_t*) jl_wrap_vararg(jl_tparam1(v), jl_tparam0(v)); + result = (jl_value_t*)jl_tupletype_fill(1, tva); + } JL_GC_POP(); return result; } @@ -592,6 +596,8 @@ static size_t tuple_intersect_size(jl_svec_t *a, jl_svec_t *b, int *bot) jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) { if (n == NULL) { + if (t == NULL) + return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, NULL, 0); jl_value_t *env[2]; env[0] = jl_tparam0(jl_vararg_type); env[1] = t; @@ -2535,6 +2541,8 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // subtype comparison static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant); +static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant); +static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant); static int jl_tuple_subtype_old(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta, int invariant) @@ -2556,7 +2564,7 @@ static int jl_tuple_subtype_old(jl_value_t **child, size_t cl, if (cseq) ce = jl_tparam0(ce); if (pseq) pe = jl_tparam0(pe); - if (!jl_subtype_le(ce, pe, ta, invariant)) + if (!jl_subtype_le_old(ce, pe, ta, invariant)) return 0; if (cseq && pseq) return 1; @@ -2592,33 +2600,57 @@ static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, jl_value_t *ce=NULL, *pe=NULL; int cseq=0, pseq=0; // Stage 3 + int result = 0;//, recheck = 0; while (1) { if (!cseq) cseq = !ta && ci= clenf) - return pi>=plenf || (pseq && (!invariant || parent[plenr-1] != (jl_value_t*)jl_vararg_type)); // Note: may need equivalent of || jl_subtype_le_((jl_value_t*)jl_anytuple_type, a, 0, 1), but tests pass without it + break; + if (ci >= clenf) { + result = pi >= plenf || (pseq && !invariant); + break; + } if (pi >= plenf && !pseq) - return 0; + break; if (ci < clenr) { ce = child[ci]; if (jl_is_vararg_type(ce)) ce = jl_tparam0(ce); } if (pi < plenr) { pe = parent[pi]; - if (jl_is_vararg_type(pe)) pe = jl_tparam0(pe); + if (jl_is_vararg_type(pe)) { + /* + if (invariant && pe == (jl_value_t*)jl_vararg_type) { + pe = jl_bottom_type; + recheck = 1; + } + else + pe = jl_tparam0(pe); + if (invariant) + recheck = 1; + */ + pe = jl_tparam0(pe); + } } - if (!jl_subtype_le(ce, pe, ta, invariant)) - return 0; + if (!jl_subtype_le_new_(ce, pe, ta, invariant)) + break; - if (cseq && pseq) return 1; + if (cseq && pseq) { + result = 1; + break; + } ci++; pi++; } + /* + // The following is needed for Array{Tuple{Vararg}} <: Array{Tuple{Vararg}} + if (!result && recheck && clenr == plenr) + return jl_subtype_le_new_(child[clenr-1], parent[plenr-1], ta, invariant); + */ + return result; } static int jl_tuple_subtype_(jl_value_t **child, size_t cl, @@ -2654,7 +2686,7 @@ static int tuple_all_subtype(jl_datatype_t *t, jl_value_t *super, int ta, int in jl_value_t *ce = jl_tparam(t,ci); if (!ta && jl_is_vararg_type(ce)) ce = jl_tparam0(ce); - if (!jl_subtype_le(ce, super, ta, invariant)) + if (!jl_subtype_le_old(ce, super, ta, invariant)) return 0; } return 1; @@ -2824,7 +2856,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; if (ta) { if (jl_is_type_type(b)) { - return jl_is_type(a) && jl_subtype_le_new(a, jl_tparam0(b), 0, 1); + return jl_is_type(a) && jl_subtype_le_new_(a, jl_tparam0(b), 0, 1); } } else if (a == b) { @@ -2840,7 +2872,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) return jl_subtype_le_new(a,b,0,0) && jl_subtype_le_new(b,a,0,0); } for(i=0; i < l_ap; i++) { - if (!jl_subtype_le_new(jl_svecref(ap,i), b, 0, invariant)) + if (!jl_subtype_le_new_(jl_svecref(ap,i), b, 0, invariant)) return 0; } return 1; @@ -2851,14 +2883,14 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(tp0a)) { jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; - if (jl_subtype_le_new(ub, b, 1, 0) && - !jl_subtype_le_new((jl_value_t*)jl_any_type, ub, 0, 0)) { - if (jl_subtype_le_new(lb, b, 1, 0)) + if (jl_subtype_le_new_(ub, b, 1, 0) && + !jl_subtype_le_new_((jl_value_t*)jl_any_type, ub, 0, 0)) { + if (jl_subtype_le_new_(lb, b, 1, 0)) return 1; } } else { - if (jl_subtype_le_new(tp0a, b, 1, 0)) + if (jl_subtype_le_new_(tp0a, b, 1, 0)) return 1; } } @@ -2868,7 +2900,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_subtype_le_new(a, jl_svecref(bp,i), ta, invariant)) + if (jl_subtype_le_new_(a, jl_svecref(bp,i), ta, invariant)) return 1; } return 0; @@ -2894,7 +2926,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) while (tta != (jl_datatype_t*)jl_any_type) { if (tta->name == ttb->name) { if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_subtype_le_new(a, jl_tparam0(b), 0, 1)) + if (jl_subtype_le_new_(a, jl_tparam0(b), 0, 1)) return 1; } if (invariant && ttb == (jl_datatype_t*)ttb->name->primary) @@ -2909,7 +2941,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (!jl_is_typevar(apara)) return 0; } - if (!jl_subtype_le_new(apara, bpara, 0, 1)) + if (!jl_subtype_le_new_(apara, bpara, 0, 1)) return 0; } return 1; @@ -2926,30 +2958,47 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); } if (invariant) { return 0; } - return jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + return jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); } if (jl_is_typevar(b)) { - return jl_subtype_le_new(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + return jl_subtype_le_new_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); } if ((jl_datatype_t*)a == jl_any_type) return 0; return jl_egal(a, b); } +static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant) +{ + jl_value_t *newa=NULL, *newb=NULL; + JL_GC_PUSH2(&newa, &newb); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + int result = jl_subtype_le_new(newa, newb, ta, invariant); + JL_GC_POP(); + return result; +} + +int warnonce_subtype(int ta, int invariant, uintptr_t a, uintptr_t b); + static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) { int retold = jl_subtype_le_old(a, b, ta, invariant); - if (!needs_translation(a) && !needs_translation(b)) - return retold; jl_value_t *newa=NULL, *newb=NULL; JL_GC_PUSH2(&newa, &newb); if (needs_translation(a)) @@ -2962,12 +3011,15 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) newb = b; int retnew = jl_subtype_le_new(newa, newb, ta, invariant); if (retnew != retold) { - jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); - jl_(a); - jl_(b); + if (warnonce_subtype(ta, invariant, jl_object_id(a), jl_object_id(b))) { + jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); + jl_(a); + jl_(b); + } } JL_GC_POP(); return retnew; + //return retold; } JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) @@ -3719,6 +3771,7 @@ void jl_init_types(void) jl_tuple_typename = jl_anytuple_type->name; jl_anytuple_type->uid = 0; jl_anytuple_type->parameters = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL)); + //jl_anytuple_type->parameters = jl_svec(1, jl_wrap_vararg((jl_value_t*)NULL, (jl_value_t*)NULL)); jl_anytuple_type->types = jl_anytuple_type->parameters; jl_anytuple_type->nfields = 1; diff --git a/src/warnonce.cpp b/src/warnonce.cpp new file mode 100644 index 0000000000000..01e1a0ec9c19f --- /dev/null +++ b/src/warnonce.cpp @@ -0,0 +1,27 @@ +#include "julia.h" +#include "julia_internal.h" + +#include +#include + +std::set > wo_subtype; + +extern "C" { + +int warnonce_subtype(int ta, int invariant, uintptr_t ha, uintptr_t hb) +{ + std::vector v(4); + v[0] = (size_t) ta; + v[1] = (size_t) invariant; + v[2] = (size_t) ha; + v[3] = (size_t) hb; + std::set >::iterator it; + it = wo_subtype.find(v); + if (it == wo_subtype.end()) { + wo_subtype.insert(v); + return 1; + } + return 0; +} + +} diff --git a/test/core.jl b/test/core.jl index c80d7960e7bc4..7c930ea5b2e92 100644 --- a/test/core.jl +++ b/test/core.jl @@ -136,20 +136,33 @@ end @test () != Type{Tuple{}} -let N = TypeVar(:N,true), V = TypeVar(:V, NTuple{N,Int}), T = TypeVar(:T,true) - @test Tuple{} <: NTuple{N,Int} - @test Tuple{} <: NTuple{N,T} - @test Array{Tuple{}} <: Array{NTuple{N,Int}} - @test Array{Tuple{}} <: Array{NTuple{N,T}} - @test Tuple{Type{Int8}, Tuple{}} <: Tuple{Type{Int8}, NTuple{N,Int}} - @test Tuple{Type{Int8}, Tuple{Int,Int}} <: Tuple{Type{Int8}, NTuple{N,Int}} - @test V <: NTuple - # @test !(V <: Tuple{Vararg}) # current behavior, but this conflicts with the above -end +#let N = TypeVar(:N,true), V = TypeVar(:V, NTuple{N,Int}), T = TypeVar(:T,true) +# @test Tuple{} <: NTuple +# @test Tuple{} <: NTuple{N,Int} +# @test Tuple{} <: NTuple{N,T} +# @test !(Array{Tuple{}} <: Array{NTuple}) # is the difference... +# @test Array{Tuple{}} <: Array{NTuple{N}} # ...here desirable? +# @test Array{Tuple{}} <: Array{NTuple{N,Int}} +# @test Array{Tuple{}} <: Array{NTuple{N,T}} +# @test Array{Tuple{Int}} <: Array{NTuple{N,Int}} +# @test Array{Tuple{}} <: Array{NTuple{TypeVar(:N),Int}} # these two... +# @test !(Array{Tuple{Int}} <: Array{Tuple{Vararg{Int}}}) # ...conflict +# @test !(Array{Tuple{Int}} <: Array{Tuple{Int,Vararg{Int}}}) +# @test Tuple{Type{Int8}, Tuple{}} <: Tuple{Type{Int8}, NTuple{N,Int}} +# @test Tuple{Type{Int8}, Tuple{Int,Int}} <: Tuple{Type{Int8}, NTuple{N,Int}} +# @test V <: NTuple # and... +# @test !(V <: Tuple{Vararg}) # ...here +#end # issue #6561 +# We have to decide whether NTuple translates to Tuple{Vararg} or +# Tuple{Vararg{Any}}. Assuming the former, then it's hard to get +# Array{Tuple{Vararg}} <: Array{Tuple{Vararg{Any}}} +# because the LHS is Array{Tuple{Vararg{T<:Any}}}. +# Another option is to make Tuple === Tuple{Vararg{T<:Any}} @test issubtype(Array{Tuple}, Array{NTuple}) @test issubtype(Array{Tuple{Vararg{Any}}}, Array{NTuple}) +#@test issubtype(Array{Tuple{Vararg}}, Array{NTuple}) @test !issubtype(Array{Tuple{Vararg{Int}}}, Array{NTuple}) @test !issubtype(Array{Tuple{Int,Int}}, Array{NTuple}) @test !issubtype(Type{Tuple{Void}}, Tuple{Type{Void}}) From 612520285e6ebeed49597c10d18460b22abec9ce Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 9 May 2015 10:40:30 -0500 Subject: [PATCH 06/32] Update jl_type_morespecific --- src/jltypes.c | 247 ++++++++++++++++++++++++++++++++++++++++++++--- src/warnonce.cpp | 16 +++ 2 files changed, 252 insertions(+), 11 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index dbf43ad1b5e9e..72db0e37266c1 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3011,11 +3011,13 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) newb = b; int retnew = jl_subtype_le_new(newa, newb, ta, invariant); if (retnew != retold) { + /* if (warnonce_subtype(ta, invariant, jl_object_id(a), jl_object_id(b))) { jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); jl_(a); jl_(b); } + */ } JL_GC_POP(); return retnew; @@ -3035,8 +3037,9 @@ int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta) // specificity comparison static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant); +static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant); -static int jl_tuple_morespecific_(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) +static int jl_tuple_morespecific_old(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) { size_t cl = jl_nparams(cdt); jl_value_t **child = jl_svec_data(cdt->parameters); @@ -3090,6 +3093,73 @@ static int jl_tuple_morespecific_(jl_datatype_t *cdt, jl_datatype_t *pdt, int in return 0; } +static int jl_tuple_morespecific_new(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) +{ + size_t clenr = jl_nparams(cdt); + jl_value_t **child = jl_svec_data(cdt->parameters); + size_t plenr = jl_nparams(pdt); + jl_value_t **parent = jl_svec_data(pdt->parameters); + size_t plenf, clenf; + JL_VARARG_KIND ckind, pkind; + JL_TUPLE_LENKIND clenkind, plenkind; + clenf = tuple_vararg_params(cdt->parameters, NULL, &ckind, &clenkind); + plenf = tuple_vararg_params(pdt->parameters, NULL, &pkind, &plenkind); + size_t ci=0, pi=0; + int cseq=0, pseq=0; + int some_morespecific = 0; + jl_value_t *ce=NULL, *pe=NULL; + while (1) { + if (!cseq) + cseq = (ci= clenf && !cseq) + return some_morespecific || pi>=plenf || (pseq && !invariant); + if (pi >= plenf && !pseq) + return some_morespecific; + if (ci < clenr) { + ce = child[ci]; + if (jl_is_vararg_type(ce)) ce = jl_tparam0(ce); + } + if (pi < plenr) { + pe = parent[pi]; + if (jl_is_vararg_type(pe)) pe = jl_tparam0(pe); + } + + if (!jl_type_morespecific_(ce, pe, invariant)) { + if (type_eqv_(ce,pe)) { + if (ci==clenf-1 && pi==plenf-1) { + if (!cseq && pseq) + return 1; + if (!some_morespecific) + return 0; + } + } + else { + return 0; + } + } + + if (some_morespecific && cseq && !pseq) + return 1; + + // at this point we know one element is strictly more specific + if (!(jl_types_equal(ce,pe) || + (jl_is_typevar(pe) && + jl_types_equal(ce,((jl_tvar_t*)pe)->ub)))) { + some_morespecific = 1; + // here go into a different mode where we return 1 + // if the only reason the child is not more specific is + // argument count (i.e. ...) + } + + if (cseq && pseq) return 1; + ci++; + pi++; + } + return 0; +} + static int tuple_all_morespecific(jl_datatype_t *t, jl_value_t *super, int invariant) { size_t ci; @@ -3120,7 +3190,7 @@ static int partially_morespecific(jl_value_t *a, jl_value_t *b, int invariant) return jl_type_morespecific_(a, b, invariant); } -static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) +static int jl_type_morespecific_old(jl_value_t *a, jl_value_t *b, int invariant) { if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; @@ -3135,7 +3205,7 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) return tuple_all_morespecific((jl_datatype_t*)a, jl_tparam(b,1), invariant); } if (jl_is_tuple_type(b)) { - return jl_tuple_morespecific_((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); + return jl_tuple_morespecific_old((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); } } @@ -3156,7 +3226,7 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) for(i=0; i < l_ap; i++) { jl_value_t *ai = jl_svecref(ap,i); if (partially_morespecific(ai, b, invariant) && - !jl_type_morespecific_(b, ai, invariant)) { + !jl_type_morespecific_old(b, ai, invariant)) { if (partially_morespecific(b, a, invariant)) return 0; return 1; @@ -3185,7 +3255,7 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_type_morespecific_(a, jl_svecref(bp,i), invariant)) + if (jl_type_morespecific_old(a, jl_svecref(bp,i), invariant)) return 1; } return 0; @@ -3199,7 +3269,7 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) // only ((T>:S)...,) can be a supertype of NTuple[N,S] jl_value_t *ntp = jl_tparam(a, 1); if (jl_nparams(b) == 1 && jl_is_va_tuple((jl_datatype_t*)b)) { - return jl_type_morespecific_(ntp, jl_tparam0(jl_tparam0(b)), invariant); + return jl_type_morespecific_old(ntp, jl_tparam0(jl_tparam0(b)), invariant); } } if (!jl_is_typevar(a)) @@ -3219,17 +3289,17 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) } if (tta->name == jl_ntuple_typename) { // NTuple must be covariant - return jl_type_morespecific_(jl_tparam(tta,1), jl_tparam(ttb,1), invariant); + return jl_type_morespecific_old(jl_tparam(tta,1), jl_tparam(ttb,1), invariant); } if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_type_morespecific_(a, jl_tparam0(b), 1)) + if (jl_type_morespecific_old(a, jl_tparam0(b), 1)) return 1; } assert(jl_nparams(tta) == jl_nparams(ttb)); for(i=0; i < jl_nparams(tta); i++) { jl_value_t *apara = jl_tparam(tta,i); jl_value_t *bpara = jl_tparam(ttb,i); - if (!jl_type_morespecific_(apara, bpara, 1)) + if (!jl_type_morespecific_old(apara, bpara, 1)) return 0; } return 1; @@ -3245,9 +3315,9 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_type_morespecific_((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_type_morespecific_old((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0) && - jl_type_morespecific_((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_type_morespecific_old((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0); } if (invariant) @@ -3263,6 +3333,161 @@ static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) return 0; } +static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) +{ + if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; + if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; + if (a == b) { + // TODO; maybe change this + return 1; + } + size_t i; + if (jl_is_tuple_type(a)) { + if (jl_is_tuple_type(b)) { + return jl_tuple_morespecific_new((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); + } + } + + if (jl_is_uniontype(a)) { + jl_svec_t *ap = ((jl_uniontype_t*)a)->types; + size_t l_ap = jl_svec_len(ap); + if (jl_subtype_le(b, a, 0, 0)) { + // fixes issue #4413 + if (!jl_subtype_le(a, b, 0, invariant)) + return 0; + } + else if (jl_subtype_le(a, b, 0, invariant)) { + return 1; + } + // Union a is more specific than b if some element of a is + // more specific than b, and b is not more specific than any + // element of a. + for(i=0; i < l_ap; i++) { + jl_value_t *ai = jl_svecref(ap,i); + if (partially_morespecific(ai, b, invariant) && + !jl_type_morespecific_new_(b, ai, invariant)) { + if (partially_morespecific(b, a, invariant)) + return 0; + return 1; + } + } + return 0; + } + + if (jl_is_type_type(a) && !invariant) { + jl_value_t *tp0a = jl_tparam0(a); + if (jl_is_typevar(tp0a)) { + jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; + if (jl_subtype_le(ub, b, 1, 0) && + !jl_subtype_le((jl_value_t*)jl_any_type, ub, 0, 0)) { + return 1; + } + } + else { + if (jl_subtype_le(tp0a, b, 1, 0)) + return 1; + } + } + + if (jl_is_uniontype(b)) { + if (invariant) + return 0; + jl_svec_t *bp = ((jl_uniontype_t*)b)->types; + for(i=0; i < jl_svec_len(bp); i++) { + if (jl_type_morespecific_new_(a, jl_svecref(bp,i), invariant)) + return 1; + } + return 0; + } + + if (!invariant && (jl_datatype_t*)b == jl_any_type) return 1; + + if (jl_is_datatype(a) && jl_is_datatype(b)) { + if ((jl_datatype_t*)a == jl_any_type) return 0; + jl_datatype_t *tta = (jl_datatype_t*)a; + jl_datatype_t *ttb = (jl_datatype_t*)b; + int super=0; + while (tta != (jl_datatype_t*)jl_any_type) { + if (tta->name == ttb->name) { + if (super) { + if (tta->name != jl_type_type->name) + return 1; + } + if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { + if (jl_type_morespecific_new_(a, jl_tparam0(b), 1)) + return 1; + } + assert(jl_nparams(tta) == jl_nparams(ttb)); + for(i=0; i < jl_nparams(tta); i++) { + jl_value_t *apara = jl_tparam(tta,i); + jl_value_t *bpara = jl_tparam(ttb,i); + if (!jl_type_morespecific_new_(apara, bpara, 1)) + return 0; + } + return 1; + } + else if (invariant) { + return 0; + } + tta = tta->super; super = 1; + } + return 0; + } + + if (jl_is_typevar(a)) { + if (jl_is_typevar(b)) { + return + jl_type_morespecific_new_((jl_value_t*)((jl_tvar_t*)a)->ub, + (jl_value_t*)((jl_tvar_t*)b)->ub, 0) && + jl_type_morespecific_new_((jl_value_t*)((jl_tvar_t*)b)->lb, + (jl_value_t*)((jl_tvar_t*)a)->lb, 0); + } + if (invariant) + return 0; + return jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + } + if (jl_is_typevar(b)) { + return jl_subtype_le(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + } + if ((jl_datatype_t*)a == jl_any_type) return 0; + + return 0; +} + +static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant) +{ + jl_value_t *newa=NULL, *newb=NULL; + JL_GC_PUSH2(&newa, &newb); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + int retnew = jl_type_morespecific_new(newa, newb, invariant); + JL_GC_POP(); + return retnew; +} + +int warnonce_morespecific(int invariant, uintptr_t a, uintptr_t b); + +static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) +{ + int retold = jl_type_morespecific_old(a, b, invariant); + int retnew = jl_type_morespecific_new_(a, b, invariant); + if (retnew != retold) { + if (warnonce_morespecific(invariant, jl_object_id(a), jl_object_id(b))) { + jl_printf(JL_STDOUT, "Disagree jl_type_morespecific_ with retnew = %d, retold = %d (invariant = %d):\n", retnew, retold, invariant); + jl_(a); + jl_(b); + } + } + return retnew; +} + JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b) { return jl_type_morespecific_(a, b, 0); diff --git a/src/warnonce.cpp b/src/warnonce.cpp index 01e1a0ec9c19f..143639ce3fffa 100644 --- a/src/warnonce.cpp +++ b/src/warnonce.cpp @@ -5,6 +5,7 @@ #include std::set > wo_subtype; +std::set > wo_morespecific; extern "C" { @@ -24,4 +25,19 @@ int warnonce_subtype(int ta, int invariant, uintptr_t ha, uintptr_t hb) return 0; } +int warnonce_morespecific(int invariant, uintptr_t ha, uintptr_t hb) +{ + std::vector v(3); + v[0] = (size_t) invariant; + v[1] = (size_t) ha; + v[2] = (size_t) hb; + std::set >::iterator it; + it = wo_morespecific.find(v); + if (it == wo_morespecific.end()) { + wo_morespecific.insert(v); + return 1; + } + return 0; +} + } From 469a24421a8a3675c2e4200b547ccc44373adb98 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 May 2015 04:36:50 -0500 Subject: [PATCH 07/32] Update type_match for new va tuples --- src/jltypes.c | 352 ++++++++++++++++++++++++++++++++++++++++++++--- src/warnonce.cpp | 17 +++ test/core.jl | 15 ++ 3 files changed, 366 insertions(+), 18 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index 72db0e37266c1..ac3a299c0c563 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2671,7 +2671,7 @@ static int jl_tuple_subtype_(jl_value_t **child, size_t cl, jl_(newpdt); } JL_GC_POP(); - return retold; + return retnew; } int jl_tuple_subtype(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta) @@ -3010,15 +3010,15 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) else newb = b; int retnew = jl_subtype_le_new(newa, newb, ta, invariant); + /* if (retnew != retold) { - /* if (warnonce_subtype(ta, invariant, jl_object_id(a), jl_object_id(b))) { jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); jl_(a); jl_(b); } - */ } + */ JL_GC_POP(); return retnew; //return retold; @@ -3500,8 +3500,11 @@ int type_match_invariance_mask = 1; static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); +static jl_value_t *type_match_old(jl_value_t *child, jl_value_t *parent, + cenv_t *env, int morespecific, int invariant); +static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); -static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, +static jl_value_t *tuple_match_old(jl_datatype_t *child, jl_datatype_t *parent, cenv_t *env, int morespecific, int invariant) { size_t ci=0, pi=0; @@ -3524,7 +3527,7 @@ static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, if (pseq) pe = jl_tparam0(pe); int n = env->n; - if (type_match_(ce, pe, env, morespecific, invariant) == jl_false) { + if (type_match_old(ce, pe, env, morespecific, invariant) == jl_false) { env->n = n; if (jl_types_equal_generic(ce,pe,1)) { if (ci==cl-1 && pi==pl-1 && !cseq && pseq) { @@ -3555,7 +3558,87 @@ static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, return jl_false; } -static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, +static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, + cenv_t *env, int morespecific, int invariant) +{ + size_t ci=0, pi=0; + size_t clenr = jl_nparams(child); + size_t plenr = jl_nparams(parent); + size_t plenf, clenf; + JL_VARARG_KIND ckind, pkind; + JL_TUPLE_LENKIND clenkind, plenkind; + clenf = tuple_vararg_params(child->parameters, NULL, &ckind, &clenkind); + plenf = tuple_vararg_params(parent->parameters, NULL, &pkind, &plenkind); + int cseq=0, pseq=0; + jl_value_t *ce=NULL, *pe=NULL, *cn=NULL, *pn=NULL; + int mode = 0; + while(1) { + if (!cseq) + cseq = (ci= clenf && !cseq) + return (mode || pi>=plenf || (pseq && !invariant)) ? jl_true : jl_false; + if (pi >= plenf && !pseq) + return mode ? jl_true : jl_false; + if (ci < clenr) { + ce = jl_tparam(child,ci); + if (jl_is_vararg_type(ce)) { + cn = jl_tparam1(ce); + ce = jl_tparam0(ce); + } + } + if (pi < plenr) { + pe = jl_tparam(parent,pi); + if (jl_is_vararg_type(pe)) { + pn = jl_tparam1(pe); + pe = jl_tparam0(pe); + } + } + + int n = env->n; + if (type_match_new_(ce, pe, env, morespecific, invariant) == jl_false) { + env->n = n; + if (jl_types_equal_generic(ce,pe,1)) { + if (ci==clenf-1 && pi==plenf-1 && !cseq && pseq) { + return jl_true; + } + if (!mode) return jl_false; + } + else { + return jl_false; + } + } + // Match the number parameter in Vararg, too + if (cseq && pseq) { + n = env->n; + if (type_match_new_(cn, pn, env, morespecific, invariant) == jl_false) { + env->n = n; + return jl_false; + } + } + + if (mode && cseq && !pseq) + return jl_true; + + if (morespecific) { + if (!(jl_types_equal_generic(ce,pe,1) || + (jl_is_typevar(pe) && + jl_types_equal(ce,((jl_tvar_t*)pe)->ub)))) { + mode = 1; + } + } + + if (cseq && pseq) return jl_true; + ci++; + pi++; + } + return jl_false; +} + +static jl_value_t *type_match_old(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) { jl_value_t *tmp, *tmp2; @@ -3641,18 +3724,18 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t tenv; tenv.data = rts; for(i=0; i < jl_svec_len(t); i++) { int n = env->n; - tmp = type_match_(jl_svecref(t,i), parent, env, 1, invariant); + tmp = type_match_old(jl_svecref(t,i), parent, env, 1, invariant); if (tmp != jl_false) { tenv.n = 0; - tmp2 = type_match_(parent, jl_svecref(t,i), &tenv, 1, invariant); + tmp2 = type_match_old(parent, jl_svecref(t,i), &tenv, 1, invariant); if (tmp2 == jl_false) { n = env->n; for(j=0; j < jl_svec_len(t); j++) { tenv.n = 0; env->n = n; - if (type_match_(parent, jl_svecref(t,j), + if (type_match_old(parent, jl_svecref(t,j), &tenv, 1, invariant) != jl_false && - type_match_(jl_svecref(t,j), parent, + type_match_old(jl_svecref(t,j), parent, env, 1, invariant) == jl_false) { env->n = n; JL_GC_POP(); @@ -3673,7 +3756,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, else { for(i=0; i < jl_svec_len(t); i++) { int n = env->n; - if (type_match_(jl_svecref(t,i), parent, env, morespecific, + if (type_match_old(jl_svecref(t,i), parent, env, morespecific, invariant) == jl_false) { env->n = n; return jl_false; } } @@ -3688,7 +3771,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, int n = env->n; for(i=0; i < jl_svec_len(t); i++) { env->n = n; - if (type_match_(child, jl_svecref(t,i), env, + if (type_match_old(child, jl_svecref(t,i), env, morespecific, invariant) != jl_false) return jl_true; } @@ -3707,7 +3790,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, jl_value_t *childlen = jl_box_long(jl_nparams(child)); if (jl_is_typevar(nt_len)) { int n = env->n; - if (type_match_(childlen, nt_len, env, morespecific, + if (type_match_old(childlen, nt_len, env, morespecific, invariant) == jl_false) { env->n = n; return jl_false; } } @@ -3718,14 +3801,14 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, JL_GC_PUSH1(&p_seq); p_seq = (jl_value_t*)jl_svec1(p_seq); p_seq = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)p_seq); - tmp = tuple_match((jl_tupletype_t*)child, (jl_tupletype_t*)p_seq, + tmp = tuple_match_old((jl_tupletype_t*)child, (jl_tupletype_t*)p_seq, env, morespecific, invariant); JL_GC_POP(); return tmp; } if (jl_is_tuple_type(parent)) { - return tuple_match((jl_datatype_t*)child, (jl_datatype_t*)parent, env, + return tuple_match_old((jl_datatype_t*)child, (jl_datatype_t*)parent, env, morespecific, invariant); } return jl_false; @@ -3736,11 +3819,197 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, // only ((T>:S)...,) can be a supertype of NTuple[N,S] jl_value_t *ntp = jl_tparam(child, 1); if (jl_nparams(parent) == 1 && jl_is_va_tuple((jl_datatype_t*)parent)) { - return type_match_(ntp, jl_tparam0(jl_tparam0(parent)), env, morespecific, invariant); + return type_match_old(ntp, jl_tparam0(jl_tparam0(parent)), env, morespecific, invariant); + } + } + return jl_false; + } + + if (!jl_is_datatype(child) || !jl_is_datatype(parent)) { + return jl_egal(child,parent) ? jl_true : jl_false; + } + jl_datatype_t *tta = (jl_datatype_t*)child; + jl_datatype_t *ttb = (jl_datatype_t*)parent; + int super = 0; + while (tta != (jl_datatype_t*)jl_any_type) { + if (tta->name == ttb->name) { + // note: DataType <: Type, but Type{T} <: DataType + // for any specific T. + if (super && morespecific && tta->name != jl_type_type->name) + return jl_true; + assert(jl_nparams(tta) == jl_nparams(ttb)); + for(i=0; i < jl_nparams(tta); i++) { + int n = env->n; + if (type_match_old(jl_tparam(tta,i), jl_tparam(ttb,i), + env, morespecific, 1) == jl_false) + { env->n = n; return jl_false; } + } + return jl_true; + } + else if (invariant) { + return jl_false; + } + tta = tta->super; super = 1; + } + assert(!invariant); + if (((jl_datatype_t*)child)->name == jl_type_type->name && + ttb->name != jl_type_type->name) { + // Type{T} also matches >:typeof(T) + return type_match_old(jl_typeof(jl_tparam0(child)), + parent, env, morespecific, 0); + } + return jl_false; +} + +static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, + cenv_t *env, int morespecific, int invariant) +{ + jl_value_t *tmp, *tmp2; + if (jl_is_typector(child)) + child = (jl_value_t*)((jl_typector_t*)child)->body; + if (jl_is_typector(parent)) + parent = (jl_value_t*)((jl_typector_t*)parent)->body; + size_t i, j; + if (match_intersection_mode && jl_is_typevar(child) && !jl_is_typevar(parent)) { + tmp = child; + child = parent; + parent = tmp; + } + if (jl_is_typevar(parent)) { + // make sure type is within this typevar's bounds + if (morespecific) { + if (!jl_type_morespecific_(child, parent, 0)) + return jl_false; + } + else { + if (!jl_subtype_le(child, parent, 0, 0)) + return jl_false; + } + if (!match_intersection_mode) { + if (!((jl_tvar_t*)parent)->bound) return jl_true; + } + for(int i=0; i < env->n; i+=2) { + if (env->data[i] == (jl_value_t*)parent) { + jl_value_t *pv = env->data[i+1]; + if (jl_is_typevar(pv) && jl_is_typevar(child)) { + if (pv == (jl_value_t*)child) + return jl_true; + return jl_false; + } + if (morespecific) { + if (jl_type_morespecific_(child, pv, 0)) { + return jl_true; + } + else if (!jl_is_typevar(child) && !jl_type_morespecific_(pv, child, 0)) { + return jl_true; + } + else if (jl_subtype(pv, child, 0)) { + env->data[i+1] = (jl_value_t*)child; + return jl_true; + } + } + else { + if (type_eqv_(child, pv)) + return jl_true; + } + return jl_false; + } + } + extend(parent, child, env); + return jl_true; + } + + if (child == parent) return jl_true; + + if (jl_is_typevar(child)) { + if (!invariant || morespecific) { + if (morespecific) { + if (jl_type_morespecific_(child, parent, 0)) + return jl_true; + } + else { + if (jl_subtype_le(child, parent, 0, 0)) + return jl_true; } } return jl_false; } + if (!invariant && parent == (jl_value_t*)jl_any_type) + return jl_true; + if (child == (jl_value_t*)jl_any_type) return jl_false; + + if (jl_is_uniontype(child)) { + jl_svec_t *t = ((jl_uniontype_t*)child)->types; + if (morespecific) { + jl_value_t **rts; + JL_GC_PUSHARGS(rts, MAX_CENV_SIZE); + cenv_t tenv; tenv.data = rts; + for(i=0; i < jl_svec_len(t); i++) { + int n = env->n; + tmp = type_match_new_(jl_svecref(t,i), parent, env, 1, invariant); + if (tmp != jl_false) { + tenv.n = 0; + tmp2 = type_match_new_(parent, jl_svecref(t,i), &tenv, 1, invariant); + if (tmp2 == jl_false) { + n = env->n; + for(j=0; j < jl_svec_len(t); j++) { + tenv.n = 0; + env->n = n; + if (type_match_new_(parent, jl_svecref(t,j), + &tenv, 1, invariant) != jl_false && + type_match_new_(jl_svecref(t,j), parent, + env, 1, invariant) == jl_false) { + env->n = n; + JL_GC_POP(); + return jl_false; + } + } + JL_GC_POP(); + return jl_true; + } + } + else { + env->n = n; + } + } + JL_GC_POP(); + return jl_false; + } + else { + for(i=0; i < jl_svec_len(t); i++) { + int n = env->n; + if (type_match_new_(jl_svecref(t,i), parent, env, morespecific, + invariant) == jl_false) + { env->n = n; return jl_false; } + } + if (invariant && child == (jl_value_t*)jl_bottom_type && + !jl_is_typevar(parent)) + return jl_false; + } + return jl_true; + } + if (jl_is_uniontype(parent)) { + jl_svec_t *t = ((jl_uniontype_t*)parent)->types; + int n = env->n; + for(i=0; i < jl_svec_len(t); i++) { + env->n = n; + if (type_match_new_(child, jl_svecref(t,i), env, + morespecific, invariant) != jl_false) + return jl_true; + } + return jl_false; + } + + if (jl_is_tuple_type(child)) { + if (jl_is_tuple_type(parent)) { + return tuple_match_new((jl_datatype_t*)child, (jl_datatype_t*)parent, env, + morespecific, invariant); + } + return jl_false; + } + if (jl_is_tuple_type(parent)) { + return jl_false; + } if (!jl_is_datatype(child) || !jl_is_datatype(parent)) { return jl_egal(child,parent) ? jl_true : jl_false; @@ -3757,7 +4026,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, assert(jl_nparams(tta) == jl_nparams(ttb)); for(i=0; i < jl_nparams(tta); i++) { int n = env->n; - if (type_match_(jl_tparam(tta,i), jl_tparam(ttb,i), + if (type_match_new_(jl_tparam(tta,i), jl_tparam(ttb,i), env, morespecific, 1) == jl_false) { env->n = n; return jl_false; } } @@ -3772,12 +4041,59 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, if (((jl_datatype_t*)child)->name == jl_type_type->name && ttb->name != jl_type_type->name) { // Type{T} also matches >:typeof(T) - return type_match_(jl_typeof(jl_tparam0(child)), + return type_match_new_(jl_typeof(jl_tparam0(child)), parent, env, morespecific, 0); } return jl_false; } +static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) +{ + jl_value_t *newc=NULL, *newp=NULL; + JL_GC_PUSH2(&newc, &newp); + if (needs_translation(child)) + newc = ntuple_translate(child); + else + newc = child; + if (needs_translation(parent)) + newp = ntuple_translate(parent); + else + newp = parent; + jl_value_t *retnew = type_match_new(newc, newp, env, morespecific, invariant); + JL_GC_POP(); + return retnew; +} + +int warnonce_typematch(int morespecific, int invariant, uintptr_t a, uintptr_t b); + +static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, + cenv_t *env, int morespecific, int invariant) +{ + int n = env->n; + jl_value_t *retold = type_match_old(child, parent, env, morespecific, invariant); + env->n = n; + jl_value_t *retnew = type_match_new_(child, parent, env, morespecific, invariant); + if (retnew != retold) { + if (warnonce_typematch(morespecific, invariant, jl_object_id(child), jl_object_id(parent))) { + jl_printf(JL_STDOUT, "Disagree type_match_ with retnew = %d, retold = %d (morespecific = %d, invariant = %d):\n", retnew==jl_true, retold==jl_true, morespecific, invariant); + jl_(child); + jl_(parent); + } + } + return retnew; +} + +JL_DLLEXPORT jl_value_t *jl_my_type_match(jl_value_t *child, jl_value_t *parent, + int morespecific, int invariant) +{ + jl_value_t **rts; + JL_GC_PUSHARGS(rts, MAX_CENV_SIZE); + cenv_t env; env.n = 0; env.data = rts; + jl_value_t *m = type_match_(child, parent, &env, morespecific, invariant); + JL_GC_POP(); + return m; +} + /* typically a is a concrete type and b is a type containing typevars. this function tries to find a typevar assignment such that "a" is a subtype diff --git a/src/warnonce.cpp b/src/warnonce.cpp index 143639ce3fffa..08af9f9bde5e8 100644 --- a/src/warnonce.cpp +++ b/src/warnonce.cpp @@ -6,6 +6,7 @@ std::set > wo_subtype; std::set > wo_morespecific; +std::set > wo_typematch; extern "C" { @@ -40,4 +41,20 @@ int warnonce_morespecific(int invariant, uintptr_t ha, uintptr_t hb) return 0; } +int warnonce_typematch(int morespecific, int invariant, uintptr_t ha, uintptr_t hb) +{ + std::vector v(4); + v[0] = (size_t) morespecific; + v[1] = (size_t) invariant; + v[2] = (size_t) ha; + v[3] = (size_t) hb; + std::set >::iterator it; + it = wo_typematch.find(v); + if (it == wo_typematch.end()) { + wo_typematch.insert(v); + return 1; + } + return 0; +} + } diff --git a/test/core.jl b/test/core.jl index 7c930ea5b2e92..2943ad0cee935 100644 --- a/test/core.jl +++ b/test/core.jl @@ -641,6 +641,21 @@ let @test is(g(a),a) end +# Method specificity +begin + local f + f{T}(dims::Tuple{}, A::AbstractArray{T,0}) = 1 + f{T,N}(dims::NTuple{N,Int}, A::AbstractArray{T,N}) = 2 + f{T,M,N}(dims::NTuple{M,Int}, A::AbstractArray{T,N}) = 3 + A = zeros(2,2) + @test f((1,2,3), A) == 3 + @test f((1,2), A) == 2 + @test f((), reshape([1])) == 1 + f{T,N}(dims::NTuple{N,Int}, A::AbstractArray{T,N}) = 4 + @test f((1,2), A) == 4 + @test f((1,2,3), A) == 3 +end + # dispatch using Val{T}. See discussion in #9452 for instances vs types let local firstlast From d0c5848fe69da6f262363abf158e73a6c194c4a7 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 May 2015 04:54:23 -0500 Subject: [PATCH 08/32] Implement jl_type_intersect for new Vararg tuples --- src/jltypes.c | 413 +++++++++++++++++++++++++++++++++++++++++++++-- src/julia.h | 5 + src/warnonce.cpp | 16 ++ 3 files changed, 423 insertions(+), 11 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index ac3a299c0c563..10b280844eb37 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -472,6 +472,9 @@ static void extend(jl_value_t *var, jl_value_t *val, cenv_t *soln) static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); +static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); +static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); + static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) @@ -518,11 +521,16 @@ static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, /* Simplification of varargs tuple types: - JL_TUPLE_FIXED: tuples of known length (JL_VARARG_NONE or JL_VARARG_INT) - JL_TUPLE_VAR: tuples of unknown length (JL_VARARG_BOUND or JL_VARARG_UNBOUND) + JL_TUPLE_FIXED: tuples of known length (e.g., JL_VARARG_NONE or JL_VARARG_INT) + JL_TUPLE_VAR: tuples of unknown length (e.g., JL_VARARG_BOUND or JL_VARARG_UNBOUND) In some cases, JL_VARARG_BOUND tuples get described as JL_TUPLE_FIXED, if the constraints on length are already known. + +lenr = "representation length" (the number of parameters) +lenf = "full length" (including the Vararg length, if known) + +In general, lenf >= lenr-1. The lower bound is achieved only for a Vararg of length 0. */ typedef enum { JL_TUPLE_FIXED = 0, @@ -611,7 +619,7 @@ jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, env, 2); } -static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, +static jl_value_t *intersect_tuple_old(jl_datatype_t *a, jl_datatype_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { jl_svec_t *ap = a->parameters, *bp = b->parameters; @@ -645,7 +653,7 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, bi++; } assert(ae!=NULL && be!=NULL); - ce = jl_type_intersect(ae,be,penv,eqc,var); + ce = jl_type_intersect_old(ae,be,penv,eqc,var); if (ce == (jl_value_t*)jl_bottom_type) { if (var!=invariant && aseq && bseq) { // (X∩Y)==∅ → (X...)∩(Y...) == () @@ -669,6 +677,147 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, return result; } +/* +Tuple intersection +Stage 1: compute lengths of each tuple +-------------------------------------- +See above + +Stage 2: paired length analysis +------------------------------- +Check and combine lengths. In cells of the following table, +- row 1 is the criterion that must be satisfied, or Bottom will be returned +- row 2 is the allocated length for the output tuple +- row 3, if present, indicates any additional steps taken at the time + of length computation + + b + FIXED VAR + |---------------------------------------| + | alenf == blenf | alenf+1 >= blenr | + FIXED | alenf | alenf | + | | bind b? | +a |---------------------------------------| + | blenf+1 >= alenr | | + VAR | blenf | max(alenr,blenr) | + | bind a? | flag? | + |---------------------------------------| + +"bind" is performed if the VAR tuple is of state BOUND, using (for +the b BOUND case) N == alenf-blenr+1 for b's length parameter N. + +"flag" is set if at least one of the tuples is of state BOUND. With +this, we signify that the intersection of these tuples is going to +have to be repeated once all lengths are constrained. + +Stage 3: slot type intersection +------------------------------- +Iterate over each slot of the _output_ tuple, intersecting +corresponding pairs of types. Any intersection failure causes Bottom +to be returned, with one exception illustrated by: + typeintersect(Tuple{A, Vararg{B}}, Tuple{A, Vararg{C}}) == Tuple{A} +where typeintersect(B,C) == Bottom. +*/ + +int recheck_tuple_intersection = 0; // "flag" above + +static jl_value_t *intersect_tuple_new(jl_datatype_t *a, jl_datatype_t *b, + cenv_t *penv, cenv_t *eqc, variance_t var) +{ + jl_svec_t *ap = a->parameters, *bp = b->parameters; + size_t alenr = jl_svec_len(ap), blenr = jl_svec_len(bp); + size_t alenf, blenf; + JL_VARARG_KIND akind, bkind; + JL_TUPLE_LENKIND alenkind, blenkind; + int bottom = 0; + size_t n; + // Stage 1 + alenf = tuple_vararg_params(ap, eqc, &akind, &alenkind); + blenf = tuple_vararg_params(bp, eqc, &bkind, &blenkind); + // Stage 2 + if (alenkind == JL_TUPLE_FIXED && blenkind == JL_TUPLE_FIXED) { + bottom = alenf != blenf; + n = alenf; + } + else if (alenkind == JL_TUPLE_FIXED && blenkind == JL_TUPLE_VAR) { + bottom = alenf+1 < blenf; + n = alenf; + if (bkind == JL_VARARG_BOUND) + extend(jl_tparam1(jl_svecref(bp, blenr-1)), jl_box_long(alenf-blenr+1), eqc); + } + else if (alenkind == JL_TUPLE_VAR && blenkind == JL_TUPLE_FIXED) { + bottom = blenf+1 < alenf; + n = blenf; + if (akind == JL_VARARG_BOUND) + extend(jl_tparam1(jl_svecref(ap, alenr-1)), jl_box_long(blenf-alenr+1), eqc); + } + else { + n = alenr > blenr ? alenr : blenr; + // Do we need to store "at least N" constraints in penv? + // Formerly, typeintersect(Tuple{A,Vararg{B}}, NTuple{N,C}) did that + if (akind == JL_VARARG_BOUND || bkind == JL_VARARG_BOUND) + recheck_tuple_intersection = 1; + } + if (bottom) return (jl_value_t*) jl_bottom_type; + if (n == 0) return jl_typeof(jl_emptytuple); + jl_svec_t *tc = jl_alloc_svec(n); + jl_value_t *result = (jl_value_t*)tc; + jl_value_t *ce = NULL; + JL_GC_PUSH2(&tc, &ce); + size_t ai=0, bi=0, ci; + jl_value_t *ae=NULL, *be=NULL, *an=NULL, *bn=NULL; + int aseq=0, bseq=0; + // Stage 3 + for(ci=0; ci < n; ci++) { + if (ai < alenr) { + ae = jl_svecref(ap,ai); + if (jl_is_vararg_type(ae)) { + if (alenkind != JL_TUPLE_FIXED) { + an = jl_tparam1(ae); + aseq = 1; + } + ae = jl_tparam0(ae); + } + ai++; + } + if (bi < blenr) { + be = jl_svecref(bp,bi); + if (jl_is_vararg_type(be)) { + if (blenkind != JL_TUPLE_FIXED) { + bn = jl_tparam1(be); + bseq=1; + } + be = jl_tparam0(be); + } + bi++; + } + assert(ae!=NULL && be!=NULL); + ce = jl_type_intersect_new_(ae,be,penv,eqc,var); + if (ce == (jl_value_t*)jl_bottom_type) { + if (var!=invariant && aseq && bseq) { + // (X∩Y)==∅ → (X...)∩(Y...) == () + // We don't need to set bindings here because + // recheck_tuple_intersection=1 + if (n == 1) { + JL_GC_POP(); + return (jl_value_t*)jl_typeof(jl_emptytuple); + } + jl_svec_set_len_unsafe(tc,jl_svec_len(tc)-1); + goto done_intersect_tuple; + } + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + if (aseq && bseq) + ce = (jl_value_t*)jl_wrap_vararg(ce, akind==JL_VARARG_BOUND ? bn : an); + jl_svecset(tc, ci, ce); + } + done_intersect_tuple: + result = (jl_value_t*)jl_apply_tuple_type(tc); + JL_GC_POP(); + return result; +} + static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { @@ -977,7 +1126,7 @@ static int has_ntuple_intersect_tuple = 0; static jl_datatype_t *inst_tupletype_unchecked_uncached(jl_svec_t *p); -static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, +static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { if (jl_is_typector(a)) @@ -1086,14 +1235,14 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, } } if (jl_is_tuple_type(b)) { - a = intersect_tuple((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); + a = intersect_tuple_old((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); JL_GC_POP(); return a; } JL_GC_POP(); } if (jl_is_tuple_type(b)) { - return jl_type_intersect(b, a, penv,eqc,var); + return jl_type_intersect_old(b, a, penv,eqc,var); } if (jl_is_ntuple_type(a)) { if (jl_is_ntuple_type(b)) { @@ -1181,7 +1330,206 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); else env = (jl_value_t*)sub->super; - super = (jl_datatype_t*)jl_type_intersect((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); + super = (jl_datatype_t*)jl_type_intersect_old((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); + + if ((jl_value_t*)super == jl_bottom_type) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + + // super needs to be instantiated so the matching below finds actual types + // and doesn't fail due to the presence of extra typevars. + super = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)super, eqc->data, eqc->n/2); + + size_t n = jl_svec_len(sub->parameters); + + assert(sub->name->primary != NULL); + jl_value_t *tc = sub->name->primary; + jl_svec_t *tc_params = ((jl_datatype_t*)tc)->parameters; + // compute what constraints the supertype imposes on the subtype + jl_svec_t *subs_sup_params = + ((jl_datatype_t*)((jl_datatype_t*)tc)->super)->parameters; + // match the intersected supertype against the pattern this subtype + // uses to instantiate its supertype. this tells us what subtype parameter + // values are implied by the intersected supertype, or that the + // intersected supertype cannot come from this subtype (in which case + // our final answer is Union()). + size_t i; + // hack: we need type_match to find assignments for all typevars + int prev_mim = match_intersection_mode; + match_intersection_mode = 1; + // TODO get rid of these intermediate tuple types + p = (jl_value_t*)jl_apply_tuple_type(super->parameters); + temp3 = (jl_value_t*)jl_apply_tuple_type(subs_sup_params); + env = jl_type_match(p, temp3); + int sub_needs_parameters = 0; + if (env == jl_false) { + env = jl_type_match(temp3, p); + } + else { + // this means it needs to be possible to instantiate the subtype + // such that the supertype gets the matching parameters we just + // determined. + sub_needs_parameters = 1; + } + match_intersection_mode = prev_mim; + if (env == jl_false) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + if (sub_needs_parameters) { + for(int e=0; e < jl_svec_len(env); e+=2) { + jl_value_t *tp = jl_svecref(env, e); + // make sure each needed parameter is actually set by the subtype + size_t j; + for(j=0; j < n; j++) { + if (tp == jl_svecref(tc_params, j)) + break; + } + if (j >= n) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + } + } + + p = (jl_value_t*)jl_alloc_svec(n); + for(i=0; i < n; i++) { + jl_value_t *tp = jl_svecref(tc_params, i); + jl_value_t *elt = jl_svecref(sub->parameters, i); + for(int e=0; e < jl_svec_len(env); e+=2) { + if (jl_svecref(env, e) == tp) { + elt = jl_type_intersect_old(elt, jl_svecref(env, e+1), + penv, eqc, invariant); + // note: elt might be Union() if "Union()" was the type parameter + break; + } + } + jl_svecset(p, i, elt); + } + jl_value_t *result = (jl_value_t*)jl_apply_type(tc, (jl_svec_t*)p); + JL_GC_POP(); + return result; +} + +static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, + cenv_t *penv, cenv_t *eqc, variance_t var) +{ + if (jl_is_typector(a)) + a = (jl_value_t*)((jl_typector_t*)a)->body; + if (jl_is_typector(b)) + b = (jl_value_t*)((jl_typector_t*)b)->body; + if (a == b) return a; + if (jl_is_typevar(a)) { + if (var == covariant && !((jl_tvar_t*)a)->bound) + a = ((jl_tvar_t*)a)->ub; + else if (a != jl_ANY_flag) + return intersect_typevar((jl_tvar_t*)a, b, penv, eqc, var); + } + if (jl_is_typevar(b)) { + if (var == covariant && !((jl_tvar_t*)b)->bound) + b = ((jl_tvar_t*)b)->ub; + else if (b != jl_ANY_flag) + return intersect_typevar((jl_tvar_t*)b, a, penv, eqc, var); + } + if (a == (jl_value_t*)jl_bottom_type || b == (jl_value_t*)jl_bottom_type) + return (jl_value_t*)jl_bottom_type; + if (!jl_has_typevars(a) && !jl_has_typevars(b)) { + if (jl_subtype(a, b, 0)) + return a; + if (jl_subtype(b, a, 0)) + return b; + } + // union + if (jl_is_uniontype(a)) + return intersect_union((jl_uniontype_t*)a, b, penv, eqc, var); + if (jl_is_uniontype(b)) + return intersect_union((jl_uniontype_t*)b, a, penv, eqc, var); + if (a == (jl_value_t*)jl_any_type || a == jl_ANY_flag) return b; + if (b == (jl_value_t*)jl_any_type || b == jl_ANY_flag) return a; + // tuple + if (jl_is_tuple_type(a)) { + if (jl_is_tuple_type(b)) { + return intersect_tuple_new((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); + } + } + if (jl_is_tuple_type(b)) { + return jl_type_intersect_new(b, a, penv,eqc,var); + } + // tag + if (!jl_is_datatype(a) || !jl_is_datatype(b)) + return (jl_value_t*)jl_bottom_type; + jl_datatype_t *tta = (jl_datatype_t*)a; + jl_datatype_t *ttb = (jl_datatype_t*)b; + if (tta->name == ttb->name) + return (jl_value_t*)intersect_tag(tta, ttb, penv, eqc, var); + jl_datatype_t *super = NULL; + jl_datatype_t *sub = NULL; + jl_value_t *env = NULL; + jl_value_t *p = NULL; + jl_value_t *temp3 = NULL; + JL_GC_PUSH5(&super, &sub, &env, &p, &temp3); + while (tta != jl_any_type) { + if (tta->name == ttb->name) { + sub = (jl_datatype_t*)a; + super = (jl_datatype_t*)b; + break; + } + tta = tta->super; + } + if (sub == NULL) { + tta = (jl_datatype_t*)a; + while (ttb != jl_any_type) { + if (tta->name == ttb->name) { + sub = (jl_datatype_t*)b; + super = (jl_datatype_t*)a; + break; + } + ttb = ttb->super; + } + if (sub == NULL) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + } + + if (sub->super == jl_type_type && jl_is_type_type((jl_value_t*)super)) { + // subtypes of Type like DataType do not constrain the type + // parameter, and yet contain Type instances with a more specific + // parameter (like Type{Int}). This is a special case. + jl_value_t *tp0 = jl_tparam0(super); + if (jl_is_typevar(tp0) || (jl_value_t*)sub == jl_typeof(tp0)) { + JL_GC_POP(); + return (jl_value_t*)super; + } + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + + /* + issue #6387 + Say we have + + type DateRange{C} <: Range{Date{C}}; end + + and + + vcat{T}(r::Range{T}) = ... + + Then inferring vcat(::DateRange) concludes that T==Date{C}, but it should + conclude T<:Date{C}. The core problem seems to be that in moving from a + type to its supertype, we drop the environment that binds C --- we + forget that C is a variable in Range{Date{C}}. For now I work around this + by rewriting this type to Range{_<:Date{C}}, effectively tagging type + parameters that are variable due to the extra (dropped) environment. + */ + if (var == covariant && + sub == (jl_datatype_t*)sub->name->primary && + jl_has_typevars_from((jl_value_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters)) + env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); + else + env = (jl_value_t*)sub->super; + super = (jl_datatype_t*)jl_type_intersect_new_((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); if ((jl_value_t*)super == jl_bottom_type) { JL_GC_POP(); @@ -1250,7 +1598,7 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, jl_value_t *elt = jl_svecref(sub->parameters, i); for(int e=0; e < jl_svec_len(env); e+=2) { if (jl_svecref(env, e) == tp) { - elt = jl_type_intersect(elt, jl_svecref(env, e+1), + elt = jl_type_intersect_new_(elt, jl_svecref(env, e+1), penv, eqc, invariant); // note: elt might be Union{} if "Union{}" was the type parameter break; @@ -1263,6 +1611,49 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, return result; } +static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) +{ + jl_value_t *newa=NULL, *newb=NULL, *retnew=NULL; + JL_GC_PUSH3(&newa, &newb, &retnew); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + retnew = jl_type_intersect_new(newa, newb, penv, eqc, var); + JL_GC_POP(); + return retnew; +} + +int warnonce_intersect(int var, uintptr_t ha, uintptr_t hb); + +static int extensionally_same_type(jl_value_t *a, jl_value_t *b); + +static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) +{ + int np = penv->n, nc = eqc->n; + jl_value_t *retold = NULL, *retnew = NULL; + JL_GC_PUSH2(&retold, &retnew); + retold = jl_type_intersect_old(a, b, penv, eqc, var); + penv->n = np; + eqc->n = nc; + retnew = jl_type_intersect_new_(a, b, penv, eqc, var); + if (!extensionally_same_type(retold, retnew)) { //(!jl_types_equal(retnew, retold)) { + if (warnonce_intersect(var, jl_object_id(a), jl_object_id(b))) { + jl_printf(JL_STDOUT, "Disagree jl_type_intersect (var = %d):\n", var); + jl_(a); + jl_(b); + jl_(retold); + jl_(retnew); + } + } + JL_GC_POP(); + return retnew; +} + JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) { jl_svec_t *env = jl_emptysvec; @@ -1613,7 +2004,7 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_value_t **pti = &rts[0]; jl_value_t **extraroot = &rts[1]; - has_ntuple_intersect_tuple = 0; + has_ntuple_intersect_tuple = recheck_tuple_intersection = 0; JL_TRY { // This is kind of awful, but an inner call to instantiate_type // might fail due to a mismatched type parameter. The problem is @@ -1633,7 +2024,7 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, int e; - if (has_ntuple_intersect_tuple) { + if (has_ntuple_intersect_tuple || recheck_tuple_intersection) { for(e=0; e < eqc.n; e+=2) { jl_value_t *val = eqc.data[e+1]; if (jl_is_long(val)) diff --git a/src/julia.h b/src/julia.h index 1f4293d9180f4..1d0ca14615791 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1063,6 +1063,11 @@ JL_DLLEXPORT int jl_get_size(jl_value_t *val, size_t *pnt); #define jl_long_type jl_int32_type #endif +// Each tuple can exist in one of 4 Vararg states: +// NONE: no vararg Tuple{Int,Float32} +// INT: vararg with integer length Tuple{Int,Vararg{Float32,2}} +// BOUND: vararg with bound TypeVar length Tuple{Int,Vararg{Float32,N}} +// UNBOUND: vararg with unbound length Tuple{Int,Vararg{Float32}} typedef enum { JL_VARARG_NONE = 0, JL_VARARG_INT = 1, diff --git a/src/warnonce.cpp b/src/warnonce.cpp index 08af9f9bde5e8..66d1a94a657f7 100644 --- a/src/warnonce.cpp +++ b/src/warnonce.cpp @@ -4,12 +4,28 @@ #include #include +std::set > wo_intersect; std::set > wo_subtype; std::set > wo_morespecific; std::set > wo_typematch; extern "C" { +int warnonce_intersect(int var, uintptr_t ha, uintptr_t hb) +{ + std::vector v(3); + v[0] = (size_t) var; + v[1] = (size_t) ha; + v[2] = (size_t) hb; + std::set >::iterator it; + it = wo_intersect.find(v); + if (it == wo_intersect.end()) { + wo_intersect.insert(v); + return 1; + } + return 0; +} + int warnonce_subtype(int ta, int invariant, uintptr_t ha, uintptr_t hb) { std::vector v(4); From a4903e4d3c51b1ac2e850c289660b3c50681665d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 May 2015 05:35:16 -0500 Subject: [PATCH 09/32] Update typejoin for new Varargs This also turns debugging output back on in preparation for the final implementation The cmdlineargs test fails, but only due to the extra output generated. --- base/promotion.jl | 62 ++++++++++++++++++++++++++++++----------------- src/jltypes.c | 3 --- test/core.jl | 4 +++ 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/base/promotion.jl b/base/promotion.jl index af38a41118235..c2cc6028f85f0 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -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 @@ -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])) diff --git a/src/jltypes.c b/src/jltypes.c index 10b280844eb37..c056bddd48616 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3401,7 +3401,6 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) else newb = b; int retnew = jl_subtype_le_new(newa, newb, ta, invariant); - /* if (retnew != retold) { if (warnonce_subtype(ta, invariant, jl_object_id(a), jl_object_id(b))) { jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); @@ -3409,10 +3408,8 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) jl_(b); } } - */ JL_GC_POP(); return retnew; - //return retold; } JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) diff --git a/test/core.jl b/test/core.jl index 2943ad0cee935..80991d14cff6e 100644 --- a/test/core.jl +++ b/test/core.jl @@ -255,6 +255,10 @@ let @test typejoin(typejoin(b,c), a) == typejoin(typejoin(b,a), c) == Foo____{Int64} end +# typejoin with Vararg{T,N} +@test is(typejoin(Tuple{Vararg{Int,2}}, Tuple{Int,Int,Int}), Tuple{Int,Int,Vararg{Int}}) +@test is(typejoin(Tuple{Vararg{Int,2}}, Tuple{Vararg{Int}}), Tuple{Vararg{Int}}) + @test promote_type(Bool,Bottom) === Bool # ntuples From 302a951dda03b9d0972537a82e0e9e79ced85f0a Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 May 2015 12:38:26 -0500 Subject: [PATCH 10/32] Delete redundant debugging code --- src/Makefile | 2 +- src/jltypes.c | 1401 +++++-------------------------------------------- 2 files changed, 127 insertions(+), 1276 deletions(-) diff --git a/src/Makefile b/src/Makefile index 4784b0ff3160c..9589bf3bd5ed9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,7 +28,7 @@ SRCS := \ jltypes gf typemap ast builtins module interpreter \ alloc dlload sys init task array dump toplevel jl_uv jlapi signal-handling \ simplevector APInt-C runtime_intrinsics runtime_ccall \ - threadgroup threading stackwalk gc warnonce + threadgroup threading stackwalk gc ifeq ($(JULIACODEGEN),LLVM) SRCS += codegen disasm debuginfo llvm-simdloop llvm-gcroot diff --git a/src/jltypes.c b/src/jltypes.c index c056bddd48616..ad5da5284fc8c 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -472,7 +472,6 @@ static void extend(jl_value_t *var, jl_value_t *val, cenv_t *soln) static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); -static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); @@ -575,32 +574,6 @@ static size_t tuple_vararg_params(jl_svec_t *a, cenv_t *eqc, JL_VARARG_KIND *kin return data_vararg_params(jl_svec_data(a), jl_svec_len(a), eqc, kind, lenkind); } -// if returns with *bot!=0, then intersection is Union{} -static size_t tuple_intersect_size(jl_svec_t *a, jl_svec_t *b, int *bot) -{ - size_t al = jl_svec_len(a); - size_t bl = jl_svec_len(b); - *bot = 0; - if (al == bl) return al; - if (al > bl) return tuple_intersect_size(b, a, bot); - assert(al < bl); - if (jl_is_vararg_type(jl_svecref(b,bl-1))) { - if (al > 0 && jl_is_vararg_type(jl_svecref(a,al-1))) { - return bl; - } - else { - if (bl == al+1) - return al; - *bot=1; - return 0; - } - } - if (al > 0 && jl_is_vararg_type(jl_svecref(a,al-1))) - return bl; - *bot=1; - return 0; -} - jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) { if (n == NULL) { @@ -619,64 +592,6 @@ jl_datatype_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) return (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)jl_vararg_type, env, 2); } -static jl_value_t *intersect_tuple_old(jl_datatype_t *a, jl_datatype_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) -{ - jl_svec_t *ap = a->parameters, *bp = b->parameters; - size_t al = jl_svec_len(ap), bl = jl_svec_len(bp); - int bot=0; - size_t n = tuple_intersect_size(ap, bp, &bot); - if (bot) return (jl_value_t*)jl_bottom_type; - if (n == 0) return jl_typeof(jl_emptytuple); - jl_svec_t *tc = jl_alloc_svec(n); - jl_value_t *result = (jl_value_t*)tc; - jl_value_t *ce = NULL; - JL_GC_PUSH2(&tc, &ce); - size_t ai=0, bi=0, ci; - jl_value_t *ae=NULL, *be=NULL; - int aseq=0, bseq=0; - for(ci=0; ci < n; ci++) { - if (ai < al) { - ae = jl_svecref(ap,ai); - if (jl_is_vararg_type(ae)) { - aseq=1; - ae = jl_tparam0(ae); - } - ai++; - } - if (bi < bl) { - be = jl_svecref(bp,bi); - if (jl_is_vararg_type(be)) { - bseq=1; - be = jl_tparam0(be); - } - bi++; - } - assert(ae!=NULL && be!=NULL); - ce = jl_type_intersect_old(ae,be,penv,eqc,var); - if (ce == (jl_value_t*)jl_bottom_type) { - if (var!=invariant && aseq && bseq) { - // (X∩Y)==∅ → (X...)∩(Y...) == () - if (n == 1) { - JL_GC_POP(); - return (jl_value_t*)jl_typeof(jl_emptytuple); - } - jl_svec_set_len_unsafe(tc,jl_svec_len(tc)-1); - goto done_intersect_tuple; - } - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - if (aseq && bseq) - ce = (jl_value_t*)jl_wrap_vararg(ce, (jl_value_t*) NULL); - jl_svecset(tc, ci, ce); - } - done_intersect_tuple: - result = (jl_value_t*)jl_apply_tuple_type(tc); - JL_GC_POP(); - return result; -} - /* Tuple intersection Stage 1: compute lengths of each tuple @@ -827,84 +742,69 @@ static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, JL_GC_PUSH1(&p); jl_value_t *ti; size_t i; - if (a->name == jl_ntuple_typename) { - assert(jl_svec_len(p) == 2); - // NOTE: tuples are covariant, so NTuple element type is too - ti = jl_type_intersect(jl_tparam0(a),jl_tparam0(b),penv,eqc,invariant); - jl_svecset(p, 0, ti); - ti = jl_type_intersect(jl_tparam1(a),jl_tparam1(b),penv,eqc,var); - if (ti==(jl_value_t*)jl_bottom_type || - jl_svecref(p,0)==(jl_value_t*)jl_bottom_type) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; + for(i=0; i < jl_svec_len(p); i++) { + jl_value_t *ap = jl_svecref(a->parameters,i); + jl_value_t *bp = jl_svecref(b->parameters,i); + if (jl_is_typevar(ap)) { + if (var==invariant && jl_is_typevar(bp)) { + if (((jl_tvar_t*)ap)->bound != ((jl_tvar_t*)bp)->bound) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + if ((is_unspec(a) && is_bnd((jl_tvar_t*)bp,penv)) || + (is_bnd((jl_tvar_t*)ap,penv) && is_unspec(b))) { + // Foo{T} and Foo can never be equal since the former + // is always a subtype of the latter + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + } + ti = jl_type_intersect(ap,bp,penv,eqc,invariant); + if (bp == (jl_value_t*)jl_bottom_type && + !((jl_tvar_t*)ap)->bound) { + // "Union{}" as a type parameter + jl_svecset(p, i, ti); + continue; + } } - jl_svecset(p, 1, ti); - } - else { - for(i=0; i < jl_svec_len(p); i++) { - jl_value_t *ap = jl_svecref(a->parameters,i); - jl_value_t *bp = jl_svecref(b->parameters,i); - if (jl_is_typevar(ap)) { - if (var==invariant && jl_is_typevar(bp)) { - if (((jl_tvar_t*)ap)->bound != ((jl_tvar_t*)bp)->bound) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - if ((is_unspec(a) && is_bnd((jl_tvar_t*)bp,penv)) || - (is_bnd((jl_tvar_t*)ap,penv) && is_unspec(b))) { - // Foo{T} and Foo can never be equal since the former - // is always a subtype of the latter - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } + else if (jl_is_typevar(bp)) { + ti = jl_type_intersect(ap,bp,penv,eqc,invariant); + if (ap == (jl_value_t*)jl_bottom_type && + !((jl_tvar_t*)bp)->bound) { + // "Union{}" as a type parameter + jl_svecset(p, i, ti); + continue; + } + } + else { + int tva = jl_has_typevars_(ap,0); + int tvb = jl_has_typevars_(bp,0); + if (tva || tvb) { + if (jl_subtype_invariant(ap,bp,0) || + jl_subtype_invariant(bp,ap,0)) { + ti = jl_type_intersect(ap,bp,penv,eqc,invariant); } - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); - if (bp == (jl_value_t*)jl_bottom_type && - !((jl_tvar_t*)ap)->bound) { - // "Union{}" as a type parameter - jl_svecset(p, i, ti); - continue; + else { + ti = (jl_value_t*)jl_bottom_type; } } - else if (jl_is_typevar(bp)) { - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); - if (ap == (jl_value_t*)jl_bottom_type && - !((jl_tvar_t*)bp)->bound) { + else if (type_eqv_(ap,bp)) { + ti = ap; + if (ti == (jl_value_t*)jl_bottom_type) { // "Union{}" as a type parameter jl_svecset(p, i, ti); continue; } } else { - int tva = jl_has_typevars_(ap,0); - int tvb = jl_has_typevars_(bp,0); - if (tva || tvb) { - if (jl_subtype_invariant(ap,bp,0) || - jl_subtype_invariant(bp,ap,0)) { - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); - } - else { - ti = (jl_value_t*)jl_bottom_type; - } - } - else if (type_eqv_(ap,bp)) { - ti = ap; - if (ti == (jl_value_t*)jl_bottom_type) { - // "Union{}" as a type parameter - jl_svecset(p, i, ti); - continue; - } - } - else { - ti = (jl_value_t*)jl_bottom_type; - } + ti = (jl_value_t*)jl_bottom_type; } - if (ti == (jl_value_t*)jl_bottom_type) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - jl_svecset(p, i, ti); } + if (ti == (jl_value_t*)jl_bottom_type) { + JL_GC_POP(); + return (jl_value_t*)jl_bottom_type; + } + jl_svecset(p, i, ti); } if (a->name->primary != NULL) { jl_value_t *res = (jl_value_t*)jl_apply_type(a->name->primary, p); @@ -1126,7 +1026,7 @@ static int has_ntuple_intersect_tuple = 0; static jl_datatype_t *inst_tupletype_unchecked_uncached(jl_svec_t *p); -static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, +static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { if (jl_is_typector(a)) @@ -1163,99 +1063,12 @@ static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, if (b == (jl_value_t*)jl_any_type || b == jl_ANY_flag) return a; // tuple if (jl_is_tuple_type(a)) { - size_t alen = jl_nparams(a); - jl_value_t *temp=NULL; - JL_GC_PUSH2(&b, &temp); - if (jl_is_ntuple_type(b)) { - has_ntuple_intersect_tuple = 1; - jl_value_t *lenvar = jl_tparam0(b); - jl_value_t *elty = jl_tparam1(b); - int i; - for(i=0; i < eqc->n; i+=2) { - if (eqc->data[i] == lenvar) { - jl_value_t *v = eqc->data[i+1]; - // N is already known in NTuple{N,...} - if (jl_get_size(v, &alen)) break; - } - } - b = (jl_value_t*)jl_tupletype_fill(alen, elty); - if (i >= eqc->n) { - // don't know N yet, so add a constraint for it based on - // the length of the other tuple - if (jl_is_va_tuple((jl_datatype_t*)a)) { - temp = (jl_value_t*)jl_svec_copy(((jl_datatype_t*)b)->parameters); - jl_svecset(temp, alen-1, jl_wrap_vararg(elty, (jl_value_t*)NULL)); - b = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)temp); - if (jl_is_typevar(lenvar)) { - // store "at least N" constraints in the <: env - for(i=0; i < penv->n; i+=2) { - if (penv->data[i] == lenvar) { - jl_value_t *v = penv->data[i+1]; - size_t vallen; - if (jl_get_size(v, &vallen)) { - int bot = 0; - long met = meet_tuple_lengths(~vallen, ~(alen-1), &bot); - if (bot) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - penv->data[i+1] = jl_box_long(~met); - break; - } - } - } - if (i >= penv->n) { - temp = jl_box_long(alen-1); - extend(lenvar, temp, penv); - } - } - } - else { - if (jl_is_typevar(lenvar)) { - // store "== N" constraints in the == env - temp = jl_box_long(alen); - if (intersect_typevar((jl_tvar_t*)lenvar,temp,penv,eqc, - invariant) == - (jl_value_t*)jl_bottom_type) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - } - } - } - } - if (jl_is_type_type(b)) { - jl_value_t *btp0v = jl_tparam0(b); - if (jl_is_typevar(btp0v)) { - jl_tvar_t *btp0 = (jl_tvar_t*)btp0v; - if (jl_subtype(btp0->ub, a, 1)) { - JL_GC_POP(); - return b; - } - } - } if (jl_is_tuple_type(b)) { - a = intersect_tuple_old((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); - JL_GC_POP(); - return a; + return intersect_tuple_new((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); } - JL_GC_POP(); } if (jl_is_tuple_type(b)) { - return jl_type_intersect_old(b, a, penv,eqc,var); - } - if (jl_is_ntuple_type(a)) { - if (jl_is_ntuple_type(b)) { - jl_value_t *tag = intersect_tag((jl_datatype_t*)a, - (jl_datatype_t*)b, penv, eqc, var); - // The length parameter must be a TypeVar - return tag == jl_bottom_type ? jl_typeof(jl_emptytuple) : tag; - } - else if (jl_is_type_type(b)) { - jl_value_t *temp = a; - a = b; - b = temp; - } + return jl_type_intersect_new(b, a, penv,eqc,var); } // tag if (!jl_is_datatype(a) || !jl_is_datatype(b)) @@ -1330,7 +1143,7 @@ static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); else env = (jl_value_t*)sub->super; - super = (jl_datatype_t*)jl_type_intersect_old((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); + super = (jl_datatype_t*)jl_type_intersect_new_((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); if ((jl_value_t*)super == jl_bottom_type) { JL_GC_POP(); @@ -1399,7 +1212,7 @@ static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, jl_value_t *elt = jl_svecref(sub->parameters, i); for(int e=0; e < jl_svec_len(env); e+=2) { if (jl_svecref(env, e) == tp) { - elt = jl_type_intersect_old(elt, jl_svecref(env, e+1), + elt = jl_type_intersect_new_(elt, jl_svecref(env, e+1), penv, eqc, invariant); // note: elt might be Union() if "Union()" was the type parameter break; @@ -1412,256 +1225,38 @@ static jl_value_t *jl_type_intersect_old(jl_value_t *a, jl_value_t *b, return result; } -static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) +static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { - if (jl_is_typector(a)) - a = (jl_value_t*)((jl_typector_t*)a)->body; - if (jl_is_typector(b)) - b = (jl_value_t*)((jl_typector_t*)b)->body; - if (a == b) return a; - if (jl_is_typevar(a)) { - if (var == covariant && !((jl_tvar_t*)a)->bound) - a = ((jl_tvar_t*)a)->ub; - else if (a != jl_ANY_flag) - return intersect_typevar((jl_tvar_t*)a, b, penv, eqc, var); - } - if (jl_is_typevar(b)) { - if (var == covariant && !((jl_tvar_t*)b)->bound) - b = ((jl_tvar_t*)b)->ub; - else if (b != jl_ANY_flag) - return intersect_typevar((jl_tvar_t*)b, a, penv, eqc, var); - } - if (a == (jl_value_t*)jl_bottom_type || b == (jl_value_t*)jl_bottom_type) - return (jl_value_t*)jl_bottom_type; - if (!jl_has_typevars(a) && !jl_has_typevars(b)) { - if (jl_subtype(a, b, 0)) - return a; - if (jl_subtype(b, a, 0)) - return b; - } - // union - if (jl_is_uniontype(a)) - return intersect_union((jl_uniontype_t*)a, b, penv, eqc, var); - if (jl_is_uniontype(b)) - return intersect_union((jl_uniontype_t*)b, a, penv, eqc, var); - if (a == (jl_value_t*)jl_any_type || a == jl_ANY_flag) return b; - if (b == (jl_value_t*)jl_any_type || b == jl_ANY_flag) return a; - // tuple - if (jl_is_tuple_type(a)) { - if (jl_is_tuple_type(b)) { - return intersect_tuple_new((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); - } - } - if (jl_is_tuple_type(b)) { - return jl_type_intersect_new(b, a, penv,eqc,var); - } - // tag - if (!jl_is_datatype(a) || !jl_is_datatype(b)) - return (jl_value_t*)jl_bottom_type; - jl_datatype_t *tta = (jl_datatype_t*)a; - jl_datatype_t *ttb = (jl_datatype_t*)b; - if (tta->name == ttb->name) - return (jl_value_t*)intersect_tag(tta, ttb, penv, eqc, var); - jl_datatype_t *super = NULL; - jl_datatype_t *sub = NULL; - jl_value_t *env = NULL; - jl_value_t *p = NULL; - jl_value_t *temp3 = NULL; - JL_GC_PUSH5(&super, &sub, &env, &p, &temp3); - while (tta != jl_any_type) { - if (tta->name == ttb->name) { - sub = (jl_datatype_t*)a; - super = (jl_datatype_t*)b; - break; - } - tta = tta->super; - } - if (sub == NULL) { - tta = (jl_datatype_t*)a; - while (ttb != jl_any_type) { - if (tta->name == ttb->name) { - sub = (jl_datatype_t*)b; - super = (jl_datatype_t*)a; - break; - } - ttb = ttb->super; - } - if (sub == NULL) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - } - - if (sub->super == jl_type_type && jl_is_type_type((jl_value_t*)super)) { - // subtypes of Type like DataType do not constrain the type - // parameter, and yet contain Type instances with a more specific - // parameter (like Type{Int}). This is a special case. - jl_value_t *tp0 = jl_tparam0(super); - if (jl_is_typevar(tp0) || (jl_value_t*)sub == jl_typeof(tp0)) { - JL_GC_POP(); - return (jl_value_t*)super; - } - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - - /* - issue #6387 - Say we have + jl_value_t *newa=NULL, *newb=NULL, *retnew=NULL; + JL_GC_PUSH3(&newa, &newb, &retnew); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + retnew = jl_type_intersect_new(newa, newb, penv, eqc, var); + JL_GC_POP(); + return retnew; +} - type DateRange{C} <: Range{Date{C}}; end +static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) +{ + return jl_type_intersect_new_(a, b, penv, eqc, var); +} - and +static int extensionally_same_type(jl_value_t *a, jl_value_t *b); - vcat{T}(r::Range{T}) = ... - - Then inferring vcat(::DateRange) concludes that T==Date{C}, but it should - conclude T<:Date{C}. The core problem seems to be that in moving from a - type to its supertype, we drop the environment that binds C --- we - forget that C is a variable in Range{Date{C}}. For now I work around this - by rewriting this type to Range{_<:Date{C}}, effectively tagging type - parameters that are variable due to the extra (dropped) environment. - */ - if (var == covariant && - sub == (jl_datatype_t*)sub->name->primary && - jl_has_typevars_from((jl_value_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters)) - env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); - else - env = (jl_value_t*)sub->super; - super = (jl_datatype_t*)jl_type_intersect_new_((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); - - if ((jl_value_t*)super == jl_bottom_type) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - - // super needs to be instantiated so the matching below finds actual types - // and doesn't fail due to the presence of extra typevars. - super = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)super, eqc->data, eqc->n/2); - - size_t n = jl_svec_len(sub->parameters); - - assert(sub->name->primary != NULL); - jl_value_t *tc = sub->name->primary; - jl_svec_t *tc_params = ((jl_datatype_t*)tc)->parameters; - // compute what constraints the supertype imposes on the subtype - jl_svec_t *subs_sup_params = - ((jl_datatype_t*)((jl_datatype_t*)tc)->super)->parameters; - // match the intersected supertype against the pattern this subtype - // uses to instantiate its supertype. this tells us what subtype parameter - // values are implied by the intersected supertype, or that the - // intersected supertype cannot come from this subtype (in which case - // our final answer is Union{}). - size_t i; - // hack: we need type_match to find assignments for all typevars - int prev_mim = match_intersection_mode; - match_intersection_mode = 1; - // TODO get rid of these intermediate tuple types - p = (jl_value_t*)inst_tupletype_unchecked_uncached(super->parameters); - temp3 = (jl_value_t*)inst_tupletype_unchecked_uncached(subs_sup_params); - env = jl_type_match(p, temp3); - int sub_needs_parameters = 0; - if (env == jl_false) { - env = jl_type_match(temp3, p); - } - else { - // this means it needs to be possible to instantiate the subtype - // such that the supertype gets the matching parameters we just - // determined. - sub_needs_parameters = 1; - } - match_intersection_mode = prev_mim; - if (env == jl_false) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - if (sub_needs_parameters) { - for(int e=0; e < jl_svec_len(env); e+=2) { - jl_value_t *tp = jl_svecref(env, e); - // make sure each needed parameter is actually set by the subtype - size_t j; - for(j=0; j < n; j++) { - if (tp == jl_svecref(tc_params, j)) - break; - } - if (j >= n) { - JL_GC_POP(); - return (jl_value_t*)jl_bottom_type; - } - } - } - - p = (jl_value_t*)jl_alloc_svec(n); - for(i=0; i < n; i++) { - jl_value_t *tp = jl_svecref(tc_params, i); - jl_value_t *elt = jl_svecref(sub->parameters, i); - for(int e=0; e < jl_svec_len(env); e+=2) { - if (jl_svecref(env, e) == tp) { - elt = jl_type_intersect_new_(elt, jl_svecref(env, e+1), - penv, eqc, invariant); - // note: elt might be Union{} if "Union{}" was the type parameter - break; - } - } - jl_svecset(p, i, elt); - } - jl_value_t *result = (jl_value_t*)jl_apply_type(tc, (jl_svec_t*)p); - JL_GC_POP(); - return result; -} - -static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) -{ - jl_value_t *newa=NULL, *newb=NULL, *retnew=NULL; - JL_GC_PUSH3(&newa, &newb, &retnew); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - retnew = jl_type_intersect_new(newa, newb, penv, eqc, var); - JL_GC_POP(); - return retnew; -} - -int warnonce_intersect(int var, uintptr_t ha, uintptr_t hb); - -static int extensionally_same_type(jl_value_t *a, jl_value_t *b); - -static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) -{ - int np = penv->n, nc = eqc->n; - jl_value_t *retold = NULL, *retnew = NULL; - JL_GC_PUSH2(&retold, &retnew); - retold = jl_type_intersect_old(a, b, penv, eqc, var); - penv->n = np; - eqc->n = nc; - retnew = jl_type_intersect_new_(a, b, penv, eqc, var); - if (!extensionally_same_type(retold, retnew)) { //(!jl_types_equal(retnew, retold)) { - if (warnonce_intersect(var, jl_object_id(a), jl_object_id(b))) { - jl_printf(JL_STDOUT, "Disagree jl_type_intersect (var = %d):\n", var); - jl_(a); - jl_(b); - jl_(retold); - jl_(retnew); - } - } - JL_GC_POP(); - return retnew; -} - -JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) -{ - jl_svec_t *env = jl_emptysvec; - JL_GC_PUSH1(&env); - jl_value_t *ti = jl_type_intersection_matching(a, b, &env, jl_emptysvec); - JL_GC_POP(); - return ti; -} +JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) +{ + jl_svec_t *env = jl_emptysvec; + JL_GC_PUSH1(&env); + jl_value_t *ti = jl_type_intersection_matching(a, b, &env, jl_emptysvec); + JL_GC_POP(); + return ti; +} /* constraint satisfaction algorithm: @@ -2932,39 +2527,8 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // subtype comparison static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant); -static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant); static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant); -static int jl_tuple_subtype_old(jl_value_t **child, size_t cl, - jl_datatype_t *pdt, int ta, int invariant) -{ - size_t pl = jl_nparams(pdt); - jl_value_t **parent = jl_svec_data(pdt->parameters); - size_t ci=0, pi=0; - while (1) { - int cseq = !ta && (ci= cl) - return pi>=pl || (pseq && !invariant); - if (pi >= pl) - return 0; - jl_value_t *ce = child[ci]; - jl_value_t *pe = parent[pi]; - if (cseq) ce = jl_tparam0(ce); - if (pseq) pe = jl_tparam0(pe); - - if (!jl_subtype_le_old(ce, pe, ta, invariant)) - return 0; - - if (cseq && pseq) return 1; - if (!cseq) ci++; - if (!pseq) pi++; - } - return 0; -} - static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, jl_datatype_t *pdt, int ta, int invariant) { @@ -3047,20 +2611,12 @@ static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, static int jl_tuple_subtype_(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta, int invariant) { - int retold = jl_tuple_subtype_old(child, cl, pdt, ta, invariant); - if (!needs_translation_data(child, cl) && !needs_translation((jl_value_t*)pdt)) - return retold; jl_svec_t *newchilds=NULL; jl_datatype_t *newpdt=NULL; JL_GC_PUSH2(&newchilds, &newpdt); newchilds = ntuple_translate_data(child, cl); newpdt = (jl_datatype_t*) ntuple_translate((jl_value_t*)pdt); int retnew = jl_tuple_subtype_new(jl_svec_data(newchilds), cl, newpdt, ta, invariant); - if (retnew != retold) { - jl_printf(JL_STDOUT, "Disagree jl_tuple_subtype_ with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); - jl_(newchilds); - jl_(newpdt); - } JL_GC_POP(); return retnew; } @@ -3070,27 +2626,13 @@ int jl_tuple_subtype(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta) return jl_tuple_subtype_(child, cl, pdt, ta, 0); } -static int tuple_all_subtype(jl_datatype_t *t, jl_value_t *super, int ta, int invariant) -{ - size_t ci; - for(ci=0; ci < jl_nparams(t); ci++) { - jl_value_t *ce = jl_tparam(t,ci); - if (!ta && jl_is_vararg_type(ce)) - ce = jl_tparam0(ce); - if (!jl_subtype_le_old(ce, super, ta, invariant)) - return 0; - } - return 1; -} - -// ta specifies whether typeof() should be implicitly applied to a. -static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant) +int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) { if (!ta&&jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; if (ta) { if (jl_is_type_type(b)) { - return jl_is_type(a) && jl_subtype_le_old(a, jl_tparam0(b), 0, 1); + return jl_is_type(a) && jl_subtype_le_new_(a, jl_tparam0(b), 0, 1); } } else if (a == b) { @@ -3103,10 +2645,10 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant jl_svec_t *ap = ((jl_uniontype_t*)a)->types; size_t l_ap = jl_svec_len(ap); if (invariant && !jl_is_typevar(b)) { - return jl_subtype_le_old(a,b,0,0) && jl_subtype_le_old(b,a,0,0); + return jl_subtype_le_new(a,b,0,0) && jl_subtype_le_new(b,a,0,0); } for(i=0; i < l_ap; i++) { - if (!jl_subtype_le_old(jl_svecref(ap,i), b, 0, invariant)) + if (!jl_subtype_le_new_(jl_svecref(ap,i), b, 0, invariant)) return 0; } return 1; @@ -3117,14 +2659,14 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant if (jl_is_typevar(tp0a)) { jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; - if (jl_subtype_le_old(ub, b, 1, 0) && - !jl_subtype_le_old((jl_value_t*)jl_any_type, ub, 0, 0)) { - if (jl_subtype_le_old(lb, b, 1, 0)) + if (jl_subtype_le_new_(ub, b, 1, 0) && + !jl_subtype_le_new_((jl_value_t*)jl_any_type, ub, 0, 0)) { + if (jl_subtype_le_new_(lb, b, 1, 0)) return 1; } } else { - if (jl_subtype_le_old(tp0a, b, 1, 0)) + if (jl_subtype_le_new_(tp0a, b, 1, 0)) return 1; } } @@ -3134,7 +2676,7 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_subtype_le_old(a, jl_svecref(bp,i), ta, invariant)) + if (jl_subtype_le_new_(a, jl_svecref(bp,i), ta, invariant)) return 1; } if (!ta && jl_is_typevar(a) && ((jl_tvar_t*)a)->ub == jl_bottom_type) @@ -3145,21 +2687,8 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant if (ta) a = (jl_value_t*)jl_typeof(a); if (jl_is_tuple_type(a)) { - if (jl_is_datatype(b)) { - if (((jl_datatype_t*)b)->name == jl_ntuple_typename) { - jl_value_t *tp = jl_tparam1(b); - if (tuple_all_subtype((jl_datatype_t*)a, tp, 0, invariant)) { - if (invariant) { - return (jl_datatype_t*)b != jl_ntuple_type || - jl_subtype_le_old((jl_value_t*)jl_anytuple_type, a, 0, 1); - } - return 1; - } - return 0; - } - } if (jl_is_tuple_type(b)) { - return jl_tuple_subtype_old(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), + return jl_tuple_subtype_new(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), (jl_datatype_t*)b, 0, invariant); } } @@ -3167,18 +2696,6 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant if (a == b) return 1; if (!invariant && (jl_datatype_t*)b == jl_any_type) return 1; - if (jl_is_tuple_type(b)) { - if (jl_is_datatype(a) && - ((jl_datatype_t*)a)->name == jl_ntuple_typename) { - // only ((T>:S)...,) can be a supertype of NTuple{N,S} - jl_value_t *ntp = jl_tparam1(a); - if (jl_nparams(b) == 1 && jl_is_va_tuple((jl_datatype_t*)b)) { - return jl_subtype_le_old(ntp, jl_tparam0(jl_tparam0(b)), 0, invariant); - } - } - return 0; - } - if (jl_is_datatype(a) && jl_is_datatype(b)) { if ((jl_datatype_t*)a == jl_any_type) return 0; jl_datatype_t *tta = (jl_datatype_t*)a; @@ -3186,12 +2703,8 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant int super=0; while (tta != (jl_datatype_t*)jl_any_type) { if (tta->name == ttb->name) { - if (tta->name == jl_ntuple_typename) { - // NTuple must be covariant - return jl_subtype_le_old(jl_tparam(tta,1), jl_tparam(ttb,1), 0, invariant); - } if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_subtype_le_old(a, jl_tparam0(b), 0, 1)) + if (jl_subtype_le_new_(a, jl_tparam0(b), 0, 1)) return 1; } assert(jl_nparams(tta) == jl_nparams(ttb)); @@ -3205,7 +2718,7 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant return 0; } } - if (!jl_subtype_le_old(apara, bpara, 0, 1)) + if (!jl_subtype_le_new_(apara, bpara, 0, 1)) return 0; } return 1; @@ -3222,200 +2735,51 @@ static int jl_subtype_le_old(jl_value_t *a, jl_value_t *b, int ta, int invariant if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); } if (invariant) { return 0; } - return jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + return jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); } if (jl_is_typevar(b)) { - return jl_subtype_le_old(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_old((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + return jl_subtype_le_new_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); } if ((jl_datatype_t*)a == jl_any_type) return 0; return jl_egal(a, b); } -int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) +static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant) { - if (!ta&&jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; - if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; - if (ta) { - if (jl_is_type_type(b)) { - return jl_is_type(a) && jl_subtype_le_new_(a, jl_tparam0(b), 0, 1); - } - } - else if (a == b) { - // Union() <: Union() - return 1; - } - - size_t i; - if (!ta && jl_is_uniontype(a)) { - jl_svec_t *ap = ((jl_uniontype_t*)a)->types; - size_t l_ap = jl_svec_len(ap); - if (invariant && !jl_is_typevar(b)) { - return jl_subtype_le_new(a,b,0,0) && jl_subtype_le_new(b,a,0,0); - } - for(i=0; i < l_ap; i++) { - if (!jl_subtype_le_new_(jl_svecref(ap,i), b, 0, invariant)) - return 0; - } - return 1; - } + jl_value_t *newa=NULL, *newb=NULL; + JL_GC_PUSH2(&newa, &newb); + if (needs_translation(a)) + newa = ntuple_translate(a); + else + newa = a; + if (needs_translation(b)) + newb = ntuple_translate(b); + else + newb = b; + int result = jl_subtype_le_new(newa, newb, ta, invariant); + JL_GC_POP(); + return result; +} - if (!ta && jl_is_type_type(a) && !invariant) { - jl_value_t *tp0a = jl_tparam0(a); - if (jl_is_typevar(tp0a)) { - jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; - jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; - if (jl_subtype_le_new_(ub, b, 1, 0) && - !jl_subtype_le_new_((jl_value_t*)jl_any_type, ub, 0, 0)) { - if (jl_subtype_le_new_(lb, b, 1, 0)) - return 1; - } - } - else { - if (jl_subtype_le_new_(tp0a, b, 1, 0)) - return 1; - } - } +static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) +{ + return jl_subtype_le_new_(a, b, ta, invariant); +} - if (jl_is_uniontype(b)) { - if (invariant) - return 0; - jl_svec_t *bp = ((jl_uniontype_t*)b)->types; - for(i=0; i < jl_svec_len(bp); i++) { - if (jl_subtype_le_new_(a, jl_svecref(bp,i), ta, invariant)) - return 1; - } - return 0; - } - - if (ta) a = (jl_value_t*)jl_typeof(a); - - if (jl_is_tuple_type(a)) { - if (jl_is_tuple_type(b)) { - return jl_tuple_subtype_new(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), - (jl_datatype_t*)b, 0, invariant); - } - } - - if (a == b) return 1; - if (!invariant && (jl_datatype_t*)b == jl_any_type) return 1; - - if (jl_is_datatype(a) && jl_is_datatype(b)) { - if ((jl_datatype_t*)a == jl_any_type) return 0; - jl_datatype_t *tta = (jl_datatype_t*)a; - jl_datatype_t *ttb = (jl_datatype_t*)b; - int super=0; - while (tta != (jl_datatype_t*)jl_any_type) { - if (tta->name == ttb->name) { - if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_subtype_le_new_(a, jl_tparam0(b), 0, 1)) - return 1; - } - if (invariant && ttb == (jl_datatype_t*)ttb->name->primary) - return 0; - assert(jl_nparams(tta) == jl_nparams(ttb)); - size_t l = jl_nparams(tta); - for(i=0; i < l; i++) { - jl_value_t *apara = jl_tparam(tta,i); - jl_value_t *bpara = jl_tparam(ttb,i); - if (invariant && jl_is_typevar(bpara) && - !((jl_tvar_t*)bpara)->bound) { - if (!jl_is_typevar(apara)) - return 0; - } - if (!jl_subtype_le_new_(apara, bpara, 0, 1)) - return 0; - } - return 1; - } - else if (invariant) { - return 0; - } - tta = tta->super; super = 1; - } - assert(!invariant); - return 0; - } - - if (jl_is_typevar(a)) { - if (jl_is_typevar(b)) { - return - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, - (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, - (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); - } - if (invariant) { - return 0; - } - return jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); - } - if (jl_is_typevar(b)) { - return jl_subtype_le_new_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); - } - if ((jl_datatype_t*)a == jl_any_type) return 0; - - return jl_egal(a, b); -} - -static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant) -{ - jl_value_t *newa=NULL, *newb=NULL; - JL_GC_PUSH2(&newa, &newb); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - int result = jl_subtype_le_new(newa, newb, ta, invariant); - JL_GC_POP(); - return result; -} - -int warnonce_subtype(int ta, int invariant, uintptr_t a, uintptr_t b); - -static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) -{ - int retold = jl_subtype_le_old(a, b, ta, invariant); - jl_value_t *newa=NULL, *newb=NULL; - JL_GC_PUSH2(&newa, &newb); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - int retnew = jl_subtype_le_new(newa, newb, ta, invariant); - if (retnew != retold) { - if (warnonce_subtype(ta, invariant, jl_object_id(a), jl_object_id(b))) { - jl_printf(JL_STDOUT, "Disagree jl_subtype_le with retnew = %d, retold = %d (ta = %d, invariant = %d):\n", retnew, retold, ta, invariant); - jl_(a); - jl_(b); - } - } - JL_GC_POP(); - return retnew; -} - -JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) -{ - return jl_subtype_le(a, b, ta, 0); -} +JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) +{ + return jl_subtype_le(a, b, ta, 0); +} int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta) { @@ -3427,60 +2791,6 @@ int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta) static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant); static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant); -static int jl_tuple_morespecific_old(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) -{ - size_t cl = jl_nparams(cdt); - jl_value_t **child = jl_svec_data(cdt->parameters); - size_t pl = jl_nparams(pdt); - jl_value_t **parent = jl_svec_data(pdt->parameters); - size_t ci=0, pi=0; - int some_morespecific = 0; - while (1) { - int cseq = (ci= cl) - return 1; - if (pi >= pl) - return some_morespecific; - jl_value_t *ce = child[ci]; - jl_value_t *pe = parent[pi]; - if (cseq) ce = jl_tparam0(ce); - if (pseq) pe = jl_tparam0(pe); - - if (!jl_type_morespecific_(ce, pe, invariant)) { - if (type_eqv_(ce,pe)) { - if (ci==cl-1 && pi==pl-1) { - if (!cseq && pseq) - return 1; - if (!some_morespecific) - return 0; - } - } - else { - return 0; - } - } - - if (some_morespecific && cseq && !pseq) - return 1; - - // at this point we know one element is strictly more specific - if (!(jl_types_equal(ce,pe) || - (jl_is_typevar(pe) && - jl_types_equal(ce,((jl_tvar_t*)pe)->ub)))) { - some_morespecific = 1; - // here go into a different mode where we return 1 - // if the only reason the child is not more specific is - // argument count (i.e. ...) - } - - if (cseq && pseq) return 1; - if (!cseq) ci++; - if (!pseq) pi++; - } - return 0; -} - static int jl_tuple_morespecific_new(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) { size_t clenr = jl_nparams(cdt); @@ -3548,19 +2858,6 @@ static int jl_tuple_morespecific_new(jl_datatype_t *cdt, jl_datatype_t *pdt, int return 0; } -static int tuple_all_morespecific(jl_datatype_t *t, jl_value_t *super, int invariant) -{ - size_t ci; - for(ci=0; ci < jl_nparams(t); ci++) { - jl_value_t *ce = jl_tparam(t,ci); - if (jl_is_vararg_type(ce)) - ce = jl_tparam0(ce); - if (!jl_type_morespecific_(ce, super, invariant)) - return 0; - } - return 1; -} - static int partially_morespecific(jl_value_t *a, jl_value_t *b, int invariant) { if (jl_is_uniontype(b)) { @@ -3578,149 +2875,6 @@ static int partially_morespecific(jl_value_t *a, jl_value_t *b, int invariant) return jl_type_morespecific_(a, b, invariant); } -static int jl_type_morespecific_old(jl_value_t *a, jl_value_t *b, int invariant) -{ - if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; - if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; - if (a == b) { - // TODO; maybe change this - return 1; - } - size_t i; - if (jl_is_tuple_type(a)) { - if (jl_is_datatype(b) && - ((jl_datatype_t*)b)->name == jl_ntuple_typename) { - return tuple_all_morespecific((jl_datatype_t*)a, jl_tparam(b,1), invariant); - } - if (jl_is_tuple_type(b)) { - return jl_tuple_morespecific_old((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); - } - } - - if (jl_is_uniontype(a)) { - jl_svec_t *ap = ((jl_uniontype_t*)a)->types; - size_t l_ap = jl_svec_len(ap); - if (jl_subtype_le(b, a, 0, 0)) { - // fixes issue #4413 - if (!jl_subtype_le(a, b, 0, invariant)) - return 0; - } - else if (jl_subtype_le(a, b, 0, invariant)) { - return 1; - } - // Union a is more specific than b if some element of a is - // more specific than b, and b is not more specific than any - // element of a. - for(i=0; i < l_ap; i++) { - jl_value_t *ai = jl_svecref(ap,i); - if (partially_morespecific(ai, b, invariant) && - !jl_type_morespecific_old(b, ai, invariant)) { - if (partially_morespecific(b, a, invariant)) - return 0; - return 1; - } - } - return 0; - } - - if (jl_is_type_type(a) && !invariant) { - jl_value_t *tp0a = jl_tparam0(a); - if (jl_is_typevar(tp0a)) { - jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; - if (jl_subtype_le(ub, b, 1, 0) && - !jl_subtype_le((jl_value_t*)jl_any_type, ub, 0, 0)) { - return 1; - } - } - else { - if (jl_subtype_le(tp0a, b, 1, 0)) - return 1; - } - } - - if (jl_is_uniontype(b)) { - if (invariant) - return 0; - jl_svec_t *bp = ((jl_uniontype_t*)b)->types; - for(i=0; i < jl_svec_len(bp); i++) { - if (jl_type_morespecific_old(a, jl_svecref(bp,i), invariant)) - return 1; - } - return 0; - } - - if (!invariant && (jl_datatype_t*)b == jl_any_type) return 1; - - if (jl_is_tuple_type(b)) { - if (jl_is_datatype(a) && - ((jl_datatype_t*)a)->name == jl_ntuple_typename) { - // only ((T>:S)...,) can be a supertype of NTuple[N,S] - jl_value_t *ntp = jl_tparam(a, 1); - if (jl_nparams(b) == 1 && jl_is_va_tuple((jl_datatype_t*)b)) { - return jl_type_morespecific_old(ntp, jl_tparam0(jl_tparam0(b)), invariant); - } - } - if (!jl_is_typevar(a)) - return 0; - } - - if (jl_is_datatype(a) && jl_is_datatype(b)) { - if ((jl_datatype_t*)a == jl_any_type) return 0; - jl_datatype_t *tta = (jl_datatype_t*)a; - jl_datatype_t *ttb = (jl_datatype_t*)b; - int super=0; - while (tta != (jl_datatype_t*)jl_any_type) { - if (tta->name == ttb->name) { - if (super) { - if (tta->name != jl_type_type->name) - return 1; - } - if (tta->name == jl_ntuple_typename) { - // NTuple must be covariant - return jl_type_morespecific_old(jl_tparam(tta,1), jl_tparam(ttb,1), invariant); - } - if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_type_morespecific_old(a, jl_tparam0(b), 1)) - return 1; - } - assert(jl_nparams(tta) == jl_nparams(ttb)); - for(i=0; i < jl_nparams(tta); i++) { - jl_value_t *apara = jl_tparam(tta,i); - jl_value_t *bpara = jl_tparam(ttb,i); - if (!jl_type_morespecific_old(apara, bpara, 1)) - return 0; - } - return 1; - } - else if (invariant) { - return 0; - } - tta = tta->super; super = 1; - } - return 0; - } - - if (jl_is_typevar(a)) { - if (jl_is_typevar(b)) { - return - jl_type_morespecific_old((jl_value_t*)((jl_tvar_t*)a)->ub, - (jl_value_t*)((jl_tvar_t*)b)->ub, 0) && - jl_type_morespecific_old((jl_value_t*)((jl_tvar_t*)b)->lb, - (jl_value_t*)((jl_tvar_t*)a)->lb, 0); - } - if (invariant) - return 0; - return jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); - } - if (jl_is_typevar(b)) { - return jl_subtype_le(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); - } - if ((jl_datatype_t*)a == jl_any_type) return 0; - - return 0; -} - static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) { if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; @@ -3860,20 +3014,9 @@ static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant return retnew; } -int warnonce_morespecific(int invariant, uintptr_t a, uintptr_t b); - static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) { - int retold = jl_type_morespecific_old(a, b, invariant); - int retnew = jl_type_morespecific_new_(a, b, invariant); - if (retnew != retold) { - if (warnonce_morespecific(invariant, jl_object_id(a), jl_object_id(b))) { - jl_printf(JL_STDOUT, "Disagree jl_type_morespecific_ with retnew = %d, retold = %d (invariant = %d):\n", retnew, retold, invariant); - jl_(a); - jl_(b); - } - } - return retnew; + return jl_type_morespecific_new_(a, b, invariant); } JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b) @@ -3888,64 +3031,8 @@ int type_match_invariance_mask = 1; static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); -static jl_value_t *type_match_old(jl_value_t *child, jl_value_t *parent, - cenv_t *env, int morespecific, int invariant); static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); -static jl_value_t *tuple_match_old(jl_datatype_t *child, jl_datatype_t *parent, - cenv_t *env, int morespecific, int invariant) -{ - size_t ci=0, pi=0; - size_t cl = jl_nparams(child); - size_t pl = jl_nparams(parent); - int mode = 0; - invariant = invariant & type_match_invariance_mask; - while(1) { - int cseq = (ci= cl) - return (mode || pi>=pl || (pseq && !invariant)) ? jl_true : jl_false; - if (pi >= pl) - return mode ? jl_true : jl_false; - jl_value_t *ce = jl_tparam(child,ci); - jl_value_t *pe = jl_tparam(parent,pi); - if (cseq) ce = jl_tparam0(ce); - if (pseq) pe = jl_tparam0(pe); - - int n = env->n; - if (type_match_old(ce, pe, env, morespecific, invariant) == jl_false) { - env->n = n; - if (jl_types_equal_generic(ce,pe,1)) { - if (ci==cl-1 && pi==pl-1 && !cseq && pseq) { - return jl_true; - } - if (!mode) return jl_false; - } - else { - return jl_false; - } - } - - if (mode && cseq && !pseq) - return jl_true; - - if (morespecific) { - if (!(jl_types_equal_generic(ce,pe,1) || - (jl_is_typevar(pe) && - jl_types_equal(ce,((jl_tvar_t*)pe)->ub)))) { - mode = 1; - } - } - - if (cseq && pseq) return jl_true; - if (!cseq) ci++; - if (!pseq) pi++; - } - return jl_false; -} - static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, cenv_t *env, int morespecific, int invariant) { @@ -4026,229 +3113,6 @@ static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, return jl_false; } -static jl_value_t *type_match_old(jl_value_t *child, jl_value_t *parent, - cenv_t *env, int morespecific, int invariant) -{ - jl_value_t *tmp, *tmp2; - invariant = invariant & type_match_invariance_mask; - if (jl_is_typector(child)) - child = (jl_value_t*)((jl_typector_t*)child)->body; - if (jl_is_typector(parent)) - parent = (jl_value_t*)((jl_typector_t*)parent)->body; - size_t i, j; - if (match_intersection_mode && jl_is_typevar(child) && !jl_is_typevar(parent)) { - tmp = child; - child = parent; - parent = tmp; - } - if (jl_is_typevar(parent)) { - // make sure type is within this typevar's bounds - if (morespecific) { - if (!jl_type_morespecific_(child, parent, 0)) - return jl_false; - } - else { - if (!jl_subtype_le(child, parent, 0, 0)) - return jl_false; - } - if (!match_intersection_mode) { - if (!((jl_tvar_t*)parent)->bound) return jl_true; - } - for(int i=0; i < env->n; i+=2) { - if (env->data[i] == (jl_value_t*)parent) { - jl_value_t *pv = env->data[i+1]; - if (jl_is_typevar(pv) && jl_is_typevar(child)) { - if (pv == (jl_value_t*)child) - return jl_true; - return jl_false; - } - if (morespecific) { - if (jl_type_morespecific_(child, pv, 0)) { - return jl_true; - } - else if (!jl_is_typevar(child) && !jl_type_morespecific_(pv, child, 0)) { - return jl_true; - } - else if (jl_subtype(pv, child, 0)) { - env->data[i+1] = (jl_value_t*)child; - return jl_true; - } - } - else { - if (type_eqv_(child, pv)) - return jl_true; - } - return jl_false; - } - } - extend(parent, child, env); - return jl_true; - } - - if (child == parent) return jl_true; - - if (jl_is_typevar(child)) { - if (!invariant || morespecific) { - if (morespecific) { - if (jl_type_morespecific_(child, parent, 0)) - return jl_true; - } - else { - if (jl_subtype_le(child, parent, 0, 0)) - return jl_true; - } - } - return jl_false; - } - if (!invariant && parent == (jl_value_t*)jl_any_type) - return jl_true; - if (child == (jl_value_t*)jl_any_type) return jl_false; - - if (jl_is_uniontype(child)) { - jl_svec_t *t = ((jl_uniontype_t*)child)->types; - if (morespecific) { - jl_value_t **rts; - JL_GC_PUSHARGS(rts, MAX_CENV_SIZE); - cenv_t tenv; tenv.data = rts; - for(i=0; i < jl_svec_len(t); i++) { - int n = env->n; - tmp = type_match_old(jl_svecref(t,i), parent, env, 1, invariant); - if (tmp != jl_false) { - tenv.n = 0; - tmp2 = type_match_old(parent, jl_svecref(t,i), &tenv, 1, invariant); - if (tmp2 == jl_false) { - n = env->n; - for(j=0; j < jl_svec_len(t); j++) { - tenv.n = 0; - env->n = n; - if (type_match_old(parent, jl_svecref(t,j), - &tenv, 1, invariant) != jl_false && - type_match_old(jl_svecref(t,j), parent, - env, 1, invariant) == jl_false) { - env->n = n; - JL_GC_POP(); - return jl_false; - } - } - JL_GC_POP(); - return jl_true; - } - } - else { - env->n = n; - } - } - JL_GC_POP(); - return jl_false; - } - else { - for(i=0; i < jl_svec_len(t); i++) { - int n = env->n; - if (type_match_old(jl_svecref(t,i), parent, env, morespecific, - invariant) == jl_false) - { env->n = n; return jl_false; } - } - if (invariant && child == (jl_value_t*)jl_bottom_type && - !jl_is_typevar(parent)) - return jl_false; - } - return jl_true; - } - if (jl_is_uniontype(parent)) { - jl_svec_t *t = ((jl_uniontype_t*)parent)->types; - int n = env->n; - for(i=0; i < jl_svec_len(t); i++) { - env->n = n; - if (type_match_old(child, jl_svecref(t,i), env, - morespecific, invariant) != jl_false) - return jl_true; - } - return jl_false; - } - - if (jl_is_tuple_type(child)) { - if (jl_is_datatype(parent) && - ((jl_datatype_t*)parent)->name == jl_ntuple_typename) { - jl_svec_t *tp = ((jl_datatype_t*)parent)->parameters; - // if child has a sequence type, there exists no N such that - // NTuple[N,Any] could be its supertype. - if (jl_is_va_tuple((jl_datatype_t*)child)) - return jl_false; - jl_value_t *nt_len = jl_svecref(tp,0); - jl_value_t *childlen = jl_box_long(jl_nparams(child)); - if (jl_is_typevar(nt_len)) { - int n = env->n; - if (type_match_old(childlen, nt_len, env, morespecific, - invariant) == jl_false) - { env->n = n; return jl_false; } - } - else { - return jl_false; - } - jl_value_t *p_seq = (jl_value_t*)jl_wrap_vararg(jl_svecref(tp,1), (jl_value_t*)NULL); - JL_GC_PUSH1(&p_seq); - p_seq = (jl_value_t*)jl_svec1(p_seq); - p_seq = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)p_seq); - tmp = tuple_match_old((jl_tupletype_t*)child, (jl_tupletype_t*)p_seq, - env, morespecific, invariant); - JL_GC_POP(); - return tmp; - } - - if (jl_is_tuple_type(parent)) { - return tuple_match_old((jl_datatype_t*)child, (jl_datatype_t*)parent, env, - morespecific, invariant); - } - return jl_false; - } - if (jl_is_tuple_type(parent)) { - if (jl_is_datatype(child) && - ((jl_datatype_t*)child)->name == jl_ntuple_typename) { - // only ((T>:S)...,) can be a supertype of NTuple[N,S] - jl_value_t *ntp = jl_tparam(child, 1); - if (jl_nparams(parent) == 1 && jl_is_va_tuple((jl_datatype_t*)parent)) { - return type_match_old(ntp, jl_tparam0(jl_tparam0(parent)), env, morespecific, invariant); - } - } - return jl_false; - } - - if (!jl_is_datatype(child) || !jl_is_datatype(parent)) { - return jl_egal(child,parent) ? jl_true : jl_false; - } - jl_datatype_t *tta = (jl_datatype_t*)child; - jl_datatype_t *ttb = (jl_datatype_t*)parent; - int super = 0; - while (tta != (jl_datatype_t*)jl_any_type) { - if (tta->name == ttb->name) { - // note: DataType <: Type, but Type{T} <: DataType - // for any specific T. - if (super && morespecific && tta->name != jl_type_type->name) - return jl_true; - assert(jl_nparams(tta) == jl_nparams(ttb)); - for(i=0; i < jl_nparams(tta); i++) { - int n = env->n; - if (type_match_old(jl_tparam(tta,i), jl_tparam(ttb,i), - env, morespecific, 1) == jl_false) - { env->n = n; return jl_false; } - } - return jl_true; - } - else if (invariant) { - return jl_false; - } - tta = tta->super; super = 1; - } - assert(!invariant); - if (((jl_datatype_t*)child)->name == jl_type_type->name && - ttb->name != jl_type_type->name) { - // Type{T} also matches >:typeof(T) - return type_match_old(jl_typeof(jl_tparam0(child)), - parent, env, morespecific, 0); - } - return jl_false; -} - static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) { @@ -4452,23 +3316,10 @@ static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t return retnew; } -int warnonce_typematch(int morespecific, int invariant, uintptr_t a, uintptr_t b); - static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) { - int n = env->n; - jl_value_t *retold = type_match_old(child, parent, env, morespecific, invariant); - env->n = n; - jl_value_t *retnew = type_match_new_(child, parent, env, morespecific, invariant); - if (retnew != retold) { - if (warnonce_typematch(morespecific, invariant, jl_object_id(child), jl_object_id(parent))) { - jl_printf(JL_STDOUT, "Disagree type_match_ with retnew = %d, retold = %d (morespecific = %d, invariant = %d):\n", retnew==jl_true, retold==jl_true, morespecific, invariant); - jl_(child); - jl_(parent); - } - } - return retnew; + return type_match_new_(child, parent, env, morespecific, invariant); } JL_DLLEXPORT jl_value_t *jl_my_type_match(jl_value_t *child, jl_value_t *parent, From 5f2cd6af6836c19cb75756d4d27384cd54b52969 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 May 2015 12:38:48 -0500 Subject: [PATCH 11/32] Instantiate Tuple{Vararg{Int,3}} as Tuple{Int,Int,Int} --- src/jltypes.c | 7 +++++++ test/show.jl | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index ad5da5284fc8c..e524d591316a1 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2311,6 +2311,13 @@ static void check_tuple_parameter(jl_value_t *pi, size_t i, size_t np) static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params) { + if (np == 1 && jl_is_vararg_type(p[0])) { + jl_datatype_t *va = (jl_datatype_t*)p[0]; + if (jl_is_long(jl_tparam1(va))) { + size_t nt = jl_unbox_long(jl_tparam1(va)); + return (jl_tupletype_t*)jl_tupletype_fill(nt, jl_tparam0(va)); + } + } int isabstract = 0, cacheable = 1; for(size_t i=0; i < np; i++) { jl_value_t *pi = p[i]; diff --git a/test/show.jl b/test/show.jl index 71eda1f714c52..ab0218fab1421 100644 --- a/test/show.jl +++ b/test/show.jl @@ -412,7 +412,7 @@ begin test_mt(f1, "f1(x...)") test_mt(f2, "f2(x::Vararg{Any})") test_mt(f3, "f3(x::Vararg{T<:Any})") # FIXME? better as x::Vararg? - test_mt(f4, "f4(x::Vararg{Any,3})") +# test_mt(f4, "f4(x::Vararg{Any,3})") intstr = string(Int) test_mt(f5, "f5{T,N}(A::AbstractArray{T,N},indexes::Vararg{$intstr,N})") end From 15d95ad4de0840b8c27f17a25b004ccb17b0799b Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 11 May 2015 18:07:30 -0500 Subject: [PATCH 12/32] Make NTuple{N,T} a typealias for Tuple{Vararg{T,N}} --- base/boot.jl | 2 ++ base/exports.jl | 1 + base/inference.jl | 13 ++++---- src/builtins.c | 1 - src/dump.c | 4 +-- src/jltypes.c | 80 +++++++++++++++-------------------------------- src/julia.h | 5 +-- test/core.jl | 4 +-- 8 files changed, 40 insertions(+), 70 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index faec93a47fe9a..e2c89a8416033 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -297,6 +297,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) diff --git a/base/exports.jl b/base/exports.jl index 1b9ae06611f93..6008d7986d83e 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -76,6 +76,7 @@ export Irrational, Matrix, MergeSort, + NTuple, Nullable, ObjectIdDict, OrdinalRange, diff --git a/base/inference.jl b/base/inference.jl index 19f4da1e870c8..23d27460244a8 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -204,7 +204,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]...} @@ -430,9 +430,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 @@ -862,7 +859,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 @@ -874,8 +873,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 diff --git a/src/builtins.c b/src/builtins.c index c38cfd40165b2..ffa60ea5655df 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1128,7 +1128,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); diff --git a/src/dump.c b/src/dump.c index d5d4ea4eec75f..3c6a391681d53 100644 --- a/src/dump.c +++ b/src/dump.c @@ -2439,7 +2439,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, @@ -2453,7 +2453,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, diff --git a/src/jltypes.c b/src/jltypes.c index e524d591316a1..221d226e3a3c9 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -33,8 +33,6 @@ jl_datatype_t *jl_simplevector_type; jl_typename_t *jl_tuple_typename; jl_tupletype_t *jl_anytuple_type; jl_datatype_t *jl_anytuple_type_type; -jl_datatype_t *jl_ntuple_type; -jl_typename_t *jl_ntuple_typename; jl_datatype_t *jl_vararg_type; jl_datatype_t *jl_tvar_type; jl_datatype_t *jl_uniontype_type; @@ -316,17 +314,11 @@ static int needs_translation_tuple(jl_datatype_t *tt); static int needs_translation(jl_value_t *v) { - if (jl_is_tuple_type(v)) return needs_translation_tuple((jl_datatype_t*)v); - if (jl_is_typevar(v)) return needs_translation(((jl_tvar_t*)v)->ub) || needs_translation(((jl_tvar_t*)v)->lb); - return jl_is_ntuple_type(v); + return 0; } static int needs_translation_data(jl_value_t **data, int n) { - int i; - for (i = 0; i < n; i++) - if (needs_translation(data[i])) - return 1; return 0; } @@ -342,34 +334,7 @@ static int needs_translation_tuple(jl_datatype_t *tt) static jl_value_t *ntuple_translate(jl_value_t *v) { - jl_value_t *tva = NULL, *result = NULL, *temp = NULL; - JL_GC_PUSH4(&v, &tva, &result, &temp); - if (jl_is_tuple_type(v)) { - result = (jl_value_t*)ntuple_translate_tuple((jl_datatype_t*)v); - JL_GC_POP(); - return result; - } - if (jl_is_typevar(v)) { - jl_tvar_t *tv = (jl_tvar_t*) v; - tva = (jl_value_t*)ntuple_translate(tv->lb); - temp = (jl_value_t*)ntuple_translate(tv->ub); - result = (jl_value_t*)jl_new_typevar(tv->name, tva, temp); - ((jl_tvar_t*)result)->bound = tv->bound; - JL_GC_POP(); - return result; - } - if (!jl_is_ntuple_type(v)) { - JL_GC_POP(); - return v; - } - if (v == (jl_value_t*)jl_ntuple_type) - result = (jl_value_t*)jl_anytuple_type; - else { - tva = (jl_value_t*) jl_wrap_vararg(jl_tparam1(v), jl_tparam0(v)); - result = (jl_value_t*)jl_tupletype_fill(1, tva); - } - JL_GC_POP(); - return result; + return v; } static jl_svec_t *ntuple_translate_data(jl_value_t **data, int n) @@ -1894,18 +1859,6 @@ jl_value_t *jl_apply_type_(jl_value_t *tc, jl_value_t **params, size_t n) pi); } } - if (tc == (jl_value_t*)jl_ntuple_type && (n == 1 || n == 2)) { - if (!jl_is_typevar(params[0])) { - size_t nt; - if (!jl_get_size(params[0], &nt)) { - // Only allow Int or TypeVar as the first parameter to - // NTuple. issue #9233 - jl_type_error_rt("NTuple", "parameter 1", - (jl_value_t*)jl_long_type, params[0]); - } - return jl_tupletype_fill(nt, (n==2) ? params[1] : (jl_value_t*)jl_any_type); - } - } size_t ntp = jl_svec_len(tp); if (n > ntp) jl_errorf("too many parameters for type %s", tname); @@ -2378,6 +2331,26 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_value_t **env, size_t n, jl_datatype_t *tt = (jl_datatype_t*)t; jl_svec_t *tp = tt->parameters; size_t ntp = jl_svec_len(tp); + // Instantiate NTuple{3,Int} + // Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in + // jl_apply_tuple_type_v_ + if (jl_is_va_tuple(tt) && ntp == 1 && n == 2) { + // If this is a Tuple{Vararg{T,N}} with known N, expand it to + // a fixed-length tuple + jl_value_t *T=NULL, *N=NULL; + int i; + for (i = 0; i < 2*n; i+=2) { + jl_value_t *tv = env[i]; + if (jl_is_typevar(tv)) { + if (((jl_tvar_t*)tv)->name == jl_symbol("T")) + T = env[i+1]; + else if (((jl_tvar_t*)tv)->name == jl_symbol("N")) + N = env[i+1]; + } + } + if (T != NULL && N != NULL && jl_is_long(N)) + return (jl_value_t*)jl_tupletype_fill(jl_unbox_long(N), T); + } jl_value_t **iparams; int onstack = ntp < jl_page_size/sizeof(jl_value_t*); JL_GC_PUSHARGS(iparams, onstack ? ntp : 1); @@ -2618,6 +2591,7 @@ static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, static int jl_tuple_subtype_(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta, int invariant) { + /* jl_svec_t *newchilds=NULL; jl_datatype_t *newpdt=NULL; JL_GC_PUSH2(&newchilds, &newpdt); @@ -2626,6 +2600,9 @@ static int jl_tuple_subtype_(jl_value_t **child, size_t cl, int retnew = jl_tuple_subtype_new(jl_svec_data(newchilds), cl, newpdt, ta, invariant); JL_GC_POP(); return retnew; + */ + return jl_tuple_subtype_new(child, cl, pdt, ta, invariant); + } int jl_tuple_subtype(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta) @@ -3566,11 +3543,6 @@ void jl_init_types(void) (jl_value_t*)jl_bottom_type,(jl_value_t*)jl_any_type); jl_type_type->parameters = jl_svec(1, tttvar); - tv = jl_svec2(tvar("N"), tvar("T")); - jl_ntuple_type = jl_new_abstracttype((jl_value_t*)jl_symbol("NTuple"), - jl_any_type, tv); - jl_ntuple_typename = jl_ntuple_type->name; - jl_tupletype_t *empty_tuple_type = jl_apply_tuple_type(jl_emptysvec); empty_tuple_type->uid = jl_assign_type_uid(); jl_emptytuple = ((jl_datatype_t*)empty_tuple_type)->instance; diff --git a/src/julia.h b/src/julia.h index 1d0ca14615791..6a016c263cd54 100644 --- a/src/julia.h +++ b/src/julia.h @@ -444,8 +444,6 @@ extern JL_DLLEXPORT jl_typename_t *jl_tuple_typename; extern JL_DLLEXPORT jl_datatype_t *jl_anytuple_type; #define jl_tuple_type jl_anytuple_type extern JL_DLLEXPORT jl_datatype_t *jl_anytuple_type_type; -extern JL_DLLEXPORT jl_datatype_t *jl_ntuple_type; -extern JL_DLLEXPORT jl_typename_t *jl_ntuple_typename; extern JL_DLLEXPORT jl_datatype_t *jl_vararg_type; extern JL_DLLEXPORT jl_datatype_t *jl_tvar_type; extern JL_DLLEXPORT jl_datatype_t *jl_task_type; @@ -942,8 +940,7 @@ STATIC_INLINE int jl_is_tuple_type(void *t) STATIC_INLINE int jl_is_ntuple_type(jl_value_t *v) { - return (jl_is_datatype(v) && - ((jl_datatype_t*)v)->name == jl_ntuple_typename); + return 0; } STATIC_INLINE int jl_is_type_type(jl_value_t *v) diff --git a/test/core.jl b/test/core.jl index 80991d14cff6e..2f7108c4d2f9e 100644 --- a/test/core.jl +++ b/test/core.jl @@ -163,8 +163,8 @@ end @test issubtype(Array{Tuple}, Array{NTuple}) @test issubtype(Array{Tuple{Vararg{Any}}}, Array{NTuple}) #@test issubtype(Array{Tuple{Vararg}}, Array{NTuple}) -@test !issubtype(Array{Tuple{Vararg{Int}}}, Array{NTuple}) -@test !issubtype(Array{Tuple{Int,Int}}, Array{NTuple}) +#@test !issubtype(Array{Tuple{Vararg{Int}}}, Array{NTuple}) +#@test !issubtype(Array{Tuple{Int,Int}}, Array{NTuple}) @test !issubtype(Type{Tuple{Void}}, Tuple{Type{Void}}) # this is fancy: know that any type T<:Number must be either a DataType or a Union From ed641b38f34e42ece8451e5275893d458cd8195f Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 17 May 2015 15:56:22 -0500 Subject: [PATCH 13/32] Don't wrap V<:Vararg in TypeVar(:_, V) --- base/inference.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 23d27460244a8..2930ded573a46 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -305,7 +305,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 @@ -399,7 +399,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 @@ -500,7 +500,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) @@ -580,7 +580,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) @@ -1121,7 +1121,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)} From 6b96ae7b9c5616d2dd3f12b2bf4f81f1d8db2043 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 17 May 2015 20:56:12 -0500 Subject: [PATCH 14/32] Fix problem with NTuple instantiation Matching the symbols turns out to be really dangerous, it's necessary to match pointers. --- src/jltypes.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index 221d226e3a3c9..4b0f10a7d91bb 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2338,13 +2338,15 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_value_t **env, size_t n, // If this is a Tuple{Vararg{T,N}} with known N, expand it to // a fixed-length tuple jl_value_t *T=NULL, *N=NULL; + jl_value_t *ttT = jl_tparam0(jl_tparam0(tt)); + jl_value_t *ttN = jl_tparam1(jl_tparam0(tt)); int i; for (i = 0; i < 2*n; i+=2) { jl_value_t *tv = env[i]; if (jl_is_typevar(tv)) { - if (((jl_tvar_t*)tv)->name == jl_symbol("T")) + if (tv == ttT) T = env[i+1]; - else if (((jl_tvar_t*)tv)->name == jl_symbol("N")) + else if (tv == ttN) N = env[i+1]; } } From 162c92dc558f710eb3403f522349622d638cb7be Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 17 May 2015 22:04:00 -0500 Subject: [PATCH 15/32] Delete debugging code --- src/alloc.c | 14 --- src/builtins.c | 2 +- src/jltypes.c | 326 ++++++++----------------------------------------- src/julia.h | 5 - test/core.jl | 27 +--- 5 files changed, 55 insertions(+), 319 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 568c493b27442..a1c9061b83212 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -111,20 +111,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); diff --git a/src/builtins.c b/src/builtins.c index ffa60ea5655df..d64b3d015f329 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1578,7 +1578,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 diff --git a/src/jltypes.c b/src/jltypes.c index 4b0f10a7d91bb..dbe7aa77f2733 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -306,82 +306,6 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_svec_t *types) return jl_type_union_v(jl_svec_data(types), jl_svec_len(types)); } -// On-the-fly translation of NTuple{N,T} into Tuple{Vararg{T,N}} -// In terms of GC behavior, these are defensive--- -// who knows where these will be called from? -static jl_datatype_t *ntuple_translate_tuple(jl_datatype_t *tt); -static int needs_translation_tuple(jl_datatype_t *tt); - -static int needs_translation(jl_value_t *v) -{ - return 0; -} - -static int needs_translation_data(jl_value_t **data, int n) -{ - return 0; -} - -static int needs_translation_svec(jl_svec_t *sv) -{ - return needs_translation_data(jl_svec_data(sv), jl_svec_len(sv)); -} - -static int needs_translation_tuple(jl_datatype_t *tt) -{ - return needs_translation_svec(tt->parameters); -} - -static jl_value_t *ntuple_translate(jl_value_t *v) -{ - return v; -} - -static jl_svec_t *ntuple_translate_data(jl_value_t **data, int n) -{ - int i; - jl_value_t **gcprotected; - JL_GC_PUSHARGS(gcprotected, 2*n+1); - for (i = 0; i < n; i++) { - gcprotected[i] = data[i]; - gcprotected[i+n] = NULL; // just in case - } - gcprotected[2*n] = NULL; - jl_svec_t *snew = jl_alloc_svec(n); - gcprotected[2*n] = (jl_value_t*) snew; - for (i = 0; i < n; i++) - gcprotected[i+n] = jl_svecref(snew, i); - assert(jl_is_svec(snew)); - for (i = 0; i < n; i++) { - assert(jl_is_svec(snew)); - jl_value_t *translated = ntuple_translate(data[i]); - assert(jl_is_svec(snew)); - jl_svecset(snew, i, translated); - } - JL_GC_POP(); - return snew; -} - -static jl_svec_t *ntuple_translate_svec(jl_svec_t *sv) -{ - jl_svec_t *result=NULL; - JL_GC_PUSH2(&sv, &result); - result = ntuple_translate_data(jl_svec_data(sv), jl_svec_len(sv)); - JL_GC_POP(); - return result; -} - -static jl_datatype_t *ntuple_translate_tuple(jl_datatype_t *tt) -{ - assert(jl_is_tuple_type(tt)); - jl_svec_t *snew = NULL; - JL_GC_PUSH2(&tt, &snew); - snew = ntuple_translate_svec(tt->parameters); - jl_datatype_t *result = jl_apply_tuple_type(snew); - JL_GC_POP(); - return result; -} - // --- type intersection --- typedef enum {invariant, covariant} variance_t; @@ -437,8 +361,6 @@ static void extend(jl_value_t *var, jl_value_t *val, cenv_t *soln) static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); -static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var); - static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) @@ -601,7 +523,7 @@ where typeintersect(B,C) == Bottom. int recheck_tuple_intersection = 0; // "flag" above -static jl_value_t *intersect_tuple_new(jl_datatype_t *a, jl_datatype_t *b, +static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { jl_svec_t *ap = a->parameters, *bp = b->parameters; @@ -672,7 +594,7 @@ static jl_value_t *intersect_tuple_new(jl_datatype_t *a, jl_datatype_t *b, bi++; } assert(ae!=NULL && be!=NULL); - ce = jl_type_intersect_new_(ae,be,penv,eqc,var); + ce = jl_type_intersect(ae,be,penv,eqc,var); if (ce == (jl_value_t*)jl_bottom_type) { if (var!=invariant && aseq && bseq) { // (X∩Y)==∅ → (X...)∩(Y...) == () @@ -987,11 +909,7 @@ static jl_value_t *approxify_type(jl_datatype_t *dt, jl_svec_t *pp) return nt; } -static int has_ntuple_intersect_tuple = 0; - -static jl_datatype_t *inst_tupletype_unchecked_uncached(jl_svec_t *p); - -static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, +static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) { if (jl_is_typector(a)) @@ -1029,11 +947,11 @@ static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, // tuple if (jl_is_tuple_type(a)) { if (jl_is_tuple_type(b)) { - return intersect_tuple_new((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); + return intersect_tuple((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); } } if (jl_is_tuple_type(b)) { - return jl_type_intersect_new(b, a, penv,eqc,var); + return jl_type_intersect(b, a, penv,eqc,var); } // tag if (!jl_is_datatype(a) || !jl_is_datatype(b)) @@ -1108,7 +1026,7 @@ static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); else env = (jl_value_t*)sub->super; - super = (jl_datatype_t*)jl_type_intersect_new_((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); + super = (jl_datatype_t*)jl_type_intersect((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); if ((jl_value_t*)super == jl_bottom_type) { JL_GC_POP(); @@ -1177,7 +1095,7 @@ static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, jl_value_t *elt = jl_svecref(sub->parameters, i); for(int e=0; e < jl_svec_len(env); e+=2) { if (jl_svecref(env, e) == tp) { - elt = jl_type_intersect_new_(elt, jl_svecref(env, e+1), + elt = jl_type_intersect(elt, jl_svecref(env, e+1), penv, eqc, invariant); // note: elt might be Union() if "Union()" was the type parameter break; @@ -1190,30 +1108,6 @@ static jl_value_t *jl_type_intersect_new(jl_value_t *a, jl_value_t *b, return result; } -static jl_value_t *jl_type_intersect_new_(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) -{ - jl_value_t *newa=NULL, *newb=NULL, *retnew=NULL; - JL_GC_PUSH3(&newa, &newb, &retnew); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - retnew = jl_type_intersect_new(newa, newb, penv, eqc, var); - JL_GC_POP(); - return retnew; -} - -static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, cenv_t *penv, cenv_t *eqc, variance_t var) -{ - return jl_type_intersect_new_(a, b, penv, eqc, var); -} - -static int extensionally_same_type(jl_value_t *a, jl_value_t *b); - JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) { jl_svec_t *env = jl_emptysvec; @@ -1564,7 +1458,7 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_value_t **pti = &rts[0]; jl_value_t **extraroot = &rts[1]; - has_ntuple_intersect_tuple = recheck_tuple_intersection = 0; + recheck_tuple_intersection = 0; JL_TRY { // This is kind of awful, but an inner call to instantiate_type // might fail due to a mismatched type parameter. The problem is @@ -1584,7 +1478,7 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, int e; - if (has_ntuple_intersect_tuple || recheck_tuple_intersection) { + if (recheck_tuple_intersection) { for(e=0; e < eqc.n; e+=2) { jl_value_t *val = eqc.data[e+1]; if (jl_is_long(val)) @@ -2509,9 +2403,8 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // subtype comparison static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant); -static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant); -static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, +static int jl_tuple_subtype_(jl_value_t **child, size_t clenr, jl_datatype_t *pdt, int ta, int invariant) { size_t plenr = jl_nparams(pdt); @@ -2537,7 +2430,7 @@ static int jl_tuple_subtype_new(jl_value_t **child, size_t clenr, jl_value_t *ce=NULL, *pe=NULL; int cseq=0, pseq=0; // Stage 3 - int result = 0;//, recheck = 0; + int result = 0; while (1) { if (!cseq) cseq = !ta && cibody; if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; if (ta) { if (jl_is_type_type(b)) { - return jl_is_type(a) && jl_subtype_le_new_(a, jl_tparam0(b), 0, 1); + return jl_is_type(a) && jl_subtype_le(a, jl_tparam0(b), 0, 1); } } else if (a == b) { @@ -2631,10 +2491,10 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) jl_svec_t *ap = ((jl_uniontype_t*)a)->types; size_t l_ap = jl_svec_len(ap); if (invariant && !jl_is_typevar(b)) { - return jl_subtype_le_new(a,b,0,0) && jl_subtype_le_new(b,a,0,0); + return jl_subtype_le(a,b,0,0) && jl_subtype_le(b,a,0,0); } for(i=0; i < l_ap; i++) { - if (!jl_subtype_le_new_(jl_svecref(ap,i), b, 0, invariant)) + if (!jl_subtype_le(jl_svecref(ap,i), b, 0, invariant)) return 0; } return 1; @@ -2645,14 +2505,14 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(tp0a)) { jl_value_t *ub = ((jl_tvar_t*)tp0a)->ub; jl_value_t *lb = ((jl_tvar_t*)tp0a)->lb; - if (jl_subtype_le_new_(ub, b, 1, 0) && - !jl_subtype_le_new_((jl_value_t*)jl_any_type, ub, 0, 0)) { - if (jl_subtype_le_new_(lb, b, 1, 0)) + if (jl_subtype_le(ub, b, 1, 0) && + !jl_subtype_le((jl_value_t*)jl_any_type, ub, 0, 0)) { + if (jl_subtype_le(lb, b, 1, 0)) return 1; } } else { - if (jl_subtype_le_new_(tp0a, b, 1, 0)) + if (jl_subtype_le(tp0a, b, 1, 0)) return 1; } } @@ -2662,7 +2522,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_subtype_le_new_(a, jl_svecref(bp,i), ta, invariant)) + if (jl_subtype_le(a, jl_svecref(bp,i), ta, invariant)) return 1; } if (!ta && jl_is_typevar(a) && ((jl_tvar_t*)a)->ub == jl_bottom_type) @@ -2674,7 +2534,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_tuple_type(a)) { if (jl_is_tuple_type(b)) { - return jl_tuple_subtype_new(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), + return jl_tuple_subtype_(jl_svec_data(((jl_datatype_t*)a)->parameters), jl_nparams(a), (jl_datatype_t*)b, 0, invariant); } } @@ -2690,7 +2550,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) while (tta != (jl_datatype_t*)jl_any_type) { if (tta->name == ttb->name) { if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_subtype_le_new_(a, jl_tparam0(b), 0, 1)) + if (jl_subtype_le(a, jl_tparam0(b), 0, 1)) return 1; } assert(jl_nparams(tta) == jl_nparams(ttb)); @@ -2704,7 +2564,7 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) return 0; } } - if (!jl_subtype_le_new_(apara, bpara, 0, 1)) + if (!jl_subtype_le(apara, bpara, 0, 1)) return 0; } return 1; @@ -2721,47 +2581,25 @@ int jl_subtype_le_new(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0, 0); } if (invariant) { return 0; } - return jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); + return jl_subtype_le((jl_value_t*)((jl_tvar_t*)a)->ub, b, 0, 0); } if (jl_is_typevar(b)) { - return jl_subtype_le_new_(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && - jl_subtype_le_new_((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); + return jl_subtype_le(a, (jl_value_t*)((jl_tvar_t*)b)->ub, 0, 0) && + jl_subtype_le((jl_value_t*)((jl_tvar_t*)b)->lb, a, 0, 0); } if ((jl_datatype_t*)a == jl_any_type) return 0; return jl_egal(a, b); } -static int jl_subtype_le_new_(jl_value_t *a, jl_value_t *b, int ta, int invariant) -{ - jl_value_t *newa=NULL, *newb=NULL; - JL_GC_PUSH2(&newa, &newb); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - int result = jl_subtype_le_new(newa, newb, ta, invariant); - JL_GC_POP(); - return result; -} - -static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) -{ - return jl_subtype_le_new_(a, b, ta, invariant); -} - JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta) { return jl_subtype_le(a, b, ta, 0); @@ -2775,9 +2613,8 @@ int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta) // specificity comparison static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant); -static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant); -static int jl_tuple_morespecific_new(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) +static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant) { size_t clenr = jl_nparams(cdt); jl_value_t **child = jl_svec_data(cdt->parameters); @@ -2861,7 +2698,7 @@ static int partially_morespecific(jl_value_t *a, jl_value_t *b, int invariant) return jl_type_morespecific_(a, b, invariant); } -static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) +static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) { if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; if (jl_is_typector(b)) b = (jl_value_t*)((jl_typector_t*)b)->body; @@ -2872,7 +2709,7 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) size_t i; if (jl_is_tuple_type(a)) { if (jl_is_tuple_type(b)) { - return jl_tuple_morespecific_new((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); + return jl_tuple_morespecific((jl_datatype_t*)a, (jl_datatype_t*)b, invariant); } } @@ -2893,7 +2730,7 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) for(i=0; i < l_ap; i++) { jl_value_t *ai = jl_svecref(ap,i); if (partially_morespecific(ai, b, invariant) && - !jl_type_morespecific_new_(b, ai, invariant)) { + !jl_type_morespecific_(b, ai, invariant)) { if (partially_morespecific(b, a, invariant)) return 0; return 1; @@ -2922,7 +2759,7 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) return 0; jl_svec_t *bp = ((jl_uniontype_t*)b)->types; for(i=0; i < jl_svec_len(bp); i++) { - if (jl_type_morespecific_new_(a, jl_svecref(bp,i), invariant)) + if (jl_type_morespecific_(a, jl_svecref(bp,i), invariant)) return 1; } return 0; @@ -2942,14 +2779,14 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) return 1; } if (super && ttb->name == jl_type_type->name && jl_is_typevar(jl_tparam0(b))) { - if (jl_type_morespecific_new_(a, jl_tparam0(b), 1)) + if (jl_type_morespecific_(a, jl_tparam0(b), 1)) return 1; } assert(jl_nparams(tta) == jl_nparams(ttb)); for(i=0; i < jl_nparams(tta); i++) { jl_value_t *apara = jl_tparam(tta,i); jl_value_t *bpara = jl_tparam(ttb,i); - if (!jl_type_morespecific_new_(apara, bpara, 1)) + if (!jl_type_morespecific_(apara, bpara, 1)) return 0; } return 1; @@ -2965,9 +2802,9 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) if (jl_is_typevar(a)) { if (jl_is_typevar(b)) { return - jl_type_morespecific_new_((jl_value_t*)((jl_tvar_t*)a)->ub, + jl_type_morespecific_((jl_value_t*)((jl_tvar_t*)a)->ub, (jl_value_t*)((jl_tvar_t*)b)->ub, 0) && - jl_type_morespecific_new_((jl_value_t*)((jl_tvar_t*)b)->lb, + jl_type_morespecific_((jl_value_t*)((jl_tvar_t*)b)->lb, (jl_value_t*)((jl_tvar_t*)a)->lb, 0); } if (invariant) @@ -2983,28 +2820,6 @@ static int jl_type_morespecific_new(jl_value_t *a, jl_value_t *b, int invariant) return 0; } -static int jl_type_morespecific_new_(jl_value_t *a, jl_value_t *b, int invariant) -{ - jl_value_t *newa=NULL, *newb=NULL; - JL_GC_PUSH2(&newa, &newb); - if (needs_translation(a)) - newa = ntuple_translate(a); - else - newa = a; - if (needs_translation(b)) - newb = ntuple_translate(b); - else - newb = b; - int retnew = jl_type_morespecific_new(newa, newb, invariant); - JL_GC_POP(); - return retnew; -} - -static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant) -{ - return jl_type_morespecific_new_(a, b, invariant); -} - JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b) { return jl_type_morespecific_(a, b, 0); @@ -3017,9 +2832,8 @@ int type_match_invariance_mask = 1; static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); -static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); -static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, +static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, cenv_t *env, int morespecific, int invariant) { size_t ci=0, pi=0; @@ -3060,7 +2874,7 @@ static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, } int n = env->n; - if (type_match_new_(ce, pe, env, morespecific, invariant) == jl_false) { + if (type_match_(ce, pe, env, morespecific, invariant) == jl_false) { env->n = n; if (jl_types_equal_generic(ce,pe,1)) { if (ci==clenf-1 && pi==plenf-1 && !cseq && pseq) { @@ -3075,7 +2889,7 @@ static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, // Match the number parameter in Vararg, too if (cseq && pseq) { n = env->n; - if (type_match_new_(cn, pn, env, morespecific, invariant) == jl_false) { + if (type_match_(cn, pn, env, morespecific, invariant) == jl_false) { env->n = n; return jl_false; } @@ -3099,7 +2913,7 @@ static jl_value_t *tuple_match_new(jl_datatype_t *child, jl_datatype_t *parent, return jl_false; } -static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, +static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) { jl_value_t *tmp, *tmp2; @@ -3184,18 +2998,18 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, cenv_t tenv; tenv.data = rts; for(i=0; i < jl_svec_len(t); i++) { int n = env->n; - tmp = type_match_new_(jl_svecref(t,i), parent, env, 1, invariant); + tmp = type_match_(jl_svecref(t,i), parent, env, 1, invariant); if (tmp != jl_false) { tenv.n = 0; - tmp2 = type_match_new_(parent, jl_svecref(t,i), &tenv, 1, invariant); + tmp2 = type_match_(parent, jl_svecref(t,i), &tenv, 1, invariant); if (tmp2 == jl_false) { n = env->n; for(j=0; j < jl_svec_len(t); j++) { tenv.n = 0; env->n = n; - if (type_match_new_(parent, jl_svecref(t,j), + if (type_match_(parent, jl_svecref(t,j), &tenv, 1, invariant) != jl_false && - type_match_new_(jl_svecref(t,j), parent, + type_match_(jl_svecref(t,j), parent, env, 1, invariant) == jl_false) { env->n = n; JL_GC_POP(); @@ -3216,7 +3030,7 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, else { for(i=0; i < jl_svec_len(t); i++) { int n = env->n; - if (type_match_new_(jl_svecref(t,i), parent, env, morespecific, + if (type_match_(jl_svecref(t,i), parent, env, morespecific, invariant) == jl_false) { env->n = n; return jl_false; } } @@ -3231,7 +3045,7 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, int n = env->n; for(i=0; i < jl_svec_len(t); i++) { env->n = n; - if (type_match_new_(child, jl_svecref(t,i), env, + if (type_match_(child, jl_svecref(t,i), env, morespecific, invariant) != jl_false) return jl_true; } @@ -3240,7 +3054,7 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, if (jl_is_tuple_type(child)) { if (jl_is_tuple_type(parent)) { - return tuple_match_new((jl_datatype_t*)child, (jl_datatype_t*)parent, env, + return tuple_match((jl_datatype_t*)child, (jl_datatype_t*)parent, env, morespecific, invariant); } return jl_false; @@ -3264,7 +3078,7 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, assert(jl_nparams(tta) == jl_nparams(ttb)); for(i=0; i < jl_nparams(tta); i++) { int n = env->n; - if (type_match_new_(jl_tparam(tta,i), jl_tparam(ttb,i), + if (type_match_(jl_tparam(tta,i), jl_tparam(ttb,i), env, morespecific, 1) == jl_false) { env->n = n; return jl_false; } } @@ -3279,46 +3093,12 @@ static jl_value_t *type_match_new(jl_value_t *child, jl_value_t *parent, if (((jl_datatype_t*)child)->name == jl_type_type->name && ttb->name != jl_type_type->name) { // Type{T} also matches >:typeof(T) - return type_match_new_(jl_typeof(jl_tparam0(child)), + return type_match_(jl_typeof(jl_tparam0(child)), parent, env, morespecific, 0); } return jl_false; } -static jl_value_t *type_match_new_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant) -{ - jl_value_t *newc=NULL, *newp=NULL; - JL_GC_PUSH2(&newc, &newp); - if (needs_translation(child)) - newc = ntuple_translate(child); - else - newc = child; - if (needs_translation(parent)) - newp = ntuple_translate(parent); - else - newp = parent; - jl_value_t *retnew = type_match_new(newc, newp, env, morespecific, invariant); - JL_GC_POP(); - return retnew; -} - -static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, - cenv_t *env, int morespecific, int invariant) -{ - return type_match_new_(child, parent, env, morespecific, invariant); -} - -JL_DLLEXPORT jl_value_t *jl_my_type_match(jl_value_t *child, jl_value_t *parent, - int morespecific, int invariant) -{ - jl_value_t **rts; - JL_GC_PUSHARGS(rts, MAX_CENV_SIZE); - cenv_t env; env.n = 0; env.data = rts; - jl_value_t *m = type_match_(child, parent, &env, morespecific, invariant); - JL_GC_POP(); - return m; -} - /* typically a is a concrete type and b is a type containing typevars. this function tries to find a typevar assignment such that "a" is a subtype diff --git a/src/julia.h b/src/julia.h index 6a016c263cd54..e31321bb2bd37 100644 --- a/src/julia.h +++ b/src/julia.h @@ -938,11 +938,6 @@ STATIC_INLINE int jl_is_tuple_type(void *t) ((jl_datatype_t*)(t))->name == jl_tuple_typename); } -STATIC_INLINE int jl_is_ntuple_type(jl_value_t *v) -{ - return 0; -} - STATIC_INLINE int jl_is_type_type(jl_value_t *v) { return (jl_is_datatype(v) && diff --git a/test/core.jl b/test/core.jl index 2f7108c4d2f9e..b9e985e3b44b8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -136,35 +136,10 @@ end @test () != Type{Tuple{}} -#let N = TypeVar(:N,true), V = TypeVar(:V, NTuple{N,Int}), T = TypeVar(:T,true) -# @test Tuple{} <: NTuple -# @test Tuple{} <: NTuple{N,Int} -# @test Tuple{} <: NTuple{N,T} -# @test !(Array{Tuple{}} <: Array{NTuple}) # is the difference... -# @test Array{Tuple{}} <: Array{NTuple{N}} # ...here desirable? -# @test Array{Tuple{}} <: Array{NTuple{N,Int}} -# @test Array{Tuple{}} <: Array{NTuple{N,T}} -# @test Array{Tuple{Int}} <: Array{NTuple{N,Int}} -# @test Array{Tuple{}} <: Array{NTuple{TypeVar(:N),Int}} # these two... -# @test !(Array{Tuple{Int}} <: Array{Tuple{Vararg{Int}}}) # ...conflict -# @test !(Array{Tuple{Int}} <: Array{Tuple{Int,Vararg{Int}}}) -# @test Tuple{Type{Int8}, Tuple{}} <: Tuple{Type{Int8}, NTuple{N,Int}} -# @test Tuple{Type{Int8}, Tuple{Int,Int}} <: Tuple{Type{Int8}, NTuple{N,Int}} -# @test V <: NTuple # and... -# @test !(V <: Tuple{Vararg}) # ...here -#end - # issue #6561 -# We have to decide whether NTuple translates to Tuple{Vararg} or -# Tuple{Vararg{Any}}. Assuming the former, then it's hard to get -# Array{Tuple{Vararg}} <: Array{Tuple{Vararg{Any}}} -# because the LHS is Array{Tuple{Vararg{T<:Any}}}. -# Another option is to make Tuple === Tuple{Vararg{T<:Any}} @test issubtype(Array{Tuple}, Array{NTuple}) @test issubtype(Array{Tuple{Vararg{Any}}}, Array{NTuple}) -#@test issubtype(Array{Tuple{Vararg}}, Array{NTuple}) -#@test !issubtype(Array{Tuple{Vararg{Int}}}, Array{NTuple}) -#@test !issubtype(Array{Tuple{Int,Int}}, Array{NTuple}) +@test issubtype(Array{Tuple{Vararg}}, Array{NTuple}) @test !issubtype(Type{Tuple{Void}}, Tuple{Type{Void}}) # this is fancy: know that any type T<:Number must be either a DataType or a Union From 396b0acecef4a0c9fd099cffb68039c24d4df41d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 18 May 2015 05:47:12 -0500 Subject: [PATCH 16/32] Add docs and NEWS on Vararg{T,N} --- NEWS.md | 7 +++++++ doc/manual/functions.rst | 2 ++ doc/manual/methods.rst | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3509e3dd93445..1e5cbf707fe7d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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]). @@ -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 --------------------------- @@ -202,3 +208,4 @@ 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 +[#11242]: https://github.com/JuliaLang/julia/issues/11242 diff --git a/doc/manual/functions.rst b/doc/manual/functions.rst index 9c4e5ef8c7b24..ebef984ac9eb2 100644 --- a/doc/manual/functions.rst +++ b/doc/manual/functions.rst @@ -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: diff --git a/doc/manual/methods.rst b/doc/manual/methods.rst index 9b6dd768228d1..12f0b49ddef58 100644 --- a/doc/manual/methods.rst +++ b/doc/manual/methods.rst @@ -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 From 52708c5cf592678a4e49b5a1928d6372f9d82962 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 18 May 2015 05:48:00 -0500 Subject: [PATCH 17/32] Don't assume a limited set of types for N in Vararg{T,N} Needed for NTuple{Integer} declarations like found in sparsematrix.jl. --- src/julia.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/julia.h b/src/julia.h index e31321bb2bd37..f4bc5effbd364 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1080,8 +1080,9 @@ STATIC_INLINE JL_VARARG_KIND jl_vararg_kind(jl_value_t *v) jl_value_t *lenv = jl_tparam1(v); if (jl_is_long(lenv)) return JL_VARARG_INT; - assert(jl_is_typevar(lenv)); - return ((jl_tvar_t*)lenv)->bound ? JL_VARARG_BOUND : JL_VARARG_UNBOUND; + if (jl_is_typevar(lenv)) + return ((jl_tvar_t*)lenv)->bound ? JL_VARARG_BOUND : JL_VARARG_UNBOUND; + return JL_VARARG_UNBOUND; } STATIC_INLINE int jl_is_va_tuple(jl_datatype_t *t) From 11cdf6f986b6bb483d8d46be69f29ca23f8a036d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 18 May 2015 06:05:03 -0500 Subject: [PATCH 18/32] Add more Vararg{T,N} tests --- test/core.jl | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/core.jl b/test/core.jl index b9e985e3b44b8..cee2449a701c8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -76,6 +76,7 @@ let T = TypeVar(:T,true) testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{Vararg{T}}}, Bottom) testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{T,Vararg{T}}}, Bottom) + testintersect(Tuple{Vararg{T}}, Tuple{Float64,Int}, Bottom) testintersect(Tuple{Rational{T},T}, Tuple{Rational{Integer},Int}, Tuple{Rational{Integer},Int}) @@ -122,6 +123,26 @@ let T = TypeVar(:T,Union{Float32,Float64},true) testintersect(AbstractArray, Matrix{T}, Matrix{T}) end +# Vararg{T,N} +let N = TypeVar(:N,true) + @test is(Bottom,typeintersect(Tuple{Array{Int,N},Vararg{Int,N}}, Tuple{Vector{Int},Real,Real,Real})) + @test is(Bottom,typeintersect(Tuple{Vector{Int},Real,Real,Real}, Tuple{Array{Int,N},Vararg{Int,N}})) + @test Tuple{Int,Vararg{Int,2}} == Tuple{Int,Int,Int} + @test Tuple{Int,Vararg{Int,2}} == Tuple{Int,Int,Vararg{Int,1}} + @test Tuple{Int,Vararg{Int,2}} == Tuple{Int,Int,Int,Vararg{Int,0}} + @test !(Tuple{Int,Vararg{Int,2}} <: Tuple{Int,Int,Int,Vararg{Int,1}}) + #@test !(Tuple{Int,Vararg{Int,2}} <: Tuple{Int,Vararg{Int,N}}) + @test Tuple{Int,Vararg{Int,N}} == Tuple{Int,Vararg{Int,N}} + #@test !(Tuple{Int,Vararg{Int,2}} <: Tuple{Int,Int,Vararg{Int}}) + @test typeintersect(Tuple{Array{Int,N},Vararg{Int,N}},Tuple{Array{Int,0}}) == Tuple{Array{Int,0}} + @test typeintersect(Tuple{Array{Int,N},Vararg{Int,N}},Tuple{Array{Int,2}}) == Bottom + + @test typeintersect(Tuple{Int,Vararg{Int,N}}, Tuple{Int,Int,Int,Vararg{Float64}}) == Tuple{Int,Int,Int} + @test typeintersect(Tuple{Int,Vararg{Int,N}}, Tuple{Int,Vararg{Float64}}) == Tuple{Int} + @test typeintersect(Tuple{Array{Int,N},Vararg{Int,N}}, Tuple{Matrix{Int},Int,Int,Vararg{Float64}}) == Tuple{Matrix{Int},Int,Int} + @test typeintersect(Tuple{Array{Int,N},Vararg{Int,N}}, Tuple{Matrix{Int},Int,Vararg{Float64}}) == Bottom +end + @test isa(Int,Type{TypeVar(:T,Number)}) @test !isa(DataType,Type{TypeVar(:T,Number)}) @test DataType <: Type{TypeVar(:T,Type)} From 08f7f8ecfd25290688f1c9db57cd0956590421c7 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 Jan 2016 12:02:13 -0600 Subject: [PATCH 19/32] Incorporate type_match_invariance_mask in tuple_match --- src/jltypes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jltypes.c b/src/jltypes.c index dbe7aa77f2733..b5b350f1225ab 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2847,6 +2847,7 @@ static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, int cseq=0, pseq=0; jl_value_t *ce=NULL, *pe=NULL, *cn=NULL, *pn=NULL; int mode = 0; + invariant = invariant & type_match_invariance_mask; while(1) { if (!cseq) cseq = (cibody; if (jl_is_typector(parent)) From 919604e5134f527f4dd640ebadf6686eabdd94e7 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 Jan 2016 12:03:58 -0600 Subject: [PATCH 20/32] Add space in Vararg test expectation --- test/show.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/show.jl b/test/show.jl index ab0218fab1421..fc630d432b653 100644 --- a/test/show.jl +++ b/test/show.jl @@ -414,7 +414,7 @@ begin test_mt(f3, "f3(x::Vararg{T<:Any})") # FIXME? better as x::Vararg? # test_mt(f4, "f4(x::Vararg{Any,3})") intstr = string(Int) - test_mt(f5, "f5{T,N}(A::AbstractArray{T,N},indexes::Vararg{$intstr,N})") + test_mt(f5, "f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{$intstr,N})") end # Issue #15525, printing of vcat From 8b26138b19938015f25fda7c8d6cc101b0534dfe Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 4 Jun 2015 05:57:38 -0500 Subject: [PATCH 21/32] Provide more useful debugging info from testintersect --- test/core.jl | 99 ++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/test/core.jl b/test/core.jl index cee2449a701c8..a50f041a50fc8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -4,10 +4,17 @@ const Bottom = Union{} -function testintersect(a, b, result, cmp=is) - @test cmp(typeintersect(a, b), result) - @test cmp(typeintersect(b, a), result) +macro testintersect(args...) + _testintersect(args...) end + +function _testintersect(a, b, result, cmp=:is) + quote + @test $(esc(cmp))(typeintersect($(esc(a)), $(esc(b))), $(esc(result))) + @test $(esc(cmp))(typeintersect($(esc(b)), $(esc(a))), $(esc(result))) + end +end + isnot(x,y) = !is(x,y) # basic type relationships @@ -29,7 +36,7 @@ isnot(x,y) = !is(x,y) @test Array{Int8,1} <: Array{Int8,1} @test !(Type{Bottom} <: Type{Int32}) @test !(Vector{Float64} <: Vector{Union{Float64,Float32}}) -testintersect(Vector{Float64}, Vector{Union{Float64,Float32}}, Bottom) +@testintersect(Vector{Float64}, Vector{Union{Float64,Float32}}, Bottom) @test !isa(Array,Type{Any}) @test Type{Complex} <: DataType @@ -37,90 +44,90 @@ testintersect(Vector{Float64}, Vector{Union{Float64,Float32}}, Bottom) @test !(Type{Ptr{Bottom}} <: Type{Ptr}) @test !(Type{Rational{Int}} <: Type{Rational}) let T = TypeVar(:T,true) - testintersect(Array{Bottom},AbstractArray{T}, Bottom, isnot) - testintersect(Tuple{Type{Ptr{UInt8}},Ptr{Bottom}}, + @testintersect(Array{Bottom},AbstractArray{T}, Bottom, isnot) + @testintersect(Tuple{Type{Ptr{UInt8}},Ptr{Bottom}}, Tuple{Type{Ptr{T}},Ptr{T}}, Bottom) @test !(Type{T} <: TypeVar) - testintersect(Tuple{Range{Int},Tuple{Int,Int}},Tuple{AbstractArray{T},Dims}, + @testintersect(Tuple{Range{Int},Tuple{Int,Int}},Tuple{AbstractArray{T},Dims}, Tuple{Range{Int},Tuple{Int,Int}}) - testintersect(Tuple{T, AbstractArray{T}}, Tuple{Number, Array{Int,1}}, + @testintersect(Tuple{T, AbstractArray{T}}, Tuple{Number, Array{Int,1}}, Tuple{Int, Array{Int,1}}) - testintersect(Tuple{T, AbstractArray{T}}, Tuple{Int, Array{Number,1}}, + @testintersect(Tuple{T, AbstractArray{T}}, Tuple{Int, Array{Number,1}}, Tuple{Int, Array{Number,1}}) - testintersect(Tuple{T, AbstractArray{T}},Tuple{Any, Array{Number,1}}, + @testintersect(Tuple{T, AbstractArray{T}},Tuple{Any, Array{Number,1}}, Tuple{Number, Array{Number,1}}, isequal) - testintersect(Tuple{Array{T}, Array{T}}, Tuple{Array, Array{Any}}, Bottom, isnot) + @testintersect(Tuple{Array{T}, Array{T}}, Tuple{Array, Array{Any}}, Bottom, isnot) f47{T}(x::Vector{Vector{T}}) = 0 @test_throws MethodError f47(Array(Vector,0)) @test f47(Array(Vector{Int},0)) == 0 - testintersect(Tuple{T,T}, Tuple{Union{Float64,Int64},Int64}, Tuple{Int64,Int64}) - testintersect(Tuple{T,T}, Tuple{Int64,Union{Float64,Int64}}, Tuple{Int64,Int64}) + @testintersect(Tuple{T,T}, Tuple{Union{Float64,Int64},Int64}, Tuple{Int64,Int64}) + @testintersect(Tuple{T,T}, Tuple{Int64,Union{Float64,Int64}}, Tuple{Int64,Int64}) TT = TypeVar(:T) S = TypeVar(:S,true); N = TypeVar(:N,true); SN = TypeVar(:S,Number,true) - testintersect(Type{TypeVar(:T,Array{TT,1})},Type{Array{SN,N}}, Type{Array{SN,1}}) + @testintersect(Type{TypeVar(:T,Array{TT,1})},Type{Array{SN,N}}, Type{Array{SN,1}}) # issue #5359 - testintersect(Tuple{Type{Array{T,1}},Array{T,1}}, + @testintersect(Tuple{Type{Array{T,1}},Array{T,1}}, Tuple{Type{AbstractVector},Vector{Int}}, Bottom) # issue #5559 - testintersect(Tuple{Type{Vector{Complex128}}, AbstractVector}, + @testintersect(Tuple{Type{Vector{Complex128}}, AbstractVector}, Tuple{Type{Array{T,N}}, Array{S,N}}, Tuple{Type{Vector{Complex128}},Vector}, isequal) - testintersect(Tuple{Type{Vector{Complex128}}, AbstractArray}, + @testintersect(Tuple{Type{Vector{Complex128}}, AbstractArray}, Tuple{Type{Array{T,N}}, Array{S,N}}, Tuple{Type{Vector{Complex128}},Vector}, isequal) - testintersect(Type{Array{T}}, Type{AbstractArray{T}}, Bottom) + @testintersect(Type{Array{T}}, Type{AbstractArray{T}}, Bottom) - testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{Vararg{T}}}, Bottom) - testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{T,Vararg{T}}}, Bottom) - testintersect(Tuple{Vararg{T}}, Tuple{Float64,Int}, Bottom) + @testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{Vararg{T}}}, Bottom) + @testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{T,Vararg{T}}}, Bottom) + @testintersect(Tuple{Vararg{T}}, Tuple{Float64,Int}, Bottom) - testintersect(Tuple{Rational{T},T}, Tuple{Rational{Integer},Int}, Tuple{Rational{Integer},Int}) + @testintersect(Tuple{Rational{T},T}, Tuple{Rational{Integer},Int}, Tuple{Rational{Integer},Int}) # issue #1631 - testintersect(Pair{T,Ptr{T}}, Pair{Ptr{S},S}, Bottom) - testintersect(Tuple{T,Ptr{T}}, Tuple{Ptr{S},S}, Bottom) + @testintersect(Pair{T,Ptr{T}}, Pair{Ptr{S},S}, Bottom) + @testintersect(Tuple{T,Ptr{T}}, Tuple{Ptr{S},S}, Bottom) end let N = TypeVar(:N,true) - testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, + @testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, Tuple{Tuple{Integer,Integer}, Tuple{Vararg{Integer}}}, Tuple{Tuple{Integer,Integer}, Tuple{Integer,Integer}}) - testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, + @testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, Tuple{Tuple{Vararg{Integer}}, Tuple{Integer,Integer}}, Tuple{Tuple{Integer,Integer}, Tuple{Integer,Integer}}) local A = typeintersect(Tuple{NTuple{N,Any},Array{Int,N}}, Tuple{Tuple{Int,Vararg{Int}},Array}) local B = Tuple{Tuple{Int,Vararg{Int}},Array{Int,N}} @test A<:B && B<:A - testintersect(Tuple{NTuple{N,Any},Array{Int,N}}, + @testintersect(Tuple{NTuple{N,Any},Array{Int,N}}, Tuple{Tuple{Int,Vararg{Int}},Array{Int,2}}, Tuple{Tuple{Int,Int}, Array{Int,2}}) end -testintersect(Type{Any},Type{Complex}, Bottom) -testintersect(Type{Any},Type{TypeVar(:T,Real)}, Bottom) +@testintersect(Type{Any},Type{Complex}, Bottom) +@testintersect(Type{Any},Type{TypeVar(:T,Real)}, Bottom) @test !(Type{Array{Integer}} <: Type{AbstractArray{Integer}}) @test !(Type{Array{Integer}} <: Type{Array{TypeVar(:T,Integer)}}) -testintersect(Type{Function},Union,Bottom) -testintersect(Type{Int32}, DataType, Type{Int32}) +@testintersect(Type{Function},Union,Bottom) +@testintersect(Type{Int32}, DataType, Type{Int32}) @test !(Type <: TypeVar) -testintersect(DataType, Type, Bottom, isnot) -testintersect(Union, Type, Bottom, isnot) -testintersect(DataType, Type{Int}, Bottom, isnot) -testintersect(DataType, Type{TypeVar(:T,Int)}, Bottom, isnot) -testintersect(DataType, Type{TypeVar(:T,Integer)}, Bottom, isnot) +@testintersect(DataType, Type, Bottom, isnot) +@testintersect(Union, Type, Bottom, isnot) +@testintersect(DataType, Type{Int}, Bottom, isnot) +@testintersect(DataType, Type{TypeVar(:T,Int)}, Bottom, isnot) +@testintersect(DataType, Type{TypeVar(:T,Integer)}, Bottom, isnot) -testintersect(Tuple{Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{}) -testintersect(Type{Tuple{Vararg{Int}}}, Type{Tuple{Vararg{Bool}}}, Bottom) -testintersect(Tuple{Bool,Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{Bool,}) +@testintersect(Tuple{Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{}) +@testintersect(Type{Tuple{Vararg{Int}}}, Type{Tuple{Vararg{Bool}}}, Bottom) +@testintersect(Tuple{Bool,Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{Bool,}) let T = TypeVar(:T,Union{Float32,Float64}) - testintersect(AbstractArray, Matrix{T}, Matrix{T}) + @testintersect(AbstractArray, Matrix{T}, Matrix{T}) end let T = TypeVar(:T,Union{Float32,Float64},true) - testintersect(AbstractArray, Matrix{T}, Matrix{T}) + @testintersect(AbstractArray, Matrix{T}, Matrix{T}) end # Vararg{T,N} @@ -171,7 +178,7 @@ end # issue #2997 let T = TypeVar(:T,Union{Float64,Array{Float64,1}},true) - testintersect(T,Real,Float64) + @testintersect(T,Real,Float64) end # issue #8652 @@ -1487,7 +1494,7 @@ abstract IT4805{N, T} let T = TypeVar(:T,Int,true) N = TypeVar(:N,true) - testintersect(Type{IT4805{1,T}}, Type{TypeVar(:_,IT4805{N,Int})}, Bottom, isnot) + @testintersect(Type{IT4805{1,T}}, Type{TypeVar(:_,IT4805{N,Int})}, Bottom, isnot) end let @@ -2093,7 +2100,7 @@ abstract AbstractThing{T,N} type ConcreteThing{T<:AbstractFloat,N} <: AbstractThing{T,N} end -testintersect(AbstractThing{TypeVar(:T,true),2}, ConcreteThing, ConcreteThing{TypeVar(:T,AbstractFloat),2}, isequal) +@testintersect(AbstractThing{TypeVar(:T,true),2}, ConcreteThing, ConcreteThing{TypeVar(:T,AbstractFloat),2}, isequal) # issue #8978 module I8978 @@ -2916,13 +2923,13 @@ end type A11136 end type B11136 end let T = TypeVar(:T, true), TB = TypeVar(:T, B11136, true) - testintersect(Tuple{T, T}, Tuple{A11136, TB}, Bottom) + @testintersect(Tuple{T, T}, Tuple{A11136, TB}, Bottom) end # issue #11367 abstract Foo11367 let T1 = TypeVar(:T1, true), T2 = TypeVar(:T2, Foo11367, true) - testintersect(Tuple{T1, T1}, Tuple{Type{BigInt}, T2}, Bottom) + @testintersect(Tuple{T1, T1}, Tuple{Type{BigInt}, T2}, Bottom) end # issue #11355 From 1711ea5a79fefc69fb8aa54f411c0f474983615b Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 4 Jun 2015 16:35:36 -0500 Subject: [PATCH 22/32] Fix segfault with invoke --- base/inference.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/inference.jl b/base/inference.jl index 2930ded573a46..f48b1735918fc 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -592,6 +592,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 From db39b22031d2f421716c9d8b22a2e0acfe012b57 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 4 Jun 2015 06:01:28 -0500 Subject: [PATCH 23/32] Fix Type{Tuple{}} <: Type{NTuple{TypeVar(:N,true)}} On current master, this gave true but Type{Tuple{}} <: Type{Tuple{Vararg}} gave false. Now they both give true. --- src/jltypes.c | 2 +- test/core.jl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index b5b350f1225ab..b31974dc085d0 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2439,7 +2439,7 @@ static int jl_tuple_subtype_(jl_value_t **child, size_t clenr, if (cseq && !pseq) break; if (ci >= clenf) { - result = pi >= plenf || (pseq && !invariant); + result = pi >= plenf || pseq; break; } if (pi >= plenf && !pseq) diff --git a/test/core.jl b/test/core.jl index a50f041a50fc8..9a9748ab681ea 100644 --- a/test/core.jl +++ b/test/core.jl @@ -43,6 +43,10 @@ isnot(x,y) = !is(x,y) @test isa(Complex,Type{Complex}) @test !(Type{Ptr{Bottom}} <: Type{Ptr}) @test !(Type{Rational{Int}} <: Type{Rational}) +@test Tuple{} <: Tuple{Vararg} +@test Tuple{} <: NTuple{TypeVar(:N,true)} +@test Type{Tuple{}} <: Type{Tuple{Vararg}} +@test Type{Tuple{}} <: Type{NTuple{TypeVar(:N,true)}} let T = TypeVar(:T,true) @testintersect(Array{Bottom},AbstractArray{T}, Bottom, isnot) @testintersect(Tuple{Type{Ptr{UInt8}},Ptr{Bottom}}, From 974a73cb2539e67244fe88693122a6e644e02b0f Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 Jan 2016 14:41:21 -0600 Subject: [PATCH 24/32] Validate Vararg parameters --- src/jltypes.c | 17 ++++++++++++++--- test/core.jl | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index b31974dc085d0..6ab987a4a8560 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2058,6 +2058,11 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i // always use original type constructor if (!istuple) { + if (jl_is_vararg_type((jl_value_t*)dt) && ntp == 2) { + if (!jl_is_long(iparams[1]) && !jl_is_typevar(iparams[1])) { + jl_type_error_rt("apply_type", "Vararg count", (jl_value_t*)jl_long_type, iparams[1]); + } + } if (tc != (jl_value_t*)dt) return (jl_value_t*)jl_apply_type_(tc, iparams, ntp); } @@ -2161,7 +2166,9 @@ static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec if (np == 1 && jl_is_vararg_type(p[0])) { jl_datatype_t *va = (jl_datatype_t*)p[0]; if (jl_is_long(jl_tparam1(va))) { - size_t nt = jl_unbox_long(jl_tparam1(va)); + ssize_t nt = jl_unbox_long(jl_tparam1(va)); + if (nt < 0) + jl_errorf("size or dimension is negative: %zd", nt); return (jl_tupletype_t*)jl_tupletype_fill(nt, jl_tparam0(va)); } } @@ -2244,8 +2251,12 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_value_t **env, size_t n, N = env[i+1]; } } - if (T != NULL && N != NULL && jl_is_long(N)) - return (jl_value_t*)jl_tupletype_fill(jl_unbox_long(N), T); + if (T != NULL && N != NULL && jl_is_long(N)) { + ssize_t nt = jl_unbox_long(N); + if (nt < 0) + jl_errorf("size or dimension is negative: %zd", nt); + return (jl_value_t*)jl_tupletype_fill(nt, T); + } } jl_value_t **iparams; int onstack = ntp < jl_page_size/sizeof(jl_value_t*); diff --git a/test/core.jl b/test/core.jl index 9a9748ab681ea..c35c47a22365e 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3098,7 +3098,7 @@ let @test false catch err @test isa(err, TypeError) - @test err.func == :NTuple + @test err.func == :apply_type @test err.expected == Int @test err.got == Int end @@ -3108,7 +3108,7 @@ let @test false catch err @test isa(err, TypeError) - @test err.func == :NTuple + @test err.func == :apply_type @test err.expected == Int @test err.got == 0x1 end From 8dc43c5068b24983bce146088b2a8f13283991bd Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 3 Jan 2016 15:09:34 -0600 Subject: [PATCH 25/32] Re-fix #12092 --- src/jltypes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index 6ab987a4a8560..aea66b5b867ea 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2646,7 +2646,7 @@ static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int inv if (!pseq) pseq = (pi= clenf && !cseq) - return some_morespecific || pi>=plenf || (pseq && !invariant); + return 1; if (pi >= plenf && !pseq) return some_morespecific; if (ci < clenr) { From 908047bf2d8c32468817acfaf9c9f68f2d7ceb82 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 Jan 2016 07:45:44 -0600 Subject: [PATCH 26/32] Rename enum types --- src/jltypes.c | 22 +++++++++++----------- src/julia.h | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index aea66b5b867ea..e643789dcdfb7 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -421,11 +421,11 @@ In general, lenf >= lenr-1. The lower bound is achieved only for a Vararg of len typedef enum { JL_TUPLE_FIXED = 0, JL_TUPLE_VAR = 1 -} JL_TUPLE_LENKIND; +} jl_tuple_lenkind_t; // Set the parameters for a single tuple // returns lenf, sets kind and lenkind -static size_t data_vararg_params(jl_value_t **data, size_t lenr, cenv_t *eqc, JL_VARARG_KIND *kind, JL_TUPLE_LENKIND *lenkind) +static size_t data_vararg_params(jl_value_t **data, size_t lenr, cenv_t *eqc, jl_vararg_kind_t *kind, jl_tuple_lenkind_t *lenkind) { size_t lenf = lenr; int i; @@ -456,7 +456,7 @@ static size_t data_vararg_params(jl_value_t **data, size_t lenr, cenv_t *eqc, JL return lenf; } -static size_t tuple_vararg_params(jl_svec_t *a, cenv_t *eqc, JL_VARARG_KIND *kind, JL_TUPLE_LENKIND *lenkind) +static size_t tuple_vararg_params(jl_svec_t *a, cenv_t *eqc, jl_vararg_kind_t *kind, jl_tuple_lenkind_t *lenkind) { return data_vararg_params(jl_svec_data(a), jl_svec_len(a), eqc, kind, lenkind); } @@ -529,8 +529,8 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, jl_svec_t *ap = a->parameters, *bp = b->parameters; size_t alenr = jl_svec_len(ap), blenr = jl_svec_len(bp); size_t alenf, blenf; - JL_VARARG_KIND akind, bkind; - JL_TUPLE_LENKIND alenkind, blenkind; + jl_vararg_kind_t akind, bkind; + jl_tuple_lenkind_t alenkind, blenkind; int bottom = 0; size_t n; // Stage 1 @@ -2421,8 +2421,8 @@ static int jl_tuple_subtype_(jl_value_t **child, size_t clenr, size_t plenr = jl_nparams(pdt); jl_value_t **parent = jl_svec_data(pdt->parameters); size_t plenf, clenf; - JL_VARARG_KIND ckind, pkind; - JL_TUPLE_LENKIND clenkind, plenkind; + jl_vararg_kind_t ckind, pkind; + jl_tuple_lenkind_t clenkind, plenkind; int bottom = 0; // Stage 1 clenf = data_vararg_params(child, clenr, NULL, &ckind, &clenkind); @@ -2632,8 +2632,8 @@ static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int inv size_t plenr = jl_nparams(pdt); jl_value_t **parent = jl_svec_data(pdt->parameters); size_t plenf, clenf; - JL_VARARG_KIND ckind, pkind; - JL_TUPLE_LENKIND clenkind, plenkind; + jl_vararg_kind_t ckind, pkind; + jl_tuple_lenkind_t clenkind, plenkind; clenf = tuple_vararg_params(cdt->parameters, NULL, &ckind, &clenkind); plenf = tuple_vararg_params(pdt->parameters, NULL, &pkind, &plenkind); size_t ci=0, pi=0; @@ -2851,8 +2851,8 @@ static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, size_t clenr = jl_nparams(child); size_t plenr = jl_nparams(parent); size_t plenf, clenf; - JL_VARARG_KIND ckind, pkind; - JL_TUPLE_LENKIND clenkind, plenkind; + jl_vararg_kind_t ckind, pkind; + jl_tuple_lenkind_t clenkind, plenkind; clenf = tuple_vararg_params(child->parameters, NULL, &ckind, &clenkind); plenf = tuple_vararg_params(parent->parameters, NULL, &pkind, &plenkind); int cseq=0, pseq=0; diff --git a/src/julia.h b/src/julia.h index f4bc5effbd364..f4d5facc0f85d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1065,7 +1065,7 @@ typedef enum { JL_VARARG_INT = 1, JL_VARARG_BOUND = 2, JL_VARARG_UNBOUND = 3 -} JL_VARARG_KIND; +} jl_vararg_kind_t; STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) { @@ -1073,7 +1073,7 @@ STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) ((jl_datatype_t*)(v))->name == jl_vararg_type->name); } -STATIC_INLINE JL_VARARG_KIND jl_vararg_kind(jl_value_t *v) +STATIC_INLINE jl_vararg_kind_t jl_vararg_kind(jl_value_t *v) { if (!jl_is_vararg_type(v)) return JL_VARARG_NONE; @@ -1092,7 +1092,7 @@ STATIC_INLINE int jl_is_va_tuple(jl_datatype_t *t) return (l>0 && jl_is_vararg_type(jl_tparam(t,l-1))); } -STATIC_INLINE JL_VARARG_KIND jl_va_tuple_kind(jl_datatype_t *t) +STATIC_INLINE jl_vararg_kind_t jl_va_tuple_kind(jl_datatype_t *t) { assert(jl_is_tuple_type(t)); size_t l = jl_svec_len(t->parameters); From ddf288b1395a99d9d42cc5ada4f76ff25bcb72c5 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 10 Jan 2016 07:57:19 -0600 Subject: [PATCH 27/32] Delete unused inst_tupletype_unchecked_uncached --- src/jltypes.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index e643789dcdfb7..572cd3a5d3096 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2207,11 +2207,6 @@ jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np) return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, 0, NULL, NULL, 0); } -static jl_datatype_t *inst_tupletype_unchecked_uncached(jl_svec_t *p) -{ - return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 0, 1, NULL, NULL, 0); -} - static jl_svec_t *inst_all(jl_svec_t *p, jl_value_t **env, size_t n, jl_typestack_t *stack, int check) { From ac9ed2be7042f8e6dbd93602e511248721263f13 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 9 Apr 2016 22:02:06 -0500 Subject: [PATCH 28/32] Fix Vararg method printing --- base/methodshow.jl | 38 +++++++++++++++++++++++++------------- test/show.jl | 26 ++++++++++++-------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/base/methodshow.jl b/base/methodshow.jl index 6dd20826e3f31..9b3257c8cb39b 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -10,9 +10,6 @@ function get_lambda(m::TypeMapEntry) end function argtype_decl(env, n, t) # -> (argname, argtype) - if isvarargtype(t) - return argtype_decl_vararg(env, n, t) - end if isa(n,Expr) n = n.args[1] # handle n::T in arg list end @@ -24,20 +21,35 @@ function argtype_decl(env, n, t) # -> (argname, argtype) if t === Any && !isempty(s) return s, "" end - return s, string(t) + if isvarargtype(t) + 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 == ByteString + return s, "ByteString" + end + return s, string_with_env(env, t) end function argtype_decl_vararg(env, n, t) - 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]) * "..." + 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 == ByteString + return s, "ByteString" end - elseif t == ByteString - return s, "ByteString" end # x::Vararg, x::Vararg{T}, or x::Vararg{T,N} declaration s, length(n.args[2].args) < 4 ? diff --git a/test/show.jl b/test/show.jl index fc630d432b653..e1ee82a8ce59f 100644 --- a/test/show.jl +++ b/test/show.jl @@ -400,22 +400,20 @@ function test_mt(f, str) io = IOBuffer() show(io, defs) strio = takebuf_string(io) + strio = split(strio, " at")[1] @test strio[1:length(str)] == str end -begin - local f1, f2, f3, f4, f5 - f1(x...) = [x...] - f2(x::Vararg{Any}) = [x...] - f3(x::Vararg) = [x...] - f4(x::Vararg{Any,3}) = [x...] - f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{Int,N}) = [indexes...] - test_mt(f1, "f1(x...)") - test_mt(f2, "f2(x::Vararg{Any})") - test_mt(f3, "f3(x::Vararg{T<:Any})") # FIXME? better as x::Vararg? -# test_mt(f4, "f4(x::Vararg{Any,3})") - intstr = string(Int) - test_mt(f5, "f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{$intstr,N})") -end +show_f1(x...) = [x...] +show_f2(x::Vararg{Any}) = [x...] +show_f3(x::Vararg) = [x...] +show_f4(x::Vararg{Any,3}) = [x...] +show_f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{Int,N}) = [indexes...] +test_mt(show_f1, "show_f1(x...)") +test_mt(show_f2, "show_f2(x...)") +test_mt(show_f3, "show_f3(x...)") +test_mt(show_f4, "show_f4(x::Vararg{Any,3})") +intstr = string(Int) +test_mt(show_f5, "show_f5{T,N}(A::AbstractArray{T,N}, indexes::Vararg{$intstr,N})") # Issue #15525, printing of vcat @test sprint(show, :([a;])) == ":([a;])" From 9f3f07537d410d8dd4f6cf0f18c0860afbc79754 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 29 Apr 2016 19:15:19 -0400 Subject: [PATCH 29/32] normalize more Tuple{Vararg{T,N}} to Tuple{T,...} c.f. "Instantiate Tuple{Vararg{Int,3}} as Tuple{Int,Int,Int}" --- src/jltypes.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index 572cd3a5d3096..0ae942695f708 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2056,6 +2056,18 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i if (stack_lkup) return stack_lkup; + if (istuple && ntp == 1 && jl_is_vararg_type(iparams[0])) { + // normalize Tuple{Vararg{Int,3}} to Tuple{Int,Int,Int} + jl_datatype_t *va = (jl_datatype_t*)iparams[0]; + if (jl_is_long(jl_tparam1(va))) { + ssize_t nt = jl_unbox_long(jl_tparam1(va)); + if (nt < 0) + jl_errorf("apply_type: Vararg length N is negative: %zd", nt); + if (jl_is_leaf_type(jl_tparam0(va))) + return jl_tupletype_fill(nt, jl_tparam0(va)); + } + } + // always use original type constructor if (!istuple) { if (jl_is_vararg_type((jl_value_t*)dt) && ntp == 2) { @@ -2163,15 +2175,6 @@ static void check_tuple_parameter(jl_value_t *pi, size_t i, size_t np) static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params) { - if (np == 1 && jl_is_vararg_type(p[0])) { - jl_datatype_t *va = (jl_datatype_t*)p[0]; - if (jl_is_long(jl_tparam1(va))) { - ssize_t nt = jl_unbox_long(jl_tparam1(va)); - if (nt < 0) - jl_errorf("size or dimension is negative: %zd", nt); - return (jl_tupletype_t*)jl_tupletype_fill(nt, jl_tparam0(va)); - } - } int isabstract = 0, cacheable = 1; for(size_t i=0; i < np; i++) { jl_value_t *pi = p[i]; From 0bd3fb56650cb145974816a24acaf31c0ca3a74f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 29 Apr 2016 20:40:18 -0400 Subject: [PATCH 30/32] apply type-signature correction to ml-matches this ensures that type-inference gets the same method signature from type-intersection as will be used for the actual call --- src/gf.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gf.c b/src/gf.c index ca0e785969250..265ddf5b64aa8 100644 --- a/src/gf.c +++ b/src/gf.c @@ -628,7 +628,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca jl_svecset(newparams, i, jl_any_type); } origtype = jl_apply_tuple_type(newparams); - temp = origtype; + temp = (jl_value_t*)origtype; } // here we infer types and specialize the method @@ -1676,7 +1676,7 @@ static int tvar_exists_at_top_level(jl_value_t *tv, jl_tupletype_t *sig, int att struct ml_matches_env { struct typemap_intersection_env match; jl_value_t *t; - jl_svec_t *matc; + jl_value_t *matc; int lim; }; static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure0) @@ -1689,7 +1689,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio more generally, we can stop when the type is a subtype of the union of all the signatures examined so far. */ - assert(ml->func.linfo); + assert(ml->func.method); int skip = 0; size_t len = jl_array_len(closure->t); if (closure->lim >= 0) { @@ -1725,7 +1725,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio closure->t = (jl_value_t*)jl_false; return 0; // terminate search } - closure->matc = jl_svec(3, closure->match.ti, closure->match.env, ml); + closure->matc = (jl_value_t*)join_tsig((jl_tupletype_t*)closure->match.ti, ml->sig); + closure->matc = (jl_value_t*)jl_svec(3, closure->matc, closure->match.env, ml); /* Check whether all static parameters matched. If not, then we have an argument type like Vector{T{Int,_}}, and a signature like From 578fe68c917f39b4fae1720cbabd02a318b3cfc4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 1 May 2016 20:06:59 -0400 Subject: [PATCH 31/32] move normalization of Varargs type signature tuple earlier --- base/inference.jl | 107 +++++++++++++++++++-------------------------- base/tuple.jl | 18 +++++++- src/codegen.cpp | 19 ++++---- src/gf.c | 109 ++++++++++++++++++++++++++++++++++++---------- src/julia.h | 4 ++ src/typemap.c | 2 +- 6 files changed, 162 insertions(+), 97 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index f48b1735918fc..22e3576ecdf09 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -91,48 +91,33 @@ type InferenceState n = length(linfo.code) s = Any[ () for i=1:n ] # initial types - s[1] = Any[ VarState(Bottom,true) for i=1:nslots ] + s[1] = Any[ VarState(Bottom, true) for i=1:nslots ] la = linfo.nargs - if la > 0 - if linfo.isva - if atypes === Tuple - if la > 1 - atypes = Tuple{Any[Any for i=1:la-1]..., Tuple.parameters[1]} - end - s[1][la] = VarState(Tuple,false) + if atypes === Tuple + if la > 0 + if linfo.isva + atypes = Tuple{Any[Any for i = 1:la-1]..., Tuple{Vararg{Any}}} else - s[1][la] = VarState(tuple_tfunc(limit_tuple_depth(tupletype_tail(atypes,la))),false) + atypes = Tuple{Any[Any for i = 1:la]...} end - la -= 1 + else + atypes = Tuple{} end end - laty = length(atypes.parameters) - if laty > 0 - lastatype = atypes.parameters[laty] - if isvarargtype(lastatype) - lastatype = lastatype.parameters[1] - laty -= 1 - end - if isa(lastatype, TypeVar) - lastatype = lastatype.ub - end - if laty > la - laty = la - end - for i=1:laty + @assert la == laty # wrong number of arguments + if la > 0 + for i = 1:la atyp = atypes.parameters[i] if isa(atyp, TypeVar) atyp = atyp.ub end s[1][i] = VarState(atyp, false) end - for i=laty+1:la - s[1][i] = VarState(lastatype, false) + if linfo.isva + s[1][la] = VarState(limit_tuple_depth(s[1][la].typ), false) end - else - @assert la == 0 # wrong number of arguments end gensym_uses = find_gensym_uses(linfo.code) @@ -755,14 +740,17 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv) # limit argument type tuple growth lsig = length(m[3].sig.parameters) - ls = length(sig.parameters) # look at the existing edges to detect growing argument lists limitlength = false - for (callee, _) in sv.edges - callee = callee::InferenceState - if method === callee.linfo.def && ls > length(callee.atypes.parameters) - limitlength = true - break + isva = m[3].va #!isempty(m[3].sig) && isvarargtype(m[3].sig[end]) + if isva + nva = length(sig.parameters[end].parameters) + for (callee, _) in sv.edges + callee = callee::InferenceState + if method === callee.linfo.def && nva > length(callee.atypes.parameters[end].parameters) + limitlength = true + break + end end end @@ -773,7 +761,7 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv) infstate = infstate::InferenceState if isdefined(infstate.linfo, :def) && method === infstate.linfo.def td = type_depth(sig) - if ls > length(infstate.atypes.parameters) + if isva && nva > length(infstate.atypes.parameters[end].parameters) limitlength = true end if td > type_depth(infstate.atypes) @@ -783,26 +771,24 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv) break else p1, p2 = sig.parameters, infstate.atypes.parameters - if length(p2) == ls - limitdepth = false - newsig = Array(Any, ls) - for i = 1:ls - if p1[i] <: Function && type_depth(p1[i]) > type_depth(p2[i]) && - isa(p1[i],DataType) - # if a Function argument is growing (e.g. nested closures) - # then widen to the outermost function type. without this - # inference fails to terminate on do_quadgk. - newsig[i] = p1[i].name.primary - limitdepth = true - else - newsig[i] = limit_type_depth(p1[i], 1, true, []) - end - end - if limitdepth - sig = Tuple{newsig...} - break + limitdepth = false + newsig = Array(Any, lsig) + for i = 1:lsig + if p1[i] <: Function && type_depth(p1[i]) > type_depth(p2[i]) && + isa(p1[i],DataType) + # if a Function argument is growing (e.g. nested closures) + # then widen to the outermost function type. without this + # inference fails to terminate on do_quadgk. + newsig[i] = p1[i].name.primary + limitdepth = true + else + newsig[i] = limit_type_depth(p1[i], 1, true, []) end end + if limitdepth + sig = Tuple{newsig...} + break + end end end end @@ -817,21 +803,23 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv) # limit length based on size of definition signature. # for example, given function f(T, Any...), limit to 3 arguments # instead of the default (MAX_TUPLETYPE_LEN) - if limitlength && ls > lsig + 1 + if limitlength && nva > 1 if !istopfunction(tm, f, :promote_typeof) - fst = sig.parameters[lsig+1] + vaty = sig.parameters[end] + fst = vaty.parameters[1] allsame = true # allow specializing on longer arglists if all the trailing # arguments are the same, since there is no exponential # blowup in this case. - for i = lsig+2:ls - if sig.parameters[i] != fst + for i = 2:length(vaty.parameters) + if vaty.parameters[i] != fst allsame = false break end end if !allsame - sig = limit_tuple_type_n(sig, lsig+1) + vaty = limit_tuple_type_n(vaty, 1) + sig = Tuple{sig.parameters[1:end-1]..., vaty} end end end @@ -1409,9 +1397,6 @@ end function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool, optimize::Bool, cached::Bool, caller) #println(method) - if method.module === Core && isempty(method.lambda_template.sparam_syms) - atypes = Tuple - end local frame = nothing offs = 0 # check cached t-functions diff --git a/base/tuple.jl b/base/tuple.jl index 030e8ead2a04d..987ddac94d999 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -2,6 +2,14 @@ ## indexing ## +length{T<:Tuple}(t::Type{T}) = length(t.parameters) +endof{T<:Tuple}(t::Type{T}) = length(t) +size{T<:Tuple}(t::Type{T}, d) = d==1 ? length(t) : throw(ArgumentError("invalid tuple dimension $d")) +getindex{T<:Tuple}(t::Type{T}, i::Int) = t.parameters[i] +getindex{T<:Tuple}(t::Type{T}, i::Real) = getindex(t, convert(Int, i)) +getindex{T<:Tuple}(t::Type{T}, r::AbstractArray) = Tuple{[t[ri] for ri in r]...} +getindex{T<:Tuple}(t::Type{T}, b::AbstractArray{Bool}) = getindex(t, find(b)) + length(t::Tuple) = nfields(t) endof(t::Tuple) = length(t) size(t::Tuple, d) = d==1 ? length(t) : throw(ArgumentError("invalid tuple dimension $d")) @@ -12,6 +20,12 @@ getindex(t::Tuple, b::AbstractArray{Bool}) = getindex(t,find(b)) ## iterating ## +start{T<:Tuple}(t::Type{T}) = 1 +done{T<:Tuple}(t::Type{T}, i::Int) = (length(t) < i) +next{T<:Tuple}(t::Type{T}, i::Int) = (t.parameters[i], i + 1) + +eachindex{T<:Tuple}(t::Type{T}) = 1:length(t) + start(t::Tuple) = 1 done(t::Tuple, i::Int) = (length(t) < i) next(t::Tuple, i::Int) = (t[i], i+1) @@ -30,8 +44,8 @@ end # this allows partial evaluation of bounded sequences of next() calls on tuples, # while reducing to plain next() for arbitrary iterables. -indexed_next(t::Tuple, i::Int, state) = (t[i], i+1) -indexed_next(a::Array, i::Int, state) = (a[i], i+1) +indexed_next(t::Tuple, i::Int, state) = (t[i], i + 1) +indexed_next(a::Array, i::Int, state) = (a[i], i + 1) indexed_next(I, i, state) = done(I,state) ? throw(BoundsError()) : next(I, state) # eltype diff --git a/src/codegen.cpp b/src/codegen.cpp index f297a828538ed..4cbb211e42026 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3990,17 +3990,19 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func size_t vinfoslen = jl_array_dim0(lam->slotnames); ctx.slots.resize(vinfoslen); size_t nreq = largslen; - int va = 0; assert(lam->specTypes); // this could happen if the user tries to compile a generic-function // without specializing (or unspecializing) it first // compiling this would cause all specializations to inherit // this code and could create an broken compile / function cache - if (nreq > 0 && lam->isva) { + int va = lam->isva; + if (lam->def && lam->def->isstaged && lam == lam->def->lambda_template) + va = 0; // TODO: this method shouldn't have been marked as va + if (va) { + assert(nreq > 0); nreq--; - va = 1; - jl_sym_t *vn = (jl_sym_t*)jl_cellref(lam->slotnames,largslen-1); + jl_sym_t *vn = (jl_sym_t*)jl_cellref(lam->slotnames, largslen - 1); if (vn != unused_sym) ctx.vaSlot = largslen-1; } @@ -4012,19 +4014,14 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func // step 3. some variable analysis size_t i; - for(i=0; i < nreq; i++) { - jl_sym_t *argname = (jl_sym_t*)jl_cellref(lam->slotnames,i); + for(i=0; i < largslen; i++) { + jl_sym_t *argname = (jl_sym_t*)jl_cellref(lam->slotnames, i); if (argname == unused_sym) continue; jl_varinfo_t &varinfo = ctx.slots[i]; varinfo.isArgument = true; jl_value_t *ty = jl_nth_slot_type(lam->specTypes, i); varinfo.value = mark_julia_type((Value*)NULL, false, ty, &ctx); } - if (va && ctx.vaSlot != -1) { - jl_varinfo_t &varinfo = ctx.slots[ctx.vaSlot]; - varinfo.isArgument = true; - varinfo.value = mark_julia_type((Value*)NULL, false, jl_tuple_type, &ctx); - } for(i=0; i < vinfoslen; i++) { jl_varinfo_t &varinfo = ctx.slots[i]; diff --git a/src/gf.c b/src/gf.c index 265ddf5b64aa8..8d77a17d3867e 100644 --- a/src/gf.c +++ b/src/gf.c @@ -305,18 +305,76 @@ jl_value_t *jl_nth_slot_type(jl_tupletype_t *sig, size_t i) return NULL; } +// for varargs functions, the argument tuple type needs to be corrected to reflect the number of arguments +static jl_tupletype_t *join_varargs(jl_tupletype_t *tt, jl_tupletype_t *sig) +{ + size_t np = jl_nparams(tt), nsig = jl_datatype_nfields(sig); + if (nsig == 0) + return tt; + jl_value_t *va = jl_tparam(sig, nsig - 1); + if (jl_is_vararg_type(va)) { + va = jl_tparam0(va); + size_t i, n = nsig - 1; + jl_svec_t *newparams = jl_alloc_svec(nsig); + JL_GC_PUSH1(&newparams); + for (i = 0; i < n; i++) { + jl_svecset(newparams, i, jl_svecref(tt->parameters, i)); + } + jl_svec_t *p = jl_alloc_svec(np - n); + jl_svecset(newparams, n, p); + for (i = n; i < np; i++) { + jl_value_t *elt = jl_svecref(tt->parameters, i); + jl_value_t *va_N = NULL; + jl_svecset(p, i - n, elt); + if (jl_is_vararg_type(elt)) { + va_N = jl_tparam1(elt); + elt = jl_tparam0(elt); + } + if (jl_is_type_type(elt)) { + elt = jl_typeof(jl_tparam0(elt)); + if (elt == (jl_value_t*)jl_tvar_type) + elt = (jl_value_t*)jl_type_type; + if (va_N) + elt = (jl_value_t*)jl_wrap_vararg(elt, va_N); + jl_svecset(p, i - n, elt); + } + assert(elt != (jl_value_t*)jl_tvar_type); + } + jl_svecset(newparams, n, jl_apply_tuple_type(p)); + tt = jl_apply_tuple_type(newparams); + JL_GC_POP(); + } + return tt; +} + // after intersection, the argument tuple type needs to be corrected to reflect the signature match // that occurred, if the arguments contained a Type but the signature matched on the kind static jl_tupletype_t *join_tsig(jl_tupletype_t *tt, jl_tupletype_t *sig) { + size_t i, n, np = jl_nparams(tt), nsig = jl_datatype_nfields(sig); + if (nsig == 0) + return tt; jl_svec_t *newparams = NULL; JL_GC_PUSH1(&newparams); - int changed = 0; - size_t i, np; - for (i = 0, np = jl_nparams(tt); i < np; i++) { - jl_value_t *elt = jl_tparam(tt, i); + jl_value_t *va = jl_tparam(sig, nsig - 1); + if (va && jl_is_vararg_type(va)) { + va = jl_tparam0(va); + n = nsig - 1; + assert(np >= n); + } + else { + va = NULL; + n = nsig; + assert(np == nsig); + } + for (i = 0; i < np; i++) { jl_value_t *newelt = NULL; - jl_value_t *decl_i = jl_nth_slot_type(sig, i); + jl_value_t *elt = jl_tparam(tt, i); + jl_value_t *decl_i; + if (va == NULL || i < n) + decl_i = jl_tparam(sig, i); + else + decl_i = va; if (jl_is_type_type(elt)) { // if the declared type was not Any or Union{Type, ...}, @@ -341,21 +399,19 @@ static jl_tupletype_t *join_tsig(jl_tupletype_t *tt, jl_tupletype_t *sig) } // prepare to build a new type with the replacement above if (newelt) { - if (!changed) { + if (newparams == NULL) newparams = jl_svec_copy(tt->parameters); - changed = 1; - } jl_svecset(newparams, i, newelt); } } - if (changed) + if (newparams) tt = jl_apply_tuple_type(newparams); JL_GC_POP(); return tt; } static jl_value_t *ml_matches(union jl_typemap_t ml, int offs, - jl_tupletype_t *type, int lim); + jl_tupletype_t *type, int vsig, int lim); static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *cache, jl_value_t *parent, jl_tupletype_t *type, jl_tupletype_t *origtype, @@ -372,10 +428,10 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca jl_value_t *temp=NULL; jl_value_t *temp2=NULL; jl_value_t *temp3=NULL; - jl_lambda_info_t *newmeth=NULL; + jl_value_t *temp4=NULL; jl_svec_t *newparams=NULL; jl_svec_t *limited=NULL; - JL_GC_PUSH5(&temp, &temp2, &temp3, &newmeth, &newparams); + JL_GC_PUSH5(&temp, &temp2, &temp3, &temp4, &newparams); size_t np = jl_nparams(type); newparams = jl_svec_copy(type->parameters); if (type == origtype) @@ -560,7 +616,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca temp2 = (jl_value_t*)type; } if (need_guard_entries) { - temp = ml_matches(mt->defs, 0, type, -1); // TODO: use MAX_UNSPECIALIZED_CONFLICTS? + temp = ml_matches(mt->defs, 0, type, 0, -1); // TODO: use MAX_UNSPECIALIZED_CONFLICTS? int guards = 0; if (temp == jl_false) { cache_with_orig = 1; @@ -634,6 +690,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca // here we infer types and specialize the method jl_array_t *lilist=NULL; jl_lambda_info_t *li=NULL; + temp4 = (jl_value_t*)join_varargs(type, decl); if (definition->specializations != NULL) { // reuse code already generated for this combination of lambda and // arguments types. this happens for inner generic functions where @@ -642,7 +699,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca int k; for(k=0; k < lilist->nrows; k++) { li = (jl_lambda_info_t*)jl_cellref(lilist, k); - if (jl_types_equal((jl_value_t*)li->specTypes, (jl_value_t*)type)) + if (jl_types_equal((jl_value_t*)li->specTypes, temp4)) break; } if (k == lilist->nrows) lilist=NULL; @@ -650,14 +707,15 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca if (lilist != NULL && !li->inInference) { assert(li); - newmeth = li; - jl_typemap_insert(cache, parent, type, jl_emptysvec, origtype, guardsigs, (jl_value_t*)newmeth, jl_cachearg_offset(mt), &lambda_cache, NULL); + temp4 = (jl_value_t*)li; + jl_typemap_insert(cache, parent, type, jl_emptysvec, origtype, guardsigs, (jl_value_t*)li, jl_cachearg_offset(mt), &lambda_cache, NULL); JL_GC_POP(); JL_UNLOCK(&codegen_lock); - return newmeth; + return li; } - newmeth = jl_get_specialized(definition, type, sparams); + jl_lambda_info_t *newmeth = jl_get_specialized(definition, (jl_tupletype_t*)temp4, sparams); + temp4 = (jl_value_t*)newmeth; jl_typemap_insert(cache, parent, type, jl_emptysvec, origtype, guardsigs, (jl_value_t*)newmeth, jl_cachearg_offset(mt), &lambda_cache, NULL); if (newmeth->code != NULL) { @@ -698,10 +756,13 @@ static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t * sig = join_tsig(tt, m->sig); jl_lambda_info_t *nf; - if (!cache) + if (!cache) { + sig = join_varargs(sig, m->sig); nf = jl_get_specialized(m->func.method, sig, env); - else + } + else { nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, sig, tt, m, env); + } JL_GC_POP(); return nf; } @@ -1678,6 +1739,7 @@ struct ml_matches_env { jl_value_t *t; jl_value_t *matc; int lim; + int vsig; }; static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersection_env *closure0) { @@ -1726,6 +1788,8 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio return 0; // terminate search } closure->matc = (jl_value_t*)join_tsig((jl_tupletype_t*)closure->match.ti, ml->sig); + if (closure->vsig) + closure->matc = (jl_value_t*)join_varargs((jl_tupletype_t*)closure->matc, ml->sig); closure->matc = (jl_value_t*)jl_svec(3, closure->matc, closure->match.env, ml); /* Check whether all static parameters matched. If not, then we @@ -1773,7 +1837,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio // // returns a match as and array of svec(argtypes, static_params, Method) static jl_value_t *ml_matches(union jl_typemap_t defs, int offs, - jl_tupletype_t *type, int lim) + jl_tupletype_t *type, int vsig, int lim) { size_t l = jl_svec_len(type->parameters); jl_value_t *va = NULL; @@ -1793,6 +1857,7 @@ static jl_value_t *ml_matches(union jl_typemap_t defs, int offs, env.t = jl_an_empty_cell; env.matc = NULL; env.lim = lim; + env.vsig = vsig; JL_GC_PUSH4(&env.t, &env.matc, &env.match.env, &env.match.ti); jl_typemap_intersection_visitor(defs, offs, &env.match); JL_GC_POP(); @@ -1815,7 +1880,7 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim) jl_methtable_t *mt = ((jl_datatype_t*)jl_tparam0(types))->name->mt; if (mt == NULL) return (jl_value_t*)jl_alloc_cell_1d(0); - return ml_matches(mt->defs, 0, types, lim); + return ml_matches(mt->defs, 0, types, 1, lim); } #ifdef __cplusplus diff --git a/src/julia.h b/src/julia.h index f4d5facc0f85d..c2fd4e8fa9c61 100644 --- a/src/julia.h +++ b/src/julia.h @@ -596,6 +596,10 @@ typedef struct _jl_gcframe_t { void *__gc_stkf[] = {(void*)11, jl_pgcstack, arg1, arg2, arg3, arg4, arg5}; \ jl_pgcstack = (jl_gcframe_t*)__gc_stkf; +#define JL_GC_PUSH6(arg1, arg2, arg3, arg4, arg5, arg6) \ + void *__gc_stkf[] = {(void*)13, jl_pgcstack, arg1, arg2, arg3, arg4, arg5, arg6}; \ + jl_pgcstack = (jl_gcframe_t*)__gc_stkf; + #define JL_GC_PUSHARGS(rts_var,n) \ rts_var = ((jl_value_t**)alloca(((n)+2)*sizeof(jl_value_t*)))+2; \ ((void**)rts_var)[-2] = (void*)(((size_t)(n))<<1); \ diff --git a/src/typemap.c b/src/typemap.c index e311b075f45e3..0e1c800581c9d 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -394,7 +394,7 @@ int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, jl_typemap_level_t *cache = map.node; jl_value_t *ty = NULL; size_t l = jl_datatype_nfields(closure->type); - if (closure->va && l == offs - 1) { + if (closure->va && l == offs - 1) { // TODO: l >= offs - 1 ? ty = closure->va; } else if (l > offs) { From 47101ac74e97d47f87f98d118a28d198bc50aba0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 1 May 2016 20:18:16 -0400 Subject: [PATCH 32/32] fix typemap va marking rebase error --- src/typemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/typemap.c b/src/typemap.c index 0e1c800581c9d..7b4a5bec13a65 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -841,7 +841,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par jl_gc_wb(ml, ml->simplesig); ml->tvars = tvars; jl_gc_wb(ml, ml->tvars); - ml->va = jl_va_tuple_kind(type) == JL_VARARG_UNBOUND; + ml->va = jl_is_va_tuple(type); // TODO: `l->func` or `l->func->roots` might need to be rooted ml->func.value = newvalue; if (newvalue) @@ -861,7 +861,7 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par newrec->guardsigs = guardsigs; newrec->next = (jl_typemap_entry_t*)jl_nothing; // compute the complexity of this type signature - newrec->va = jl_va_tuple_kind(type) == JL_VARARG_UNBOUND; + newrec->va = jl_is_va_tuple(type); newrec->issimplesig = (tvars == jl_emptysvec); // a TypeVar environment needs an complex matching test newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted JL_GC_PUSH1(&newrec);