@@ -64,6 +64,7 @@ typedef struct jl_varbinding_t {
64
64
int8_t occurs_inv ; // occurs in invariant position
65
65
int8_t occurs_cov ; // # of occurrences in covariant position
66
66
int8_t concrete ; // 1 if another variable has a constraint forcing this one to be concrete
67
+ int8_t upper_bounded ; // var upper bound has been constrained
67
68
// in covariant position, we need to try constraining a variable in different ways:
68
69
// 0 - unconstrained
69
70
// 1 - less than
@@ -145,7 +146,7 @@ static void save_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se)
145
146
v = v -> prev ;
146
147
}
147
148
* root = (jl_value_t * )jl_alloc_svec (len * 3 );
148
- se -> buf = (int8_t * )(len ? malloc (len * 2 ) : NULL );
149
+ se -> buf = (int8_t * )(len ? malloc (len * 3 ) : NULL );
149
150
#ifdef __clang_analyzer__
150
151
if (len )
151
152
memset (se -> buf , 0 , len * 2 );
@@ -157,6 +158,7 @@ static void save_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se)
157
158
jl_svecset (* root , i ++ , (jl_value_t * )v -> innervars );
158
159
se -> buf [j ++ ] = v -> occurs_inv ;
159
160
se -> buf [j ++ ] = v -> occurs_cov ;
161
+ se -> buf [j ++ ] = v -> upper_bounded ;
160
162
v = v -> prev ;
161
163
}
162
164
se -> rdepth = e -> Runions .depth ;
@@ -176,13 +178,46 @@ static void restore_env(jl_stenv_t *e, jl_value_t *root, jl_savedenv_t *se) JL_N
176
178
assert (se -> buf );
177
179
v -> occurs_inv = se -> buf [j ++ ];
178
180
v -> occurs_cov = se -> buf [j ++ ];
181
+ v -> upper_bounded = se -> buf [j ++ ];
179
182
v = v -> prev ;
180
183
}
181
184
e -> Runions .depth = se -> rdepth ;
182
185
if (e -> envout && e -> envidx < e -> envsz )
183
186
memset (& e -> envout [e -> envidx ], 0 , (e -> envsz - e -> envidx )* sizeof (void * ));
184
187
}
185
188
189
+ // restore just occurs_inv and occurs_cov from `se` back to `e`
190
+ static void restore_var_counts (jl_stenv_t * e , jl_savedenv_t * se ) JL_NOTSAFEPOINT
191
+ {
192
+ jl_varbinding_t * v = e -> vars ;
193
+ int j = 0 ;
194
+ while (v != NULL ) {
195
+ assert (se -> buf );
196
+ v -> occurs_inv = se -> buf [j ++ ];
197
+ v -> occurs_cov = se -> buf [j ++ ];
198
+ j ++ ;
199
+ v = v -> prev ;
200
+ }
201
+ }
202
+
203
+ // compute the maximum of the occurence counts in `e` and `se`, storing them in `se`
204
+ static void max_var_counts (jl_stenv_t * e , jl_savedenv_t * se ) JL_NOTSAFEPOINT
205
+ {
206
+ jl_varbinding_t * v = e -> vars ;
207
+ int j = 0 ;
208
+ while (v != NULL ) {
209
+ assert (se -> buf );
210
+ if (v -> occurs_inv > se -> buf [j ])
211
+ se -> buf [j ] = v -> occurs_inv ;
212
+ j ++ ;
213
+ if (v -> occurs_cov > se -> buf [j ])
214
+ se -> buf [j ] = v -> occurs_cov ;
215
+ j ++ ;
216
+ j ++ ;
217
+ v = v -> prev ;
218
+ }
219
+ }
220
+
186
221
// type utilities
187
222
188
223
// quickly test that two types are identical
@@ -542,6 +577,7 @@ static int var_lt(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int param)
542
577
else {
543
578
bb -> ub = simple_meet (bb -> ub , a );
544
579
}
580
+ bb -> upper_bounded = 1 ;
545
581
assert (bb -> ub != (jl_value_t * )b );
546
582
if (jl_is_typevar (a )) {
547
583
jl_varbinding_t * aa = lookup (e , (jl_tvar_t * )a );
@@ -657,7 +693,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
657
693
}
658
694
btemp = btemp -> prev ;
659
695
}
660
- jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , NULL , 0 , 0 , 0 , 0 , e -> invdepth , 0 , NULL , e -> vars };
696
+ jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , NULL , 0 , 0 , 0 , 0 , 0 , e -> invdepth , 0 , NULL , e -> vars };
661
697
JL_GC_PUSH4 (& u , & vb .lb , & vb .ub , & vb .innervars );
662
698
e -> vars = & vb ;
663
699
int ans ;
@@ -671,7 +707,9 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
671
707
// fill variable values into `envout` up to `envsz`
672
708
if (e -> envidx < e -> envsz ) {
673
709
jl_value_t * val ;
674
- if (!vb .occurs_inv && vb .lb != jl_bottom_type )
710
+ if (vb .lb == vb .ub && vb .upper_bounded )
711
+ val = vb .lb ;
712
+ else if (!vb .occurs_inv && vb .lb != jl_bottom_type )
675
713
val = is_leaf_bound (vb .lb ) ? vb .lb : (jl_value_t * )jl_new_typevar (u -> var -> name , jl_bottom_type , vb .lb );
676
714
else if (vb .lb == vb .ub )
677
715
val = vb .lb ;
@@ -720,7 +758,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
720
758
else if (!is_leaf_bound (vb .lb )) {
721
759
ans = 0 ;
722
760
}
723
- if (ans ) {
761
+ if (ans && vb . lb != vb . ub ) {
724
762
// if we occur as another var's lower bound, record the fact that we
725
763
// were concrete so that subtype can return true for that var.
726
764
/*
@@ -731,6 +769,17 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
731
769
btemp = btemp->prev;
732
770
}
733
771
*/
772
+ // a diagonal var cannot be >: another diagonal var at a different invariant depth, e.g.
773
+ // Ref{Tuple{T,T} where T} !<: Ref{Tuple{T,T}} where T
774
+ btemp = vb .prev ;
775
+ while (btemp != NULL ) {
776
+ if (btemp -> lb == (jl_value_t * )u -> var && btemp -> depth0 != vb .depth0 &&
777
+ (btemp -> concrete || (btemp -> occurs_cov > 1 && btemp -> occurs_inv == 0 ))) {
778
+ ans = 0 ;
779
+ break ;
780
+ }
781
+ btemp = btemp -> prev ;
782
+ }
734
783
}
735
784
}
736
785
@@ -811,7 +860,7 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in
811
860
else if ((vvy && ly > lx + 1 ) || (!vvy && lx != ly )) {
812
861
return 0 ;
813
862
}
814
- param = ( param == 0 ? 1 : param ) ;
863
+ param = 1 ;
815
864
jl_value_t * lastx = NULL , * lasty = NULL ;
816
865
while (i < lx ) {
817
866
jl_value_t * xi = jl_tparam (xd , i );
@@ -1067,6 +1116,12 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
1067
1116
{
1068
1117
if (obviously_egal (x , y )) return 1 ;
1069
1118
1119
+ jl_savedenv_t se ; // original env
1120
+ jl_savedenv_t me ; // for accumulating maximum var counts
1121
+ jl_value_t * saved = NULL ;
1122
+ save_env (e , & saved , & se );
1123
+ save_env (e , & saved , & me );
1124
+
1070
1125
jl_unionstate_t oldLunions = e -> Lunions ;
1071
1126
memset (e -> Lunions .stack , 0 , sizeof (e -> Lunions .stack ));
1072
1127
int sub ;
@@ -1096,11 +1151,27 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
1096
1151
statestack_set (& e -> Lunions , i , 0 );
1097
1152
lastset = set - 1 ;
1098
1153
statestack_set (& e -> Lunions , lastset , 1 );
1154
+ // take the maximum of var counts over all choices, to identify
1155
+ // diagonal variables better.
1156
+ max_var_counts (e , & me );
1157
+ restore_var_counts (e , & se );
1099
1158
}
1100
1159
}
1101
1160
1102
1161
e -> Lunions = oldLunions ;
1103
- return sub && subtype (y , x , e , 0 );
1162
+ if (sub ) {
1163
+ // avoid double-counting variables when we check subtype in both directions.
1164
+ // e.g. in `Ref{Tuple{T}}` the `T` occurs once even though we recursively
1165
+ // call `subtype` on it twice.
1166
+ max_var_counts (e , & me );
1167
+ restore_var_counts (e , & se );
1168
+ sub = subtype (y , x , e , 2 );
1169
+ max_var_counts (e , & me );
1170
+ restore_var_counts (e , & me );
1171
+ }
1172
+ free (se .buf );
1173
+ free (me .buf );
1174
+ return sub ;
1104
1175
}
1105
1176
1106
1177
static int exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , jl_value_t * saved , jl_savedenv_t * se , int param )
@@ -1961,7 +2032,7 @@ static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_
1961
2032
{
1962
2033
jl_value_t * res = NULL , * res2 = NULL , * save = NULL , * save2 = NULL ;
1963
2034
jl_savedenv_t se , se2 ;
1964
- jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , NULL , 0 , 0 , 0 , 0 , e -> invdepth , 0 , NULL , e -> vars };
2035
+ jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , NULL , 0 , 0 , 0 , 0 , 0 , e -> invdepth , 0 , NULL , e -> vars };
1965
2036
JL_GC_PUSH6 (& res , & save2 , & vb .lb , & vb .ub , & save , & vb .innervars );
1966
2037
save_env (e , & save , & se );
1967
2038
res = intersect_unionall_ (t , u , e , R , param , & vb );
0 commit comments