From 5cb5e96cb21a4e407c0839167e2ca3496e8214b4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 May 2016 15:38:12 -0400 Subject: [PATCH] some type signatures are only partly more specific than TypeName and require creation of an extra guard entry to split the priority between linear_leaf and linear [ci skip] --- src/typemap.c | 129 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 115 insertions(+), 14 deletions(-) diff --git a/src/typemap.c b/src/typemap.c index 0dfc04944f5e7..5163878cbde7c 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -27,30 +27,37 @@ static int jl_is_any(jl_value_t *t1) // the goal here is to compute if sig is more-specific // than something we can put into the TypeName-based hash tables -static int jl_args_morespecific_typename(jl_value_t *t1) +// returns: 0 -> less specific, 1 -> more specific, 2 -> indeterminate (both) +static int jl_args_morespecific_typename(jl_value_t *t1, int covariant) { if (jl_is_typector(t1)) t1 = (jl_value_t*)((jl_typector_t*)t1)->body; - if (jl_is_uniontype(t1)) { + if (covariant && jl_is_uniontype(t1)) { jl_uniontype_t *ut = (jl_uniontype_t*)t1; size_t i, l = jl_svec_len(ut->types); - for (i = 0; i < l; i++) { - if (jl_args_morespecific_typename(jl_svecref(ut->types, i))) - return 1; + if (l == 0) + return 0; + int morespec = jl_args_morespecific_typename(jl_svecref(ut->types, 0), 0); + for (i = 1; i < l; i++) { + if (morespec != jl_args_morespecific_typename(jl_svecref(ut->types, i), 0)) + return 2; } - return 0; + return morespec; + } + else if (jl_is_vararg_type(t1)) { + return covariant ? jl_args_morespecific_typename(jl_tparam0(t1), covariant) : 0; } else if (jl_is_typevar(t1)) { - return jl_args_morespecific_typename(((jl_tvar_t*)t1)->ub); + return jl_args_morespecific_typename(((jl_tvar_t*)t1)->ub, 1); } else if (jl_is_tuple(t1)) { - return 0; + return 0; // tuples aren't considered eligible for the TypeName level } else if (jl_is_type_type(t1)) { - return jl_args_morespecific_typename(jl_tparam0(t1)); + return jl_args_morespecific_typename(jl_tparam0(t1), 0); } else if (jl_is_datatype(t1)) { - return !((jl_datatype_t*)t1)->abstract && !is_kind(t1); + return !((jl_datatype_t*)t1)->abstract && !is_kind(t1) ? 1 : 0; } return 0; } @@ -73,6 +80,69 @@ static jl_value_t* jl_type_extract_name(jl_value_t *t1) return NULL; } +// note: this is carefully matched to jl_args_morespecific_typename +// to ensure that it won't be asked to split something any more +// complicated than it knows how to handle +static jl_value_t *jl_arg_split_spec(jl_value_t *t1, int covariant) +{ + if (jl_is_typector(t1)) + t1 = (jl_value_t*)((jl_typector_t*)t1)->body; + if (covariant && jl_is_uniontype(t1)) { + jl_uniontype_t *ut = (jl_uniontype_t*)t1; + size_t i, l = jl_svec_len(ut->types); + size_t n = 0; + for (i = 0; i < l; i++) { + jl_value_t *elem = jl_svecref(ut->types, i); + int elem_morespec = jl_args_morespecific_typename(elem, covariant); + if (elem_morespec == 2 || ((elem_morespec != 0) == (morespec != 0))) + n++; + } + jl_svec_t *u = jl_alloc_svec(n); + JL_GC_PUSH1(&u); + n = 0; + for (i = 0; i < l; i++) { + jl_value_t *elem = jl_svecref(ut->types, i); + int elem_morespec = jl_args_morespecific_typename(elem, covariant); + if (elem_morespec == 2) + elem = jl_arg_split_spec(jl_svecref(ut->types, i), 0); + else if (elem_morespec == 0) + continue; + jl_svecset(u, n++, elem); + } + jl_value_t *uu = jl_type_union(u); + JL_GC_POP(); + return uu; + } + else if (jl_is_vararg_type(t1)) { + if (!covariant) + return t1; + jl_value_t *p = jl_arg_split_spec(jl_tparam0(t1), covariant); + JL_GC_PUSH1(&p); + assert(p != jl_tparam0(t1)); + p = (jl_value_t*)jl_wrap_vararg(p, jl_tparam1(t1)); + JL_GC_POP(); + return p; + } + else if (jl_is_typevar(t1)) { + jl_tvar_t *tv = (jl_tvar_t*)t1; + jl_value_t *tv2 = jl_arg_split_spec(tv->ub, 1); + JL_GC_PUSH1(&tv2); + assert(tv2 != tv->ub); + tv = jl_new_typevar(tv->name, tv->lb, tv2); + JL_GC_POP(); + return (jl_value_t*)tv; + } + else if (jl_is_type_type(t1)) { + jl_value_t *p = jl_arg_split_spec(jl_tparam0(t1), 0); + JL_GC_PUSH1(&p); + assert(p != jl_tparam0(t1)); + t1 = (jl_value_t*)jl_wrap_Type(p); + JL_GC_POP(); + return t1; + } + return t1; +} + // ----- Type Signature Subtype Testing ----- // @@ -953,7 +1023,8 @@ static unsigned jl_typemap_list_count(jl_typemap_entry_t *ml) return count; } -static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams); +static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, + const struct jl_typemap_info *tparams); static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams); @@ -973,7 +1044,8 @@ static jl_typemap_level_t *jl_new_typemap_level(void) return cache; } -static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs) +static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs, + const struct jl_typemap_info *tparams) { jl_typemap_level_t *cache = jl_new_typemap_level(); cache->key = key; @@ -982,7 +1054,7 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *m while (ml != (void*)jl_nothing) { next = ml->next; ml->next = (jl_typemap_entry_t*)jl_nothing; - jl_typemap_level_insert_(cache, ml, offs, 0); + jl_typemap_level_insert_(cache, ml, offs, tparams); ml = next; } JL_GC_POP(); @@ -1014,7 +1086,7 @@ static void jl_typemap_insert_generic(union jl_typemap_t *pml, jl_value_t *paren unsigned count = jl_typemap_list_count(pml->leaf); if (count > MAX_METHLIST_COUNT) { - pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs); + pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs, tparams); jl_gc_wb(parent, pml->node); jl_typemap_level_insert_(pml->node, newrec, offs, tparams); return; @@ -1081,6 +1153,35 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry if (a0 && jl_typemap_array_insert_(&cache->name1, a0, newrec, (jl_value_t*)cache, 2, offs, tparams)) return; } + if (t1 == NULL) { + assert(0); // not implemented yet + return; + } + if (jl_args_morespecific_typename(t1, 1)) { + // need to split this union into components more-specific than TypeName, and those less-specific + jl_value_t *morespec_sig = NULL; + JL_GC_PUSH1(&morespec_sig); + while (1) { + // XXX: do stuff here + morespec_sig = (jl_value_t*)jl_svec_copy(newrec->sig->parameters); + if (l <= offs) offs = l - 1; // bound Vararg to the length of the signature + jl_value_t *elem = jl_tparam(newrec->sig, offs); + jl_svecset(morespec_sig, offs, jl_arg_split_spec(elem, 1)); + morespec_sig = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)morespec_sig); + + jl_typemap_entry_t *newrec2 = (jl_typemap_entry_t*)jl_gc_allocobj(sizeof(jl_typemap_entry_t)); + jl_set_typeof(newrec2, jl_typemap_entry_type); + *newrec2 = *newrec; // copy newrec to newrec2 + // TODO: mark newrec2 as a non-primary entry (ignored for lookup operations) + newrec2->sig = (jl_datatype_t*)morespec_sig; + morespec_sig = (jl_value_t*)newrec2; + jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec2, tparams); + } + JL_GC_POP(); + // fall-through. newrec is unmodified since lessspec_sig <: newrec->sig, + // and the user might try to look up the original sig directly + // (either through invoke or exact extraction) + } jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams); }