Community
Participate
Working Groups
When I upgraded from M1 to M2, a new compiler error was introduced to my code. #### import java.util.Iterator; import java.util.List; public class GenericsTest<A> { interface Factory<T> { T invoke(); } public static <E> Iterator<E> iterate(Iterable<E> iterable) { return iterable.iterator(); } public Factory<Iterator<? extends A>> factory(final Factory<? extends List<? extends A>> factory) { return new Factory<Iterator<? extends A>>() { public Iterator<? extends A> invoke() { return iterate(factory.invoke()); } }; } } #### Removing one of the '? extends ...' parts in the declaration of the parameter factory public Factory<Iterator<? extends A>> factory(final FactoryList<? extends A>> factory) or public Factory<Iterator<? extends A>> factory(final Factory<? extends List<A>> factory) or calling the iterator method directly on the generated object return factory.invoke().iterator(); causes M2 to remove the error, but javac successfully compiles both the original and the changed code.
This is a consequence of fix for bug 107079 which got addressed in between 3.2m1 and m2. Note it also affects 3.1.1, and code was accepted in 3.1.0.
According to JLS15.12.2.7, it seems to imply that wildcards should be ignored during inference when involved in the actual (A) type part. e.g. p 453 (2nd discussion) ---------------------------------- DISCUSSION For simplicity, assume that G takes a single type argument. If the method invocation being examined is to be applicable, it must be the case that A is a subtype of some invocation of G. Otherwise, A << F would never be true. In other words, A << F, where F = G<U>, implies that A << G<V> for some V. Now, since U is a type expression (and therefore, U is not a wildcard type argument), it must be the case that U = V, by the non-variance of ordinary parameterized type invocations. The formulation above merely generalizes this reasoning to generics with an arbitrary number of type arguments. ---------------------------------- However, if doing so, the program of this bug report would be rejected. The invocation of #iterate performs inference based on initial constraint: capture-of ? extends List<? extends A> << Iterable<E> i.e. Iterable<? extends A> << Iterable<E> and according to discussion quoted above, would yield nothing.
If we said: capture(Factory<? extends List<? extends A>>) is: Factory<capture-of ? extends List<capture-of ? extends A>> (observe double capturing) Then this program would compile ok, and still we would reject code from bug 107079, as first program no longer uses wildcards during inference, but capture type variables. Now, this contradicts the spec near capture definition where it says that capture doesn't apply recursively. This would likely mean recursively on nested type arguments; but still should perform on wildcard bound (if any).
Fix would then be to uncomment the following 2 lines in CaptureBinding#initializeBounds(...) TypeBinding substitutedWildcardBound = originalWildcardBound == null ? null : originalWildcardBound.capture(scope, this.position); if (substitutedWildcardBound == this) substitutedWildcardBound = originalWildcardBound; And enable GenericTypeTest#test836-837
Ping'ed spec lead for clarification.
Applied suggested fix. Released in 3.1 maintenance since can be perceived as a regression over 3.1.0 (though it was passing for the wrong reason back then). Also releasing fix in 3.2 stream.
Changed fix due to regression, see bug 112666. Only recapturing for '? extends X' case.
Verified for 3.1.2 in M20060109-0800.
Verified for 3.2M4 in I20051215-1506
Re-opening because the fix in this bug appears to be bogus and has caused numerous bugs in the sequel. Based on Philipe's comments I assumed that performing recursive capture, while being against the spec, was coordinated with a spec author. Meanwhile I was told that javac does not perform any form of recursive capturing, but still produces the results we have been seeing all the time. Hence, the capture algorithm may not even be the culprit here.
After reverting the bogus change in capturing, we can fix the issue (in 1.8) by reducing ? extends A <= E#0 to a type bound E#0 = ? extends A To me this looks like a fair extension of JLS 18.2.3, I've asked Dan Smith for comments. In all of RunJava8Tests this only conflicts with bug 321485, but perhaps that test just needs its expectation adjusted. I don't have an answer for Java 7, though.
New Gerrit change created: https://git.eclipse.org/r/80726
(In reply to Eclipse Genie from comment #12) > New Gerrit change created: https://git.eclipse.org/r/80726 Contained in this change: 1. stop recursive capture at 1.8 and above (I don't yet have a good replacement at 1.7) 2. speculatively add the new reduction rule mentioned in comment 11, to fix the current bug at 1.8 3. added tests for related bug 472851 and bug 441905 4. adjusted tests: GTT.test0910(): expect different capture ids, depending on (1) GTT.test1118(): at 1.8 expect the correct answer (reject) (see bug 177715) AMT.test087(): at 1.8 expect different answer (which I assume to be right)
Release for 4.7 M2 via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=84c10c2837d11d68071e121c7bfdefafa4489d33 I filed bug 501106 for some follow-up.
*** Bug 177715 has been marked as a duplicate of this bug. ***
*** Bug 321485 has been marked as a duplicate of this bug. ***
*** Bug 441905 has been marked as a duplicate of this bug. ***
*** Bug 472851 has been marked as a duplicate of this bug. ***
*** Bug 469297 has been marked as a duplicate of this bug. ***
Verified for Eclipse Oxygen 4.7 M2 with build id: Build id: I20160912-1005