Skip to content

Commit 7df1dfa

Browse files
authored
subtype: fast path for Type == TypeVar (#56640)
close #56606
1 parent 81568a6 commit 7df1dfa

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
@@ -1660,6 +1660,42 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
16601660
return sub;
16611661
}
16621662

1663+
static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e)
1664+
{
1665+
assert(e->Loffset == 0);
1666+
// Theoretically bounds change would be merged for union inputs.
1667+
// But intersection is not happy as splitting helps to avoid circular env.
1668+
assert(!e->intersection || !jl_is_uniontype(x));
1669+
jl_varbinding_t *vb = lookup(e, v);
1670+
if (e->intersection && vb != NULL && vb->lb == vb->ub && jl_is_typevar(vb->lb))
1671+
return equal_var((jl_tvar_t *)vb->lb, x, e);
1672+
record_var_occurrence(vb, e, 2);
1673+
if (vb == NULL)
1674+
return e->ignore_free || (
1675+
local_forall_exists_subtype(x, v->lb, e, 2, !jl_has_free_typevars(x)) &&
1676+
local_forall_exists_subtype(v->ub, x, e, 0, 0));
1677+
if (!vb->right)
1678+
return local_forall_exists_subtype(x, vb->lb, e, 2, !jl_has_free_typevars(x)) &&
1679+
local_forall_exists_subtype(vb->ub, x, e, 0, 0);
1680+
if (vb->lb == x)
1681+
return var_lt(v, x, e, 0);
1682+
if (!subtype_ccheck(x, vb->ub, e))
1683+
return 0;
1684+
jl_value_t *lb = simple_join(vb->lb, x);
1685+
JL_GC_PUSH1(&lb);
1686+
if (!e->intersection || !jl_is_typevar(lb) || !reachable_var(lb, v, e))
1687+
vb->lb = lb;
1688+
JL_GC_POP();
1689+
if (vb->ub == x)
1690+
return 1;
1691+
if (!subtype_ccheck(vb->lb, x, e))
1692+
return 0;
1693+
// skip `simple_meet` here as we have proven `x <: vb->ub`
1694+
if (!e->intersection || !reachable_var(x, v, e))
1695+
vb->ub = x;
1696+
return 1;
1697+
}
1698+
16631699
static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
16641700
{
16651701
if (obviously_egal(x, y)) return 1;
@@ -1690,6 +1726,12 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
16901726
}
16911727
}
16921728

1729+
if (e->Loffset == 0 && jl_is_typevar(y) && jl_is_type(x) && (!e->intersection || !jl_is_uniontype(x))) {
1730+
// Fastpath for Type == TypeVar.
1731+
// Avoid duplicated `<:` check between adjacent `var_gt` and `var_lt`
1732+
return equal_var((jl_tvar_t *)y, x, e);
1733+
}
1734+
16931735
jl_saved_unionstate_t oldLunions; push_unionstate(&oldLunions, &e->Lunions);
16941736

16951737
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
@@ -2730,3 +2730,19 @@ let S = Dict{V,V} where {V},
27302730
@test A <: typeintersect(S, T)
27312731
@test A <: typeintersect(T, S)
27322732
end
2733+
2734+
#issue 56606
2735+
let
2736+
A = Tuple{Val{1}}
2737+
B = Tuple{Val}
2738+
for _ in 1:30
2739+
A = Tuple{Val{A}}
2740+
B = Tuple{Val{<:B}}
2741+
end
2742+
@test A <: B
2743+
end
2744+
@testintersect(
2745+
Val{Tuple{Int,S,T}} where {S<:Any,T<:Vector{Vector{Int}}},
2746+
Val{Tuple{T,R,S}} where {T,R<:Vector{T},S<:Vector{R}},
2747+
Val{Tuple{Int, Vector{Int}, T}} where T<:Vector{Vector{Int}},
2748+
)

0 commit comments

Comments
 (0)