Skip to content

Commit ed270c4

Browse files
committed
simplify tuple type specificity implementation
1 parent f004bf1 commit ed270c4

File tree

1 file changed

+63
-107
lines changed

1 file changed

+63
-107
lines changed

src/subtype.c

Lines changed: 63 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,48 +2217,6 @@ JL_DLLEXPORT jl_svec_t *jl_env_from_type_intersection(jl_value_t *a, jl_value_t
22172217

22182218
// specificity comparison
22192219

2220-
/*
2221-
Simplification of varargs tuple types:
2222-
JL_TUPLE_FIXED: tuples of known length (e.g., JL_VARARG_NONE or JL_VARARG_INT)
2223-
JL_TUPLE_VAR: tuples of unknown length (e.g., JL_VARARG_BOUND or JL_VARARG_UNBOUND)
2224-
2225-
In some cases, JL_VARARG_BOUND tuples get described as JL_TUPLE_FIXED,
2226-
if the constraints on length are already known.
2227-
2228-
lenr = "representation length" (the number of parameters)
2229-
lenf = "full length" (including the Vararg length, if known)
2230-
2231-
In general, lenf >= lenr-1. The lower bound is achieved only for a Vararg of length 0.
2232-
*/
2233-
typedef enum {
2234-
JL_TUPLE_FIXED = 0,
2235-
JL_TUPLE_VAR = 1
2236-
} jl_tuple_lenkind_t;
2237-
2238-
static size_t tuple_vararg_params(jl_svec_t *a, jl_vararg_kind_t *kind, jl_tuple_lenkind_t *lenkind)
2239-
{
2240-
jl_value_t **data = jl_svec_data(a); size_t lenr = jl_svec_len(a);
2241-
size_t lenf = lenr;
2242-
if (lenr == 0) {
2243-
*kind = JL_VARARG_NONE;
2244-
*lenkind = JL_TUPLE_FIXED;
2245-
return lenf;
2246-
}
2247-
*lenkind = JL_TUPLE_VAR;
2248-
jl_value_t *last = data[lenr-1];
2249-
*kind = jl_vararg_kind(last);
2250-
if (*kind == JL_VARARG_NONE || *kind == JL_VARARG_INT)
2251-
*lenkind = JL_TUPLE_FIXED;
2252-
if (*kind == JL_VARARG_INT || *kind == JL_VARARG_BOUND) {
2253-
jl_value_t *N = jl_tparam1(jl_unwrap_unionall(last));
2254-
if (jl_is_long(N)) {
2255-
lenf += jl_unbox_long(N)-1;
2256-
*lenkind = JL_TUPLE_FIXED;
2257-
}
2258-
}
2259-
return lenf;
2260-
}
2261-
22622220
static int eq_msp(jl_value_t *a, jl_value_t *b, jl_typeenv_t *env)
22632221
{
22642222
// equate ANY and Any for specificity purposes, #16153
@@ -2298,97 +2256,100 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
22982256

22992257
static int num_occurs(jl_tvar_t *v, jl_typeenv_t *env);
23002258

2259+
static jl_value_t *nth_tuple_elt(jl_datatype_t *t, size_t i)
2260+
{
2261+
size_t len = jl_field_count(t);
2262+
if (len == 0)
2263+
return NULL;
2264+
if (i < len-1)
2265+
return jl_tparam(t, i);
2266+
jl_value_t *last = jl_unwrap_unionall(jl_tparam(t, len-1));
2267+
if (jl_is_vararg_type(last)) {
2268+
jl_value_t *n = jl_tparam1(last);
2269+
if (jl_is_long(n) && i >= len-1+jl_unbox_long(n))
2270+
return NULL;
2271+
return jl_tparam0(last);
2272+
}
2273+
if (i == len-1)
2274+
return jl_tparam(t, i);
2275+
return NULL;
2276+
}
2277+
23012278
static int tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int invariant, jl_typeenv_t *env)
23022279
{
2303-
size_t clenr = jl_nparams(cdt);
2304-
jl_value_t **child = jl_svec_data(cdt->parameters);
23052280
size_t plenr = jl_nparams(pdt);
2306-
jl_value_t **parent = jl_svec_data(pdt->parameters);
2307-
size_t plenf, clenf;
2308-
jl_vararg_kind_t ckind, pkind;
2309-
jl_tuple_lenkind_t clenkind, plenkind;
2310-
clenf = tuple_vararg_params(cdt->parameters, &ckind, &clenkind);
2311-
plenf = tuple_vararg_params(pdt->parameters, &pkind, &plenkind);
2312-
size_t ci=0, pi=0;
2313-
int cseq=0, pseq=0, cdiag=0, pdiag=0;
2281+
if (plenr == 0) return 0;
2282+
size_t clenr = jl_nparams(cdt);
2283+
if (clenr == 0) return 1;
2284+
int i = 0;
2285+
int cva = jl_vararg_kind(jl_tparam(cdt,clenr-1)) > JL_VARARG_INT;
2286+
int pva = jl_vararg_kind(jl_tparam(pdt,plenr-1)) > JL_VARARG_INT;
2287+
int cdiag = 0, pdiag = 0;
23142288
int some_morespecific = 0;
2315-
jl_value_t *ce=NULL, *pe=NULL;
23162289
while (1) {
2317-
if (!cseq)
2318-
cseq = (ci<clenr) && clenkind != JL_TUPLE_FIXED && jl_is_vararg_type(child[ci]);
2319-
if (!pseq)
2320-
pseq = (pi<plenr) && plenkind != JL_TUPLE_FIXED && jl_is_vararg_type(parent[pi]);
2321-
2322-
if (ci >= clenf && !cseq) {
2323-
if (pseq && plenr <= clenr+1) return 1;
2324-
// shorter tuples are more specific, to ensure transitivity with varargs
2325-
if (!pseq && clenr < plenr) return 1;
2326-
if (!pseq && clenr > plenr) return 0;
2327-
break;
2328-
}
2329-
if (pi >= plenf && !pseq) {
2330-
if (!cseq && plenr < clenr && !some_morespecific) return 0;
2331-
break;
2332-
}
2290+
if (cva && pva && i >= clenr && i >= plenr) break;
2291+
jl_value_t *ce = nth_tuple_elt(cdt, i);
2292+
jl_value_t *pe = nth_tuple_elt(pdt, i);
23332293

2334-
if (ci < clenr) {
2335-
ce = child[ci];
2336-
if (jl_is_vararg_type(ce)) ce = jl_unwrap_vararg(ce);
2294+
if (ce == NULL) {
2295+
if (pe == NULL) break;
2296+
return 1;
23372297
}
2338-
if (pi < plenr) {
2339-
pe = parent[pi];
2340-
if (jl_is_vararg_type(pe)) pe = jl_unwrap_vararg(pe);
2298+
if (pe == NULL) {
2299+
if (!cva && !some_morespecific) return 0;
2300+
break;
23412301
}
2342-
23432302
if (type_morespecific_(pe, ce, invariant, env)) {
23442303
assert(!type_morespecific_(ce, pe, invariant, env));
23452304
return 0;
23462305
}
2347-
23482306
if (!cdiag && jl_is_typevar(ce) && num_occurs((jl_tvar_t*)ce,env) > 1)
23492307
cdiag = 1;
23502308
if (!pdiag && jl_is_typevar(pe) && num_occurs((jl_tvar_t*)pe,env) > 1)
23512309
pdiag = 1;
23522310

23532311
// in Tuple{a,b...} and Tuple{c,d...} allow b and d to be disjoint
2354-
if (cseq && pseq && (some_morespecific || (cdiag && !pdiag))) return 1;
2312+
if (cva && pva && i >= clenr-1 && i >= plenr-1 && (some_morespecific || (cdiag && !pdiag))) return 1;
23552313

23562314
int cms = type_morespecific_(ce, pe, invariant, env);
23572315
int eqv = !cms && eq_msp(ce, pe, env);
23582316

23592317
if (!cms && !eqv) return 0;
23602318

23612319
if (cms) some_morespecific = 1;
2362-
2363-
if (cms && ci==clenr-1 && pi==plenr-1 && clenr == plenr && !cseq && pseq) {
2364-
// make Vararg{X, 1} more specific than Vararg{X, N}
2365-
if (jl_is_vararg_type(child[ci]) && eqv)
2366-
return 1;
2367-
}
2368-
2369-
if (cseq && pseq) {
2370-
if (clenr > plenr && (!pdiag || cdiag))
2371-
return 1;
2372-
break;
2373-
}
2374-
ci++;
2375-
pi++;
2320+
i++;
23762321
}
2322+
if (cva && pva && clenr > plenr && (!pdiag || cdiag))
2323+
return 1;
23772324
return some_morespecific || (cdiag && !pdiag);
23782325
}
23792326

2327+
static size_t tuple_full_length(jl_value_t *t)
2328+
{
2329+
size_t n = jl_nparams(t);
2330+
if (n == 0) return 0;
2331+
jl_value_t *last = jl_unwrap_unionall(jl_tparam(t,n-1));
2332+
if (jl_is_vararg_type(last)) {
2333+
jl_value_t *N = jl_tparam1(last);
2334+
if (jl_is_long(N))
2335+
n += jl_unbox_long(N)-1;
2336+
}
2337+
return n;
2338+
}
2339+
23802340
// Called when a is a bound-vararg and b is not a vararg. Sets the vararg length
23812341
// in a to match b, as long as this makes some earlier argument more specific.
23822342
static int args_morespecific_fix1(jl_value_t *a, jl_value_t *b, int swap, jl_typeenv_t *env)
23832343
{
23842344
size_t n = jl_nparams(a);
2385-
int nfix = jl_nparams(b)-n+1;
2386-
assert(jl_is_va_tuple(a));
2387-
assert(nfix >= 0);
2345+
int nfix = tuple_full_length(b)-n+1;
2346+
if (nfix <= 0)
2347+
return -1;
2348+
assert(jl_is_va_tuple((jl_datatype_t*)a));
23882349
jl_datatype_t *newtta = NULL;
2389-
jl_value_t *env[2] = { jl_tparam1(jl_unwrap_unionall(jl_tparam(a, n-1))), jl_box_long(nfix) };
2390-
JL_GC_PUSH2(&newtta, &env[1]);
2391-
newtta = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)a, env, 1);
2350+
jl_value_t *e[2] = { jl_tparam1(jl_unwrap_unionall(jl_tparam(a, n-1))), jl_box_long(nfix) };
2351+
JL_GC_PUSH2(&newtta, &e[1]);
2352+
newtta = (jl_datatype_t*)jl_instantiate_type_with((jl_value_t*)a, e, 1);
23922353
int changed = 0;
23932354
for (size_t i = 0; i < n-1; i++) {
23942355
if (jl_tparam(a, i) != jl_tparam(newtta, i)) {
@@ -2473,19 +2434,14 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty
24732434
}
24742435

24752436
if (jl_is_tuple_type(a) && jl_is_tuple_type(b)) {
2476-
jl_datatype_t *tta = (jl_datatype_t*)a;
2477-
jl_datatype_t *ttb = (jl_datatype_t*)b;
2478-
size_t alenf, blenf;
2479-
jl_vararg_kind_t akind, bkind;
2480-
jl_tuple_lenkind_t alenkind, blenkind;
2481-
alenf = tuple_vararg_params(tta->parameters, &akind, &alenkind);
2482-
blenf = tuple_vararg_params(ttb->parameters, &bkind, &blenkind);
24832437
// When one is JL_VARARG_BOUND and the other has fixed length,
24842438
// allow the argument length to fix the tvar
2439+
jl_vararg_kind_t ak = jl_va_tuple_kind((jl_datatype_t*)a);
2440+
jl_vararg_kind_t bk = jl_va_tuple_kind((jl_datatype_t*)b);
24852441
int ans = -1;
2486-
if (akind == JL_VARARG_BOUND && blenkind == JL_TUPLE_FIXED && blenf >= alenf)
2442+
if (ak == JL_VARARG_BOUND && bk < JL_VARARG_BOUND)
24872443
ans = args_morespecific_fix1(a, b, 0, env);
2488-
if (bkind == JL_VARARG_BOUND && alenkind == JL_TUPLE_FIXED && alenf >= blenf)
2444+
if (bk == JL_VARARG_BOUND && ak < JL_VARARG_BOUND)
24892445
ans = args_morespecific_fix1(b, a, 1, env);
24902446
if (ans != -1) return ans;
24912447
return tuple_morespecific((jl_datatype_t*)a, (jl_datatype_t*)b, invariant, env);

0 commit comments

Comments
 (0)