Skip to content

Commit 357b052

Browse files
authored
fix #23327, subtyping bug in bounds containing free variables (#23643)
1 parent 368bb49 commit 357b052

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

src/subtype.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ typedef struct _varbinding {
6464
int8_t occurs_inv; // occurs in invariant position
6565
int8_t occurs_cov; // # of occurrences in covariant position
6666
int8_t concrete; // 1 if another variable has a constraint forcing this one to be concrete
67+
// set if this variable's bounds contain a free variable that's been removed from
68+
// the environment.
69+
int8_t hasfree;
6770
// in covariant position, we need to try constraining a variable in different ways:
6871
// 0 - unconstrained
6972
// 1 - less than
@@ -139,14 +142,15 @@ static void save_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se)
139142
v = v->prev;
140143
}
141144
*root = (jl_value_t*)jl_alloc_svec(len*3);
142-
se->buf = (int8_t*)(len ? malloc(len*2) : NULL);
145+
se->buf = (int8_t*)(len ? malloc(len*3) : NULL);
143146
int i=0, j=0; v = e->vars;
144147
while (v != NULL) {
145148
jl_svecset(*root, i++, v->lb);
146149
jl_svecset(*root, i++, v->ub);
147150
jl_svecset(*root, i++, (jl_value_t*)v->innervars);
148151
se->buf[j++] = v->occurs_inv;
149152
se->buf[j++] = v->occurs_cov;
153+
se->buf[j++] = v->hasfree;
150154
v = v->prev;
151155
}
152156
se->rdepth = e->Runions.depth;
@@ -165,6 +169,7 @@ static void restore_env(jl_stenv_t *e, jl_value_t *root, jl_savedenv_t *se)
165169
i++;
166170
v->occurs_inv = se->buf[j++];
167171
v->occurs_cov = se->buf[j++];
172+
v->hasfree = se->buf[j++];
168173
v = v->prev;
169174
}
170175
e->Runions.depth = se->rdepth;
@@ -562,7 +567,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
562567
}
563568
btemp = btemp->prev;
564569
}
565-
jl_varbinding_t vb = { u->var, u->var->lb, u->var->ub, R, NULL, 0, 0, 0, 0, e->invdepth, 0, NULL, e->vars };
570+
jl_varbinding_t vb = { u->var, u->var->lb, u->var->ub, R, NULL, 0, 0, 0, 0, 0, e->invdepth, 0, NULL, e->vars };
566571
JL_GC_PUSH3(&u, &vb.lb, &vb.ub);
567572
e->vars = &vb;
568573
int ans;
@@ -599,6 +604,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
599604
else {
600605
ans = subtype(u->body, t, e, param);
601606
}
607+
if (vb.hasfree) ans = 0;
602608

603609
// handle the "diagonal dispatch" rule, which says that a type var occurring more
604610
// than once, and only in covariant position, is constrained to concrete types. E.g.
@@ -638,14 +644,16 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8
638644
e->vars = vb.prev;
639645

640646
btemp = e->vars;
641-
while (btemp != NULL) {
642-
jl_value_t *vi = btemp->ub;
643-
// TODO: this takes a significant amount of time
644-
if (vi != (jl_value_t*)vb.var && btemp->var->ub != vi && jl_has_typevar(vi, vb.var)) {
645-
btemp->ub = jl_new_struct(jl_unionall_type, vb.var, vi);
646-
btemp->lb = jl_bottom_type;
647+
if (vb.lb != vb.ub) {
648+
while (btemp != NULL) {
649+
jl_value_t *vu = btemp->ub;
650+
jl_value_t *vl = btemp->lb;
651+
// TODO: this takes a significant amount of time
652+
if ((vu != (jl_value_t*)vb.var && btemp->var->ub != vu && jl_has_typevar(vu, vb.var)) ||
653+
(vl != (jl_value_t*)vb.var && btemp->var->lb != vl && jl_has_typevar(vl, vb.var)))
654+
btemp->hasfree = 1;
655+
btemp = btemp->prev;
647656
}
648-
btemp = btemp->prev;
649657
}
650658

651659
JL_GC_POP();
@@ -1548,7 +1556,7 @@ static jl_value_t *intersect_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_
15481556
{
15491557
jl_value_t *res=NULL, *res2=NULL, *save=NULL, *save2=NULL;
15501558
jl_savedenv_t se, se2;
1551-
jl_varbinding_t vb = { u->var, u->var->lb, u->var->ub, R, NULL, 0, 0, 0, 0, e->invdepth, 0, NULL, e->vars };
1559+
jl_varbinding_t vb = { u->var, u->var->lb, u->var->ub, R, NULL, 0, 0, 0, 0, 0, e->invdepth, 0, NULL, e->vars };
15521560
JL_GC_PUSH6(&res, &save2, &vb.lb, &vb.ub, &save, &vb.innervars);
15531561
save_env(e, &save, &se);
15541562
res = intersect_unionall_(t, u, e, R, param, &vb);

test/subtype.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,21 @@ function test_3()
256256
@test !issub((@UnionAll T>:Integer @UnionAll S>:Ptr Tuple{Ptr{T},Ptr{S}}), B)
257257

258258
@test issub((@UnionAll T>:Ptr @UnionAll S>:Integer Tuple{Ptr{T},Ptr{S}}), B)
259+
260+
# issue #23327
261+
@test !issub((Type{AbstractArray{Array{T}} where T}), Type{AbstractArray{S}} where S)
262+
@test !issub((Val{AbstractArray{Array{T}} where T}), Val{AbstractArray{T}} where T)
263+
@test !issub((Array{Array{Array{T}} where T}), Array{Array{T}} where T)
264+
@test !issub((Array{Array{T, 1}, 1} where T), AbstractArray{Vector})
265+
266+
@test !issub((Ref{Pair{Pair{T, R}, R} where R} where T),
267+
(Ref{Pair{A, B} where B} where A))
268+
@test !issub((Ref{Pair{Pair{A, B}, B} where B} where A),
269+
(Ref{Pair{A, B2} where B2 <: B} where A where B))
270+
271+
@test !issub(Tuple{Type{Vector{T}} where T, Vector{Float64}}, Tuple{Type{T}, T} where T)
272+
@test !issub(Tuple{Vector{Float64}, Type{Vector{T}} where T}, Tuple{T, Type{T}} where T)
273+
@test !issub(Tuple{Type{Ref{T}} where T, Vector{Float64}}, Tuple{Ref{T}, T} where T)
259274
end
260275

261276
# level 4: Union
@@ -1149,3 +1164,10 @@ end
11491164
Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,
11501165
Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,
11511166
Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64} <: (Tuple{Vararg{T}} where T<:Number))
1167+
1168+
# part of issue #23327
1169+
let
1170+
triangular(::Type{<:AbstractArray{T}}) where {T} = T
1171+
triangular(::Type{<:AbstractArray}) = Any
1172+
@test triangular(Array{Array{T, 1}, 1} where T) === Any
1173+
end

0 commit comments

Comments
 (0)