From 9e146005aefc9d7abaaa91c4b88c71e14d4925c2 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Tue, 22 Apr 2025 23:37:56 +0800 Subject: [PATCH 1/2] subtype: add repeating/separable fast path into `subtype_vararg` fix #58115 --- src/subtype.c | 36 ++++++++++++++++++++++++++++-------- test/subtype.jl | 4 ++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index ed6a8818dc3f2..cc46eaf4f5254 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1069,7 +1069,8 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e); static int subtype_tuple_varargs( jl_vararg_t *vtx, jl_vararg_t *vty, - size_t vx, size_t vy, + jl_value_t *lastx, jl_value_t *lasty, + size_t vx, size_t vy, size_t x_reps, jl_stenv_t *e, int param) { jl_value_t *xp0 = jl_unwrap_vararg(vtx); jl_value_t *xp1 = jl_unwrap_vararg_num(vtx); @@ -1111,12 +1112,30 @@ static int subtype_tuple_varargs( } } } - - // in Vararg{T1} <: Vararg{T2}, need to check subtype twice to - // simulate the possibility of multiple arguments, which is needed - // to implement the diagonal rule correctly. - if (!subtype(xp0, yp0, e, param)) return 0; - if (!subtype(xp0, yp0, e, 1)) return 0; + int x_same = vx > 1 || (lastx && obviously_egal(xp0, lastx)); + int y_same = vy > 1 || (lasty && obviously_egal(yp0, lasty)); + // keep track of number of consecutive identical subtyping + x_reps = y_same && x_same ? x_reps + 1 : 1; + if (x_reps > 2) { + // an identical type on the left doesn't need to be compared to the same + // element type on the right more than twice. + } + else if (x_same && e->Runions.depth == 0 && y_same && + !jl_has_free_typevars(xp0) && !jl_has_free_typevars(yp0)) { + // fast path for repeated elements + } + else if (e->Runions.depth == 0 && !jl_has_free_typevars(xp0) && !jl_has_free_typevars(yp0)) { + // fast path for separable sub-formulas + if (!jl_subtype(xp0, yp0)) + return 0; + } + else { + // in Vararg{T1} <: Vararg{T2}, need to check subtype twice to + // simulate the possibility of multiple arguments, which is needed + // to implement the diagonal rule correctly. + if (!subtype(xp0, yp0, e, param)) return 0; + if (x_reps < 2 && !subtype(xp0, yp0, e, 1)) return 0; + } constrain_length: if (!yp1) { @@ -1246,7 +1265,8 @@ static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl return subtype_tuple_varargs( (jl_vararg_t*)xi, (jl_vararg_t*)yi, - vx, vy, e, param); + lastx, lasty, + vx, vy, x_reps, e, param); } if (j >= ly) diff --git a/test/subtype.jl b/test/subtype.jl index da69022b1466e..dbd761c7f5867 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2782,3 +2782,7 @@ let Tvar1 = TypeVar(:Tvar1), Tvar2 = TypeVar(:Tvar2) V2 = UnionAll(Tvar2, Union{(@eval($(Symbol(:T58129, k)){$Tvar2}) for k in 1:100)...}) @test Set{<:V2} <: AbstractSet{<:V1} end + +#issue 58115 +@test Tuple{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{ Union{Tuple{}, Tuple{Tuple{}}}}}}}}}}}}} , Tuple{}} <: + Tuple{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Tuple{Vararg{Union{Tuple{}, Tuple{Tuple{}}}}}}}}}}}}}}}, Tuple{}} From 103f91893de16b206189304d1f8d840102a27808 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Tue, 22 Apr 2025 23:52:11 +0800 Subject: [PATCH 2/2] subtype: enable more separable fast path for Tuple. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an element in the left Tuple is concrete, then there's no ∀ union inside it. The separable fast path should be safe for this case. --- src/subtype.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index cc46eaf4f5254..3d50dc492e190 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1124,7 +1124,7 @@ static int subtype_tuple_varargs( !jl_has_free_typevars(xp0) && !jl_has_free_typevars(yp0)) { // fast path for repeated elements } - else if (e->Runions.depth == 0 && !jl_has_free_typevars(xp0) && !jl_has_free_typevars(yp0)) { + else if ((e->Runions.depth == 0 ? !jl_has_free_typevars(xp0) : jl_is_concrete_type(xp0)) && !jl_has_free_typevars(yp0)) { // fast path for separable sub-formulas if (!jl_subtype(xp0, yp0)) return 0; @@ -1287,7 +1287,7 @@ static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl (yi == lastx && !vx && vy && jl_is_concrete_type(xi)))) { // fast path for repeated elements } - else if (e->Runions.depth == 0 && !jl_has_free_typevars(xi) && !jl_has_free_typevars(yi)) { + else if ((e->Runions.depth == 0 ? !jl_has_free_typevars(xi) : jl_is_concrete_type(xi)) && !jl_has_free_typevars(yi)) { // fast path for separable sub-formulas if (!jl_subtype(xi, yi)) return 0;