Skip to content

Commit 7bfd9f4

Browse files
N5N3KristofferC
authored andcommitted
Subtype: skip slow-path in local_∀_∃_subtype if inputs contain no ∃ typevar. (#53429)
This should be safe as ∀ vars' bounds are frozen in env. If there's no ∃ var, then the current env won't change after `local_∀_∃_subtype`. Thus, the slow path should be equivalent to the fast path if the latter returns 1. Close #53371. (cherry picked from commit 37c48e8)
1 parent 8f3304a commit 7bfd9f4

File tree

4 files changed

+38
-5
lines changed

4 files changed

+38
-5
lines changed

src/jltypes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v)
215215
}
216216

217217
// test whether a type has vars bound by the given environment
218-
static int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT
218+
int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT
219219
{
220220
while (1) {
221221
if (jl_is_typevar(v)) {

src/julia_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl
696696
JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype);
697697
jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED;
698698
int jl_obviously_unequal(jl_value_t *a, jl_value_t *b);
699+
int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT;
699700
JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v);
700701
int jl_has_fixed_layout(jl_datatype_t *t);
701702
JL_DLLEXPORT int jl_struct_try_layout(jl_datatype_t *dt);

src/subtype.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,23 @@ static int may_contain_union_decision(jl_value_t *x, jl_stenv_t *e, jl_typeenv_t
15061506
may_contain_union_decision(xb ? xb->ub : ((jl_tvar_t *)x)->ub, e, &newlog);
15071507
}
15081508

1509+
static int has_exists_typevar(jl_value_t *x, jl_stenv_t *e) JL_NOTSAFEPOINT
1510+
{
1511+
jl_typeenv_t *env = NULL;
1512+
jl_varbinding_t *v = e->vars;
1513+
while (v != NULL) {
1514+
if (v->right) {
1515+
jl_typeenv_t *newenv = (jl_typeenv_t*)alloca(sizeof(jl_typeenv_t));
1516+
newenv->var = v->var;
1517+
newenv->val = NULL;
1518+
newenv->prev = env;
1519+
env = newenv;
1520+
}
1521+
v = v->prev;
1522+
}
1523+
return env != NULL && jl_has_bound_typevars(x, env);
1524+
}
1525+
15091526
static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int limit_slow)
15101527
{
15111528
int16_t oldRmore = e->Runions.more;
@@ -1525,13 +1542,19 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
15251542
int count = 0, noRmore = 0;
15261543
sub = _forall_exists_subtype(x, y, e, param, &count, &noRmore);
15271544
pop_unionstate(&e->Runions, &oldRunions);
1528-
// we should not try the slow path if `forall_exists_subtype` has tested all cases;
1529-
// Once limit_slow == 1, also skip it if
1530-
// 1) `forall_exists_subtype` return false
1545+
// We could skip the slow path safely if
1546+
// 1) `_∀_∃_subtype` has tested all cases
1547+
// 2) `_∀_∃_subtype` returns 1 && `x` and `y` contain no ∃ typevar
1548+
// Once `limit_slow == 1`, also skip it if
1549+
// 1) `_∀_∃_subtype` returns 0
15311550
// 2) the left `Union` looks big
1551+
// TODO: `limit_slow` ignores complexity from inner `local_∀_exists_subtype`.
15321552
if (limit_slow == -1)
15331553
limit_slow = kindx || kindy;
1534-
if (noRmore || (limit_slow && (count > 3 || !sub)))
1554+
int skip = noRmore || (limit_slow && (count > 3 || !sub)) ||
1555+
(sub && (kindx || !has_exists_typevar(x, e)) &&
1556+
(kindy || !has_exists_typevar(y, e)));
1557+
if (skip)
15351558
e->Runions.more = oldRmore;
15361559
}
15371560
else {

test/subtype.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2562,3 +2562,12 @@ let a = Tuple{Union{Nothing, Type{Pair{T1}} where T1}}
25622562
b = Tuple{Type{X2} where X2<:(Pair{T2, Y2} where {Src, Z2<:Src, Y2<:Union{Val{Z2}, Z2}})} where T2
25632563
@test !Base.has_free_typevars(typeintersect(a, b))
25642564
end
2565+
2566+
#issue 53371
2567+
struct T53371{A,B,C,D,E} end
2568+
S53371{A} = Union{Int, <:A}
2569+
R53371{A} = Val{V} where V<:(T53371{B,C,D,E,F} where {B<:Val{A}, C<:S53371{B}, D<:S53371{B}, E<:S53371{B}, F<:S53371{B}})
2570+
let S = Type{T53371{A, B, C, D, E}} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}},
2571+
T = Type{T53371{A, B, C, D, E} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}}}
2572+
@test !(S <: T)
2573+
end

0 commit comments

Comments
 (0)