Skip to content

Commit dc689fe

Browse files
committed
subtype: combine the fast & slow path in local_∀_∃_<:.
This commit integrates the union complexity limitation and other optimization into the slow path. Consequently, the slow path should achieve speeds comparable to the fast path in most cases, and we can remove the latter to avoid some re-subtyping. The previous `may_contain_union` check has also been removed, which fix issue #55807.
1 parent aee69a4 commit dc689fe

File tree

1 file changed

+52
-64
lines changed

1 file changed

+52
-64
lines changed

src/subtype.c

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,37 +1565,12 @@ static int is_definite_length_tuple_type(jl_value_t *x)
15651565
return k == JL_VARARG_NONE || k == JL_VARARG_INT;
15661566
}
15671567

1568-
static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore);
1569-
1570-
static int may_contain_union_decision(jl_value_t *x, jl_stenv_t *e, jl_typeenv_t *log) JL_NOTSAFEPOINT
1568+
static int is_exists_typevar(jl_value_t *x, jl_stenv_t *e)
15711569
{
1572-
if (x == NULL || x == (jl_value_t*)jl_any_type || x == jl_bottom_type)
1573-
return 0;
1574-
if (jl_is_unionall(x))
1575-
return may_contain_union_decision(((jl_unionall_t *)x)->body, e, log);
1576-
if (jl_is_datatype(x)) {
1577-
jl_datatype_t *xd = (jl_datatype_t *)x;
1578-
for (int i = 0; i < jl_nparams(xd); i++) {
1579-
jl_value_t *param = jl_tparam(xd, i);
1580-
if (jl_is_vararg(param))
1581-
param = jl_unwrap_vararg(param);
1582-
if (may_contain_union_decision(param, e, log))
1583-
return 1;
1584-
}
1585-
return 0;
1586-
}
15871570
if (!jl_is_typevar(x))
1588-
return jl_is_type(x);
1589-
jl_typeenv_t *t = log;
1590-
while (t != NULL) {
1591-
if (x == (jl_value_t *)t->var)
1592-
return 1;
1593-
t = t->prev;
1594-
}
1595-
jl_typeenv_t newlog = { (jl_tvar_t*)x, NULL, log };
1596-
jl_varbinding_t *xb = lookup(e, (jl_tvar_t *)x);
1597-
return may_contain_union_decision(xb ? xb->lb : ((jl_tvar_t *)x)->lb, e, &newlog) ||
1598-
may_contain_union_decision(xb ? xb->ub : ((jl_tvar_t *)x)->ub, e, &newlog);
1571+
return 0;
1572+
jl_varbinding_t *vb = lookup(e, (jl_tvar_t *)x);
1573+
return vb && vb->right;
15991574
}
16001575

