From 7bfd9f4dc30135a12770dd714c854d51996b7050 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Fri, 23 Feb 2024 07:06:06 +0800 Subject: [PATCH] =?UTF-8?q?Subtype:=20skip=20slow-path=20in=20`local=5F?= =?UTF-8?q?=E2=88=80=5F=E2=88=83=5Fsubtype`=20if=20inputs=20contain=20no?= =?UTF-8?q?=20=E2=88=83=20typevar.=20(#53429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 37c48e8b11d4742818571405019d80b59fceab49) --- src/jltypes.c | 2 +- src/julia_internal.h | 1 + src/subtype.c | 31 +++++++++++++++++++++++++++---- test/subtype.jl | 9 +++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index d61a06b06f159..66db26a575e90 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -215,7 +215,7 @@ JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v) } // test whether a type has vars bound by the given environment -static int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT +int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT { while (1) { if (jl_is_typevar(v)) { diff --git a/src/julia_internal.h b/src/julia_internal.h index 89f31f1702db7..4fa3154b765d1 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -696,6 +696,7 @@ jl_tupletype_t *jl_lookup_arg_tuple_type(jl_value_t *arg1 JL_PROPAGATES_ROOT, jl JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED; int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); +int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); int jl_has_fixed_layout(jl_datatype_t *t); JL_DLLEXPORT int jl_struct_try_layout(jl_datatype_t *dt); diff --git a/src/subtype.c b/src/subtype.c index 86b441f9aaec0..3d874872d6b44 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1506,6 +1506,23 @@ static int may_contain_union_decision(jl_value_t *x, jl_stenv_t *e, jl_typeenv_t may_contain_union_decision(xb ? xb->ub : ((jl_tvar_t *)x)->ub, e, &newlog); } +static int has_exists_typevar(jl_value_t *x, jl_stenv_t *e) JL_NOTSAFEPOINT +{ + jl_typeenv_t *env = NULL; + jl_varbinding_t *v = e->vars; + while (v != NULL) { + if (v->right) { + jl_typeenv_t *newenv = (jl_typeenv_t*)alloca(sizeof(jl_typeenv_t)); + newenv->var = v->var; + newenv->val = NULL; + newenv->prev = env; + env = newenv; + } + v = v->prev; + } + return env != NULL && jl_has_bound_typevars(x, env); +} + static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int limit_slow) { 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 int count = 0, noRmore = 0; sub = _forall_exists_subtype(x, y, e, param, &count, &noRmore); pop_unionstate(&e->Runions, &oldRunions); - // we should not try the slow path if `forall_exists_subtype` has tested all cases; - // Once limit_slow == 1, also skip it if - // 1) `forall_exists_subtype` return false + // We could skip the slow path safely if + // 1) `_∀_∃_subtype` has tested all cases + // 2) `_∀_∃_subtype` returns 1 && `x` and `y` contain no ∃ typevar + // Once `limit_slow == 1`, also skip it if + // 1) `_∀_∃_subtype` returns 0 // 2) the left `Union` looks big + // TODO: `limit_slow` ignores complexity from inner `local_∀_exists_subtype`. if (limit_slow == -1) limit_slow = kindx || kindy; - if (noRmore || (limit_slow && (count > 3 || !sub))) + int skip = noRmore || (limit_slow && (count > 3 || !sub)) || + (sub && (kindx || !has_exists_typevar(x, e)) && + (kindy || !has_exists_typevar(y, e))); + if (skip) e->Runions.more = oldRmore; } else { diff --git a/test/subtype.jl b/test/subtype.jl index 19901897ebaaa..cd856b0b7a2ff 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2562,3 +2562,12 @@ let a = Tuple{Union{Nothing, Type{Pair{T1}} where T1}} b = Tuple{Type{X2} where X2<:(Pair{T2, Y2} where {Src, Z2<:Src, Y2<:Union{Val{Z2}, Z2}})} where T2 @test !Base.has_free_typevars(typeintersect(a, b)) end + +#issue 53371 +struct T53371{A,B,C,D,E} end +S53371{A} = Union{Int, <:A} +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}}) +let S = Type{T53371{A, B, C, D, E}} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}}, + T = Type{T53371{A, B, C, D, E} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}}} + @test !(S <: T) +end