Skip to content

Commit beab3b6

Browse files
authored
Merge pull request #16249 from JuliaLang/teh/morespecific_vararg
Fix specificity with bound varargs
2 parents 26fec34 + 9614c40 commit beab3b6

File tree

3 files changed

+114
-35
lines changed

3 files changed

+114
-35
lines changed

src/jltypes.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,21 @@ static int type_eqv_with_ANY(jl_value_t *a, jl_value_t *b)
27772777

27782778
static int jl_type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant);
27792779

2780+
jl_datatype_t *jl_fix_vararg_bound(jl_datatype_t *tt, int nfix)
2781+
{
2782+
assert(jl_is_va_tuple(tt));
2783+
assert(nfix >= 0);
2784+
jl_svec_t *tp = tt->parameters;
2785+
size_t ntp = jl_svec_len(tp);
2786+
jl_value_t *env[2] = {NULL, NULL};
2787+
JL_GC_PUSH2(&env[0], &env[1]);
2788+
env[0] = jl_tparam1(jl_tparam(tt, ntp-1));
2789+
env[1] = jl_box_long(nfix);
2790+
jl_datatype_t *ret = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)tt, env, 2);
2791+
JL_GC_POP();
2792+
return ret;
2793+
}
2794+
27802795
static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant)
27812796
{
27822797
size_t clenr = jl_nparams(cdt);
@@ -2999,6 +3014,93 @@ JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b)
29993014
return jl_type_morespecific_(a, b, 0);
30003015
}
30013016

3017+
int jl_args_morespecific_(jl_value_t *a, jl_value_t *b)
3018+
{
3019+
int msp = jl_type_morespecific(a,b);
3020+
int btv = jl_has_typevars(b);
3021+
if (btv) {
3022+
if (jl_type_match_morespecific(a,b) == (jl_value_t*)jl_false) {
3023+
if (jl_has_typevars(a))
3024+
return 0;
3025+
return msp;
3026+
}
3027+
if (jl_has_typevars(a)) {
3028+
type_match_invariance_mask = 0;
3029+
//int result = jl_type_match_morespecific(b,a) == (jl_value_t*)jl_false);
3030+
// this rule seems to work better:
3031+
int result = jl_type_match(b,a) == (jl_value_t*)jl_false;
3032+
type_match_invariance_mask = 1;
3033+
if (result)
3034+
return 1;
3035+
}
3036+
int nmsp = jl_type_morespecific(b,a);
3037+
if (nmsp == msp)
3038+
return 0;
3039+
}
3040+
if (jl_has_typevars((jl_value_t*)a)) {
3041+
int nmsp = jl_type_morespecific(b,a);
3042+
if (nmsp && msp)
3043+
return 1;
3044+
if (!btv && jl_types_equal(a,b))
3045+
return 1;
3046+
if (jl_type_match_morespecific(b,a) != (jl_value_t*)jl_false)
3047+
return 0;
3048+
}
3049+
return msp;
3050+
}
3051+
3052+
// Called when a is a bound-vararg and b is not a vararg. Sets the
3053+
// vararg length in a to match b, as long as this makes some earlier
3054+
// argument more specific.
3055+
int jl_args_morespecific_fix1(jl_value_t *a, jl_value_t *b, int swap)
3056+
{
3057+
jl_datatype_t *tta = (jl_datatype_t*)a;
3058+
jl_datatype_t *ttb = (jl_datatype_t*)b;
3059+
size_t n = jl_nparams(tta);
3060+
jl_datatype_t *newtta = jl_fix_vararg_bound(tta, jl_nparams(ttb)-n+1);
3061+
int changed = 0;
3062+
for (size_t i = 0; i < n-1; i++) {
3063+
if (jl_tparam(tta, i) != jl_tparam(newtta, i)) {
3064+
changed = 1;
3065+
break;
3066+
}
3067+
}
3068+
if (changed) {
3069+
JL_GC_PUSH1(&newtta);
3070+
int ret;
3071+
if (swap)
3072+
ret = jl_args_morespecific_(b, (jl_value_t*)newtta);
3073+
else
3074+
ret = jl_args_morespecific_((jl_value_t*)newtta, b);
3075+
JL_GC_POP();
3076+
return ret;
3077+
}
3078+
if (swap)
3079+
return jl_args_morespecific_(b, a);
3080+
return jl_args_morespecific_(a, b);
3081+
}
3082+
3083+
JL_DLLEXPORT int jl_args_morespecific(jl_value_t *a, jl_value_t *b)
3084+
{
3085+
if (jl_is_tuple_type(a) && jl_is_tuple_type(b)) {
3086+
jl_datatype_t *tta = (jl_datatype_t*)a;
3087+
jl_datatype_t *ttb = (jl_datatype_t*)b;
3088+
size_t alenf, blenf;
3089+
jl_vararg_kind_t akind, bkind;
3090+
jl_tuple_lenkind_t alenkind, blenkind;
3091+
alenf = tuple_vararg_params(tta->parameters, NULL, &akind, &alenkind);
3092+
blenf = tuple_vararg_params(ttb->parameters, NULL, &bkind, &blenkind);
3093+
// When one is JL_VARARG_BOUND and the other has fixed length,
3094+
// allow the argument length to fix the tvar
3095+
if (akind == JL_VARARG_BOUND && blenkind == JL_TUPLE_FIXED && blenf >= alenf) {
3096+
return jl_args_morespecific_fix1(a, b, 0);
3097+
}
3098+
if (bkind == JL_VARARG_BOUND && alenkind == JL_TUPLE_FIXED && alenf >= blenf) {
3099+
return jl_args_morespecific_fix1(b, a, 1);
3100+
}
3101+
}
3102+
return jl_args_morespecific_(a, b);
3103+
}
30023104