16011576
static int has_exists_typevar(jl_value_t *x, jl_stenv_t *e) JL_NOTSAFEPOINT
@@ -1626,31 +1601,9 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
16261601
int kindy = !jl_has_free_typevars(y);
16271602
if (kindx && kindy)
16281603
return jl_subtype(x, y);
1629-
if (may_contain_union_decision(y, e, NULL) && pick_union_decision(e, 1) == 0) {
1630-
jl_saved_unionstate_t oldRunions; push_unionstate(&oldRunions, &e->Runions);
1631-
e->Lunions.used = e->Runions.used = 0;
1632-
e->Lunions.depth = e->Runions.depth = 0;
1633-
e->Lunions.more = e->Runions.more = 0;
1634-
int count = 0, noRmore = 0;
1635-
sub = _forall_exists_subtype(x, y, e, param, &count, &noRmore);
1636-
pop_unionstate(&e->Runions, &oldRunions);
1637-
// We could skip the slow path safely if
1638-
// 1) `_∀_∃_subtype` has tested all cases
1639-
// 2) `_∀_∃_subtype` returns 1 && `x` and `y` contain no ∃ typevar
1640-
// Once `limit_slow == 1`, also skip it if
1641-
// 1) `_∀_∃_subtype` returns 0
1642-
// 2) the left `Union` looks big
1643-
// TODO: `limit_slow` ignores complexity from inner `local_∀_exists_subtype`.
1644-
if (limit_slow == -1)
1645-
limit_slow = kindx || kindy;
1646-
int skip = noRmore || (limit_slow && (count > 3 || !sub)) ||
1647-
(sub && (kindx || !has_exists_typevar(x, e)) &&
1648-
(kindy || !has_exists_typevar(y, e)));
1649-
if (skip)
1650-
e->Runions.more = oldRmore;
1651-
}
1652-
else {
1653-
// slow path
1604+
int has_exists = (!kindx && has_exists_typevar(x, e)) ||
1605+
(!kindy && has_exists_typevar(y, e));
1606+
if (has_exists && (is_exists_typevar(x, e) != is_exists_typevar(y, e))) {
16541607
e->Lunions.used = 0;
16551608
while (1) {
16561609
e->Lunions.more = 0;
@@ -1659,7 +1612,51 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
16591612
if (!sub || !next_union_state(e, 0))
16601613
break;
16611614
}
1615+
return sub;
16621616
}
1617+
if (limit_slow == -1)
1618+
limit_slow = kindx || kindy;
1619+
jl_savedenv_t se;
1620+
save_env(e, &se, has_exists);
1621+
int count, limited = 0, ini_count = 0;
1622+
jl_saved_unionstate_t latestLunions = {0, 0, 0, NULL};
1623+
while (1) {
1624+
count = ini_count;
1625+
if (ini_count == 0)
1626+
e->Lunions.used = 0;
1627+
else
1628+
pop_unionstate(&e->Lunions, &latestLunions);
1629+
while (1) {
1630+
e->Lunions.more = 0;
1631+
e->Lunions.depth = 0;
1632+
if (count < 4) count++;
1633+
sub = subtype(x, y, e, param);
1634+
if (limit_slow && count == 4)
1635+
limited = 1;
1636+
if (!sub || !next_union_state(e, 0))
1637+
break;
1638+
if (limited || !has_exists || e->Runions.more == oldRmore) {
1639+
// re-save env and freeze the ∃decision for previous ∀Union
1640+
// Note: We could ignore the rest `∃Union` decisions if `x` and `y`
1641+
// contain no ∃ typevar, as they have no effect on env.
1642+
ini_count = count;
1643+
push_unionstate(&latestLunions, &e->Lunions);
1644+
re_save_env(e, &se, has_exists);
1645+
e->Runions.more = oldRmore;
1646+
}
1647+
}
1648+
if (sub || e->Runions.more == oldRmore)
1649+
break;
1650+
assert(e->Runions.more > oldRmore);
1651+
next_union_state(e, 1);
1652+
restore_env(e, &se, has_exists); // also restore Rdepth here
1653+
e->Runions.more = oldRmore;
1654+
}
1655+
if (!sub)
1656+
assert(e->Runions.more == oldRmore);
1657+
else if (limited || !has_exists)
1658+
e->Runions.more = oldRmore;
1659+
free_env(&se);
16631660
return sub;
16641661
}
16651662

@@ -1729,7 +1726,7 @@ static int exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savede
17291726
}
17301727
}
17311728

1732-
static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore)
1729+
static int forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param)
17331730
{
17341731
// The depth recursion has the following shape, after simplification:
17351732
// ∀₁
@@ -1741,12 +1738,8 @@ static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, i
17411738

17421739
e->Lunions.used = 0;
17431740
int sub;
1744-
if (count) *count = 0;
1745-
if (noRmore) *noRmore = 1;
17461741
while (1) {
17471742
sub = exists_subtype(x, y, e, &se, param);
1748-
if (count) *count = (*count < 4) ? *count + 1 : 4;
1749-
if (noRmore) *noRmore = *noRmore && e->Runions.more == 0;
17501743
if (!sub || !next_union_state(e, 0))
17511744
break;
17521745
re_save_env(e, &se, 1);
@@ -1756,11 +1749,6 @@ static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, i
17561749
return sub;
17571750
}
17581751

1759-
static int forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param)
1760-
{
1761-
return _forall_exists_subtype(x, y, e, param, NULL, NULL);
1762-
}
1763-
17641752
static void init_stenv(jl_stenv_t *e, jl_value_t **env, int envsz)
17651753
{
17661754
e->vars = NULL;

0 commit comments

Comments
 (0)