Skip to content

Commit

Permalink
subtype: fast path for Type == TypeVar (JuliaLang#56640)
Browse files Browse the repository at this point in the history
  • Loading branch information
N5N3 authored Nov 26, 2024
1 parent 81568a6 commit 7df1dfa
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,42 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
return sub;
}

static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e)
{
assert(e->Loffset == 0);
// Theoretically bounds change would be merged for union inputs.
// But intersection is not happy as splitting helps to avoid circular env.
assert(!e->intersection || !jl_is_uniontype(x));
jl_varbinding_t *vb = lookup(e, v);
if (e->intersection && vb != NULL && vb->lb == vb->ub && jl_is_typevar(vb->lb))
return equal_var((jl_tvar_t *)vb->lb, x, e);
record_var_occurrence(vb, e, 2);
if (vb == NULL)
return e->ignore_free || (
local_forall_exists_subtype(x, v->lb, e, 2, !jl_has_free_typevars(x)) &&
local_forall_exists_subtype(v->ub, x, e, 0, 0));
if (!vb->right)
return local_forall_exists_subtype(x, vb->lb, e, 2, !jl_has_free_typevars(x)) &&
local_forall_exists_subtype(vb->ub, x, e, 0, 0);
if (vb->lb == x)
return var_lt(v, x, e, 0);
if (!subtype_ccheck(x, vb->ub, e))
return 0;
jl_value_t *lb = simple_join(vb->lb, x);
JL_GC_PUSH1(&lb);
if (!e->intersection || !jl_is_typevar(lb) || !reachable_var(lb, v, e))
vb->lb = lb;
JL_GC_POP();
if (vb->ub == x)
return 1;
if (!subtype_ccheck(vb->lb, x, e))
return 0;
// skip `simple_meet` here as we have proven `x <: vb->ub`
if (!e->intersection || !reachable_var(x, v, e))
vb->ub = x;
return 1;
}

static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
{
if (obviously_egal(x, y)) return 1;
Expand Down Expand Up @@ -1690,6 +1726,12 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
}
}

if (e->Loffset == 0 && jl_is_typevar(y) && jl_is_type(x) && (!e->intersection || !jl_is_uniontype(x))) {
// Fastpath for Type == TypeVar.
// Avoid duplicated `<:` check between adjacent `var_gt` and `var_lt`
return equal_var((jl_tvar_t *)y, x, e);
}

jl_saved_unionstate_t oldLunions; push_unionstate(&oldLunions, &e->Lunions);

int sub = local_forall_exists_subtype(x, y, e, 2, -1);
Expand Down
16 changes: 16 additions & 0 deletions test/subtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2730,3 +2730,19 @@ let S = Dict{V,V} where {V},
@test A <: typeintersect(S, T)
@test A <: typeintersect(T, S)
end

#issue 56606
let
A = Tuple{Val{1}}
B = Tuple{Val}
for _ in 1:30
A = Tuple{Val{A}}
B = Tuple{Val{<:B}}
end
@test A <: B
end
@testintersect(
Val{Tuple{Int,S,T}} where {S<:Any,T<:Vector{Vector{Int}}},
Val{Tuple{T,R,S}} where {T,R<:Vector{T},S<:Vector{R}},
Val{Tuple{Int, Vector{Int}, T}} where T<:Vector{Vector{Int}},
)

0 comments on commit 7df1dfa

Please sign in to comment.