@@ -68,15 +68,14 @@ typedef struct jl_varbinding_t {
68
68
int8_t occurs_inv ; // occurs in invariant position
69
69
int8_t occurs_cov ; // # of occurrences in covariant position
70
70
int8_t concrete ; // 1 if another variable has a constraint forcing this one to be concrete
71
- // in covariant position, we need to try constraining a variable in different ways:
72
- // 0 - unconstrained
73
- // 1 - less than
74
- // 2 - greater than
75
- // 3 - inexpressible - occurs when the var has non-trivial overlap with another type,
76
- // and we would need to return `intersect(var,other)`. in this case
77
- // we choose to over-estimate the intersection by returning the var.
71
+ // constraintkind: in covariant position, we try three different ways to compute var ∩ type:
72
+ // let ub = var.ub ∩ type
73
+ // 0 - var.ub <: type ? var : ub
74
+ // 1 - var.ub = ub; return var
75
+ // 2 - either (var.ub = ub; return var), or return ub
78
76
int8_t constraintkind ;
79
77
int8_t intvalued ; // must be integer-valued; i.e. occurs as N in Vararg{_,N}
78
+ int8_t limited ;
80
79
int16_t depth0 ; // # of invariant constructors nested around the UnionAll type for this var
81
80
// when this variable's integer value is compared to that of another,
82
81
// it equals `other + offset`. used by vararg length parameters.
@@ -102,6 +101,7 @@ typedef struct jl_stenv_t {
102
101
int ignore_free ; // treat free vars as black boxes; used during intersection
103
102
int intersection ; // true iff subtype is being called from intersection
104
103
int emptiness_only ; // true iff intersection only needs to test for emptiness
104
+ int triangular ; // when intersecting Ref{X} with Ref{<:Y}
105
105
} jl_stenv_t ;
106
106
107
107
// state manipulation utilities
@@ -759,7 +759,7 @@ static jl_unionall_t *unalias_unionall(jl_unionall_t *u, jl_stenv_t *e)
759
759
static int subtype_unionall (jl_value_t * t , jl_unionall_t * u , jl_stenv_t * e , int8_t R , int param )
760
760
{
761
761
u = unalias_unionall (u , e );
762
- jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , 0 , 0 , 0 , 0 , 0 ,
762
+ jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , 0 , 0 , 0 , 0 , 0 , 0 ,
763
763
R ? e -> Rinvdepth : e -> invdepth , 0 , NULL , e -> vars };
764
764
JL_GC_PUSH4 (& u , & vb .lb , & vb .ub , & vb .innervars );
765
765
e -> vars = & vb ;
@@ -1445,6 +1445,7 @@ static void init_stenv(jl_stenv_t *e, jl_value_t **env, int envsz)
1445
1445
e -> ignore_free = 0 ;
1446
1446
e -> intersection = 0 ;
1447
1447
e -> emptiness_only = 0 ;
1448
+ e -> triangular = 0 ;
1448
1449
e -> Lunions .depth = 0 ; e -> Runions .depth = 0 ;
1449
1450
e -> Lunions .more = 0 ; e -> Runions .more = 0 ;
1450
1451
e -> Lunions .used = 0 ; e -> Runions .used = 0 ;
@@ -2204,7 +2205,7 @@ static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_sten
2204
2205
return ;
2205
2206
jl_varbinding_t * btemp = e -> vars ;
2206
2207
while (btemp != NULL ) {
2207
- if (btemp -> lb == (jl_value_t * )v && btemp -> ub == (jl_value_t * )v &&
2208
+ if (( btemp -> lb == (jl_value_t * )v || btemp -> ub == (jl_value_t * )v ) &&
2208
2209
in_union (val , (jl_value_t * )btemp -> var ))
2209
2210
return ;
2210
2211
btemp = btemp -> prev ;
@@ -2256,6 +2257,21 @@ static int reachable_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e)
2256
2257
return reachable_var (xv -> ub , y , e ) || reachable_var (xv -> lb , y , e );
2257
2258
}
2258
2259
2260
+ // check whether setting v == t implies v == SomeType{v}, which is unsatisfiable.
2261
+ static int check_unsat_bound (jl_value_t * t , jl_tvar_t * v , jl_stenv_t * e ) JL_NOTSAFEPOINT
2262
+ {
2263
+ if (var_occurs_inside (t , v , 0 , 0 ))
2264
+ return 1 ;
2265
+ jl_varbinding_t * btemp = e -> vars ;
2266
+ while (btemp != NULL ) {
2267
+ if (btemp -> lb == (jl_value_t * )v && btemp -> ub == (jl_value_t * )v &&
2268
+ var_occurs_inside (t , btemp -> var , 0 , 0 ))
2269
+ return 1 ;
2270
+ btemp = btemp -> prev ;
2271
+ }
2272
+ return 0 ;
2273
+ }
2274
+
2259
2275
static jl_value_t * intersect_var (jl_tvar_t * b , jl_value_t * a , jl_stenv_t * e , int8_t R , int param )
2260
2276
{
2261
2277
jl_varbinding_t * bb = lookup (e , b );
@@ -2285,7 +2301,9 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
2285
2301
ub = a ;
2286
2302
}
2287
2303
else {
2304
+ e -> triangular ++ ;
2288
2305
ub = R ? intersect_aside (a , bb -> ub , e , 1 , d ) : intersect_aside (bb -> ub , a , e , 0 , d );
2306
+ e -> triangular -- ;
2289
2307
save_env (e , & root , & se );
2290
2308
int issub = subtype_in_env_existential (bb -> lb , ub , e , 0 , d );
2291
2309
restore_env (e , root , & se );
@@ -2297,88 +2315,44 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
2297
2315
}
2298
2316
if (ub != (jl_value_t * )b ) {
2299
2317
if (jl_has_free_typevars (ub )) {
2300
- // constraint X == Ref{X} is unsatisfiable. also check variables set equal to X.
2301
- if (var_occurs_inside (ub , b , 0 , 0 )) {
2318
+ if (check_unsat_bound (ub , b , e )) {
2302
2319
JL_GC_POP ();
2303
2320
return jl_bottom_type ;
2304
2321
}
2305
- jl_varbinding_t * btemp = e -> vars ;
2306
- while (btemp != NULL ) {
2307
- if (btemp -> lb == (jl_value_t * )b && btemp -> ub == (jl_value_t * )b &&
2308
- var_occurs_inside (ub , btemp -> var , 0 , 0 )) {
2309
- JL_GC_POP ();
2310
- return jl_bottom_type ;
2311
- }
2312
- btemp = btemp -> prev ;
2313
- }
2314
2322
}
2315
2323
bb -> ub = ub ;
2316
2324
bb -> lb = ub ;
2317
2325
}
2318
2326
JL_GC_POP ();
2319
2327
return ub ;
2320
2328
}
2321
- else if (bb -> constraintkind == 0 ) {
2322
- if (!jl_is_typevar (bb -> ub ) && !jl_is_typevar (a )) {
2323
- if (try_subtype_in_env (bb -> ub , a , e , 0 , d ))
2324
- return (jl_value_t * )b ;
2325
- }
2326
- return R ? intersect_aside (a , bb -> ub , e , 1 , d ) : intersect_aside (bb -> ub , a , e , 0 , d );
2327
- }
2328
- else if (bb -> concrete || bb -> constraintkind == 1 ) {
2329
- jl_value_t * ub = R ? intersect_aside (a , bb -> ub , e , 1 , d ) : intersect_aside (bb -> ub , a , e , 0 , d );
2330
- if (ub == jl_bottom_type )
2331
- return jl_bottom_type ;
2332
- JL_GC_PUSH1 (& ub );
2333
- if (!R && !subtype_bounds_in_env (bb -> lb , a , e , 0 , d )) {
2334
- // this fixes issue #30122. TODO: better fix for R flag.
2335
- JL_GC_POP ();
2336
- return jl_bottom_type ;
2337
- }
2338
- JL_GC_POP ();
2339
- set_bound (& bb -> ub , ub , b , e );
2340
- return (jl_value_t * )b ;
2341
- }
2342
- else if (bb -> constraintkind == 2 ) {
2343
- // TODO: removing this case fixes many test_brokens in test/subtype.jl
2344
- // but breaks other tests.
2345
- if (!subtype_bounds_in_env (a , bb -> ub , e , 1 , d )) {
2346
- // mark var as unsatisfiable by making it circular
2347
- bb -> lb = (jl_value_t * )b ;
2348
- return jl_bottom_type ;
2349
- }
2350
- jl_value_t * lb = simple_join (bb -> lb , a );
2351
- set_bound (& bb -> lb , lb , b , e );
2352
- return a ;
2353
- }
2354
- assert (bb -> constraintkind == 3 );
2355
2329
jl_value_t * ub = R ? intersect_aside (a , bb -> ub , e , 1 , d ) : intersect_aside (bb -> ub , a , e , 0 , d );
2356
2330
if (ub == jl_bottom_type )
2357
2331
return jl_bottom_type ;
2358
- if (jl_is_typevar (a ))
2332
+ if (bb -> constraintkind == 1 || e -> triangular ) {
2333
+ if (e -> triangular && check_unsat_bound (ub , b , e ))
2334
+ return jl_bottom_type ;
2335
+ set_bound (& bb -> ub , ub , b , e );
2359
2336
return (jl_value_t * )b ;
2360
- if (ub == a ) {
2361
- if (bb -> lb == jl_bottom_type ) {
2362
- set_bound (& bb -> ub , a , b , e );
2337
+ }
2338
+ else if (bb -> constraintkind == 0 ) {
2339
+ JL_GC_PUSH1 (& ub );
2340
+ if (!jl_is_typevar (a ) && try_subtype_in_env (bb -> ub , a , e , 0 , d )) {
2341
+ JL_GC_POP ();
2363
2342
return (jl_value_t * )b ;
2364
2343
}
2344
+ JL_GC_POP ();
2365
2345
return ub ;
2366
2346
}
2367
- else if (bb -> ub == bb -> lb ) {
2368
- return ub ;
2369
- }
2370
- root = NULL ;
2371
- JL_GC_PUSH2 (& root , & ub );
2372
- save_env (e , & root , & se );
2373
- jl_value_t * ii = R ? intersect_aside (a , bb -> lb , e , 1 , d ) : intersect_aside (bb -> lb , a , e , 0 , d );
2374
- if (ii == jl_bottom_type ) {
2375
- restore_env (e , root , & se );
2376
- ii = (jl_value_t * )b ;
2347
+ assert (bb -> constraintkind == 2 );
2348
+ if (!jl_is_typevar (a )) {
2349
+ if (ub == a && bb -> lb != jl_bottom_type )
2350
+ return ub ;
2351
+ else if (jl_egal (bb -> ub , bb -> lb ))
2352
+ return ub ;
2377
2353
set_bound (& bb -> ub , ub , b , e );
2378
2354
}
2379
- free_env (& se );
2380
- JL_GC_POP ();
2381
- return ii ;
2355
+ return (jl_value_t * )b ;
2382
2356
}
2383
2357
2384
2358
// test whether `var` occurs inside constructors. `want_inv` tests only inside
@@ -2422,7 +2396,7 @@ static int var_occurs_inside(jl_value_t *v, jl_tvar_t *var, int inside, int want
2422
2396
}
2423
2397
2424
2398
// Caller might not have rooted `res`
2425
- static jl_value_t * finish_unionall (jl_value_t * res JL_MAYBE_UNROOTED , jl_varbinding_t * vb , jl_stenv_t * e )
2399
+ static jl_value_t * finish_unionall (jl_value_t * res JL_MAYBE_UNROOTED , jl_varbinding_t * vb , jl_unionall_t * u , jl_stenv_t * e )
2426
2400
{
2427
2401
jl_value_t * varval = NULL ;
2428
2402
jl_tvar_t * newvar = vb -> var ;
@@ -2435,7 +2409,10 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2435
2409
// given x<:T<:x, substitute x for T
2436
2410
varval = vb -> ub ;
2437
2411
}
2438
- else if (!vb -> occurs_inv && is_leaf_bound (vb -> ub )) {
2412
+ // TODO: `vb.occurs_cov == 1` here allows substituting Tuple{<:X} => Tuple{X},
2413
+ // which is valid but changes some ambiguity errors so we don't need to do it yet.
2414
+ else if ((/*vb->occurs_cov == 1 || */ is_leaf_bound (vb -> ub )) &&
2415
+ !var_occurs_invariant (u -> body , u -> var , 0 )) {
2439
2416
// replace T<:x with x in covariant position when possible
2440
2417
varval = vb -> ub ;
2441
2418
}
@@ -2453,9 +2430,8 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2453
2430
}
2454
2431
}
2455
2432
2456
- // prefer generating a fresh typevar, to avoid repeated renaming if the result
2457
- // is compared to one of the intersected types later.
2458
- if (!varval )
2433
+ // TODO: this can prevent us from matching typevar identities later
2434
+ if (!varval && (vb -> lb != vb -> var -> lb || vb -> ub != vb -> var -> ub ))
2459
2435
newvar = jl_new_typevar (vb -> var -> name , vb -> lb , vb -> ub );
2460
2436
2461
2437
// remove/replace/rewrap free occurrences of this var in the environment
@@ -2573,8 +2549,10 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv
2573
2549
int envsize = 0 ;
2574
2550
while (btemp != NULL ) {
2575
2551
envsize ++ ;
2576
- if (envsize > 150 )
2552
+ if (envsize > 120 ) {
2553
+ vb -> limited = 1 ;
2577
2554
return t ;
2555
+ }
2578
2556
if (btemp -> var == u -> var || btemp -> lb == (jl_value_t * )u -> var ||
2579
2557
btemp -> ub == (jl_value_t * )u -> var ) {
2580
2558
u = rename_unionall (u );
@@ -2624,46 +2602,37 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv
2624
2602
}
2625
2603
if (res != jl_bottom_type )
2626
2604
// res is rooted by callee
2627
- res = finish_unionall (res , vb , e );
2605
+ res = finish_unionall (res , vb , u , e );
2628
2606
JL_GC_POP ();
2629
2607
return res ;
2630
2608
}
2631
2609
2632
2610
static jl_value_t * intersect_unionall (jl_value_t * t , jl_unionall_t * u , jl_stenv_t * e , int8_t R , int param )
2633
2611
{
2634
- jl_value_t * res = NULL , * res2 = NULL , * save = NULL , * save2 = NULL ;
2635
- jl_savedenv_t se , se2 ;
2636
- jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , 0 , 0 , 0 , 0 , 0 ,
2612
+ jl_value_t * res = NULL , * save = NULL ;
2613
+ jl_savedenv_t se ;
2614
+ jl_varbinding_t vb = { u -> var , u -> var -> lb , u -> var -> ub , R , 0 , 0 , 0 , 0 , 0 , 0 ,
2637
2615
R ? e -> Rinvdepth : e -> invdepth , 0 , NULL , e -> vars };
2638
- JL_GC_PUSH6 (& res , & save2 , & vb .lb , & vb .ub , & save , & vb .innervars );
2616
+ JL_GC_PUSH5 (& res , & vb .lb , & vb .ub , & save , & vb .innervars );
2639
2617
save_env (e , & save , & se );
2640
2618
res = intersect_unionall_ (t , u , e , R , param , & vb );
2641
- if (res != jl_bottom_type ) {
2619
+ if (vb .limited ) {
2620
+ // if the environment got too big, avoid tree recursion and propagate the flag
2621
+ if (e -> vars )
2622
+ e -> vars -> limited = 1 ;
2623
+ }
2624
+ else if (res != jl_bottom_type ) {
2642
2625
if (vb .concrete || vb .occurs_inv > 1 || u -> var -> lb != jl_bottom_type || (vb .occurs_inv && vb .occurs_cov )) {
2643
2626
restore_env (e , NULL , & se );
2644
2627
vb .occurs_cov = vb .occurs_inv = 0 ;
2645
- vb .constraintkind = 3 ;
2628
+ vb .constraintkind = vb . concrete ? 1 : 2 ;
2646
2629
res = intersect_unionall_ (t , u , e , R , param , & vb );
2647
2630
}
2648
- else if (vb .occurs_cov ) {
2649
- save_env (e , & save2 , & se2 );
2631
+ else if (vb .occurs_cov && !var_occurs_invariant (u -> body , u -> var , 0 )) {
2650
2632
restore_env (e , save , & se );
2651
2633
vb .occurs_cov = vb .occurs_inv = 0 ;
2652
- vb .lb = u -> var -> lb ; vb .ub = u -> var -> ub ;
2653
2634
vb .constraintkind = 1 ;
2654
- res2 = intersect_unionall_ (t , u , e , R , param , & vb );
2655
- if (res2 == jl_bottom_type ) {
2656
- restore_env (e , save , & se );
2657
- vb .occurs_cov = vb .occurs_inv = 0 ;
2658
- vb .lb = u -> var -> lb ; vb .ub = u -> var -> ub ;
2659
- vb .constraintkind = 2 ;
2660
- res2 = intersect_unionall_ (t , u , e , R , param , & vb );
2661
- if (res2 == jl_bottom_type )
2662
- restore_env (e , save2 , & se2 );
2663
- }
2664
- if (res2 != jl_bottom_type )
2665
- res = res2 ;
2666
- free_env (& se2 );
2635
+ res = intersect_unionall_ (t , u , e , R , param , & vb );
2667
2636
}
2668
2637
}
2669
2638
free_env (& se );
@@ -3049,14 +3018,13 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
3049
3018
jl_value_t * ub = NULL , * lb = NULL ;
3050
3019
JL_GC_PUSH2 (& lb , & ub );
3051
3020
ub = intersect_aside (xub , yub , e , 0 , xx ? xx -> depth0 : 0 );
3052
- if (xlb == y )
3021
+ if (reachable_var ( xlb , ( jl_tvar_t * ) y , e ) )
3053
3022
lb = ylb ;
3054
3023
else
3055
3024
lb = simple_join (xlb , ylb );
3056
3025
if (yy ) {
3057
- if (!subtype_by_bounds (lb , y , e ))
3058
- yy -> lb = lb ;
3059
- if (!subtype_by_bounds (y , ub , e ))
3026
+ yy -> lb = lb ;
3027
+ if (!reachable_var (ub , (jl_tvar_t * )y , e ))
3060
3028
yy -> ub = ub ;
3061
3029
assert (yy -> ub != y );
3062
3030
assert (yy -> lb != y );
0 commit comments