Skip to content

Commit e4137f9

Browse files
committed
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
1 parent 57277b4 commit e4137f9

File tree

1 file changed

+114
-17
lines changed

1 file changed

+114
-17
lines changed

src/typemap.c

Lines changed: 114 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,37 @@ static int jl_is_any(jl_value_t *t1)
2727

2828
// the goal here is to compute if sig is more-specific
2929
// than something we can put into the TypeName-based hash tables
30-
static int jl_args_morespecific_typename(jl_value_t *t1)
30+
// returns: 0 -> less specific, 1 -> more specific, 2 -> indeterminate (both)
31+
static int jl_args_morespecific_typename(jl_value_t *t1, int covariant)
3132
{
3233
if (jl_is_typector(t1))
3334
t1 = (jl_value_t*)((jl_typector_t*)t1)->body;
34-
if (jl_is_uniontype(t1)) {
35+
if (covariant && jl_is_uniontype(t1)) {
3536
jl_uniontype_t *ut = (jl_uniontype_t*)t1;
3637
size_t i, l = jl_svec_len(ut->types);
37-
for (i = 0; i < l; i++) {
38-
if (jl_args_morespecific_typename(jl_svecref(ut->types, i)))
39-
return 1;
38+
if (l == 0)
39+
return 0;
40+
int morespec = jl_args_morespecific_typename(jl_svecref(ut->types, 0), 0);
41+
for (i = 1; i < l; i++) {
42+
if (morespec != jl_args_morespecific_typename(jl_svecref(ut->types, i), 0))
43+
return 2;
4044
}
41-
return 0;
45+
return morespec;
46+
}
47+
else if (jl_is_vararg_type(t1)) {
48+
return covariant ? jl_args_morespecific_typename(jl_tparam0(t1), covariant) : 0;
4249
}
4350
else if (jl_is_typevar(t1)) {
44-
return jl_args_morespecific_typename(((jl_tvar_t*)t1)->ub);
51+
return jl_args_morespecific_typename(((jl_tvar_t*)t1)->ub, 1);
4552
}
4653
else if (jl_is_tuple(t1)) {
47-
return 0;
54+
return 0; // tuples aren't considered eligible for the TypeName level
4855
}
4956
else if (jl_is_type_type(t1)) {
50-
return jl_args_morespecific_typename(jl_tparam0(t1));
57+
return jl_args_morespecific_typename(jl_tparam0(t1), 0);
5158
}
5259
else if (jl_is_datatype(t1)) {
53-
return !((jl_datatype_t*)t1)->abstract && !is_kind(t1);
60+
return !((jl_datatype_t*)t1)->abstract && !is_kind(t1) ? 1 : 0;
5461
}
5562
return 0;
5663
}
@@ -73,6 +80,69 @@ static jl_typename_t* jl_type_extract_name(jl_value_t *t1)
7380
return NULL;
7481
}
7582

83+
// note: this is carefully matched to jl_args_morespecific_typename
84+
// to ensure that it won't be asked to split something any more
85+
// complicated than it knows how to handle
86+
static jl_value_t *jl_arg_split_spec(jl_value_t *t1, int morespec, int covariant)
87+
{
88+
if (jl_is_typector(t1))
89+
t1 = (jl_value_t*)((jl_typector_t*)t1)->body;
90+
if (covariant && jl_is_uniontype(t1)) {
91+
jl_uniontype_t *ut = (jl_uniontype_t*)t1;
92+
size_t i, l = jl_svec_len(ut->types);
93+
size_t n = 0;
94+
for (i = 0; i < l; i++) {
95+
jl_value_t *elem = jl_svecref(ut->types, i);
96+
int elem_morespec = jl_args_morespecific_typename(elem, covariant);
97+
if (elem_morespec == 2 || ((elem_morespec != 0) == (morespec != 0)))
98+
n++;
99+
}
100+
jl_value_t *u = jl_alloc_svec(n);
101+
JL_GC_PUSH1(&u);
102+
n = 0;
103+
for (i = 0; i < l; i++) {
104+
jl_value_t *elem = jl_svecref(ut->types, i);
105+
int elem_morespec = jl_args_morespecific_typename(elem, covariant);
106+
if (elem_morespec == 2)
107+
elem = jl_arg_split_spec(jl_svecref(ut->types, i), morespec, 0);
108+
else if ((elem_morespec != 0) != (morespec != 0))
109+
continue;
110+
jl_svecset(u, n++, elem);
111+
}
112+
u = jl_type_union(u);
113+
JL_GC_POP();
114+
return u;
115+
}
116+
else if (jl_is_vararg_type(t1)) {
117+
if (!covariant)
118+
return t1;
119+
jl_value_t *p = jl_arg_split_spec(jl_tparam0(t1), morespec, covariant);
120+
JL_GC_PUSH1(&p);
121+
assert(p != jl_tparam0(t1));
122+
p = jl_wrap_vararg(p, jl_tparam1(t1));
123+
JL_GC_POP();
124+
return p;
125+
}
126+
else if (jl_is_typevar(t1)) {
127+
jl_tvar_t *tv = (jl_tvar_t*)t1;
128+
jl_value_t *tv2 = jl_arg_split_spec(tv->ub, morespec, 1);
129+
JL_GC_PUSH1(&tv2);
130+
assert(tv2 != tv->ub);
131+
tv = jl_new_typevar(tv->name, tv->lb, tv2);
132+
JL_GC_POP();
133+
return (jl_value_t*)tv;
134+
}
135+
else if (jl_is_type_type(t1)) {
136+
jl_value_t *p = jl_arg_split_spec(jl_tparam0(t1), morespec, 0);
137+
JL_GC_PUSH1(&p);
138+
assert(p != jl_tparam0(t1));
139+
t1 = jl_wrap_Type(p);
140+
JL_GC_POP();
141+
return t1;
142+
}
143+
return t1;
144+
}
145+
76146

77147
// ----- Type Signature Subtype Testing ----- //
78148

@@ -943,7 +1013,8 @@ static unsigned jl_typemap_list_count(jl_typemap_entry_t *ml)
9431013
return count;
9441014
}
9451015

