@@ -1468,11 +1468,11 @@ jl_unionall_t *jl_rename_unionall(jl_unionall_t *u)
1468
1468
return (jl_unionall_t * )t ;
1469
1469
}
1470
1470
1471
- jl_value_t * jl_substitute_var_nothrow (jl_value_t * t , jl_tvar_t * var , jl_value_t * val )
1471
+ jl_value_t * jl_substitute_var_nothrow (jl_value_t * t , jl_tvar_t * var , jl_value_t * val , int nothrow )
1472
1472
{
1473
1473
if (val == (jl_value_t * )var )
1474
1474
return t ;
1475
- int nothrow = jl_is_typevar (val ) ? 0 : 1 ;
1475
+ nothrow = jl_is_typevar (val ) ? 0 : nothrow ;
1476
1476
jl_typeenv_t env = { var , val , NULL };
1477
1477
return inst_type_w_ (t , & env , NULL , 1 , nothrow );
1478
1478
}
@@ -1694,7 +1694,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable)
1694
1694
dt -> hash = typekey_hash (dt -> name , jl_svec_data (dt -> parameters ), l , cacheable );
1695
1695
}
1696
1696
1697
- static void check_datatype_parameters (jl_typename_t * tn , jl_value_t * * params , size_t np )
1697
+ static int check_datatype_parameters (jl_typename_t * tn , jl_value_t * * params , size_t np , int nothrow )
1698
1698
{
1699
1699
jl_value_t * wrapper = tn -> wrapper ;
1700
1700
jl_value_t * * bounds ;
@@ -1712,6 +1712,10 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si
1712
1712
assert (jl_is_unionall (wrapper ));
1713
1713
jl_tvar_t * tv = ((jl_unionall_t * )wrapper )-> var ;
1714
1714
if (!within_typevar (params [i ], bounds [2 * i ], bounds [2 * i + 1 ])) {
1715
+ if (nothrow ) {
1716
+ JL_GC_POP ();
1717
+ return 1 ;
1718
+ }
1715
1719
if (tv -> lb != bounds [2 * i ] || tv -> ub != bounds [2 * i + 1 ])
1716
1720
// pass a new version of `tv` containing the instantiated bounds
1717
1721
tv = jl_new_typevar (tv -> name , bounds [2 * i ], bounds [2 * i + 1 ]);
@@ -1721,12 +1725,26 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si
1721
1725
int j ;
1722
1726
for (j = 2 * i + 2 ; j < 2 * np ; j ++ ) {
1723
1727
jl_value_t * bj = bounds [j ];
1724
- if (bj != (jl_value_t * )jl_any_type && bj != jl_bottom_type )
1725
- bounds [j ] = jl_substitute_var (bj , tv , params [i ]);
1728
+ if (bj != (jl_value_t * )jl_any_type && bj != jl_bottom_type ) {
1729
+ int isub = j & 1 ;
1730
+ // use different nothrow level for lb and ub substitution.
1731
+ // TODO: This assuming the top instantiation could only start with
1732
+ // `nothrow == 2` or `nothrow == 0`. If `nothrow` is initially set to 1
1733
+ // then we might miss some inner error, perhaps the normal path should
1734
+ // also follow this rule?
1735
+ jl_value_t * nb = jl_substitute_var_nothrow (bj , tv , params [i ], nothrow ? (isub ? 2 : 1 ) : 0 );
1736
+ if (nb == NULL ) {
1737
+ assert (nothrow );
1738
+ JL_GC_POP ();
1739
+ return 1 ;
1740
+ }
1741
+ bounds [j ] = nb ;
1742
+ }
1726
1743
}
1727
1744
wrapper = ((jl_unionall_t * )wrapper )-> body ;
1728
1745
}
1729
1746
JL_GC_POP ();
1747
+ return 0 ;
1730
1748
}
1731
1749
1732
1750
jl_value_t * extract_wrapper (jl_value_t * t JL_PROPAGATES_ROOT ) JL_GLOBALLY_ROOTED
@@ -1943,13 +1961,8 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
1943
1961
// for whether this is even valid
1944
1962
if (check && !istuple ) {
1945
1963
assert (ntp > 0 );
1946
- JL_TRY {
1947
- check_datatype_parameters (tn , iparams , ntp );
1948
- }
1949
- JL_CATCH {
1950
- if (!nothrow ) jl_rethrow ();
1964
+ if (check_datatype_parameters (tn , iparams , ntp , nothrow ))
1951
1965
return NULL ;
1952
- }
1953
1966
}
1954
1967
else if (ntp == 0 && jl_emptytuple_type != NULL ) {
1955
1968
// empty tuple type case
@@ -2301,7 +2314,8 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
2301
2314
jl_value_t * elt = jl_svecref (tp , i );
2302
2315
jl_value_t * pi = inst_type_w_ (elt , env , stack , check , nothrow );
2303
2316
if (pi == NULL ) {
2304
- if (i == ntp - 1 && jl_is_vararg (elt )) {
2317
+ assert (nothrow );
2318
+ if (nothrow == 1 || (i == ntp - 1 && jl_is_vararg (elt ))) {
2305
2319
t = NULL ;
2306
2320
break ;
2307
2321
}
@@ -2320,6 +2334,10 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
2320
2334
return t ;
2321
2335
}
2322
2336
2337
+ // `nothrow` means that when type checking fails, the type instantiation should
2338
+ // return `NULL` instead of immediately throwing an error. If `nothrow` == 2 then
2339
+ // we further assume that the imprecise instantiation for non invariant parameters
2340
+ // is acceptable, and inner error (`NULL`) would be ignored.
2323
2341
static jl_value_t * inst_type_w_ (jl_value_t * t , jl_typeenv_t * env , jl_typestack_t * stack , int check , int nothrow )
2324
2342
{
2325
2343
size_t i ;
@@ -2340,11 +2358,10 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
2340
2358
jl_value_t * var = NULL ;
2341
2359
jl_value_t * newbody = NULL ;
2342
2360
JL_GC_PUSH3 (& lb , & var , & newbody );
2343
- JL_TRY {
2344
- lb = inst_type_w_ (ua -> var -> lb , env , stack , check , 0 );
2345
- }
2346
- JL_CATCH {
2347
- if (!nothrow ) jl_rethrow ();
2361
+ // set nothrow <= 1 to ensure lb's accuracy.
2362
+ lb = inst_type_w_ (ua -> var -> lb , env , stack , check , nothrow ? 1 : 0 );
2363
+ if (lb == NULL ) {
2364
+ assert (nothrow );
2348
2365
t = NULL ;
2349
2366
}
2350
2367
if (t != NULL ) {
@@ -2368,11 +2385,9 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
2368
2385
if (newbody == NULL ) {
2369
2386
t = NULL ;
2370
2387
}
2371
- else if (newbody == (jl_value_t * )jl_emptytuple_type ) {
2372
- // NTuple{0} => Tuple{} can make a typevar disappear
2373
- t = (jl_value_t * )jl_emptytuple_type ;
2374
- }
2375
- else if (nothrow && !jl_has_typevar (newbody , (jl_tvar_t * )var )) {
2388
+ else if (!jl_has_typevar (newbody , (jl_tvar_t * )var )) {
2389
+ // inner instantiation might make a typevar disappear, e.g.
2390
+ // NTuple{0,T} => Tuple{}
2376
2391
t = newbody ;
2377
2392
}
2378
2393
else if (newbody != ua -> body || var != (jl_value_t * )ua -> var ) {
@@ -2389,16 +2404,21 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
2389
2404
jl_value_t * b = NULL ;
2390
2405
JL_GC_PUSH2 (& a , & b );
2391
2406
b = inst_type_w_ (u -> b , env , stack , check , nothrow );
2407
+ if (nothrow ) {
2408
+ // ensure jl_type_union nothrow.
2409
+ if (a && !(jl_is_typevar (a ) || jl_is_type (a )))
2410
+ a = NULL ;
2411
+ if (b && !(jl_is_typevar (b ) || jl_is_type (b )))
2412
+ b = NULL ;
2413
+ }
2392
2414
if (a != u -> a || b != u -> b ) {
2393
2415
if (!check ) {
2394
2416
// fast path for `jl_rename_unionall`.
2395
2417
t = jl_new_struct (jl_uniontype_type , a , b );
2396
2418
}
2397
- else if (nothrow && a == NULL ) {
2398
- t = b ;
2399
- }
2400
- else if (nothrow && b == NULL ) {
2401
- t = a ;
2419
+ else if (a == NULL || b == NULL ) {
2420
+ assert (nothrow );
2421
+ t = nothrow == 1 ? NULL : a == NULL ? b : a ;
2402
2422
}
2403
2423
else {
2404
2424
assert (a != NULL && b != NULL );
@@ -2416,15 +2436,21 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
2416
2436
JL_GC_PUSH2 (& T , & N );
2417
2437
if (v -> T ) {
2418
2438
T = inst_type_w_ (v -> T , env , stack , check , nothrow );
2419
- if (T == NULL )
2420
- T = jl_bottom_type ;
2421
- if (v -> N ) // This branch should never throw.
2422
- N = inst_type_w_ (v -> N , env , stack , check , 0 );
2439
+ if (T == NULL ) {
2440
+ if (nothrow == 2 )
2441
+ T = jl_bottom_type ;
2442
+ else
2443
+ t = NULL ;
2444
+ }
2445
+ if (t && v -> N ) {
2446
+ // set nothrow <= 1 to ensure invariant parameter's accuracy.
2447
+ N = inst_type_w_ (v -> N , env , stack , check , nothrow ? 1 : 0 );
2448
+ if (N == NULL )
2449
+ t = NULL ;
2450
+ }
2423
2451
}
2424
- if (T != v -> T || N != v -> N ) {
2425
- // `Vararg` is special, we'd better handle inner error at Tuple level.
2452
+ if (t && (T != v -> T || N != v -> N ))
2426
2453
t = (jl_value_t * )jl_wrap_vararg (T , N , check , nothrow );
2427
- }
2428
2454
JL_GC_POP ();
2429
2455
return t ;
2430
2456
}
@@ -2443,16 +2469,15 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
2443
2469
int bound = 0 ;
2444
2470
for (i = 0 ; i < ntp ; i ++ ) {
2445
2471
jl_value_t * elt = jl_svecref (tp , i );
2446
- JL_TRY {
2447
- jl_value_t * pi = inst_type_w_ (elt , env , stack , check , 0 );
2448
- iparams [i ] = pi ;
2449
- bound |= (pi != elt );
2450
- }
2451
- JL_CATCH {
2452
- if (!nothrow ) jl_rethrow ();
2472
+ // set nothrow <= 1 to ensure invariant parameter's accuracy.
2473
+ jl_value_t * pi = inst_type_w_ (elt , env , stack , check , nothrow ? 1 : 0 );
2474
+ if (pi == NULL ) {
2475
+ assert (nothrow );
2453
2476
t = NULL ;
2477
+ break ;
2454
2478
}
2455
- if (t == NULL ) break ;
2479
+ iparams [i ] = pi ;
2480
+ bound |= (pi != elt );
2456
2481
}
2457
2482
// if t's parameters are not bound in the environment, return it uncopied (#9378)
2458
2483
if (t != NULL && bound )
0 commit comments