30033105
// ----------------------------------------------------------------------------
30043106

src/typemap.c

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,41 +1008,6 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par
10081008
return newrec;
10091009
}
10101010

1011-
JL_DLLEXPORT int jl_args_morespecific(jl_value_t *a, jl_value_t *b)
1012-
{
1013-
int msp = jl_type_morespecific(a,b);
1014-
int btv = jl_has_typevars(b);
1015-
if (btv) {
1016-
if (jl_type_match_morespecific(a,b) == (jl_value_t*)jl_false) {
1017-
if (jl_has_typevars(a))
1018-
return 0;
1019-
return msp;
1020-
}
1021-
if (jl_has_typevars(a)) {
1022-
type_match_invariance_mask = 0;
1023-
//int result = jl_type_match_morespecific(b,a) == (jl_value_t*)jl_false);
1024-
// this rule seems to work better:
1025-
int result = jl_type_match(b,a) == (jl_value_t*)jl_false;
1026-
type_match_invariance_mask = 1;
1027-
if (result)
1028-
return 1;
1029-
}
1030-
int nmsp = jl_type_morespecific(b,a);
1031-
if (nmsp == msp)
1032-
return 0;
1033-
}
1034-
if (jl_has_typevars((jl_value_t*)a)) {
1035-
int nmsp = jl_type_morespecific(b,a);
1036-
if (nmsp && msp)
1037-
return 1;
1038-
if (!btv && jl_types_equal(a,b))
1039-
return 1;
1040-
if (jl_type_match_morespecific(b,a) != (jl_value_t*)jl_false)
1041-
return 0;
1042-
}
1043-
return msp;
1044-
}
1045-
10461011
static int has_unions(jl_tupletype_t *type)
10471012
{
10481013
int i;

test/core.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ let T = TypeVar(:T, Tuple{Vararg{RangeIndex}}, true)
206206
@test args_morespecific(t2, t1)
207207
end
208208

209+
let T = TypeVar(:T, Any, true), N = TypeVar(:N, Any, true)
210+
a = Tuple{Array{T,N}, Vararg{Int,N}}
211+
b = Tuple{Array,Int}
212+
@test args_morespecific(a, b)
213+
@test !args_morespecific(b, a)
214+
a = Tuple{Array, Vararg{Int,N}}
215+
@test !args_morespecific(a, b)
216+
@test args_morespecific(b, a)
217+
end
218+
219+
# with bound varargs
220+
209221
# issue #11840
210222
typealias TT11840{T} Tuple{T,T}
211223
f11840(::Type) = "Type"

0 commit comments

Comments
 (0)