@@ -128,7 +128,7 @@ static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v) JL_GLOBALLY_ROOTED J
128
128
129
129
static int statestack_get (jl_unionstate_t * st , int i ) JL_NOTSAFEPOINT
130
130
{
131
- assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
131
+ assert (i >= 0 && i < 32767 ); // limited by the depth bit.
132
132
// get the `i`th bit in an array of 32-bit words
133
133
jl_bits_stack_t * stack = & st -> stack ;
134
134
while (i >= sizeof (stack -> data ) * 8 ) {
@@ -142,7 +142,7 @@ static int statestack_get(jl_unionstate_t *st, int i) JL_NOTSAFEPOINT
142
142
143
143
static void statestack_set (jl_unionstate_t * st , int i , int val ) JL_NOTSAFEPOINT
144
144
{
145
- assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
145
+ assert (i >= 0 && i < 32767 ); // limited by the depth bit.
146
146
jl_bits_stack_t * stack = & st -> stack ;
147
147
while (i >= sizeof (stack -> data ) * 8 ) {
148
148
if (__unlikely (stack -> next == NULL )) {
@@ -1409,11 +1409,14 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param)
1409
1409
}
1410
1410
if (jl_is_unionall (y )) {
1411
1411
jl_varbinding_t * xb = lookup (e , (jl_tvar_t * )x );
1412
- if (xb == NULL ? !e -> ignore_free : !xb -> right ) {
1412
+ jl_value_t * xub = xb == NULL ? ((jl_tvar_t * )x )-> ub : xb -> ub ;
1413
+ if ((xb == NULL ? !e -> ignore_free : !xb -> right ) && xub != y ) {
1413
1414
// We'd better unwrap `y::UnionAll` eagerly if `x` isa ∀-var.
1414
1415
// This makes sure the following cases work correct:
1415
1416
// 1) `∀T <: Union{∃S, SomeType{P}} where {P}`: `S == Any` ==> `S >: T`
1416
1417
// 2) `∀T <: Union{∀T, SomeType{P}} where {P}`:
1418
+ // note: if xub == y we'd better try `subtype_var` as `subtype_left_var`
1419
+ // hit `==` based fast path.
1417
1420
return subtype_unionall (x , (jl_unionall_t * )y , e , 1 , param );
1418
1421
}
1419
1422
}
@@ -1551,6 +1554,8 @@ static int has_exists_typevar(jl_value_t *x, jl_stenv_t *e) JL_NOTSAFEPOINT
1551
1554
return env != NULL && jl_has_bound_typevars (x , env );
1552
1555
}
1553
1556
1557
+ static int forall_exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param );
1558
+
1554
1559
static int local_forall_exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param , int limit_slow )
1555
1560
{
1556
1561
int16_t oldRmore = e -> Runions .more ;
@@ -1564,7 +1569,18 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1564
1569
return jl_subtype (x , y );
1565
1570
int has_exists = (!kindx && has_exists_typevar (x , e )) ||
1566
1571
(!kindy && has_exists_typevar (y , e ));
1567
- if (has_exists && (is_exists_typevar (x , e ) != is_exists_typevar (y , e ))) {
1572
+ if (!has_exists ) {
1573
+ // We can use ∀_∃_subtype safely for ∃ free inputs.
1574
+ // This helps to save some bits in union stack.
1575
+ jl_saved_unionstate_t oldRunions ; push_unionstate (& oldRunions , & e -> Runions );
1576
+ e -> Lunions .used = e -> Runions .used = 0 ;
1577
+ e -> Lunions .depth = e -> Runions .depth = 0 ;
1578
+ e -> Lunions .more = e -> Runions .more = 0 ;
1579
+ sub = forall_exists_subtype (x , y , e , param );
1580
+ pop_unionstate (& e -> Runions , & oldRunions );
1581
+ return sub ;
1582
+ }
1583
+ if (is_exists_typevar (x , e ) != is_exists_typevar (y , e )) {
1568
1584
e -> Lunions .used = 0 ;
1569
1585
while (1 ) {
1570
1586
e -> Lunions .more = 0 ;
@@ -1578,7 +1594,7 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1578
1594
if (limit_slow == -1 )
1579
1595
limit_slow = kindx || kindy ;
1580
1596
jl_savedenv_t se ;
1581
- save_env (e , & se , has_exists );
1597
+ save_env (e , & se , 1 );
1582
1598
int count , limited = 0 , ini_count = 0 ;
1583
1599
jl_saved_unionstate_t latestLunions = {0 , 0 , 0 , NULL };
1584
1600
while (1 ) {
@@ -1596,26 +1612,26 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
1596
1612
limited = 1 ;
1597
1613
if (!sub || !next_union_state (e , 0 ))
1598
1614
break ;
1599
- if (limited || ! has_exists || e -> Runions .more == oldRmore ) {
1615
+ if (limited || e -> Runions .more == oldRmore ) {
1600
1616
// re-save env and freeze the ∃decision for previous ∀Union
1601
1617
// Note: We could ignore the rest `∃Union` decisions if `x` and `y`
1602
1618
// contain no ∃ typevar, as they have no effect on env.
1603
1619
ini_count = count ;
1604
1620
push_unionstate (& latestLunions , & e -> Lunions );
1605
- re_save_env (e , & se , has_exists );
1621
+ re_save_env (e , & se , 1 );
1606
1622
e -> Runions .more = oldRmore ;
1607
1623
}
1608
1624
}
1609
1625
if (sub || e -> Runions .more == oldRmore )
1610
1626
break ;
1611
1627
assert (e -> Runions .more > oldRmore );
1612
1628
next_union_state (e , 1 );
1613
- restore_env (e , & se , has_exists ); // also restore Rdepth here
1629
+ restore_env (e , & se , 1 ); // also restore Rdepth here
1614
1630
e -> Runions .more = oldRmore ;
1615
1631
}
1616
1632
if (!sub )
1617
1633
assert (e -> Runions .more == oldRmore );
1618
- else if (limited || ! has_exists )
1634
+ else if (limited )
1619
1635
e -> Runions .more = oldRmore ;
1620
1636
free_env (& se );
1621
1637
return sub ;
0 commit comments