Skip to content

Commit af8ae14

Browse files
N5N3KristofferC
authored andcommitted
Intersect: try normal+reverse+existential subtyping during intersection (#57476)
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. fix #57429 fix #41561 (cherry picked from commit beb928b)
1 parent 9e35b31 commit af8ae14

File tree

2 files changed

+118
-42
lines changed

2 files changed

+118
-42
lines changed

src/subtype.c

Lines changed: 96 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,31 +2667,22 @@ static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_sten
26672667
// subtype, treating all vars as existential
26682668
static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
26692669
{
2670-
jl_varbinding_t *v = e->vars;
2671-
int len = 0;
26722670
if (x == jl_bottom_type || y == (jl_value_t*)jl_any_type)
26732671
return 1;
2674-
while (v != NULL) {
2675-
len++;
2676-
v = v->prev;
2677-
}
2678-
int8_t *rs = (int8_t*)malloc_s(len);
2672+
int8_t *rs = (int8_t*)alloca(current_env_length(e));
2673+
jl_varbinding_t *v = e->vars;
26792674
int n = 0;
2680-
v = e->vars;
2681-
while (n < len) {
2682-
assert(v != NULL);
2675+
while (v != NULL) {
26832676
rs[n++] = v->right;
26842677
v->right = 1;
26852678
v = v->prev;
26862679
}
26872680
int issub = subtype_in_env(x, y, e);
26882681
n = 0; v = e->vars;
2689-
while (n < len) {
2690-
assert(v != NULL);
2682+
while (v != NULL) {
26912683
v->right = rs[n++];
26922684
v = v->prev;
26932685
}
2694-
free(rs);
26952686
return issub;
26962687
}
26972688

@@ -2739,6 +2730,8 @@ static int check_unsat_bound(jl_value_t *t, jl_tvar_t *v, jl_stenv_t *e) JL_NOTS
27392730
}
27402731

27412732

2733+
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);
2734+
27422735
static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, int param)
27432736
{
27442737
jl_varbinding_t *bb = lookup(e, b);
@@ -2750,20 +2743,14 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
27502743
return R ? intersect(a, bb->lb, e, param) : intersect(bb->lb, a, e, param);
27512744
if (!jl_is_type(a) && !jl_is_typevar(a))
27522745
return set_var_to_const(bb, a, e, R);
2753-
jl_savedenv_t se;
27542746
if (param == 2) {
27552747
jl_value_t *ub = NULL;
27562748
JL_GC_PUSH1(&ub);
27572749
if (!jl_has_free_typevars(a)) {
2758-
save_env(e, &se, 1);
2759-
int issub = subtype_in_env_existential(bb->lb, a, e);
2760-
restore_env(e, &se, 1);
2761-
if (issub) {
2762-
issub = subtype_in_env_existential(a, bb->ub, e);
2763-
restore_env(e, &se, 1);
2764-
}
2765-
free_env(&se);
2766-
if (!issub) {
2750+
if (R) flip_offset(e);
2751+
int ccheck = intersect_var_ccheck_in_env(bb->lb, bb->ub, a, a, e, !R);
2752+
if (R) flip_offset(e);
2753+
if (!ccheck) {
27672754
JL_GC_POP();
27682755
return jl_bottom_type;
27692756
}
@@ -2773,6 +2760,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
27732760
e->triangular++;
27742761
ub = R ? intersect_aside(a, bb->ub, e, bb->depth0) : intersect_aside(bb->ub, a, e, bb->depth0);
27752762
e->triangular--;
2763+
jl_savedenv_t se;
27762764
save_env(e, &se, 1);
27772765
int issub = subtype_in_env_existential(bb->lb, ub, e);
27782766
restore_env(e, &se, 1);
@@ -3845,6 +3833,89 @@ static int subtype_by_bounds(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_NOT
38453833
return compareto_var(x, (jl_tvar_t*)y, e, -1) || compareto_var(y, (jl_tvar_t*)x, e, 1);
38463834
}
38473835

3836+
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)
3837+
{
3838+
int easy_check1 = xlb == jl_bottom_type ||
3839+
yub == (jl_value_t *)jl_any_type ||
3840+
(e->Loffset == 0 && obviously_in_union(yub, xlb));
3841+
int easy_check2 = ylb == jl_bottom_type ||
3842+
xub == (jl_value_t *)jl_any_type ||
3843+
(e->Loffset == 0 && obviously_in_union(xub, ylb));
3844+
int nofree1 = 0, nofree2 = 0;
3845+
if (!easy_check1) {
3846+
nofree1 = !jl_has_free_typevars(xlb) && !jl_has_free_typevars(yub);
3847+
if (nofree1 && e->Loffset == 0) {
3848+
easy_check1 = jl_subtype(xlb, yub);
3849+
if (!easy_check1)
3850+
return 0;
3851+
}
3852+
}
3853+
if (!easy_check2) {
3854+
nofree2 = !jl_has_free_typevars(ylb) && !jl_has_free_typevars(xub);
3855+
if (nofree2 && e->Loffset == 0) {
3856+
easy_check2 = jl_subtype(ylb, xub);
3857+
if (!easy_check2)
3858+
return 0;
3859+
}
3860+
}
3861+
if (easy_check1 && easy_check2)
3862+
return 1;
3863+
int ccheck = 0;
3864+
if ((easy_check1 || nofree1) && (easy_check2 || nofree2)) {
3865+
jl_varbinding_t *vars = e->vars;
3866+
e->vars = NULL;
3867+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3868+
if (ccheck && !easy_check2) {
3869+
flip_offset(e);
3870+
ccheck = subtype_in_env(ylb, xub, e);
3871+
flip_offset(e);
3872+
}
3873+
e->vars = vars;
3874+
return ccheck;
3875+
}
3876+
jl_savedenv_t se;
3877+
save_env(e, &se, 1);
3878+
// first try normal flip.
3879+
if (flip) flip_vars(e);
3880+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3881+
if (ccheck && !easy_check2) {
3882+
flip_offset(e);
3883+
ccheck = subtype_in_env(ylb, xub, e);
3884+
flip_offset(e);
3885+
}
3886+
if (flip) flip_vars(e);
3887+
if (!ccheck) {
3888+
// then try reverse flip.
3889+
restore_env(e, &se, 1);
3890+
if (!flip) flip_vars(e);
3891+
ccheck = easy_check1 || subtype_in_env(xlb, yub, e);
3892+
if (ccheck && !easy_check2) {
3893+
flip_offset(e);
3894+
ccheck = subtype_in_env(ylb, xub, e);
3895+
flip_offset(e);
3896+
}
3897+
if (!flip) flip_vars(e);
3898+
}
3899+
if (!ccheck) {
3900+
// then try existential.
3901+
restore_env(e, &se, 1);
3902+
if (easy_check1)
3903+
ccheck = 1;
3904+
else {
3905+
ccheck = subtype_in_env_existential(xlb, yub, e);
3906+
restore_env(e, &se, 1);
3907+
}
3908+
if (ccheck && !easy_check2) {
3909+
flip_offset(e);
3910+
ccheck = subtype_in_env_existential(ylb, xub, e);
3911+
flip_offset(e);
3912+
restore_env(e, &se, 1);
3913+
}
3914+
}
3915+
free_env(&se);
3916+
return ccheck;
3917+
}
3918+
38483919
static int has_typevar_via_env(jl_value_t *x, jl_tvar_t *t, jl_stenv_t *e)
38493920
{
38503921
if (e->Loffset == 0) {
@@ -3977,14 +4048,8 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
39774048
ccheck = 1;
39784049
}
39794050
else {
3980-
if (R) flip_vars(e);
3981-
ccheck = subtype_in_env(xlb, yub, e);
3982-
if (ccheck) {
3983-
flip_offset(e);
3984-
ccheck = subtype_in_env(ylb, xub, e);
3985-
flip_offset(e);
3986-
}
3987-
if (R) flip_vars(e);
4051+
// try many subtype check to avoid false `Union{}`
4052+
ccheck = intersect_var_ccheck_in_env(xlb, xub, ylb, yub, e, R);
39884053
}
39894054
if (R) flip_offset(e);
39904055
if (!ccheck)

test/subtype.jl

Lines changed: 22 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,15 @@ 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+
)

0 commit comments

Comments
 (0)