From ff2e1b4dfb3523360cd2a9548be3cf03ac258ff3 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 16 Dec 2019 17:21:10 -0500 Subject: [PATCH] add another tuple subtyping fast path (#34065) This handles cases like `Type{<:Tuple{A}} <: Type{Tuple{Vararg{_,N} where N}}`, i.e. where a fixed-length tuple type cannot ever equal an indefinite-length tuple type. --- base/regex.jl | 2 +- src/subtype.c | 27 +++++++++++++++++++++++++++ test/strings/basic.jl | 11 +++++++++++ test/subtype.jl | 3 +++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/base/regex.jl b/base/regex.jl index 0f5074bf026f8e..3154c56cb9712b 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -669,7 +669,7 @@ regex_opts_str(opts) = (isassigned(_regex_opts_str) ? _regex_opts_str[] : init_r # UInt32 to String mapping for some compile options const _regex_opts_str = Ref{ImmutableDict{UInt32,String}}() -init_regex() = _regex_opts_str[] = foldl(0:15, init=ImmutableDict{UInt32,String}()) do d, o +@noinline init_regex() = _regex_opts_str[] = foldl(0:15, init=ImmutableDict{UInt32,String}()) do d, o opt = UInt32(0) str = "" if o & 1 != 0 diff --git a/src/subtype.c b/src/subtype.c index 25ec9a09a9ed33..f251f7839f3093 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1346,10 +1346,37 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) return x == y || jl_egal(x, y); } +static int is_indefinite_length_tuple_type(jl_value_t *x) +{ + x = jl_unwrap_unionall(x); + if (!jl_is_tuple_type(x)) + return 0; + size_t n = jl_nparams(x); + return n > 0 && jl_vararg_kind(jl_tparam(x, n-1)) == JL_VARARG_UNBOUND; +} + +static int is_definite_length_tuple_type(jl_value_t *x) +{ + if (jl_is_typevar(x)) + x = ((jl_tvar_t*)x)->ub; + x = jl_unwrap_unionall(x); + if (!jl_is_tuple_type(x)) + return 0; + size_t n = jl_nparams(x); + if (n == 0) + return 1; + jl_vararg_kind_t k = jl_vararg_kind(jl_tparam(x, n-1)); + return k == JL_VARARG_NONE || k == JL_VARARG_INT; +} + static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) { if (obviously_egal(x, y)) return 1; + if ((is_indefinite_length_tuple_type(x) && is_definite_length_tuple_type(y)) || + (is_definite_length_tuple_type(x) && is_indefinite_length_tuple_type(y))) + return 0; + jl_unionstate_t oldLunions = e->Lunions; memset(e->Lunions.stack, 0, sizeof(e->Lunions.stack)); int sub; diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 410d7e63bc566d..d2be061b52d700 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -647,6 +647,17 @@ end @test "a" * 'b' * 'c' == "abc" end +# this tests a possible issue in subtyping with long argument lists to `string(...)` +getString(dic, key) = haskey(dic,key) ? "$(dic[key])" : "" +function getData(dic) + val = getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * + "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * + "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * + "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") * + "," * getString(dic,"") * "," * getString(dic,"") * "," * getString(dic,"") +end +@test getData(Dict()) == ",,,,,,,,,,,,,,,,,," + @testset "unrecognized escapes in string/char literals" begin @test_throws Meta.ParseError Meta.parse("\"\\.\"") @test_throws Meta.ParseError Meta.parse("\'\\.\'") diff --git a/test/subtype.jl b/test/subtype.jl index 488fcd7d4187be..093d1ad0962991 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1698,3 +1698,6 @@ s26065 = Ref{Tuple{T,Ref{Union{Ref{Tuple{Ref{Union{Ref{Ref{Tuple{Ref{Tuple{Union @testintersect(Tuple{:N,Vararg{Any,T}} where T, Tuple{T,Vararg{Any,T}} where T, Union{}) + +@test !issub(Tuple{Type{T}, T} where T<:Tuple{String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}, String, Union{Base.Regex, AbstractChar, AbstractString}}, + Tuple{Type{Tuple{Vararg{V, N} where N}}, Tuple{Vararg{V, N} where N}} where V)