@@ -139,7 +139,7 @@ static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v) JL_GLOBALLY_ROOTED J
139
139
140
140
static int statestack_get (jl_unionstate_t * st , int i ) JL_NOTSAFEPOINT
141
141
{
142
- assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
142
+ assert (i >= 0 && i < 32767 ); // limited by the depth bit.
143
143
// get the `i`th bit in an array of 32-bit words
144
144
jl_bits_stack_t * stack = & st -> stack ;
145
145
while (i >= sizeof (stack -> data ) * 8 ) {
@@ -153,7 +153,7 @@ static int statestack_get(jl_unionstate_t *st, int i) JL_NOTSAFEPOINT
153
153
154
154
static void statestack_set (jl_unionstate_t * st , int i , int val ) JL_NOTSAFEPOINT
155
155
{
156
- assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
156
+ assert (i >= 0 && i < 32767 ); // limited by the depth bit.
157
157
jl_bits_stack_t * stack = & st -> stack ;
158
158
while (i >= sizeof (stack -> data ) * 8 ) {
159
159
if (__unlikely (stack -> next == NULL )) {
@@ -1448,11 +1448,14 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param)
1448
1448
}
1449
1449
if (jl_is_unionall (y )) {
1450
1450
jl_varbinding_t * xb = lookup (e , (jl_tvar_t * )x );
1451
- if (xb == NULL ? !e -> ignore_free : !xb -> right ) {
1451
+ jl_value_t * xub = xb == NULL ? ((jl_tvar_t * )x )-> ub : xb -> ub ;
1452
+ if ((xb == NULL ? !e -> ignore_free : !xb -> right ) && xub != y ) {
1452
1453
// We'd better unwrap `y::UnionAll` eagerly if `x` isa ∀-var.
1453
1454
// This makes sure the following cases work correct:
1454
1455
// 1) `∀T <: Union{∃S, SomeType{P}} where {P}`: `S == Any` ==> `S >: T`
1455
1456
// 2) `∀T <: Union{∀T, SomeType{P}} where {P}`:
1457
+ // note: if xub == y we'd better try `subtype_var` as `subtype_left_var`
1458
+ // hit `==` based fast path.
1456
1459
return subtype_unionall (x , (jl_unionall_t * )y , e , 1 , param );
1457
1460
}
1458
1461
}
@@ -1590,6 +1593,8 @@ static int has_exists_typevar(jl_value_t *x, jl_stenv_t *e) JL_NOTSAFEPOINT
1590
1593
return env != NULL && jl_has_bound_typevars (x , env );
1591
1594
}
1592
1595
1596
+ static int forall_exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param );
1597
+
1593
1598
static int local_forall_exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param , int limit_slow )
1594
1599
{
1595
1600
int16_t oldRmore = e -> Runions .more ;
@@ -1603,7 +1608,18 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1603
1608
return jl_subtype (x , y );
1604
1609
int has_exists = (!kindx && has_exists_typevar (x , e )) ||
1605
1610
(!kindy && has_exists_typevar (y , e ));
1606
- if (has_exists && (is_exists_typevar (x , e ) != is_exists_typevar (y , e ))) {
1611
+ if (!has_exists ) {
1612
+ // We can use ∀_∃_subtype safely for ∃ free inputs.
1613
+ // This helps to save some bits in union stack.
1614
+ jl_saved_unionstate_t oldRunions ; push_unionstate (& oldRunions , & e -> Runions );
1615
+ e -> Lunions .used = e -> Runions .used = 0 ;
1616
+ e -> Lunions .depth = e -> Runions .depth = 0 ;
1617
+ e -> Lunions .more = e -> Runions .more = 0 ;
1618
+ sub = forall_exists_subtype (x , y , e , param );
1619
+ pop_unionstate (& e -> Runions , & oldRunions );
1620
+ return sub ;
1621
+ }
1622
+ if (is_exists_typevar (x , e ) != is_exists_typevar (y , e )) {
1607
1623
e -> Lunions .used = 0 ;
1608
1624
while (1 ) {
1609
1625
e -> Lunions .more = 0 ;
@@ -1617,7 +1633,7 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1617
1633
if (limit_slow == -1 )
1618
1634
limit_slow = kindx || kindy ;
1619
1635
jl_savedenv_t se ;
1620
- save_env (e , & se , has_exists );
1636
+ save_env (e , & se , 1 );
1621
1637
int count , limited = 0 , ini_count = 0 ;
1622
1638
jl_saved_unionstate_t latestLunions = {0 , 0 , 0 , NULL };
1623
1639
while (1 ) {
@@ -1635,26 +1651,26 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1635
1651
limited = 1 ;
1636
1652
if (!sub || !next_union_state (e , 0 ))
1637
1653
break ;
1638
- if (limited || ! has_exists || e -> Runions .more == oldRmore ) {
1654
+ if (limited || e -> Runions .more == oldRmore ) {
1639
1655
// re-save env and freeze the ∃decision for previous ∀Union
1640
1656
// Note: We could ignore the rest `∃Union` decisions if `x` and `y`
1641
1657
// contain no ∃ typevar, as they have no effect on env.
1642
1658
ini_count = count ;
1643
1659
push_unionstate (& latestLunions , & e -> Lunions );
1644
- re_save_env (e , & se , has_exists );
1660
+ re_save_env (e , & se , 1 );
1645
1661
e -> Runions .more = oldRmore ;
1646
1662
}
1647
1663
}
1648
1664
if (sub || e -> Runions .more == oldRmore )
1649
1665
break ;
1650
1666
assert (e -> Runions .more > oldRmore );
1651
1667
next_union_state (e , 1 );
1652
- restore_env (e , & se , has_exists ); // also restore Rdepth here
1668
+ restore_env (e , & se , 1 ); // also restore Rdepth here
1653
1669
e -> Runions .more = oldRmore ;
1654
1670
}
1655
1671
if (!sub )
1656
1672
assert (e -> Runions .more == oldRmore );
1657
- else if (limited || ! has_exists )
1673
+ else if (limited )
1658
1674
e -> Runions .more = oldRmore ;
1659
1675
free_env (& se );
1660
1676
return sub ;
0 commit comments