Skip to content

Commit c419fb1

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 8ba7399 commit c419fb1

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_value_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_svec_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+
jl_value_t *uu = jl_type_union(u);
113+
JL_GC_POP();
114+
return uu;
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_value_t*)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_value_t*)jl_wrap_Type(p);
140+
JL_GC_POP();
141+
return t1;
142+
}
143+
return t1;
144+
}
145+
76146

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

@@ -963,7 +1033,8 @@ static unsigned jl_typemap_list_count(jl_typemap_entry_t *ml)
9631033
return count;
9641034
}
9651035

966-
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);
1036+
static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs,
1037+
const struct jl_typemap_info *tparams);
9671038
static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent,
9681039
jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams);
9691040

@@ -982,7 +1053,8 @@ static jl_typemap_level_t *jl_new_typemap_level(void)
9821053
return cache;
9831054
}
9841055

985-
static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs)
1056+
static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *ml, jl_value_t *key, int8_t offs,
1057+
const struct jl_typemap_info *tparams)
9861058
{
9871059
jl_typemap_level_t *cache = jl_new_typemap_level();
9881060
cache->key = key;
@@ -991,7 +1063,7 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache(jl_typemap_entry_t *m
9911063
while (ml != (void*)jl_nothing) {
9921064
next = ml->next;
9931065
ml->next = (jl_typemap_entry_t*)jl_nothing;
994-
jl_typemap_level_insert_(cache, ml, offs, 0);
1066+
jl_typemap_level_insert_(cache, ml, offs, tparams);
9951067
ml = next;
9961068
}
9971069
JL_GC_POP();
@@ -1024,7 +1096,7 @@ static void jl_typemap_insert_generic(union jl_typemap_t *pml, jl_value_t *paren
10241096

10251097
unsigned count = jl_typemap_list_count(pml->leaf);
10261098
if (count > MAX_METHLIST_COUNT) {
1027-
pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs);
1099+
pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs, tparams);
10281100
jl_gc_wb(parent, pml->node);
10291101
jl_typemap_level_insert_(pml->node, newrec, offs, tparams);
10301102
return;
@@ -1091,9 +1163,34 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry
10911163
if (a0 && jl_typemap_array_insert_(&cache->name1, a0, newrec, (jl_value_t*)cache, 2, offs, tparams))
10921164
return;
10931165
}
1094-
if (!t1 || jl_args_morespecific_typename(t1)) {
1095-
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec, tparams);
1096-
return;
1166+
int morespec = t1 ? jl_args_morespecific_typename(t1, 1) : 1;
1167+
if (morespec) {
1168+
if (morespec == 2) {
1169+
// need to split this union into components more-specific than TypeName, and those less-specific
1170+
jl_value_t *morespec_sig = NULL;
1171+
JL_GC_PUSH1(&morespec_sig);
1172+
morespec_sig = (jl_value_t*)jl_svec_copy(newrec->sig->parameters);
1173+
if (l <= offs) offs = l - 1; // bound Vararg to the length of the signature
1174+
jl_value_t *elem = jl_tparam(newrec->sig, offs);
1175+
jl_svecset(morespec_sig, offs, jl_arg_split_spec(elem, 1, 1));
1176+
morespec_sig = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)morespec_sig);
1177+
1178+
jl_typemap_entry_t *newrec2 = (jl_typemap_entry_t*)jl_gc_allocobj(sizeof(jl_typemap_entry_t));
1179+
jl_set_typeof(newrec2, jl_typemap_entry_type);
1180+
*newrec2 = *newrec; // copy newrec to newrec2
1181+
// TODO: mark newrec2 as a non-primary entry (ignored for lookup operations)
1182+
newrec2->sig = (jl_datatype_t*)morespec_sig;
1183+
morespec_sig = (jl_value_t*)newrec2;
1184+
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec2, tparams);
1185+
JL_GC_POP();
1186+
// fall-through. newrec is unmodified since lessspec_sig <: newrec->sig,
1187+
// and the user might try to look up the original sig directly
1188+
// (either through invoke or exact extraction)
1189+
}
1190+
else {
1191+
jl_typemap_list_insert_(&cache->linear_leaf, (jl_value_t*)cache, newrec, tparams);
1192+
return;
1193+
}
10971194
}
10981195
jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams);
10991196
}

0 commit comments

Comments
 (0)