From 71b392ca3b1e2db691969e4ba30f6bdd5fa8ad41 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 4 Nov 2016 18:23:18 -0400 Subject: [PATCH] make type declarations with triangular constraints work properly e.g. fixes #6721 fixes to type instantiation --- base/abstractarray.jl | 3 +- base/array.jl | 4 + base/boot.jl | 3 +- base/deprecated.jl | 12 +-- base/dict.jl | 2 +- base/docs/Docs.jl | 11 +-- base/inference.jl | 4 +- base/reflection.jl | 3 +- base/sparse/cholmod.jl | 2 +- base/weakkeydict.jl | 2 +- src/alloc.c | 24 +----- src/builtins.c | 5 ++ src/dump.c | 2 +- src/gf.c | 16 ++-- src/jltypes.c | 187 +++++++++++++++++++++++++++-------------- src/julia.h | 2 +- src/julia_internal.h | 5 +- src/subtype.c | 132 ++++++++++++++++++++--------- src/toplevel.c | 20 ++++- src/typemap.c | 10 ++- test/subtype.jl | 16 +++- 21 files changed, 294 insertions(+), 171 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 64d58c2bc8a95..add0624734e55 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -267,6 +267,7 @@ should define `linearindexing` in the type-domain: Base.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearFast() """ linearindexing(A::AbstractArray) = linearindexing(typeof(A)) +linearindexing(::Type{Union{}}) = LinearFast() linearindexing{T<:AbstractArray}(::Type{T}) = LinearSlow() linearindexing{T<:Array}(::Type{T}) = LinearFast() linearindexing{T<:Range}(::Type{T}) = LinearFast() @@ -1023,8 +1024,6 @@ promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...)) #TODO: ERROR CHECK cat(catdim::Integer) = Array{Any,1}(0) -vcat() = Array{Any,1}(0) -hcat() = Array{Any,1}(0) typed_vcat{T}(::Type{T}) = Array{T,1}(0) typed_hcat{T}(::Type{T}) = Array{T,1}(0) diff --git a/base/array.jl b/base/array.jl index 9d0e73d2c9e8b..58d7c11fdc463 100644 --- a/base/array.jl +++ b/base/array.jl @@ -996,6 +996,10 @@ end # concatenations of homogeneous combinations of vectors, horizontal and vertical + +vcat() = Array{Any,1}(0) +hcat() = Array{Any,1}(0) + function hcat{T}(V::Vector{T}...) height = length(V[1]) for j = 2:length(V) diff --git a/base/boot.jl b/base/boot.jl index 7c21918ad5cef..641aa41197653 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -263,8 +263,7 @@ TypeVar(n::Symbol, ub::ANY) = TypeVar(n::Symbol, lb::ANY, ub::ANY) = ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, lb, ub) -UnionAll(v::TypeVar, t::ANY) = - ccall(:jl_new_unionall_type, Ref{UnionAll}, (Any, Any), v, t) +UnionAll(v::TypeVar, t::ANY) = ccall(:jl_type_unionall, Any, (Any, Any), v, t) Void() = nothing diff --git a/base/deprecated.jl b/base/deprecated.jl index e903cdcc52e90..7004cb0b09934 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -125,14 +125,14 @@ end @deprecate get_rounding rounding #13465 -@deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) Base.covm(x, mean, corrected) -@deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) Base.covm(X, mean, vardim, corrected) -@deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) Base.covm(x, mean[1], y, mean[2], corrected) +#@deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) Base.covm(x, mean, corrected) +#@deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) Base.covm(X, mean, vardim, corrected) +#@deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) Base.covm(x, mean[1], y, mean[2], corrected) @deprecate cov(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, corrected=true, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.covm(X, mean[1], Y, mean[2], vardim, corrected) -@deprecate cor(x::AbstractVector; mean=Base.mean(x)) Base.corm(x, mean) -@deprecate cor(X::AbstractMatrix; vardim=1, mean=Base.mean(X, vardim)) Base.corm(X, mean, vardim) -@deprecate cor(x::AbstractVector, y::AbstractVector; mean=(Base.mean(x), Base.mean(y))) Base.corm(x, mean[1], y, mean[2]) +#@deprecate cor(x::AbstractVector; mean=Base.mean(x)) Base.corm(x, mean) +#@deprecate cor(X::AbstractMatrix; vardim=1, mean=Base.mean(X, vardim)) Base.corm(X, mean, vardim) +#@deprecate cor(x::AbstractVector, y::AbstractVector; mean=(Base.mean(x), Base.mean(y))) Base.corm(x, mean[1], y, mean[2]) @deprecate cor(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.corm(X, mean[1], Y, mean[2], vardim) @deprecate_binding SparseMatrix SparseArrays diff --git a/base/dict.jl b/base/dict.jl index e62a44ed26fd8..e2d2abc105331 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -137,7 +137,7 @@ const AnyDict = Dict{Any,Any} Dict{K,V}(ps::Pair{K,V}...) = Dict{K,V}(ps) Dict{K }(ps::Pair{K}...,) = Dict{K,Any}(ps) -Dict{V }(ps::Pair{TypeVar(:K),V}...,) = Dict{Any,V}(ps) +Dict{V }(ps::(Pair{K,V} where K)...,) = Dict{Any,V}(ps) Dict( ps::Pair...) = Dict{Any,Any}(ps) function Dict(kv) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 2ddcedfc0b07a..86759024e9bf6 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -88,7 +88,11 @@ function signature(expr::Expr) end push!(sig.args[end].args, argtype(arg)) end - Expr(:let, Expr(:block, sig), typevars(expr)...) + tv = typevars(expr) + for i = length(tv):-1:1 + sig = Expr(:where, sig, tv[i]) + end + sig else signature(expr.args[1]) end @@ -103,14 +107,11 @@ end argtype(other) = :Any function typevars(expr::Expr) - isexpr(expr, :curly) && return [tvar(x) for x in expr.args[2:end]] + isexpr(expr, :curly) && return expr.args[2:end] typevars(expr.args[1]) end typevars(::Symbol) = [] -tvar(x::Expr) = :($(x.args[1]) = TypeVar($(quot(x.args[1])), $(x.args[2]), true)) -tvar(s::Symbol) = :($(s) = TypeVar($(quot(s)), Any, true)) - # Docsystem types. # ================ diff --git a/base/inference.jl b/base/inference.jl index 166f4ed306836..e120ba25681fc 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -741,8 +741,8 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState) return Any end meth = entry.func - (ti, env) = ccall(:jl_match_method, Ref{SimpleVector}, (Any, Any, Any), - argtype, meth.sig, meth.tvars) + (ti, env) = ccall(:jl_match_method, Ref{SimpleVector}, (Any, Any), + argtype, meth.sig) return typeinf_edge(meth::Method, ti, env, sv) end diff --git a/base/reflection.jl b/base/reflection.jl index 49bfa092df172..f784581d63e48 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -559,8 +559,7 @@ function _dump_function(f::ANY, t::ANY, native::Bool, wrapper::Bool, t = to_tuple_type(t) ft = isa(f, Type) ? Type{f} : typeof(f) tt = Tuple{ft, t.parameters...} - (ti, env) = ccall(:jl_match_method, Any, (Any, Any, Any), - tt, meth.sig, meth.tvars)::SimpleVector + (ti, env) = ccall(:jl_match_method, Any, (Any, Any, Any), tt, meth.sig)::SimpleVector meth = func_for_method_checked(meth, tt) linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), meth, tt, env, world) # get the code for it diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 5bccc8f270c26..5998a19029215 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -1136,7 +1136,7 @@ sparse{Tv}(FC::FactorComponent{Tv,:LD}) = sparse(Sparse(Factor(FC))) # Calculate the offset into the stype field of the cholmod_sparse_struct and # change the value -let offset = fieldoffset(C_Sparse{Float64}, findfirst(name -> name === :stype, fieldnames(C_Sparse))) +let offset = fieldoffset(C_Sparse{Float64}, findfirst(name -> name === :stype, fieldnames(C_Sparse{Float64}))) global change_stype! function change_stype!(A::Sparse, i::Integer) unsafe_store!(convert(Ptr{Cint}, A.p), i, div(offset, 4) + 1) diff --git a/base/weakkeydict.jl b/base/weakkeydict.jl index 46ed3e5f3fc0a..87a3c6ecb52cd 100644 --- a/base/weakkeydict.jl +++ b/base/weakkeydict.jl @@ -48,7 +48,7 @@ copy(d::WeakKeyDict) = WeakKeyDict(d) WeakKeyDict{K,V}(ps::Pair{K,V}...) = WeakKeyDict{K,V}(ps) WeakKeyDict{K }(ps::Pair{K}...,) = WeakKeyDict{K,Any}(ps) -WeakKeyDict{V }(ps::Pair{TypeVar(:K),V}...,) = WeakKeyDict{Any,V}(ps) +WeakKeyDict{V }(ps::(Pair{K,V} where K)...,) = WeakKeyDict{Any,V}(ps) WeakKeyDict( ps::Pair...) = WeakKeyDict{Any,Any}(ps) function WeakKeyDict(kv) diff --git a/src/alloc.c b/src/alloc.c index 5709545e9f594..dc3a0c16ad9cd 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -688,11 +688,6 @@ jl_method_t *jl_new_method(jl_code_info_t *definition, m->tvars = (jl_svec_t*)jl_svecref(tvars, 0); else m->tvars = tvars; - int j; - for(j=(int)jl_svec_len(tvars)-1; j >= 0 ; j--) { - m->sig = jl_new_unionall_type((jl_tvar_t*)jl_svecref(tvars,j), m->sig); - jl_gc_wb(m, m->sig); - } m->sparam_syms = sparam_syms; root = (jl_value_t*)m; jl_method_set_source(m, definition); @@ -1170,7 +1165,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super int i; int np = jl_svec_len(parameters); for (i=np-1; i >= 0; i--) { - t->name->wrapper = (jl_value_t*)jl_new_unionall_type((jl_tvar_t*)jl_svecref(parameters,i), t->name->wrapper); + t->name->wrapper = jl_new_struct(jl_unionall_type, jl_svecref(parameters,i), t->name->wrapper); jl_gc_wb(t->name, t->name->wrapper); } } @@ -1207,23 +1202,6 @@ JL_DLLEXPORT jl_datatype_t *jl_new_bitstype(jl_value_t *name, jl_datatype_t *sup return bt; } -// unionall types ------------------------------------------------------------- - -JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) -{ - jl_ptls_t ptls = jl_get_ptls_states(); - jl_tvar_t *tv = (jl_tvar_t*)jl_gc_alloc(ptls, sizeof(jl_tvar_t), jl_tvar_type); - tv->name = name; - tv->lb = lb; - tv->ub = ub; - return tv; -} - -JL_DLLEXPORT jl_unionall_t *jl_new_unionall_type(jl_tvar_t *v, jl_value_t *body) -{ - return (jl_unionall_t*)jl_new_struct(jl_unionall_type, v, body); -} - // bits constructors ---------------------------------------------------------- #define BOXN_FUNC(nb,nw) \ diff --git a/src/builtins.c b/src/builtins.c index 24fd5530b305f..0b1c4e7ecec53 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1633,6 +1633,11 @@ JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) } // TODO: better way to show method parameters type = jl_unwrap_unionall(type); + if (!jl_is_datatype(type)) { + n += jl_printf(s, " "); + n += jl_static_show(s, type); + return n; + } size_t tl = jl_nparams(type); n += jl_printf(s, "("); size_t i; diff --git a/src/dump.c b/src/dump.c index 3439f7169b701..a2acbc4e8c75f 100644 --- a/src/dump.c +++ b/src/dump.c @@ -2845,7 +2845,7 @@ jl_method_instance_t *jl_recache_method_instance(jl_method_instance_t *li, size_ jl_datatype_t *argtypes = li->specTypes; jl_set_typeof(li, (void*)(intptr_t)0x40); // invalidate the old value to help catch errors jl_svec_t *env = jl_emptysvec; - jl_value_t *ti = jl_type_intersection_matching((jl_value_t*)m->sig, (jl_value_t*)argtypes, &env, m->tvars); + jl_value_t *ti = jl_type_intersection_matching((jl_value_t*)m->sig, (jl_value_t*)argtypes, &env); //assert(ti != jl_bottom_type); (void)ti; if (ti == jl_bottom_type) env = jl_emptysvec; // the intersection may fail now if the type system had made an incorrect subtype env in the past diff --git a/src/gf.c b/src/gf.c index f798a0549b676..9c5241996461b 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2267,8 +2267,7 @@ jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs else { tt = arg_type_tuple(args, nargs); if (entry->tvars != jl_emptysvec) { - jl_value_t *ti = - jl_lookup_match((jl_value_t*)tt, (jl_value_t*)entry->sig, &tpenv, entry->tvars); + jl_value_t *ti = jl_lookup_match((jl_value_t*)tt, (jl_value_t*)entry->sig, &tpenv); assert(ti != (jl_value_t*)jl_bottom_type); (void)ti; } @@ -2351,7 +2350,7 @@ JL_DLLEXPORT jl_value_t *jl_get_invoke_lambda(jl_methtable_t *mt, JL_GC_PUSH2(&tpenv, &sig); if (entry->tvars != jl_emptysvec) { jl_value_t *ti = - jl_lookup_match((jl_value_t*)tt, (jl_value_t*)entry->sig, &tpenv, entry->tvars); + jl_lookup_match((jl_value_t*)tt, (jl_value_t*)entry->sig, &tpenv); assert(ti != (jl_value_t*)jl_bottom_type); (void)ti; } @@ -2417,13 +2416,12 @@ jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module) return jl_new_generic_function_with_supertype(name, module, jl_function_type, 0); } -JL_DLLEXPORT jl_svec_t *jl_match_method(jl_value_t *type, jl_value_t *sig, - jl_svec_t *tvars) +JL_DLLEXPORT jl_svec_t *jl_match_method(jl_value_t *type, jl_value_t *sig) { jl_svec_t *env = jl_emptysvec; jl_value_t *ti=NULL; JL_GC_PUSH2(&env, &ti); - ti = jl_lookup_match(type, (jl_value_t*)sig, &env, tvars); + ti = jl_lookup_match(type, (jl_value_t*)sig, &env); jl_svec_t *result = jl_svec2(ti, env); JL_GC_POP(); return result; @@ -2572,8 +2570,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio jl_method_t *mambig = (jl_method_t*)jl_array_ptr_ref(meth->ambig, j); env = jl_emptysvec; jl_value_t *mti = jl_type_intersection_matching((jl_value_t*)closure->match.type, - (jl_value_t*)mambig->sig, - &env, mambig->tvars); + (jl_value_t*)mambig->sig, &env); if (mti != (jl_value_t*)jl_bottom_type) { if (closure->include_ambiguous) { assert(done); @@ -2595,8 +2592,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio // the current method doesn't match if there is an intersection with an // ambiguous method that covers our intersection with this one. jl_value_t *ambi = jl_type_intersection_matching((jl_value_t*)ml->sig, - (jl_value_t*)mambig->sig, - &env, mambig->tvars); + (jl_value_t*)mambig->sig, &env); if (jl_subtype(closure->match.ti, ambi)) { return_this_match = 0; break; diff --git a/src/jltypes.c b/src/jltypes.c index c0fb884d6bf8b..c5dbda13057cf 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -93,8 +93,10 @@ static int typeenv_has(jl_typeenv_t *env, jl_tvar_t *v) static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) { - if (jl_typeis(v, jl_tvar_type)) + if (jl_typeis(v, jl_tvar_type)) { + if (v == jl_ANY_flag) return 0; return !typeenv_has(env, (jl_tvar_t*)v); + } if (jl_is_uniontype(v)) return has_free_typevars(((jl_uniontype_t*)v)->a, env) || has_free_typevars(((jl_uniontype_t*)v)->b, env); @@ -106,8 +108,8 @@ static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) } if (jl_is_datatype(v)) { int expect = ((jl_datatype_t*)v)->hasfreetypevars; - if (expect == 0) - return 0; + if (expect == 0 || env == NULL) + return expect; size_t i; for (i=0; i < jl_nparams(v); i++) { if (has_free_typevars(jl_tparam(v,i), env)) { @@ -148,6 +150,8 @@ JL_DLLEXPORT int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) return ans; } if (jl_is_datatype(v)) { + if (!((jl_datatype_t*)v)->hasfreetypevars) + return 0; size_t i; for (i=0; i < jl_nparams(v); i++) { if (jl_has_bound_typevars(jl_tparam(v,i), env)) @@ -275,7 +279,8 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) int has_free = temp[i]!=NULL && jl_has_free_typevars(temp[i]); for(j=0; j < nt; j++) { if (j != i && temp[i] && temp[j]) { - if (temp[i] == temp[j] || + if (temp[i] == temp[j] || temp[i] == jl_bottom_type || + temp[j] == (jl_value_t*)jl_any_type || (!has_free && !jl_has_free_typevars(temp[j]) && jl_subtype(temp[i], temp[j]))) { temp[i] = NULL; @@ -284,11 +289,11 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) } } jl_value_t **ptu = &temp[nt]; - *ptu = NULL; + *ptu = jl_bottom_type; int k; for (k = (int)nt-1; k >= 0; --k) { if (temp[k] != NULL) { - if (*ptu == NULL) + if (*ptu == jl_bottom_type) *ptu = temp[k]; else *ptu = jl_new_struct(jl_uniontype_type, temp[k], *ptu); @@ -300,6 +305,31 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) return tu; } +// unionall types ------------------------------------------------------------- + +JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) +{ + jl_ptls_t ptls = jl_get_ptls_states(); + jl_tvar_t *tv = (jl_tvar_t*)jl_gc_alloc(ptls, sizeof(jl_tvar_t), jl_tvar_type); + tv->name = name; + tv->lb = lb; + tv->ub = ub; + return tv; +} + +JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) +{ + // normalize `T where T<:S` => S + if (body == (jl_value_t*)v) + return v->ub; + // where var doesn't occur in body just return body + if (!jl_has_typevar(body, v)) + return body; + //if (v->lb == v->ub) // TODO maybe + // return jl_substitute_var(body, v, v->ub); + return jl_new_struct(jl_unionall_type, v, body); +} + // --- type instantiation and cache --- static int contains_unions(jl_value_t *type) @@ -553,7 +583,7 @@ static int valid_type_param(jl_value_t *v) return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v)); } -static int within_typevar(jl_value_t *t, jl_tvar_t *v) +static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub) { jl_value_t *lb = t, *ub = t; if (jl_is_typevar(t)) { @@ -564,9 +594,9 @@ static int within_typevar(jl_value_t *t, jl_tvar_t *v) //ub = ((jl_tvar_t*)t)->ub; } else if (!jl_is_type(t)) { - return v->lb == jl_bottom_type && v->ub == jl_any_type; + return vlb == jl_bottom_type && vub == (jl_value_t*)jl_any_type; } - return jl_subtype(v->lb, lb) && jl_subtype(ub, v->ub); + return jl_subtype(vlb, lb) && jl_subtype(ub, vub); } jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n) @@ -590,9 +620,8 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n) } jl_unionall_t *ua = (jl_unionall_t*)tc; - if (jl_has_free_typevars(ua->var->lb) || jl_has_free_typevars(ua->var->ub)) - jl_error("invalid instantiation"); - if (!within_typevar(pi, ua->var)) + if (!jl_has_free_typevars(ua->var->lb) && !jl_has_free_typevars(ua->var->ub) && + !within_typevar(pi, ua->var->lb, ua->var->ub)) jl_type_error_rt("type", "parameter", (jl_value_t*)ua->var, pi); tc = jl_instantiate_unionall(ua, pi); @@ -631,7 +660,11 @@ JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v) } typedef struct _jl_typestack_t { - jl_datatype_t *tt; + union { + jl_value_t *ua; + jl_datatype_t *tt; + }; + jl_value_t *ua_new; struct _jl_typestack_t *prev; } jl_typestack_t; @@ -664,7 +697,7 @@ jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u) return t; JL_GC_PUSH1(&t); t = jl_rewrap_unionall(t, ((jl_unionall_t*)u)->body); - t = jl_new_unionall_type(((jl_unionall_t*)u)->var, t); + t = jl_new_struct(jl_unionall_type, ((jl_unionall_t*)u)->var, t); JL_GC_POP(); return t; } @@ -719,6 +752,38 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt) } } +static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np) +{ + jl_value_t *wrapper = tn->wrapper; + jl_value_t **bounds; + JL_GC_PUSHARGS(bounds, np*2); + int i = 0; + while (jl_is_unionall(wrapper)) { + jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var; + bounds[i++] = tv->lb; + bounds[i++] = tv->ub; + wrapper = ((jl_unionall_t*)wrapper)->body; + } + assert(i == np*2); + wrapper = tn->wrapper; + for(i=0; i < np; i++) { + assert(jl_is_unionall(wrapper)); + jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var; + if (!within_typevar(params[i], bounds[2*i], bounds[2*i+1])) { + // TODO: pass a new version of `tv` containing the instantiated bounds + jl_type_error_rt(jl_symbol_name(tn->name), jl_symbol_name(tv->name), (jl_value_t*)tv, params[i]); + } + int j; + for(j=2*i+2; j < 2*np; j++) { + jl_value_t*bj = bounds[j]; + if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type) + bounds[j] = jl_substitute_var(bj, tv, params[i]); + } + wrapper = ((jl_unionall_t*)wrapper)->body; + } + JL_GC_POP(); +} + static arraylist_t partial_inst; int inside_typedef = 0; @@ -750,8 +815,10 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i jl_value_t *va = jl_unwrap_unionall(last); // return same `Tuple` object for types equal to it if (ntp == 1 && jl_tparam0(va) == (jl_value_t*)jl_any_type && - jl_is_unionall(last) && jl_tparam1(va) == (jl_value_t*)((jl_unionall_t*)last)->var) + jl_is_unionall(last) && jl_tparam1(va) == (jl_value_t*)((jl_unionall_t*)last)->var) { + if (cacheable) JL_UNLOCK(&typecache_lock); // Might GC return (jl_value_t*)jl_anytuple_type; + } if (jl_is_long(jl_tparam1(va))) { ssize_t nt = jl_unbox_long(jl_tparam1(va)); if (nt < 0) @@ -793,6 +860,10 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i jl_datatype_t *ndt = NULL; jl_svec_t *ftypes; + // check parameters against bounds in type definition + if (!istuple) + check_datatype_parameters(tn, iparams, ntp); + // move array of instantiated parameters to heap; we need to keep it JL_GC_PUSH2(&p, &ndt); if (p == NULL) { @@ -948,8 +1019,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ 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_ + // Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in inst_datatype if (jl_is_va_tuple(tt) && ntp == 1) { // If this is a Tuple{Vararg{T,N}} with known N, expand it to // a fixed-length tuple @@ -1011,10 +1081,11 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t while (e != NULL) { if (e->var == (jl_tvar_t*)t) { jl_value_t *val = e->val; - if (check && !jl_is_typevar(val) && !within_typevar(val, (jl_tvar_t*)t)) { - jl_type_error_rt("type parameter", - jl_symbol_name(((jl_tvar_t*)t)->name), t, val); - } + // TODO jb/subtype this seems unnecessary + //if (check && !jl_is_typevar(val) && !within_typevar(val, (jl_tvar_t*)t)) { + // jl_type_error_rt("type parameter", + // jl_symbol_name(((jl_tvar_t*)t)->name), t, val); + //} return val; } e = e->prev; @@ -1022,34 +1093,30 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return (jl_value_t*)t; } if (jl_is_unionall(t)) { - jl_unionall_t *ua = (jl_unionall_t*)t; - jl_value_t *res; - if (!jl_has_free_typevars(t)) { - return t; - } - else if (typeenv_has(env, ua->var) || jl_has_bound_typevars(ua->var->lb, env) || - jl_has_bound_typevars(ua->var->ub, env)) { - jl_value_t *lb=NULL, *ub=NULL, *body=NULL; - jl_tvar_t *ntv=NULL; - JL_GC_PUSH4(&lb, &ub, &ntv, &body); - lb = inst_type_w_(ua->var->lb, env, stack, check); - ub = inst_type_w_(ua->var->ub, env, stack, check); - ntv = jl_new_typevar(ua->var->name, lb, ub); - jl_typeenv_t newenv = { ua->var, (jl_value_t*)ntv, env }; - body = inst_type_w_(ua->body, &newenv, stack, check); - res = jl_new_struct(jl_unionall_type, ntv, body); - JL_GC_POP(); + jl_typestack_t *sp = stack; + while (sp != NULL) { + if (sp->ua == t) + return sp->ua_new; + sp = sp->prev; } - else { - jl_value_t *body=NULL; - JL_GC_PUSH1(&body); - body = inst_type_w_(ua->body, env, stack, check); - if (body == ua->body) - res = t; - else - res = jl_new_struct(jl_unionall_type, ua->var, body); - JL_GC_POP(); + if (!jl_has_free_typevars(t)) + return t; + jl_unionall_t *ua = (jl_unionall_t*)t; + jl_value_t *res=NULL, *lb=ua->var->lb, *ub=ua->var->ub; + JL_GC_PUSH3(&lb, &ub, &res); + res = jl_new_struct(jl_unionall_type, ua->var, NULL); + jl_typestack_t top = { {t}, res, stack }; + if (jl_has_bound_typevars(ua->var->lb, env) || jl_has_bound_typevars(ua->var->ub, env)) { + lb = inst_type_w_(ua->var->lb, env, &top, check); + ub = inst_type_w_(ua->var->ub, env, &top, check); } + if (lb != ua->var->lb || ub != ua->var->ub) + ((jl_unionall_t*)res)->var = jl_new_typevar(ua->var->name, lb, ub); + jl_typeenv_t newenv = { ua->var, (jl_value_t*)((jl_unionall_t*)res)->var, env }; + ((jl_unionall_t*)res)->body = inst_type_w_(ua->body, &newenv, &top, check); + if (((jl_unionall_t*)res)->body == ua->body) + res = t; + JL_GC_POP(); return res; } if (jl_is_uniontype(t)) { @@ -1079,20 +1146,12 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t if (tn == jl_tuple_typename) return inst_tuple_w_(t, env, stack, check); size_t ntp = jl_svec_len(tp); - jl_value_t *wrapper = tn->wrapper; jl_value_t **iparams; JL_GC_PUSHARGS(iparams, ntp); int cacheable = 1, bound = 0; for(i=0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); iparams[i] = (jl_value_t*)inst_type_w_(elt, env, stack, check); - assert(jl_is_unionall(wrapper)); - jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var; - if (!within_typevar(iparams[i], tv)) { - jl_type_error_rt(jl_symbol_name(tn->name), jl_symbol_name(tv->name), - tv, iparams[i]); - } - wrapper = ((jl_unionall_t*)wrapper)->body; bound |= (iparams[i] != elt); if (cacheable && jl_has_free_typevars(iparams[i])) cacheable = 0; @@ -1174,7 +1233,7 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! int k; // TODO jb/subtype - might need to allocate a new svec here for (k=0; k < jl_svec_len(t->types); k++) { - jl_svecset(t->types, k, instantiate_with(jl_svecref(t->types,k), env, n, NULL, &top)); + jl_svecset(ndt->types, k, instantiate_with(jl_svecref(t->types,k), env, n, NULL, &top)); } if (ndt->uid) { // cacheable jl_compute_field_offsets(ndt); @@ -1253,12 +1312,12 @@ static size_t data_vararg_params(jl_value_t **data, size_t lenr, jl_vararg_kind_ return lenf; } *lenkind = JL_TUPLE_VAR; - jl_value_t *last = jl_unwrap_unionall(data[lenr-1]); + jl_value_t *last = data[lenr-1]; *kind = jl_vararg_kind(last); if (*kind == JL_VARARG_NONE || *kind == JL_VARARG_INT) *lenkind = JL_TUPLE_FIXED; if (*kind == JL_VARARG_INT || *kind == JL_VARARG_BOUND) { - jl_value_t *N = jl_tparam1(last); + jl_value_t *N = jl_tparam1(jl_unwrap_unionall(last)); if (jl_is_long(N)) { lenf += jl_unbox_long(N)-1; *lenkind = JL_TUPLE_FIXED; @@ -1294,7 +1353,7 @@ static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int inv pseq = (pi= clenf && !cseq) return 1; - if (pi >= plenf && !pseq) + if (pi >= plenf && !pseq && !some_morespecific) return 0; if (ci < clenr) { ce = child[ci]; @@ -1741,7 +1800,7 @@ void jl_init_types(void) jl_tvar_t *tttvar = tvar("T"); ((jl_datatype_t*)jl_type_type)->parameters = jl_svec(1, tttvar); ((jl_datatype_t*)jl_type_type)->hasfreetypevars = 1; - jl_type_typename->wrapper = (jl_value_t*)jl_new_unionall_type(tttvar, (jl_value_t*)jl_type_type); + jl_type_typename->wrapper = jl_new_struct(jl_unionall_type, tttvar, (jl_value_t*)jl_type_type); jl_type_type = (jl_unionall_t*)jl_type_typename->wrapper; jl_tupletype_t *empty_tuple_type = jl_apply_tuple_type(jl_emptysvec); @@ -2040,12 +2099,14 @@ void jl_init_types(void) tttvar = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type, (jl_value_t*)jl_anytuple_type); - jl_anytuple_type_type = jl_new_unionall_type(tttvar, (jl_value_t*)jl_wrap_Type((jl_value_t*)tttvar)); + jl_anytuple_type_type = (jl_unionall_t*)jl_new_struct(jl_unionall_type, + tttvar, (jl_value_t*)jl_wrap_Type((jl_value_t*)tttvar)); // Type{T} jl_typetype_tvar = tvar("T"); - jl_typetype_type = jl_new_unionall_type(jl_typetype_tvar, - jl_apply_type1((jl_value_t*)jl_type_type, (jl_value_t*)jl_typetype_tvar)); + jl_typetype_type = + (jl_unionall_t*)jl_new_struct(jl_unionall_type, jl_typetype_tvar, + jl_apply_type1((jl_value_t*)jl_type_type, (jl_value_t*)jl_typetype_tvar)); jl_ANY_flag = (jl_value_t*)tvar("ANY"); diff --git a/src/julia.h b/src/julia.h index 36a7ce2e4309d..aed6f1f6d7900 100644 --- a/src/julia.h +++ b/src/julia.h @@ -987,6 +987,7 @@ JL_DLLEXPORT int jl_isa(jl_value_t *a, jl_value_t *t); JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n); JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body); JL_DLLEXPORT const char *jl_typename_str(jl_value_t *v); JL_DLLEXPORT const char *jl_typeof_str(jl_value_t *v); JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b); @@ -1004,7 +1005,6 @@ STATIC_INLINE int jl_is_leaf_type_(jl_value_t *v) // type constructors JL_DLLEXPORT jl_typename_t *jl_new_typename(jl_sym_t *name); JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub); -JL_DLLEXPORT jl_unionall_t *jl_new_unionall_type(jl_tvar_t *v, jl_value_t *body); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p); JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n); JL_DLLEXPORT jl_value_t *jl_apply_type1(jl_value_t *tc, jl_value_t *p1); diff --git a/src/julia_internal.h b/src/julia_internal.h index 9beadd31caf99..c815aa81699ab 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -329,8 +329,7 @@ jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np); jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p); JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); void jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_t fptr); -jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, - jl_svec_t **penv, jl_svec_t *tvars); +jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_svec_t **penv); jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); jl_datatype_t *jl_new_uninitialized_datatype(void); @@ -802,7 +801,7 @@ int jl_typemap_intersection_visitor(union jl_typemap_t a, int offs, struct typem int sigs_eq(jl_value_t *a, jl_value_t *b, int useenv); -jl_value_t *jl_lookup_match(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, jl_svec_t *tvars); +jl_value_t *jl_lookup_match(jl_value_t *a, jl_value_t *b, jl_svec_t **penv); unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *field_type); diff --git a/src/subtype.c b/src/subtype.c index 9004075864a7d..dfbe6be8099ed 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -83,8 +83,8 @@ typedef struct { int envsz; // length of envout int envidx; // current index in envout int invdepth; // current number of invariant constructors we're nested in - int ignore_free; - int intersection; + int ignore_free; // treat free vars as black boxes; used during intersection + int intersection; // true iff subtype is being called from intersection } jl_stenv_t; // state manipulation utilities @@ -296,16 +296,23 @@ static int var_lt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int param) record_var_occurrence(bb, e, param); if (!bb->right) // check ∀b . b<:a return subtype_ufirst(bb->ub, a, e); + if (bb->ub == a) + return 1; if (!((bb->lb == jl_bottom_type && !jl_is_type(a) && !jl_is_typevar(a)) || subtype_ufirst(bb->lb, a, e))) return 0; // for contravariance we would need to compute a meet here, but // because of invariance bb.ub ⊓ a == a here always. however for this // to work we need to compute issub(left,right) before issub(right,left), // since otherwise the issub(a, bb.ub) check in var_gt becomes vacuous. - if (e->intersection) - bb->ub = intersect_ufirst(bb->ub, a, e, bb->depth0); - else + if (e->intersection) { + jl_value_t *ub = intersect_ufirst(bb->ub, a, e, bb->depth0); + if (ub != (jl_value_t*)b) + bb->ub = ub; + } + else { bb->ub = a; // meet(bb->ub, a) + } + assert(bb->ub != (jl_value_t*)b); if (jl_is_typevar(a)) { jl_varbinding_t *aa = lookup(e, (jl_tvar_t*)a); if (aa && !aa->right && in_union(bb->lb, a) && bb->depth0 != aa->depth0 && var_outside(e, b, (jl_tvar_t*)a)) { @@ -329,6 +336,7 @@ static int var_gt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int param) if (!((bb->ub == (jl_value_t*)jl_any_type && !jl_is_type(a) && !jl_is_typevar(a)) || subtype_ufirst(a, bb->ub, e))) return 0; bb->lb = simple_join(bb->lb, a); + assert(bb->lb != (jl_value_t*)b); return 1; } @@ -585,12 +593,21 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) return 0; } if (jl_is_type_type(y) && !jl_is_type_type(x)) { - if (!jl_is_typevar(jl_tparam0(yd))) + jl_value_t *tp0 = jl_tparam0(yd); + if (!jl_is_typevar(tp0)) return 0; if (!is_kind(x)) return 0; - e->invdepth++; - int ans = subtype(x, jl_tparam0(yd), e, 2) && subtype(jl_tparam0(yd), x, e, 0); - e->invdepth--; + jl_varbinding_t *yy = lookup(e, (jl_tvar_t*)tp0); + jl_value_t *ub = yy ? yy->ub : ((jl_tvar_t*)tp0)->ub; + int ans; + if (ub == (jl_value_t*)jl_any_type) { + ans = subtype((jl_value_t*)jl_type_type, y, e, param); + } + else { + e->invdepth++; + ans = subtype(x, jl_tparam0(yd), e, 2) && subtype(jl_tparam0(yd), x, e, 0); + e->invdepth--; + } return ans; } while (xd != jl_any_type && xd->name != yd->name) @@ -893,7 +910,9 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int else if (bb->constraintkind == 2) { if (!subtype_in_env(a, bb->ub, e)) return jl_bottom_type; - bb->lb = simple_join(bb->lb, a); + jl_value_t *lb = simple_join(bb->lb, a); + if (lb != (jl_value_t*)b) + bb->lb = lb; return a; } assert(bb->constraintkind == 3); @@ -902,6 +921,10 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int return jl_bottom_type; if (jl_is_typevar(a)) return (jl_value_t*)b; + if (ub == a) { + bb->ub = ub; + return (jl_value_t*)b; + } jl_value_t *root; int8_t *buf; JL_GC_PUSH2(&root, &ub); save_env(e, &root, &buf); @@ -1013,6 +1036,7 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv } btemp = btemp->prev; } + JL_GC_PUSH1(&u); vb->var = u->var; e->vars = vb; jl_value_t *res = R ? intersect(t, u->body, e, param) : intersect(u->body, t, e, param); @@ -1068,7 +1092,7 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv } if (res != jl_bottom_type) res = finish_unionall(res, vb, e); - + JL_GC_POP(); return res; } @@ -1236,10 +1260,22 @@ static jl_value_t *intersect_sub_datatype(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t tempe; init_stenv(&tempe, env, envsz); tempe.ignore_free = 1; - if (!subtype_in_env(isuper, super_pattern, &tempe)) + if (!subtype_in_env(isuper, super_pattern, &tempe)) { ii = jl_bottom_type; - else + } + else { + jl_value_t *wr = wrapper; + int i; + for(i=0; ivar) + env[i] = jl_tparam(xd,i); + wr = ((jl_unionall_t*)wr)->body; + } ii = jl_apply_type(wrapper, env, envsz); + } JL_GC_POP(); return ii; } @@ -1291,12 +1327,17 @@ static jl_value_t *intersect_type_type(jl_value_t *x, jl_value_t *y, jl_stenv_t if (!jl_is_typevar(p0)) return (jl_typeof(p0) == y) ? x : jl_bottom_type; if (!is_kind(y)) return jl_bottom_type; + if (((jl_tvar_t*)p0)->ub == (jl_value_t*)jl_any_type) + return y; + return x; + /* jl_value_t *ii = R ? intersect_invariant(y, jl_tparam0(x), e) : intersect_invariant(jl_tparam0(x), y, e); // NOTE: we cannot express e.g. DataType ∩ (UnionAll T<:Integer Type{T}), so returning `x` // here is a conservative over-estimate. - if (ii == NULL) return x; + if (ii == NULL || ii == jl_bottom_type) return x; if (ii == y) return ii; return (jl_value_t*)jl_wrap_Type(ii); + */ } // `param` means we are currently looking at a parameter of a type constructor @@ -1361,11 +1402,14 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa ub = intersect_ufirst(xub, yub, e, xx->depth0); lb = simple_join(xlb, ylb); assert(yy); - yy->lb = lb; - yy->ub = ub; + if (lb != y) + yy->lb = lb; + if (ub != y) + yy->ub = ub; xx->lb = y; xx->ub = y; assert(yy->ub != y); + assert(yy->lb != y); assert(xx->ub != x); JL_GC_POP(); return y; @@ -1539,44 +1583,54 @@ JL_DLLEXPORT jl_value_t *jl_intersect_types(jl_value_t *x, jl_value_t *y) return intersect_all(x, y, &e, 0); } -jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, - jl_svec_t **penv, jl_svec_t *tvars) +jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_svec_t **penv) { - int sza = jl_subtype_env_size(a); int szb = jl_subtype_env_size(b); int sz = 0, i = 0; - jl_value_t **env = (jl_value_t**)alloca((sza>szb?sza:szb)*sizeof(jl_value_t*)); - jl_value_t *ans = b; + jl_value_t **env = (jl_value_t**)alloca(szb*sizeof(jl_value_t*)); + jl_value_t *ans = jl_bottom_type; + JL_GC_PUSH1(&ans); if (jl_subtype_env(a, b, env, szb)) { - ans = a; - sz = szb; + ans = a; sz = szb; } else if (jl_subtype(b, a)) { + ans = b; } - else if (jl_is_leaf_type(a) || jl_is_leaf_type(b)) { - return jl_bottom_type; - } - if (sz == 0) { - sz = szb; + else { + int lta = jl_is_leaf_type(a), ltb = jl_is_leaf_type(b); + if ((lta && ltb) || (lta && !is_kind(a)) || (ltb && !is_kind(b))) + goto bot; + jl_stenv_t e; + init_stenv(&e, NULL, 0); + e.intersection = 1; + ans = intersect_all(a, b, &e, 0); + if (ans == jl_bottom_type) goto bot; + // TODO: compute `env` directly during intersection + //if (szb > 0 && jl_subtype_env(ans, b, env, szb)) + // sz = szb; + // TODO: don't yet use the types returned by `intersect`, since it returns + // Unions of Tuples and other code can only handle direct Tuples. + ans = b; + } + if (sz == 0 && szb > 0) { while (jl_is_unionall(b)) { env[i++] = (jl_value_t*)((jl_unionall_t*)b)->var; b = ((jl_unionall_t*)b)->body; } + sz = szb; } - jl_svec_t *e = jl_alloc_svec(sz); - *penv = e; - for(i=0; i < sz; i++) - jl_svecset(e, i, env[i]); + if (penv) { + jl_svec_t *e = jl_alloc_svec(sz); + *penv = e; + for(i=0; i < sz; i++) + jl_svecset(e, i, env[i]); + } + bot: + JL_GC_POP(); return ans; } JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b) { - if (jl_subtype(a, b)) - return a; - if (jl_subtype(b, a)) - return b; - if (jl_is_leaf_type(a) || jl_is_leaf_type(b)) - return jl_bottom_type; - return b; + return jl_type_intersection_matching(a, b, NULL); } diff --git a/src/toplevel.c b/src/toplevel.c index 1f3d44a02f557..1f50f0509b042 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -816,12 +816,26 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, if (jl_subtype((jl_value_t*)ftype, (jl_value_t*)jl_builtin_type)) jl_error("cannot add methods to a builtin function"); + int j; + for(j=(int)jl_svec_len(tvars)-1; j >= 0 ; j--) + argtype = jl_new_struct(jl_unionall_type, jl_svecref(tvars,j), argtype); + m = jl_new_method(f, name, argtype, nargs, isva, tvars, isstaged == jl_true); + + if (jl_has_free_typevars(argtype)) { + jl_exceptionf(jl_argumenterror_type, + "method definition for %s at %s:%d has free type variables", + jl_symbol_name(name), + jl_symbol_name(m->file), + m->line); + } + jl_check_static_parameter_conflicts(m, tvars); - size_t i, na = jl_nparams(argtype); + jl_value_t *argtype_body = jl_unwrap_unionall(argtype); + size_t i, na = jl_svec_len(atypes); for (i = 0; i < na; i++) { - jl_value_t *elt = jl_tparam(argtype, i); + jl_value_t *elt = jl_svecref(atypes, i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_sym_t *argname = (jl_sym_t*)jl_array_ptr_ref(f->slotnames, i); if (argname == unused_sym) @@ -846,7 +860,7 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_value_t *tv = jl_svecref(tvars,i); if (!jl_is_typevar(tv)) jl_type_error_rt(jl_symbol_name(name), "method definition", (jl_value_t*)jl_tvar_type, tv); - if (!ishidden && !jl_has_typevar((jl_value_t*)argtype, (jl_tvar_t*)tv)) { + if (!ishidden && !jl_has_typevar((jl_value_t*)argtype_body, (jl_tvar_t*)tv)) { jl_printf(JL_STDERR, "WARNING: static parameter %s does not occur in signature for %s", jl_symbol_name(((jl_tvar_t*)tv)->name), jl_symbol_name(name)); diff --git a/src/typemap.c b/src/typemap.c index c280e0ac21d1e..ace8de52f1496 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -374,9 +374,9 @@ static union jl_typemap_t *mtcache_hash_bp(struct jl_ordereddict_t *pa, jl_value // ----- Sorted Type Signature Lookup Matching ----- // -jl_value_t *jl_lookup_match(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, jl_svec_t *tvars) +jl_value_t *jl_lookup_match(jl_value_t *a, jl_value_t *b, jl_svec_t **penv) { - jl_value_t *ti = jl_type_intersection_matching(a, b, penv, tvars); + jl_value_t *ti = jl_type_intersection_matching(a, b, penv); if (ti == (jl_value_t*)jl_bottom_type) return ti; JL_GC_PUSH1(&ti); @@ -505,7 +505,7 @@ static int jl_typemap_intersection_node_visitor(jl_typemap_entry_t *ml, struct t jl_value_t *ti; if (closure->env) { closure->env = jl_emptysvec; - ti = jl_lookup_match(closure->type, (jl_value_t*)ml->sig, &closure->env, ml->tvars); + ti = jl_lookup_match(closure->type, (jl_value_t*)ml->sig, &closure->env); } else { ti = jl_type_intersection(closure->type, (jl_value_t*)ml->sig); @@ -528,6 +528,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; jl_value_t *ttypes = jl_unwrap_unionall(closure->type); + assert(jl_is_datatype(ttypes)); size_t l = jl_field_count(ttypes); if (closure->va && l <= offs + 1) { ty = closure->va; @@ -631,7 +632,7 @@ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_ // which works currently because types is typically a leaf tt, // or inexact is set (which then does a sort of subtype test via jl_types_equal) // but this isn't entirely general - jl_value_t *ti = jl_lookup_match((jl_value_t*)types, (jl_value_t*)ml->sig, penv, ml->tvars); + jl_value_t *ti = jl_lookup_match((jl_value_t*)types, (jl_value_t*)ml->sig, penv); resetenv = 1; ismatch = (ti != (jl_value_t*)jl_bottom_type); if (ismatch) { @@ -708,6 +709,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ // called object is the primary key for constructors, otherwise first argument jl_value_t *ty = NULL; jl_value_t *ttypes = jl_unwrap_unionall(types); + assert(jl_is_datatype(ttypes)); size_t l = jl_field_count(ttypes); int isva = 0; // compute the type at offset `offs` into `types`, which may be a Vararg diff --git a/test/subtype.jl b/test/subtype.jl index df0fbfe5967db..8edf64e1f7c60 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -345,13 +345,13 @@ function test_5() @test !issub(Array{Tuple{Array{Int},Array{Vector{Int16}},Array{Vector{Int}},Array{Int}}}, @UnionAll T<:(@UnionAll S Tuple{Vararg{Union{Array{S}, Array{Array{S,1}}}}}) Array{T}) - @test issub(Array{Tuple{Array{Int},Array{Vector{Int }},Array{Vector{Int}},Array{Int}}}, + @test issub(Array{Tuple{Array{Int},Array{Vector{Int}},Array{Vector{Int}},Array{Int}}}, @UnionAll T<:(@UnionAll S Tuple{Vararg{Union{Array{S}, Array{Array{S,1}}}}}) Array{T}) @test !issub(Tuple{Array{Int},Array{Vector{Int16}},Array{Vector{Int}},Array{Int}}, @UnionAll S Tuple{Vararg{Union{Array{S},Array{Array{S,1}}}}}) - @test issub(Tuple{Array{Int},Array{Vector{Int }},Array{Vector{Int}},Array{Int}}, + @test issub(Tuple{Array{Int},Array{Vector{Int}},Array{Vector{Int}},Array{Int}}, @UnionAll S Tuple{Vararg{Union{Array{S},Array{Array{S,1}}}}}) B = @UnionAll S<:u Tuple{S, Tuple{Any,Any,Any}, Ref{S}} @@ -628,6 +628,10 @@ type A11136 end type B11136 end abstract Foo11367 +abstract AbstractTriangular{T,S<:AbstractMatrix} <: AbstractMatrix{T} +immutable UpperTriangular{T,S<:AbstractMatrix} <: AbstractTriangular{T,S} end +immutable UnitUpperTriangular{T,S<:AbstractMatrix} <: AbstractTriangular{T,S} end + function test_intersection() @testintersect(Vector{Float64}, Vector{Union{Float64,Float32}}, Bottom) @@ -796,6 +800,14 @@ function test_intersection() (@UnionAll X<:(@UnionAll T Tuple{T,T}) Ref{X})) @testintersect(Ref{@UnionAll T @UnionAll S Tuple{T,S}}, Ref{@UnionAll T Tuple{T,T}}, Bottom) + + @testintersect(Tuple{T,T} where T<:Union{UpperTriangular, UnitUpperTriangular}, + Tuple{AbstractArray{T,N}, AbstractArray{T,N}} where N where T, + Union{Tuple{T,T} where T<:UpperTriangular, + Tuple{T,T} where T<:UnitUpperTriangular}) + + @testintersect(DataType, Type, DataType) + @testintersect(DataType, Type{T} where T<:Integer, Type{T} where T<:Integer) end function test_intersection_properties()