diff --git a/src/gf.c b/src/gf.c index 794ab97c0c6b8..405caa438b9c1 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1126,10 +1126,12 @@ DLLEXPORT int jl_args_morespecific(jl_value_t *a, jl_value_t *b) return msp; } if (jl_has_typevars(a)) { - //if (jl_type_match_morespecific(b,a) == (jl_value_t*)jl_false) - // return 1; + type_match_invariance_mask = 0; + //int result = jl_type_match_morespecific(b,a) == (jl_value_t*)jl_false); // this rule seems to work better: - if (jl_type_match(b,a) == (jl_value_t*)jl_false) + int result = jl_type_match(b,a) == (jl_value_t*)jl_false; + type_match_invariance_mask = 1; + if (result) return 1; } int nmsp = jl_type_morespecific(b,a); diff --git a/src/jltypes.c b/src/jltypes.c index 527554b3e6343..3a3125e905ee0 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -739,6 +739,28 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, break; } } + if (jl_is_typevar(b)) { + for(i=0; i < penv->n; i+=2) { + if (penv->data[i] == b && !jl_is_typevar(penv->data[i+1])) { + jl_value_t *ti = jl_type_intersection((jl_value_t*)a, penv->data[i+1]); + if (ti == (jl_value_t*)jl_bottom_type) { + JL_GC_POP(); + return ti; + } + break; + } + } + for(i=0; i < eqc->n; i+=2) { + if (eqc->data[i] == b && !jl_is_typevar(eqc->data[i+1])) { + jl_value_t *ti = jl_type_intersection((jl_value_t*)a, eqc->data[i+1]); + if (ti == (jl_value_t*)jl_bottom_type) { + JL_GC_POP(); + return ti; + } + break; + } + } + } extend((jl_value_t*)a, b, penv); if (jl_is_typevar(b)) { JL_GC_POP(); @@ -2706,6 +2728,8 @@ int jl_type_morespecific(jl_value_t *a, jl_value_t *b) // ---------------------------------------------------------------------------- +int type_match_invariance_mask = 1; + static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, cenv_t *env, int morespecific, int invariant); @@ -2716,6 +2740,7 @@ static jl_value_t *tuple_match(jl_datatype_t *child, jl_datatype_t *parent, size_t cl = jl_nparams(child); size_t pl = jl_nparams(parent); int mode = 0; + invariant = invariant & type_match_invariance_mask; while(1) { int cseq = (cibody; if (jl_is_typector(parent)) diff --git a/src/julia_internal.h b/src/julia_internal.h index 2474f70bf1017..a75feae456d1a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -85,6 +85,7 @@ int jl_tuple_subtype(jl_value_t **child, size_t cl, jl_datatype_t *pdt, int ta); int jl_subtype_invariant(jl_value_t *a, jl_value_t *b, int ta); jl_value_t *jl_type_match(jl_value_t *a, jl_value_t *b); +extern int type_match_invariance_mask; jl_value_t *jl_type_match_morespecific(jl_value_t *a, jl_value_t *b); int jl_types_equal_generic(jl_value_t *a, jl_value_t *b, int useenv); jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np); diff --git a/test/core.jl b/test/core.jl index bcea269683f07..e643eb721ba1a 100644 --- a/test/core.jl +++ b/test/core.jl @@ -4,6 +4,12 @@ const Bottom = Union() +function testintersect(a, b, result, cmp=is) + @test cmp(typeintersect(a, b), result) + @test cmp(typeintersect(b, a), result) +end +isnot(x,y) = !is(x,y) + # basic type relationships @test Int8 <: Integer @test Int32 <: Integer @@ -23,7 +29,7 @@ const Bottom = Union() @test Array{Int8,1} <: Array{Int8,1} @test !(Type{Bottom} <: Type{Int32}) @test !(Vector{Float64} <: Vector{Union(Float64,Float32)}) -@test is(Bottom, typeintersect(Vector{Float64},Vector{Union(Float64,Float32)})) +testintersect(Vector{Float64}, Vector{Union(Float64,Float32)}, Bottom) @test !isa(Array,Type{Any}) @test Type{Complex} <: DataType @@ -31,88 +37,88 @@ const Bottom = Union() @test !(Type{Ptr{Bottom}} <: Type{Ptr}) @test !(Type{Rational{Int}} <: Type{Rational}) let T = TypeVar(:T,true) - @test !is(Bottom, typeintersect(Array{Bottom},AbstractArray{T})) - @test is(Bottom, typeintersect(Tuple{Type{Ptr{UInt8}},Ptr{Bottom}}, - Tuple{Type{Ptr{T}},Ptr{T}})) + testintersect(Array{Bottom},AbstractArray{T}, Bottom, isnot) + testintersect(Tuple{Type{Ptr{UInt8}},Ptr{Bottom}}, + Tuple{Type{Ptr{T}},Ptr{T}}, Bottom) @test !(Type{T} <: TypeVar) - @test isequal(typeintersect(Tuple{Range{Int},Tuple{Int,Int}},Tuple{AbstractArray{T},Dims}), + testintersect(Tuple{Range{Int},Tuple{Int,Int}},Tuple{AbstractArray{T},Dims}, Tuple{Range{Int},Tuple{Int,Int}}) - @test isequal(typeintersect(Tuple{T, AbstractArray{T}}, Tuple{Number, Array{Int,1}}), + testintersect(Tuple{T, AbstractArray{T}}, Tuple{Number, Array{Int,1}}, Tuple{Int, Array{Int,1}}) - @test isequal(typeintersect(Tuple{T, AbstractArray{T}}, Tuple{Int, Array{Number,1}}), + testintersect(Tuple{T, AbstractArray{T}}, Tuple{Int, Array{Number,1}}, Tuple{Int, Array{Number,1}}) - @test isequal(typeintersect(Tuple{T, AbstractArray{T}},Tuple{Any, Array{Number,1}}), - Tuple{Number, Array{Number,1}}) - @test !is(Bottom, typeintersect(Tuple{Array{T}, Array{T}}, Tuple{Array, Array{Any}})) + testintersect(Tuple{T, AbstractArray{T}},Tuple{Any, Array{Number,1}}, + Tuple{Number, Array{Number,1}}, isequal) + testintersect(Tuple{Array{T}, Array{T}}, Tuple{Array, Array{Any}}, Bottom, isnot) f47{T}(x::Vector{Vector{T}}) = 0 @test_throws MethodError f47(Array(Vector,0)) @test f47(Array(Vector{Int},0)) == 0 - @test typeintersect(Tuple{T,T}, Tuple{Union(Float64,Int64),Int64}) == Tuple{Int64,Int64} - @test typeintersect(Tuple{T,T}, Tuple{Int64,Union(Float64,Int64)}) == Tuple{Int64,Int64} + testintersect(Tuple{T,T}, Tuple{Union(Float64,Int64),Int64}, Tuple{Int64,Int64}) + testintersect(Tuple{T,T}, Tuple{Int64,Union(Float64,Int64)}, Tuple{Int64,Int64}) TT = TypeVar(:T) S = TypeVar(:S,true); N = TypeVar(:N,true); SN = TypeVar(:S,Number,true) - @test typeintersect(Type{TypeVar(:T,Array{TT,1})},Type{Array{SN,N}}) == Type{Array{SN,1}} + testintersect(Type{TypeVar(:T,Array{TT,1})},Type{Array{SN,N}}, Type{Array{SN,1}}) # issue #5359 - @test typeintersect(Tuple{Type{Array{T,1}},Array{T,1}}, - Tuple{Type{AbstractVector},Vector{Int}}) === Bottom + testintersect(Tuple{Type{Array{T,1}},Array{T,1}}, + Tuple{Type{AbstractVector},Vector{Int}}, Bottom) # issue #5559 - @test typeintersect(Tuple{Type{Vector{Complex128}}, AbstractVector}, - Tuple{Type{Array{T,N}}, Array{S,N}}) == Tuple{Type{Vector{Complex128}},Vector} - @test typeintersect(Tuple{Type{Vector{Complex128}}, AbstractArray}, - Tuple{Type{Array{T,N}}, Array{S,N}}) == Tuple{Type{Vector{Complex128}},Vector} + testintersect(Tuple{Type{Vector{Complex128}}, AbstractVector}, + Tuple{Type{Array{T,N}}, Array{S,N}}, Tuple{Type{Vector{Complex128}},Vector}, isequal) + testintersect(Tuple{Type{Vector{Complex128}}, AbstractArray}, + Tuple{Type{Array{T,N}}, Array{S,N}}, Tuple{Type{Vector{Complex128}},Vector}, isequal) - @test typeintersect(Type{Array{T}}, Type{AbstractArray{T}}) === Bottom + testintersect(Type{Array{T}}, Type{AbstractArray{T}}, Bottom) - @test typeintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{Vararg{T}}}) === Bottom - @test typeintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{T,Vararg{T}}}) === Bottom + testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{Vararg{T}}}, Bottom) + testintersect(Type{Tuple{Bool,Vararg{Int}}}, Type{Tuple{T,Vararg{T}}}, Bottom) - @test typeintersect(Tuple{Rational{T},T}, Tuple{Rational{Integer},Int}) === Tuple{Rational{Integer},Int} + testintersect(Tuple{Rational{T},T}, Tuple{Rational{Integer},Int}, Tuple{Rational{Integer},Int}) - @test typeintersect(Pair{T,Ptr{T}}, Pair{Ptr{S},S}) === Bottom - @test typeintersect(Tuple{T,Ptr{T}}, Tuple{Ptr{S},S}) === Bottom + testintersect(Pair{T,Ptr{T}}, Pair{Ptr{S},S}, Bottom) + testintersect(Tuple{T,Ptr{T}}, Tuple{Ptr{S},S}, Bottom) end let N = TypeVar(:N,true) - @test isequal(typeintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, - Tuple{Tuple{Integer,Integer}, Tuple{Vararg{Integer}}}), + testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, + Tuple{Tuple{Integer,Integer}, Tuple{Vararg{Integer}}}, Tuple{Tuple{Integer,Integer}, Tuple{Integer,Integer}}) - @test isequal(typeintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, - Tuple{Tuple{Vararg{Integer}}, Tuple{Integer,Integer}}), + testintersect(Tuple{NTuple{N,Integer},NTuple{N,Integer}}, + Tuple{Tuple{Vararg{Integer}}, Tuple{Integer,Integer}}, Tuple{Tuple{Integer,Integer}, Tuple{Integer,Integer}}) local A = typeintersect(Tuple{NTuple{N,Any},Array{Int,N}}, Tuple{Tuple{Int,Vararg{Int}},Array}) local B = Tuple{Tuple{Int,Vararg{Int}},Array{Int,N}} @test A<:B && B<:A - @test isequal(typeintersect(Tuple{NTuple{N,Any},Array{Int,N}}, - Tuple{Tuple{Int,Vararg{Int}},Array{Int,2}}), + testintersect(Tuple{NTuple{N,Any},Array{Int,N}}, + Tuple{Tuple{Int,Vararg{Int}},Array{Int,2}}, Tuple{Tuple{Int,Int}, Array{Int,2}}) end -@test is(Bottom, typeintersect(Type{Any},Type{Complex})) -@test is(Bottom, typeintersect(Type{Any},Type{TypeVar(:T,Real)})) +testintersect(Type{Any},Type{Complex}, Bottom) +testintersect(Type{Any},Type{TypeVar(:T,Real)}, Bottom) @test !(Type{Array{Integer}} <: Type{AbstractArray{Integer}}) @test !(Type{Array{Integer}} <: Type{Array{TypeVar(:T,Integer)}}) -@test is(Bottom, typeintersect(Type{Function},UnionType)) -@test is(Type{Int32}, typeintersect(Type{Int32},DataType)) +testintersect(Type{Function},UnionType,Bottom) +testintersect(Type{Int32}, DataType, Type{Int32}) @test !(Type <: TypeVar) -@test !is(Bottom, typeintersect(DataType, Type)) -@test !is(Bottom, typeintersect(UnionType, Type)) -@test !is(Bottom, typeintersect(DataType, Type{Int})) -@test !is(Bottom, typeintersect(DataType, Type{TypeVar(:T,Int)})) -@test !is(Bottom, typeintersect(DataType, Type{TypeVar(:T,Integer)})) +testintersect(DataType, Type, Bottom, isnot) +testintersect(UnionType, Type, Bottom, isnot) +testintersect(DataType, Type{Int}, Bottom, isnot) +testintersect(DataType, Type{TypeVar(:T,Int)}, Bottom, isnot) +testintersect(DataType, Type{TypeVar(:T,Integer)}, Bottom, isnot) -@test typeintersect(Tuple{Vararg{Int}}, Tuple{Vararg{Bool}}) === Tuple{} -@test typeintersect(Type{Tuple{Vararg{Int}}}, Type{Tuple{Vararg{Bool}}}) === Bottom -@test typeintersect(Tuple{Bool,Vararg{Int}}, Tuple{Vararg{Bool}}) === Tuple{Bool,} +testintersect(Tuple{Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{}) +testintersect(Type{Tuple{Vararg{Int}}}, Type{Tuple{Vararg{Bool}}}, Bottom) +testintersect(Tuple{Bool,Vararg{Int}}, Tuple{Vararg{Bool}}, Tuple{Bool,}) let T = TypeVar(:T,Union(Float32,Float64)) - @test typeintersect(AbstractArray, Matrix{T}) == Matrix{T} + testintersect(AbstractArray, Matrix{T}, Matrix{T}) end let T = TypeVar(:T,Union(Float32,Float64),true) - @test typeintersect(AbstractArray, Matrix{T}) == Matrix{T} + testintersect(AbstractArray, Matrix{T}, Matrix{T}) end @test isa(Int,Type{TypeVar(:T,Number)}) @@ -146,7 +152,20 @@ end # issue #2997 let T = TypeVar(:T,Union(Float64,Array{Float64,1}),true) - @test typeintersect(T,Real) === Float64 + testintersect(T,Real,Float64) +end + +# issue #8652 +args_morespecific(a, b) = ccall(:jl_args_morespecific, Cint, (Any,Any), a, b) != 0 +let T1 = TypeVar(:T, Integer, true), T2 = TypeVar(:T, Integer, true) + a = Tuple{Type{T1}, T1} + b2 = Tuple{Type{T2}, Integer} + @test args_morespecific(a, b2) + @test !args_morespecific(b2, a) + a = Tuple{Type{T1}, Ptr{T1}} + b2 = Tuple{Type{T2}, Ptr{Integer}} + @test args_morespecific(a, b2) + @test !args_morespecific(b2, a) end # join @@ -311,6 +330,11 @@ let m = sptest3(:a) @test is(m(0),Symbol) end +sptest4{T}(x::T, y::T) = 42 +sptest4{T}(x::T, y) = 44 +@test sptest4(1,2) == 42 +@test sptest4(1, "cat") == 44 + # closures function clotest() c = 0 @@ -1361,7 +1385,7 @@ abstract IT4805{N, T} let T = TypeVar(:T,Int,true) N = TypeVar(:N,true) - @test typeintersect(Type{IT4805{1,T}}, Type{TypeVar(:_,IT4805{N,Int})}) != Bottom + testintersect(Type{IT4805{1,T}}, Type{TypeVar(:_,IT4805{N,Int})}, Bottom, isnot) end let @@ -2002,7 +2026,7 @@ abstract AbstractThing{T,N} type ConcreteThing{T<:FloatingPoint,N} <: AbstractThing{T,N} end -@test typeintersect(AbstractThing{TypeVar(:T,true),2}, ConcreteThing) == ConcreteThing{TypeVar(:T,FloatingPoint),2} +testintersect(AbstractThing{TypeVar(:T,true),2}, ConcreteThing, ConcreteThing{TypeVar(:T,FloatingPoint),2}, isequal) # issue #8978 module I8978 @@ -2824,3 +2848,16 @@ function f11357() x[i...] end @test f11357() === 1 + +# issue #11136 +type A11136 end +type B11136 end +let T = TypeVar(:T, true), TB = TypeVar(:T, B11136, true) + testintersect(Tuple{T, T}, Tuple{A11136, TB}, Bottom) +end + +# issue #11367 +abstract Foo11367 +let T1 = TypeVar(:T1, true), T2 = TypeVar(:T2, Foo11367, true) + testintersect(Tuple{T1, T1}, Tuple{Type{BigInt}, T2}, Bottom) +end