Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix problems with TypeVars in intersection and type_match_ #11194

Merged
merged 3 commits into from
May 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 26 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);

Expand All @@ -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 = (ci<cl) && jl_is_vararg_type(jl_tparam(child,ci));
int pseq = (pi<pl) && jl_is_vararg_type(jl_tparam(parent,pi));
Expand Down Expand Up @@ -2766,6 +2791,7 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent,
cenv_t *env, int morespecific, int invariant)
{
jl_value_t *tmp, *tmp2;
invariant = invariant & type_match_invariance_mask;
if (jl_is_typector(child))
child = (jl_value_t*)((jl_typector_t*)child)->body;
if (jl_is_typector(parent))
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
133 changes: 85 additions & 48 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,96 +29,96 @@ 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
@test isa(Complex,Type{Complex})
@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)})
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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