946-
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);
1016+
static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs,
1017+
const struct jl_typemap_info *tparams);
9471018
static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent,
9481019
jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams);
9491020

@@ -962,7 +1033,8 @@ static jl_typemap_level_t *jl_new_typemap_level(void)
9621033
return cache;
9631034
}
9641035

965-
static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs)
1036+
static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs,
1037+
const struct jl_typemap_info *tparams)
9661038
{
9671039
jl_typemap_level_t *cache = jl_new_typemap_level();
9681040
cache->key = key;
@@ -971,7 +1043,7 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *m
9711043
while (ml != (void*)jl_nothing) {
9721044
next = ml->next;
9731045
ml->next = (jl_typemap_entry_t*)jl_nothing;
974-
jl_typemap_level_insert_(cache, ml, offs, 0);
1046+
jl_typemap_level_insert_(cache, ml, offs, tparams);
9751047
ml = next;
9761048
}
9771049
JL_GC_POP();
@@ -1004,7 +1076,7 @@ static void jl_typemap_insert_generic(union jl_typemap_t *pml, jl_value_t *paren
10041076

10051077
unsigned count = jl_typemap_list_count(pml->leaf);
10061078
if (count > MAX_METHLIST_COUNT) {
1007-
pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs);
1079+
pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs, tparams);
10081080
jl_gc_wb(parent, pml->node);
10091081
jl_typemap_level_insert_(pml->node, newrec, offs, tparams);
10101082
return;
@@ -1071,9 +1143,34 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry
10711143
if (a0 && jl_typemap_array_insert_(&cache->name1, a0, newrec, (jl_value_t*)cache, 2, offs, tparams))
10721144
return;
10731145
}
1074-
if (!t1 || jl_args_morespecific_typename(t1)) {
1075-
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec, tparams);
1076-
return;
1146+
int morespec = t1 ? jl_args_morespecific_typename(t1, 1) : 1;
1147+
if (morespec) {
1148+
if (morespec == 2) {
1149+
// need to split this union into components more-specific than TypeName, and those less-specific
1150+
jl_value_t *morespec_sig = NULL;
1151+
JL_GC_PUSH1(&morespec_sig);
1152+
morespec_sig = (jl_value_t*)jl_svec_copy(newrec->sig->parameters);
1153+
if (l <= offs) offs = l - 1; // bound Vararg to the length of the signature
1154+
jl_value_t *elem = jl_tparam(newrec->sig, offs);
1155+
jl_svecset(morespec_sig, offs, jl_arg_split_spec(elem, 1, 1));
1156+
morespec_sig = jl_apply_tuple_type(morespec_sig);
1157+
1158+
jl_typemap_entry_t *newrec2 = (jl_typemap_entry_t*)jl_gc_allocobj(sizeof(jl_typemap_entry_t));
1159+
jl_set_typeof(newrec2, jl_typemap_entry_type);
1160+
*newrec2 = *newrec; // copy newrec to newrec2
1161+
// TODO: mark newrec2 as a non-primary entry (ignored for lookup operations)
1162+
newrec2->sig = morespec_sig;
1163+
morespec_sig = (jl_value_t*)newrec2;
1164+
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec2, tparams);
1165+
JL_GC_POP();
1166+
// fall-through. newrec is unmodified since lessspec_sig <: newrec->sig,
1167+
// and the user might try to look up the original sig directly
1168+
// (either through invoke or exact extraction)
1169+
}
1170+
else {
1171+
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec, tparams);
1172+
return;
1173+
}
10771174
}
10781175
jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams);
10791176
}

0 commit comments

Comments
 (0)