From 4238c02d58a6cd56d92571d8f423fd819fff342a Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 13 May 2015 11:42:52 -0500 Subject: [PATCH] args_morespecific for TypeVars: don't fail due to invariance (fixes #8652) In jl_args_morespecific(a,b), one of the important tests is to call type_match_(b,a), essentially reasoning that if b <: a then a cannot be more specific than b. The problem is that this test can fail for an independent reason, like invariance. This takes the drastic step of keeping invariance=false for the type_match_ check in jl_args_morespecific. Surprisingly, this doesn't appear to break anything. --- src/gf.c | 8 +++++--- src/jltypes.c | 4 ++++ src/julia_internal.h | 1 + test/core.jl | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) 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 cf3e2ee2c6ff8..e619f643d1d09 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2718,6 +2718,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); @@ -2728,6 +2730,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 4e2981bd68279..6e6a4e3e8ec52 100644 --- a/test/core.jl +++ b/test/core.jl @@ -155,6 +155,19 @@ let T = TypeVar(:T,Union(Float64,Array{Float64,1}),true) 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 @test typejoin(Int8,Int16) === Signed @test typejoin(Int,AbstractString) === Any @@ -317,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