Skip to content

Commit d81b037

Browse files
N5N3KristofferC
authored andcommitted
subtype: fast path for Type == TypeVar (#56640)
close #56606 (cherry picked from commit 7df1dfa)
1 parent 53ba326 commit d81b037

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

src/subtype.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,42 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
15721572
return sub;
15731573
}
15741574

1575+
static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e)
1576+
{
1577+
assert(e->Loffset == 0);
1578+
// Theoretically bounds change would be merged for union inputs.
1579+
// But intersection is not happy as splitting helps to avoid circular env.
1580+
assert(!e->intersection || !jl_is_uniontype(x));
1581+
jl_varbinding_t *vb = lookup(e, v);
1582+
if (e->intersection && vb != NULL && vb->lb == vb->ub && jl_is_typevar(vb->lb))
1583+
return equal_var((jl_tvar_t *)vb->lb, x, e);
1584+
record_var_occurrence(vb, e, 2);
1585+
if (vb == NULL)
1586+
return e->ignore_free || (
1587+
local_forall_exists_subtype(x, v->lb, e, 2, !jl_has_free_typevars(x)) &&
1588+
local_forall_exists_subtype(v->ub, x, e, 0, 0));
1589+
if (!vb->right)
1590+
return local_forall_exists_subtype(x, vb->lb, e, 2, !jl_has_free_typevars(x)) &&
1591+
local_forall_exists_subtype(vb->ub, x, e, 0, 0);
1592+
if (vb->lb == x)
1593+
return var_lt(v, x, e, 0);
1594+
if (!subtype_ccheck(x, vb->ub, e))
1595+
return 0;
1596+
jl_value_t *lb = simple_join(vb->lb, x);
1597+
JL_GC_PUSH1(&lb);
1598+
if (!e->intersection || !jl_is_typevar(lb) || !reachable_var(lb, v, e))
1599+
vb->lb = lb;
1600+
JL_GC_POP();
1601+
if (vb->ub == x)
1602+
return 1;
1603+
if (!subtype_ccheck(vb->lb, x, e))
1604+
return 0;
1605+
// skip `simple_meet` here as we have proven `x <: vb->ub`
1606+
if (!e->intersection || !reachable_var(x, v, e))
1607+
vb->ub = x;
1608+
return 1;
1609+
}
1610+
15751611
static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
15761612
{
15771613
if (obviously_egal(x, y)) return 1;
@@ -1602,6 +1638,12 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
16021638
}
16031639
}
16041640

1641+
if (e->Loffset == 0 && jl_is_typevar(y) && jl_is_type(x) && (!e->intersection || !jl_is_uniontype(x))) {
1642+
// Fastpath for Type == TypeVar.
1643+
// Avoid duplicated `<:` check between adjacent `var_gt` and `var_lt`
1644+
return equal_var((jl_tvar_t *)y, x, e);
1645+
}
1646+
16051647
jl_saved_unionstate_t oldLunions; push_unionstate(&oldLunions, &e->Lunions);
16061648

16071649
int sub = local_forall_exists_subtype(x, y, e, 2, -1);

test/subtype.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,3 +2679,19 @@ let S = Dict{V,V} where {V},
26792679
@test A <: typeintersect(S, T)
26802680
@test A <: typeintersect(T, S)
26812681
end
2682+
2683+
#issue 56606
2684+
let
2685+
A = Tuple{Val{1}}
2686+
B = Tuple{Val}
2687+
for _ in 1:30
2688+
A = Tuple{Val{A}}
2689+
B = Tuple{Val{<:B}}
2690+
end
2691+
@test A <: B
2692+
end
2693+
@testintersect(
2694+
Val{Tuple{Int,S,T}} where {S<:Any,T<:Vector{Vector{Int}}},
2695+
Val{Tuple{T,R,S}} where {T,R<:Vector{T},S<:Vector{R}},
2696+
Val{Tuple{Int, Vector{Int}, T}} where T<:Vector{Vector{Int}},
2697+
)

0 commit comments

Comments
 (0)