@@ -2814,6 +2814,50 @@ static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t)
2814
2814
return res ;
2815
2815
}
2816
2816
2817
+ // TODO: fuse with reachable_var?
2818
+ static int has_typevar_via_flatten_env (jl_value_t * x , jl_tvar_t * t , jl_ivarbinding_t * allvars , int8_t * checked ) {
2819
+ if (jl_is_unionall (x )) {
2820
+ jl_tvar_t * var = ((jl_unionall_t * )x )-> var ;
2821
+ if (has_typevar_via_flatten_env (var -> lb , t , allvars , checked ) ||
2822
+ has_typevar_via_flatten_env (var -> ub , t , allvars , checked ))
2823
+ return 1 ;
2824
+ return has_typevar_via_flatten_env (((jl_unionall_t * )x )-> body , t , allvars , checked );
2825
+ }
2826
+ else if (jl_is_uniontype (x )) {
2827
+ return has_typevar_via_flatten_env (((jl_uniontype_t * )x )-> a , t , allvars , checked ) ||
2828
+ has_typevar_via_flatten_env (((jl_uniontype_t * )x )-> b , t , allvars , checked );
2829
+ }
2830
+ else if (jl_is_vararg (x )) {
2831
+ jl_vararg_t * v = (jl_vararg_t * )x ;
2832
+ return (v -> T && has_typevar_via_flatten_env (v -> T , t , allvars , checked )) ||
2833
+ (v -> N && has_typevar_via_flatten_env (v -> N , t , allvars , checked ));
2834
+ }
2835
+ else if (jl_is_datatype (x )) {
2836
+ for (size_t i = 0 ; i < jl_nparams (x ); i ++ ) {
2837
+ if (has_typevar_via_flatten_env (jl_tparam (x , i ), t , allvars , checked ))
2838
+ return 1 ;
2839
+ }
2840
+ return 0 ;
2841
+ }
2842
+ else if (jl_is_typevar (x )) {
2843
+ if (t == (jl_tvar_t * )x )
2844
+ return 1 ;
2845
+ size_t ind = 0 ;
2846
+ jl_ivarbinding_t * itemp = allvars ;
2847
+ while (itemp && * itemp -> var != (jl_tvar_t * )x )
2848
+ {
2849
+ ind ++ ;
2850
+ itemp = itemp -> next ;
2851
+ }
2852
+ if (itemp == NULL || checked [ind ])
2853
+ return 0 ;
2854
+ checked [ind ] = 1 ;
2855
+ return has_typevar_via_flatten_env (* itemp -> lb , t , allvars , checked ) ||
2856
+ has_typevar_via_flatten_env (* itemp -> ub , t , allvars , checked );
2857
+ }
2858
+ return 0 ;
2859
+ }
2860
+
2817
2861
// Caller might not have rooted `res`
2818
2862
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 )
2819
2863
{
@@ -2911,8 +2955,11 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2911
2955
// remove/replace/rewrap free occurrences of this var in the environment
2912
2956
int wrapped = 0 ;
2913
2957
jl_ivarbinding_t * pwrap = NULL ;
2958
+ int vcount = icount + current_env_length (e );
2959
+ int8_t * checked = (int8_t * )alloca (vcount );
2914
2960
for (jl_ivarbinding_t * btemp = allvars , * pbtemp = NULL ; btemp != NULL ; btemp = btemp -> next ) {
2915
2961
int bdepth0 = btemp -> root -> depth0 ;
2962
+ int innerflag = 0 ;
2916
2963
ivar = * btemp -> var ;
2917
2964
ilb = * btemp -> lb ;
2918
2965
iub = * btemp -> ub ;
@@ -2934,18 +2981,9 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2934
2981
else if (ilb == (jl_value_t * )vb -> var ) {
2935
2982
* btemp -> lb = vb -> lb ;
2936
2983
}
2937
- else if (bdepth0 == vb -> depth0 && !jl_has_typevar (vb -> lb , ivar ) && !jl_has_typevar (vb -> ub , ivar )) {
2938
- // if our variable is T, and some outer variable has constraint S = Ref{T},
2939
- // move the `where T` outside `where S` instead of putting it here. issue #21243.
2940
- if (newvar != vb -> var )
2941
- * btemp -> lb = jl_substitute_var (ilb , vb -> var , (jl_value_t * )newvar );
2942
- if (!wrapped ) pwrap = pbtemp ;
2943
- wrapped = 1 ;
2944
- }
2945
2984
else {
2946
- * btemp -> lb = jl_new_struct ( jl_unionall_type , vb -> var , ilb ) ;
2985
+ innerflag |= 1 ;
2947
2986
}
2948
- assert ((jl_value_t * )ivar != * btemp -> lb );
2949
2987
}
2950
2988
if (jl_has_typevar (iub , vb -> var )) {
2951
2989
assert (btemp -> root -> var == ivar || bdepth0 == vb -> depth0 );
@@ -2971,14 +3009,35 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2971
3009
// Tuple{Float64, T3, T4} where {S3, T3<:Tuple{S3}, T4<:S3}
2972
3010
* btemp -> ub = vb -> ub ;
2973
3011
}
2974
- else if (bdepth0 == vb -> depth0 && !jl_has_typevar (vb -> lb , ivar ) && !jl_has_typevar (vb -> ub , ivar )) {
2975
- if (newvar != vb -> var )
2976
- * btemp -> ub = jl_substitute_var (iub , vb -> var , (jl_value_t * )newvar );
2977
- if (!wrapped ) pwrap = pbtemp ;
2978
- wrapped = 1 ;
3012
+ else {
3013
+ innerflag |= 2 ;
2979
3014
}
2980
- else
2981
- * btemp -> ub = jl_new_struct (jl_unionall_type , vb -> var , iub );
3015
+ if (innerflag ) {
3016
+ memset (checked , 0 , vcount );
3017
+ if (bdepth0 != vb -> depth0 ||
3018
+ has_typevar_via_flatten_env (vb -> lb , ivar , allvars , checked ) ||
3019
+ has_typevar_via_flatten_env (vb -> ub , ivar , allvars , checked )) {
3020
+ if (innerflag & 1 )
3021
+ * btemp -> lb = jl_new_struct (jl_unionall_type , vb -> var , ilb );
3022
+ if (innerflag & 2 )
3023
+ * btemp -> ub = jl_new_struct (jl_unionall_type , vb -> var , iub );
3024
+ }
3025
+ else {
3026
+ assert (btemp -> root != vb );
3027
+ // if our variable is T, and some outer variable has constraint S = Ref{T},
3028
+ // move the `where T` outside `where S` instead of putting it here. issue #21243.
3029
+ if (newvar != vb -> var ) {
3030
+ if (innerflag & 1 )
3031
+ * btemp -> lb = jl_substitute_var (ilb , vb -> var , (jl_value_t * )newvar );
3032
+ if (innerflag & 2 )
3033
+ * btemp -> ub = jl_substitute_var (iub , vb -> var , (jl_value_t * )newvar );
3034
+ }
3035
+ if (!wrapped )
3036
+ pwrap = pbtemp ;
3037
+ wrapped = 1 ;
3038
+ }
3039
+ }
3040
+ assert ((jl_value_t * )ivar != * btemp -> lb );
2982
3041
assert ((jl_value_t * )ivar != * btemp -> ub );
2983
3042
}
2984
3043
pbtemp = btemp ;
@@ -2997,24 +3056,31 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
2997
3056
pwrap -> next = inew ;
2998
3057
else
2999
3058
allvars = inew ;
3059
+ vcount ++ ;
3000
3060
}
3001
3061
3002
3062
// Re-sort the innervar inside the (reversed) var list.
3003
3063
// `jl_has_typevar` is used as the partial-ordering predicate.
3004
3064
// If this is slow, we could possibly switch to a simpler graph sort, such as Tarjan's SCC.
3005
3065
if (icount > 0 ) {
3006
3066
jl_ivarbinding_t * pib1 = NULL ;
3067
+ #ifndef NDEBUG
3068
+ size_t sort_count = 0 ;
3069
+ #endif
3007
3070
while (1 ) {
3008
3071
jl_ivarbinding_t * ib1 = pib1 == NULL ? allvars : pib1 -> next ;
3009
3072
if (ib1 == NULL ) break ;
3010
- if (jl_has_free_typevars (* ib1 -> lb ) || jl_has_free_typevars (* ib1 -> ub )) {
3073
+ assert ((++ sort_count ) <= (vcount * (vcount + 1 )) >> 1 );
3074
+ int lbfree = jl_has_free_typevars (* ib1 -> lb );
3075
+ int ubfree = jl_has_free_typevars (* ib1 -> ub );
3076
+ if (lbfree || ubfree ) {
3011
3077
int changed = 0 ;
3012
3078
jl_ivarbinding_t * pib2 = ib1 , * ib2 = ib1 -> next ;
3013
3079
while (ib2 != NULL ) {
3014
3080
int isinnervar = ib2 -> root -> var != * ib2 -> var ;
3015
3081
if (isinnervar && ib1 -> root -> depth0 == ib2 -> root -> depth0 &&
3016
- (jl_has_typevar (* ib1 -> lb , * ib2 -> var ) ||
3017
- jl_has_typevar (* ib1 -> ub , * ib2 -> var ))) {
3082
+ (( lbfree && jl_has_typevar (* ib1 -> lb , * ib2 -> var ) ) ||
3083
+ ( ubfree && jl_has_typevar (* ib1 -> ub , * ib2 -> var ) ))) {
3018
3084
pib2 -> next = ib2 -> next ;
3019
3085
ib2 -> next = ib1 ;
3020
3086
ib2 -> root = ib1 -> root ;
@@ -3052,6 +3118,13 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
3052
3118
if (jl_has_typevar (iub , ivar ))
3053
3119
* btemp2 -> ub = jl_substitute_var (iub , ivar , nivar );
3054
3120
}
3121
+ if (!wrapped && !varval ) {
3122
+ // newvar also needs bounds substitution.
3123
+ if (jl_has_typevar (vb -> lb , ivar ))
3124
+ vb -> lb = jl_substitute_var (vb -> lb , ivar , nivar );
3125
+ if (jl_has_typevar (vb -> ub , ivar ))
3126
+ vb -> ub = jl_substitute_var (vb -> ub , ivar , nivar );
3127
+ }
3055
3128
* btemp1 -> var = (jl_tvar_t * )nivar ;
3056
3129
}
3057
3130
}
@@ -3067,11 +3140,13 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
3067
3140
}
3068
3141
if (root != vb ) icount -- ;
3069
3142
if (root -> innervars != NULL ) {
3070
- size_t len = jl_array_nrows (root -> innervars );
3143
+ jl_array_t * rinnervars = root -> innervars ;
3144
+ JL_GC_PROMISE_ROOTED (rinnervars );
3145
+ size_t len = jl_array_nrows (rinnervars );
3071
3146
if (icount > len )
3072
- jl_array_grow_end (root -> innervars , icount - len );
3147
+ jl_array_grow_end (rinnervars , icount - len );
3073
3148
if (icount < len )
3074
- jl_array_del_end (root -> innervars , len - icount );
3149
+ jl_array_del_end (rinnervars , len - icount );
3075
3150
}
3076
3151
else if (icount > 0 ) {
3077
3152
root -> innervars = jl_alloc_array_1d (jl_array_any_type , icount );
@@ -3104,6 +3179,9 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind
3104
3179
res = jl_bottom_type ;
3105
3180
}
3106
3181
else {
3182
+ // re-fresh newvar if bounds changed.
3183
+ if (vb -> lb != newvar -> lb || vb -> ub != newvar -> ub )
3184
+ newvar = jl_new_typevar (newvar -> name , vb -> lb , vb -> ub );
3107
3185
if (newvar != vb -> var )
3108
3186
res = jl_substitute_var (res , vb -> var , (jl_value_t * )newvar );
3109
3187
varval = (jl_value_t * )newvar ;
0 commit comments