Skip to content

Commit

Permalink
fix #30394, an unsoundness in ml_matches
Browse files Browse the repository at this point in the history
This fixes a corner case where a bug is caused, counter-intuitively,
by an over-estimated intersection.
We have method signatures A and B, with A<B (A is a strict subtype).
We have a dispatch tuple X, where X<:B and !(X<:A).
However, intersection returns X for intersect(X,A). Since there
appears to be a match there and A<B, ml_matches skips the match with B.
The fix just requires dispatch tuples to be a subtype of a signature
in order to match at all.
  • Loading branch information
JeffBezanson committed Dec 14, 2018
1 parent 01fe7c2 commit adaa945
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,12 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
closure->max_valid = ml->max_world;
}
}
// In some corner cases type intersection is conservative and returns something
// for intersect(A, B) even though A is a dispatch tuple and !(A <: B).
// For dispatch purposes in such a case we know there's no match. This check
// fixes issue #30394.
if (jl_is_dispatch_tupletype(closure->match.type) && !closure->match.issubty)
return 1;
// a method is shadowed if type <: S <: m->sig where S is the
// signature of another applicable method
/*
Expand Down
21 changes: 21 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2151,3 +2151,24 @@ g30098() = (h30098(:f30098); 4)
h30098(f) = getfield(@__MODULE__, f)()
@test @inferred(g30098()) == 4 # make sure that this
@test @inferred(f30098()) == 3 # doesn't pollute the inference cache of this

# issue #30394
mutable struct Base30394
a::Int
end

mutable struct Foo30394
foo_inner::Base30394
Foo30394() = new(Base30394(1))
end

mutable struct Foo30394_2
foo_inner::Foo30394
Foo30394_2() = new(Foo30394())
end

f30394(foo::T1, ::Type{T2}) where {T2, T1 <: T2} = foo

f30394(foo, T2) = f30394(foo.foo_inner, T2)

@test Base.return_types(f30394, (Foo30394_2, Type{Base30394})) == Any[Base30394]

0 comments on commit adaa945

Please sign in to comment.