Skip to content

Commit b9ea864

Browse files
committed
Intersect: try normal+reverse+existential subtyping during intersection
fix #57429 #41561 Typevars are all existential (in the sense of variable lb/ub) during intersection. This fix is somehow costly as we have to perform 3 times check to prove a false result. But a single existential <: seems too dangerous as it cause many circular env in the past.
1 parent 0fb5fa0 commit b9ea864

File tree

2 files changed

+137
-42
lines changed

2 files changed

+137
-42
lines changed

src/subtype.c

Lines changed: 114 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,31 +2678,22 @@ static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_sten
26782678
// subtype, treating all vars as existential
26792679
static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
26802680
{
2681-
jl_varbinding_t *v = e->vars;
2682-
int len = 0;
26832681
if (x == jl_bottom_type || y == (jl_value_t*)jl_any_type)
26842682
return 1;
2685-
while (v != NULL) {
2686-
len++;
2687-
v = v->prev;
2688-
}
2689-
int8_t *rs = (int8_t*)malloc_s(len);
2683+
int8_t *rs = (int8_t*)alloca(current_env_length(e));
2684+
jl_varbinding_t *v = e->vars;
26902685
int n = 0;
2691-
v = e->vars;
2692-
while (n < len) {
2693-
assert(v != NULL);
2686+
while (v != NULL) {
26942687
rs[n++] = v->right;
26952688
v->right = 1;
26962689
v = v->prev;
26972690
}
26982691
int issub = subtype_in_env(x, y, e);
26992692
n = 0; v = e->vars;
2700-
while (n < len) {
2701-
assert(v != NULL);
2693+
while (v != NULL) {
27022694
v->right = rs[n++];
27032695
v = v->prev;
27042696
}
2705-
free(rs);
27062697
return issub;
27072698
}
27082699

@@ -2750,6 +2741,8 @@ static int check_unsat_bound(jl_value_t *t, jl_tvar_t *v, jl_stenv_t *e) JL_NOTS
27502741
}
27512742

27522743

2744+
static int intersect_var_ccheck_in_env(jl_value_t *xlb, jl_value_t *xub, jl_value_t *ylb, jl_value_t *yub, jl_stenv_t *e, int flip);
2745+
27532746
static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, int param)
27542747
{
27552748
jl_varbinding_t *bb = lookup(e, b);
@@ -2766,15 +2759,10 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
27662759
jl_value_t *ub = NULL;
27672760
JL_GC_PUSH1(&ub);
27682761
if (!jl_has_free_typevars(a)) {
2769-
save_env(e, &se, 1);
2770-
int issub = subtype_in_env_existential(bb->lb, a, e);
2771-
restore_env(e, &se, 1);
2772-
if (issub) {
2773-
issub = subtype_in_env_existential(a, bb->ub, e);
2774-
restore_env(e, &se, 1);
2775-
}
2776-
free_env(&se);
2777-
if (!issub) {
2762+
if (R) flip_offset(e);
2763+
int ccheck = intersect_var_ccheck_in_env(bb->lb, bb->ub, a, a, e, !R);
2764+
if (R) flip_offset(e);
2765+
if (!ccheck) {
27782766
JL_GC_POP();
27792767
return jl_bottom_type;
27802768
}
@@ -2784,6 +2772,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
27842772
e->triangular++;
27852773
ub = R ? intersect_aside(a, bb->ub, e, bb->depth0) : intersect_aside(bb->ub, a, e, bb->depth0);
27862774
e->triangular--;
2775+
jl_savedenv_t se;
27872776
save_env(e, &se, 1);
27882777
int issub = subtype_in_env_existential(bb->lb, ub, e);
27892778
restore_env(e, &se, 1);
@@ -3374,7 +3363,24 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv
33743363
if (jl_is_typevar(vb->lb)) {
33753364
}
33763365
else if (!is_leaf_bound(vb->lb)) {
3377-
res = jl_bottom_type;
3366+
JL_GC_PUSH1(&res);
3367+
res = omit_bad_union(res, u->var);
3368+
if (res != jl_bottom_type) {
3369+
jl_varbinding_t *btemp = e->vars;
3370+
while (btemp != NULL) {
3371+
if (jl_has_typevar(btemp->lb, u->var)) {
3372+
res = jl_bottom_type;
3373+
break;
3374+
}
3375+
btemp->ub = omit_bad_union(btemp->ub, u->var);
3376+
if (btemp->ub == jl_bottom_type && btemp->ub != btemp->lb) {
3377+
res = jl_bottom_type;
3378+
break;
3379+
}
3380+
btemp = btemp->prev;
3381+
}
3382+
}
3383+
JL_GC_POP();
33783384
}
33793385
}
33803386

@@ -3856,6 +3862,89 @@ static int subtype_by_bounds(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_NOT
38563862
return compareto_var(x, (jl_tvar_t*)y, e, -1) || compareto_var(y, (jl_tvar_t*)x, e, 1);
38573863
}
38583864

3865+
static int intersect_var_ccheck_in_env(jl_value_t *xlb, jl_value_t *xub, jl_value_t *ylb, jl_value_t *yub, jl_stenv_t *e, int flip)
3866+
{
3867+
int easy_check1 = xlb == jl_bottom_type ||
3868+
yub == (jl_value_t *)jl_any_type ||
3869+
(e->Loffset == 0 && obviously_in_union(yub, xlb));
3870+
int easy_check2 = ylb == jl_bottom_type ||
3871+
xub == (jl_value_t *)jl_any_type ||
3872+
(e->Loffset == 0 && obviously_in_union(xub, ylb));
3873+
int nofree1 = 0, nofree2 = 0;
3874+
if (!easy_check1) {
3875+
nofree1 = !jl_has_free_typevars(xlb) && !jl_has_free_typevars(yub);
3876+
if (nofree1 && e->Loffset == 0) {
3877+
easy_check1 = jl_subtype(xlb, yub);
3878+
if (!easy_check1)
3879+
return 0;
3880+
}
3881+
}
3882+
if (!easy_check2) {
3883+
nofree2 = !jl_has_free_typevars(ylb) && !jl_has_free_typevars(xub);
3884+
if (nofree2 && e->Loffset == 0) {
3885+
easy_check2 = jl_subtype(ylb, xub);
3886+
if (!easy_check2)
3887+
return 0;
3888+
}
3889+
}
3890+
if (easy_check1 && easy_check2)
3891+
return 1;
3892+
int ccheck = 0;
3893+
if ((easy_check1 || nofree1) && (easy_check2 || nofree2)) {
3894+
jl_varbinding_t *vars = e->vars;
3895+
e->vars = NULL;
3896+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3897+
if (ccheck && !easy_check2) {
3898+
flip_offset(e);
3899+
ccheck = subtype_in_env(ylb, xub, e);
3900+
flip_offset(e);
3901+
}
3902+
e->vars = vars;
3903+
return ccheck;
3904+
}
3905+
jl_savedenv_t se;
3906+
save_env(e, &se, 1);
3907+
// first try normal flip.
3908+
if (flip) flip_vars(e);
3909+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3910+
if (ccheck && !easy_check2) {
3911+
flip_offset(e);
3912+
ccheck = subtype_in_env(ylb, xub, e);
3913+
flip_offset(e);
3914+
}
3915+
if (flip) flip_vars(e);
3916+
if (!ccheck) {
3917+
// then try reverse flip.
3918+
restore_env(e, &se, 1);
3919+
if (!flip) flip_vars(e);
3920+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3921+
if (ccheck && !easy_check2) {
3922+
flip_offset(e);
3923+
ccheck = subtype_in_env(ylb, xub, e);
3924+
flip_offset(e);
3925+
}
3926+
if (!flip) flip_vars(e);
3927+
}
3928+
if (!ccheck) {
3929+
// then try existential.
3930+
restore_env(e, &se, 1);
3931+
if (easy_check1)
3932+
ccheck = 1;
3933+
else {
3934+
ccheck = subtype_in_env_existential(xlb, yub, e);
3935+
restore_env(e, &se, 1);
3936+
}
3937+
if (ccheck && !easy_check2) {
3938+
flip_offset(e);
3939+
ccheck = subtype_in_env_existential(ylb, xub, e);
3940+
flip_offset(e);
3941+
restore_env(e, &se, 1);
3942+
}
3943+
}
3944+
free_env(&se);
3945+
return ccheck;
3946+
}
3947+
38593948
static int has_typevar_via_env(jl_value_t *x, jl_tvar_t *t, jl_stenv_t *e)
38603949
{
38613950
if (e->Loffset == 0) {
@@ -3988,14 +4077,8 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
39884077
ccheck = 1;
39894078
}
39904079
else {
3991-
if (R) flip_vars(e);
3992-
ccheck = subtype_in_env(xlb, yub, e);
3993-
if (ccheck) {
3994-
flip_offset(e);
3995-
ccheck = subtype_in_env(ylb, xub, e);
3996-
flip_offset(e);
3997-
}
3998-
if (R) flip_vars(e);
4080+
// try many subtype check to avoid false `Union{}`
4081+
ccheck = intersect_var_ccheck_in_env(xlb, xub, ylb, yub, e, R);
39994082
}
40004083
if (R) flip_offset(e);
40014084
if (!ccheck)

test/subtype.jl

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,9 +1691,7 @@ CovType{T} = Union{AbstractArray{T,2},
16911691
# issue #31703
16921692
@testintersect(Pair{<:Any, Ref{Tuple{Ref{Ref{Tuple{Int}}},Ref{Float64}}}},
16931693
Pair{T, S} where S<:(Ref{A} where A<:(Tuple{C,Ref{T}} where C<:(Ref{D} where D<:(Ref{E} where E<:Tuple{FF}) where FF<:B)) where B) where T,
1694-
Pair{T, Ref{Tuple{Ref{Ref{Tuple{Int}}},Ref{Float64}}}} where T)
1695-
# TODO: should be able to get this result
1696-
# Pair{Float64, Ref{Tuple{Ref{Ref{Tuple{Int}}},Ref{Float64}}}}
1694+
Pair{Float64, Ref{Tuple{Ref{Ref{Tuple{Int}}},Ref{Float64}}}})
16971695

16981696
module I31703
16991697
using Test, LinearAlgebra
@@ -1745,8 +1743,7 @@ end
17451743
Tuple{Type{SA{2, L}}, Type{SA{2, L}}} where L)
17461744
@testintersect(Tuple{Type{SA{2, L}}, Type{SA{2, 16}}} where L,
17471745
Tuple{Type{<:SA{N, L}}, Type{<:SA{N, L}}} where {N,L},
1748-
# TODO: this could be narrower
1749-
Tuple{Type{SA{2, L}}, Type{SA{2, 16}}} where L)
1746+
Tuple{Type{SA{2, 16}}, Type{SA{2, 16}}})
17501747

17511748
# issue #31993
17521749
@testintersect(Tuple{Type{<:AbstractVector{T}}, Int} where T,
@@ -1851,9 +1848,9 @@ c32703(::Type{<:Str{C}}, str::Str{C}) where {C<:CSE} = str
18511848
Tuple{Type{<:Str{C}}, Str{C}} where {C<:CSE},
18521849
Union{})
18531850
@test c32703(UTF16Str, ASCIIStr()) == 42
1854-
@test_broken typeintersect(Tuple{Vector{Vector{Float32}},Matrix,Matrix},
1855-
Tuple{Vector{V},Matrix{Int},Matrix{S}} where {S, V<:AbstractVector{S}}) ==
1856-
Tuple{Array{Array{Float32,1},1},Array{Int,2},Array{Float32,2}}
1851+
@testintersect(Tuple{Vector{Vector{Float32}},Matrix,Matrix},
1852+
Tuple{Vector{V},Matrix{Int},Matrix{S}} where {S, V<:AbstractVector{S}},
1853+
Tuple{Array{Array{Float32,1},1},Array{Int,2},Array{Float32,2}})
18571854

18581855
@testintersect(Tuple{Pair{Int, DataType}, Any},
18591856
Tuple{Pair{A, B} where B<:Type, Int} where A,
@@ -2469,16 +2466,18 @@ end
24692466
abstract type P47654{A} end
24702467
@test Wrapper47654{P47654, Vector{Union{P47654,Nothing}}} <: Wrapper47654
24712468

2469+
#issue 41561
2470+
@testintersect(Tuple{Vector{VT}, Vector{VT}} where {N1, VT<:AbstractVector{N1}},
2471+
Tuple{Vector{VN} where {N, VN<:AbstractVector{N}}, Vector{Vector{Float64}}},
2472+
Tuple{Vector{Vector{Float64}}, Vector{Vector{Float64}}})
2473+
24722474
@testset "known subtype/intersect issue" begin
24732475
#issue 45874
24742476
let S = Pair{Val{P}, AbstractVector{<:Union{P,<:AbstractMatrix{P}}}} where P,
24752477
T = Pair{Val{R}, AbstractVector{<:Union{P,<:AbstractMatrix{P}}}} where {P,R}
24762478
@test S <: T
24772479
end
24782480

2479-
#issue 41561
2480-
@test_broken typeintersect(Tuple{Vector{VT}, Vector{VT}} where {N1, VT<:AbstractVector{N1}},
2481-
Tuple{Vector{VN} where {N, VN<:AbstractVector{N}}, Vector{Vector{Float64}}}) !== Union{}
24822481
#issue 40865
24832482
@test Tuple{Set{Ref{Int}}, Set{Ref{Int}}} <: Tuple{Set{KV}, Set{K}} where {K,KV<:Union{K,Ref{K}}}
24842483
@test Tuple{Set{Val{Int}}, Set{Val{Int}}} <: Tuple{Set{KV}, Set{K}} where {K,KV<:Union{K,Val{K}}}
@@ -2746,3 +2745,16 @@ end
27462745
Val{Tuple{T,R,S}} where {T,R<:Vector{T},S<:Vector{R}},
27472746
Val{Tuple{Int, Vector{Int}, T}} where T<:Vector{Vector{Int}},
27482747
)
2748+
2749+
#issue 57429
2750+
@testintersect(
2751+
Pair{<:Any, <:Tuple{Int}},
2752+
Pair{N, S} where {N, NTuple{N,Int}<:S<:NTuple{M,Int} where {M}},
2753+
!Union{}
2754+
)
2755+
@testintersect(
2756+
Pair{N, T} where {N,NTuple{N,Int}<:T<:NTuple{N,Int}},
2757+
Pair{N, T} where {N,NTuple{N,Int}<:T<:Tuple{Int,Vararg{Int}}},
2758+
!Union{}
2759+
)
2760+

0 commit comments

Comments
 (0)