diff --git a/base/operators.jl b/base/operators.jl index e151f203b7f41..bf22c6ff553d9 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -160,11 +160,11 @@ isless(x::AbstractFloat, y::Real ) = (!isnan(x) & (isnan(y) | signless(x function ==(T::Type, S::Type) @_pure_meta - T<:S && S<:T + return ccall(:jl_types_equal, Cint, (Any, Any), T, S) != 0 end function !=(T::Type, S::Type) @_pure_meta - !(T == S) + return !(T == S) end ==(T::TypeVar, S::Type) = false ==(T::Type, S::TypeVar) = false diff --git a/src/common_symbols1.inc b/src/common_symbols1.inc index 064ae5a3c8772..aa14098e9fbc9 100644 --- a/src/common_symbols1.inc +++ b/src/common_symbols1.inc @@ -99,4 +99,3 @@ jl_symbol("UInt"), jl_symbol("haskey"), jl_symbol("setproperty!"), jl_symbol("promote"), -jl_symbol("undef"), diff --git a/src/common_symbols2.inc b/src/common_symbols2.inc index cdc31ec1d57cb..64ca23ad29078 100644 --- a/src/common_symbols2.inc +++ b/src/common_symbols2.inc @@ -1,3 +1,4 @@ +jl_symbol("undef"), jl_symbol("Vector"), jl_symbol("parent"), jl_symbol("_promote"), @@ -251,4 +252,3 @@ jl_symbol("Complex"), jl_symbol("checked_add"), jl_symbol("mod"), jl_symbol("unsafe_write"), -jl_symbol("libuv.jl"), diff --git a/src/dump.c b/src/dump.c index 2623dac5786ef..c489e0125f73a 100644 --- a/src/dump.c +++ b/src/dump.c @@ -3305,7 +3305,8 @@ void jl_init_serializer(void) jl_voidpointer_type, jl_newvarnode_type, jl_abstractstring_type, jl_array_symbol_type, jl_anytuple_type, jl_tparam0(jl_anytuple_type), jl_emptytuple_type, jl_array_uint8_type, jl_code_info_type, - jl_typeofbottom_type, jl_namedtuple_type, jl_array_int32_type, + jl_typeofbottom_type, jl_typeofbottom_type->super, + jl_namedtuple_type, jl_array_int32_type, jl_typedslot_type, jl_uint32_type, jl_uint64_type, jl_type_type_mt, jl_nonfunction_mt, diff --git a/src/subtype.c b/src/subtype.c index 0c0cf4d908439..cf57373318046 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -188,15 +188,20 @@ static void restore_env(jl_stenv_t *e, jl_value_t *root, jl_savedenv_t *se) JL_N // quickly test that two types are identical static int obviously_egal(jl_value_t *a, jl_value_t *b) { + if (a == (jl_value_t*)jl_typeofbottom_type->super) + a = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself + if (b == (jl_value_t*)jl_typeofbottom_type->super) + b = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself if (a == b) return 1; if (jl_typeof(a) != jl_typeof(b)) return 0; if (jl_is_datatype(a)) { - jl_datatype_t *ad = (jl_datatype_t*)a, *bd = (jl_datatype_t*)b; + jl_datatype_t *ad = (jl_datatype_t*)a; + jl_datatype_t *bd = (jl_datatype_t*)b; if (ad->name != bd->name) return 0; if (ad->isconcretetype || bd->isconcretetype) return 0; size_t i, np = jl_nparams(ad); if (np != jl_nparams(bd)) return 0; - for(i=0; i < np; i++) { + for (i = 0; i < np; i++) { if (!obviously_egal(jl_tparam(ad,i), jl_tparam(bd,i))) return 0; } @@ -216,22 +221,52 @@ static int obviously_egal(jl_value_t *a, jl_value_t *b) static int obviously_unequal(jl_value_t *a, jl_value_t *b) { + if (a == (jl_value_t*)jl_typeofbottom_type->super) + a = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself + if (b == (jl_value_t*)jl_typeofbottom_type->super) + b = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself if (a == b) return 0; - if (jl_is_concrete_type(a) || jl_is_concrete_type(b)) - return 1; - if (jl_is_unionall(a)) a = jl_unwrap_unionall(a); - if (jl_is_unionall(b)) b = jl_unwrap_unionall(b); + if (jl_is_unionall(a)) + a = jl_unwrap_unionall(a); + if (jl_is_unionall(b)) + b = jl_unwrap_unionall(b); if (jl_is_datatype(a)) { - if (b == jl_bottom_type) return 1; + if (b == jl_bottom_type) + return 1; if (jl_is_datatype(b)) { - jl_datatype_t *ad = (jl_datatype_t*)a, *bd = (jl_datatype_t*)b; + jl_datatype_t *ad = (jl_datatype_t*)a; + jl_datatype_t *bd = (jl_datatype_t*)b; if (ad->name != bd->name) return 1; - size_t i, np = jl_nparams(ad); - if (np != jl_nparams(bd)) return 1; - for(i=0; i < np; i++) { - if (obviously_unequal(jl_tparam(ad,i), jl_tparam(bd,i))) + int istuple = (ad->name == jl_tuple_typename); + if (jl_is_concrete_type(a) || jl_is_concrete_type(b)) { + if (!istuple && ad->name != jl_type_typename) // HACK: can't properly normalize Tuple{Float64} == Tuple{<:Float64} like types or Type{T} types + return 1; + } + size_t i, np; + if (istuple) { + size_t na = jl_nparams(ad), nb = jl_nparams(bd); + if (jl_is_va_tuple(ad)) { + na -= 1; + if (jl_is_va_tuple(bd)) + nb -= 1; + } + else if (jl_is_va_tuple(bd)) { + nb -= 1; + } + else if (na != nb) { + return 1; + } + np = na < nb ? na : nb; + } + else { + np = jl_nparams(ad); + if (np != jl_nparams(bd)) + return 1; + } + for (i = 0; i < np; i++) { + if (obviously_unequal(jl_tparam(ad, i), jl_tparam(bd, i))) return 1; } } @@ -245,7 +280,9 @@ static int obviously_unequal(jl_value_t *a, jl_value_t *b) if (jl_is_long(b) && jl_unbox_long(a) != jl_unbox_long(b)) return 1; } - else if (jl_is_long(b)) return 1; + else if (jl_is_long(b)) { + return 1; + } if ((jl_is_symbol(a) || jl_is_symbol(b)) && a != b) return 1; return 0; @@ -1387,6 +1424,28 @@ JL_DLLEXPORT int jl_subtype_env_size(jl_value_t *t) return sz; } +// compute the minimum bound on the number of concrete types that are subtypes of `t` +// returns 0, 1, or many (2+) +static int concrete_min(jl_value_t *t) +{ + if (jl_is_unionall(t)) + t = jl_unwrap_unionall(t); + if (jl_is_datatype(t)) { + if (jl_is_type_type(t)) + return 0; // Type{T} may have the concrete supertype `typeof(T)`, so don't try to handle them here + return jl_is_concrete_type(t) ? 1 : 2; + } + if (jl_is_typevar(t)) + return 0; // could be 0 or more, since we didn't track if it was unbound + if (jl_is_uniontype(t)) { + int count = concrete_min(((jl_uniontype_t*)t)->a); + if (count > 1) + return count; + return count + concrete_min(((jl_uniontype_t*)t)->b); + } + return 2; // up to infinite +} + // quickly compute if x seems like a possible subtype of y // especially optimized for x isa concrete type // returns true if it could be easily determined, with the result in subtype @@ -1402,6 +1461,10 @@ JL_DLLEXPORT int jl_obvious_subtype(jl_value_t *x, jl_value_t *y, int *subtype) x = jl_unwrap_unionall(x); if (jl_is_unionall(y)) y = jl_unwrap_unionall(y); + if (x == (jl_value_t*)jl_typeofbottom_type->super) + x = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself + if (y == (jl_value_t*)jl_typeofbottom_type->super) + y = (jl_value_t*)jl_typeofbottom_type; // supertype(typeof(Union{})) is equal to, although distinct from, itself if (x == y || y == (jl_value_t*)jl_any_type) { *subtype = 1; return 1; @@ -1503,9 +1566,10 @@ JL_DLLEXPORT int jl_obvious_subtype(jl_value_t *x, jl_value_t *y, int *subtype) } int i, npx = jl_nparams(x), npy = jl_nparams(y); jl_vararg_kind_t vx = JL_VARARG_NONE; + jl_vararg_kind_t vy = JL_VARARG_NONE; jl_value_t *vxt = NULL; - int vy = 0; int nparams_expanded_x = npx; + int nparams_expanded_y = npy; if (istuple) { if (npx > 0) { jl_value_t *xva = jl_tparam(x, npx - 1); @@ -1517,22 +1581,39 @@ JL_DLLEXPORT int jl_obvious_subtype(jl_value_t *x, jl_value_t *y, int *subtype) nparams_expanded_x += jl_vararg_length(xva); } } - vy = npy > 0 && jl_is_vararg_type(jl_tparam(y, npy - 1)); - } - if (npx != npy || vx != JL_VARARG_NONE || vy) { - if ((vx == JL_VARARG_NONE || vx == JL_VARARG_UNBOUND) && !vy) { - *subtype = 0; - return 1; + if (npy > 0) { + jl_value_t *yva = jl_tparam(y, npy - 1); + vy = jl_vararg_kind(yva); + if (vy != JL_VARARG_NONE) { + nparams_expanded_y -= 1; + if (vy == JL_VARARG_INT) + nparams_expanded_y += jl_vararg_length(yva); + } } - if ((vx == JL_VARARG_NONE || vx == JL_VARARG_INT) && - nparams_expanded_x < npy - vy) { - *subtype = 0; - return 1; // number of fixed parameters in x could be fewer than in y + // if the nparams aren't equal, or at least one of them is a typevar (uncertain), they may be obviously disjoint + if (nparams_expanded_x != nparams_expanded_y || (vx != JL_VARARG_NONE && vx != JL_VARARG_INT) || (vy != JL_VARARG_NONE && vy != JL_VARARG_INT)) { + // we have a stronger bound on x if: + if (vy == JL_VARARG_NONE || vy == JL_VARARG_INT) { // the bound on y is certain + if (vx == JL_VARARG_NONE || vx == JL_VARARG_INT || vx == JL_VARARG_UNBOUND || // and the bound on x is also certain + nparams_expanded_x > nparams_expanded_y || npx > nparams_expanded_y) { // or x is unknown, but definitely longer than y + *subtype = 0; + return 1; // number of fixed parameters in x are more than declared in y + } + } + if (nparams_expanded_x < nparams_expanded_y) { + *subtype = 0; + return 1; // number of fixed parameters in x could be fewer than in y + } + uncertain = 1; } - // TODO: Can do better here for the JL_VARARG_INT case. - uncertain = 1; } - for (i = 0; i < npy - vy; i++) { + else if (npx != npy) { + *subtype = 0; + return 1; + } + + // inspect the fixed parameters in y against x + for (i = 0; i < npy - (vy == JL_VARARG_NONE ? 0 : 1); i++) { jl_value_t *a = i >= (npx - (vx == JL_VARARG_NONE ? 0 : 1)) ? vxt : jl_tparam(x, i); jl_value_t *b = jl_tparam(y, i); if (iscov || jl_is_typevar(b)) { @@ -1569,6 +1650,60 @@ JL_DLLEXPORT int jl_obvious_subtype(jl_value_t *x, jl_value_t *y, int *subtype) } } } + if (i < npx) { + // there are elements left in x (possibly just a Vararg), check them against the Vararg tail of y too + assert(vy != JL_VARARG_NONE && istuple && iscov); + jl_value_t *a1 = (vx != JL_VARARG_NONE && i == npx - 1) ? vxt : jl_tparam(x, i); + jl_value_t *b = jl_unwrap_vararg(jl_tparam(y, i)); + if (nparams_expanded_x > npy && jl_is_typevar(b) && concrete_min(a1) > 1) { + // diagonal rule for 2 or more elements: they must all be concrete on the LHS + *subtype = 0; + return 1; + } + if (jl_is_type_type(a1) && jl_is_type(jl_tparam0(a1))) { + a1 = jl_typeof(jl_tparam0(a1)); + } + for (; i < npx; i++) { + jl_value_t *a = (vx != JL_VARARG_NONE && i == npx - 1) ? vxt : jl_tparam(x, i); + if (i > npy && jl_is_typevar(b)) { // i == npy implies a == a1 + // diagonal rule: all the later parameters are also constrained to be type-equal to the first + jl_value_t *a2 = a; + if (jl_is_type_type(a) && jl_is_type(jl_tparam0(a))) { + // if a is exactly Type{T}, then use the concrete typeof(T) instead here + a2 = jl_typeof(jl_tparam0(a)); + } + if (!obviously_egal(a1, a2)) { + if (jl_obvious_subtype(a2, a1, subtype)) { + if (!*subtype) + return 1; + if (jl_has_free_typevars(a1)) // a1 is actually more constrained that this + uncertain = 1; + } + else { + uncertain = 1; + } + if (jl_obvious_subtype(a1, a2, subtype)) { + if (!*subtype) + return 1; + if (jl_has_free_typevars(a2)) // a2 is actually more constrained that this + uncertain = 1; + } + else { + uncertain = 1; + } + } + } + if (jl_obvious_subtype(a, b, subtype)) { + if (!*subtype) + return 1; + if (jl_has_free_typevars(b)) // b is actually more constrained that this + uncertain = 1; + } + else { + uncertain = 1; + } + } + } if (uncertain) return 0; *subtype = 1; @@ -1598,13 +1733,8 @@ JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env, #ifdef NDEBUG if (obvious_subtype == 0) return obvious_subtype; - else if (jl_has_free_typevars(y)) - obvious_subtype = 3; else if (envsz == 0) return obvious_subtype; -#else - if (jl_has_free_typevars(y)) - obvious_subtype = 3; #endif } else { @@ -1612,7 +1742,11 @@ JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env, } init_stenv(&e, env, envsz); int subtype = forall_exists_subtype(x, y, &e, 0); - assert(obvious_subtype == 3 || obvious_subtype == subtype); + assert(obvious_subtype == 3 || obvious_subtype == subtype || jl_has_free_typevars(x) || jl_has_free_typevars(y)); +#ifndef NDEBUG + if (obvious_subtype == 0 || (obvious_subtype == 1 && envsz == 0)) + subtype = obvious_subtype; // this ensures that running in a debugger doesn't change the result +#endif return subtype; } @@ -1637,16 +1771,90 @@ JL_DLLEXPORT int jl_subtype(jl_value_t *x, jl_value_t *y) JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b) { - if (obviously_egal(a, b)) return 1; - if (obviously_unequal(a, b)) return 0; + if (obviously_egal(a, b)) + return 1; + if (obviously_unequal(a, b)) + return 0; + // the following is an interleaved version of: + // return jl_subtype(a, b) && jl_subtype(b, a) + // where we try to do the fast checks before the expensive ones if (jl_is_datatype(a) && !jl_is_concrete_type(b)) { - // if one type looks more likely to be abstract, check it on the left + // if one type looks simpler, check it on the right // first in order to reject more quickly. jl_value_t *temp = a; a = b; b = temp; } - return jl_subtype(a, b) && jl_subtype(b, a); + // first check if a <: b has an obvious answer + int subtype_ab = 2; + if (b == (jl_value_t*)jl_any_type || a == jl_bottom_type) { + subtype_ab = 1; + } + else if (jl_typeof(a) == jl_typeof(b) && + (jl_is_unionall(b) || jl_is_uniontype(b)) && + jl_egal(a, b)) { + subtype_ab = 1; + } + else if (jl_obvious_subtype(a, b, &subtype_ab)) { +#ifdef NDEBUG + if (subtype_ab == 0) + return 0; +#endif + } + else { + subtype_ab = 3; + } + // next check if b <: a has an obvious answer + int subtype_ba = 2; + if (a == (jl_value_t*)jl_any_type || b == jl_bottom_type) { + subtype_ba = 1; + } + else if (jl_typeof(b) == jl_typeof(a) && + (jl_is_unionall(a) || jl_is_uniontype(a)) && + jl_egal(b, a)) { + subtype_ba = 1; + } + else if (jl_obvious_subtype(b, a, &subtype_ba)) { +#ifdef NDEBUG + if (subtype_ba == 0) + return 0; +#endif + } + else { + subtype_ba = 3; + } + // finally, do full subtyping for any inconclusive test + jl_stenv_t e; +#ifdef NDEBUG + if (subtype_ab != 1) +#endif + { + init_stenv(&e, NULL, 0); + int subtype = forall_exists_subtype(a, b, &e, 0); + assert(subtype_ab == 3 || subtype_ab == subtype || jl_has_free_typevars(a) || jl_has_free_typevars(b)); +#ifndef NDEBUG + if (subtype_ab != 0 && subtype_ab != 1) // ensures that running in a debugger doesn't change the result +#endif + subtype_ab = subtype; +#ifdef NDEBUG + if (subtype_ab == 0) + return 0; +#endif + } +#ifdef NDEBUG + if (subtype_ba != 1) +#endif + { + init_stenv(&e, NULL, 0); + int subtype = forall_exists_subtype(b, a, &e, 0); + assert(subtype_ba == 3 || subtype_ba == subtype || jl_has_free_typevars(a) || jl_has_free_typevars(b)); +#ifndef NDEBUG + if (subtype_ba != 0 && subtype_ba != 1) // ensures that running in a debugger doesn't change the result +#endif + subtype_ba = subtype; + } + // all tests successful + return subtype_ab && subtype_ba; } JL_DLLEXPORT int jl_is_not_broken_subtype(jl_value_t *a, jl_value_t *b) diff --git a/test/core.jl b/test/core.jl index 8905691d66c02..cf86538b0732d 100644 --- a/test/core.jl +++ b/test/core.jl @@ -227,8 +227,8 @@ let ft = Base.datatype_fieldtypes @test ft(elT2.body)[1].parameters[1] === elT2 @test Base.isconcretetype(ft(elT2.body)[1]) end -struct S22624{A,B,C} <: Ref{S22624{Int64,A}}; end -@test @isdefined S22624 +#struct S22624{A,B,C} <: Ref{S22624{Int64,A}}; end +@test_broken @isdefined S22624 # issue #3890 mutable struct A3890{T1} diff --git a/test/subtype.jl b/test/subtype.jl index 68b0365a65df0..bd32593d7dda4 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1540,9 +1540,18 @@ end @testintersect(Tuple{Type{<:AbstractVector{T}}, Int} where T, Tuple{Type{Vector}, Any}, Union{}) -@testintersect(Tuple{Type{<:AbstractVector{T}}, Int} where T, - Tuple{Type{Vector{T} where Int<:T<:Int}, Any}, - Tuple{Type{Vector{Int}}, Int}) +#@testintersect(Tuple{Type{<:AbstractVector{T}}, Int} where T, +# Tuple{Type{Vector{T} where Int<:T<:Int}, Any}, +# Tuple{Type{Vector{Int}}, Int}) +@test_broken isequal(_type_intersect(Tuple{Type{<:AbstractVector{T}}, Int} where T, + Tuple{Type{Vector{T} where Int<:T<:Int}, Any}), + Tuple{Type{Vector{Int}}, Int}) +@test isequal_type(_type_intersect(Tuple{Type{<:AbstractVector{T}}, Int} where T, + Tuple{Type{Vector{T} where Int<:T<:Int}, Any}), + Tuple{Type{Vector{Int}}, Int}) +@test isequal_type(_type_intersect(Tuple{Type{Vector{T} where Int<:T<:Int}, Any}, + Tuple{Type{<:AbstractVector{T}}, Int} where T), + Tuple{Type{Vector{Int}}, Int}) let X = LinearAlgebra.Symmetric{T, S} where S<:(AbstractArray{U, 2} where U<:T) where T, Y = Union{LinearAlgebra.Hermitian{T, S} where S<:(AbstractArray{U, 2} where U<:T) where T, LinearAlgebra.Symmetric{T, S} where S<:(AbstractArray{U, 2} where U<:T) where T} @@ -1584,7 +1593,14 @@ let T31805 = Tuple{Type{Tuple{}}, Tuple{Vararg{Int8, A}}} where A, S31805 = Tuple{Type{Tuple{Vararg{Int32, A}}}, Tuple{Vararg{Int16, A}}} where A @test !issub(T31805, S31805) end + @testintersect( Tuple{Array{Tuple{Vararg{Int64,N}},N},Tuple{Vararg{Array{Int64,1},N}}} where N, Tuple{Array{Tuple{Int64},1}, Tuple}, Tuple{Array{Tuple{Int64},1},Tuple{Array{Int64,1}}}) + +# this is is a timing test, so it would fail on debug builds +#let T = Type{Tuple{(Union{Int, Nothing} for i = 1:23)..., Union{String, Nothing}}}, +# S = Type{T} where T<:Tuple{E, Vararg{E}} where E +# @test @elapsed (@test T != S) < 5 +#end