JDK-6391995 : REGRESSION: removal of "rvalue conversion" causes problems
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-02-28
  • Updated: 2015-12-10
  • Resolved: 2006-05-30
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b86Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-beta2-b73)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b73, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
When I test my code with 1.6.0-beta2-b73, 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 Factory<List<? 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 1.6.0-beta2-b73 to remove the error.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Simply try to compile the specified code.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should be compiled without errors.
ACTUAL -
The code produces the specified error.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Test.java:17: <E>iterate(java.lang.Iterable<E>) in Test<A> cannot be applied to
(capture#276 of ? extends java.util.List<? extends A>)
        return iterate(factory.invoke());
               ^
1 error

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
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());
      }
    };
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Removing one of the '? extends ...' parts in the declaration of the parameter factory
  public Factory<Iterator<? extends A>> factory(final Factory<List<? 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 1.6.0-beta2-b73 to remove the error.

Release Regression From : 5.0
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

Comments
SUGGESTED FIX Note - the above fix is unsafe when the return type is used in argument position in a generic method call, as it might lead to inferring a wrong type (see 6893625).
28-07-2010

EVALUATION Simplified test case: <E> void iterate(Iterable<E> iterable) { Iterable<? extends Iterable<? extends Object>> x = null; iterate(x.iterator().next()); }
12-05-2006

SUGGESTED FIX The above fix is correct and it is easy to prove that it is type safe: Since attribArgs is applied only on the left hand side of the type relation, it is trivially safe to return the upper bound. That is: upperBound(t) <: s => t <: s For example, upperBound(capture of ? extends Number) = Number <: Comparable<?> => capture of ? extends Number <: Comparable<?>
12-05-2006

SUGGESTED FIX This solves the problem but I'm not sure it is correct. Need to do more testing and discuss with Gilad. Index: j2se/src/share/classes/com/sun/tools/javac/comp/Attr.java --- /tmp/geta31410 2006-05-09 20:26:44.998764389 -0700 +++ Attr.java 2006-05-09 20:20:40.121886902 -0700 @@ -371,7 +371,7 @@ ListBuffer<Type> argtypes = new ListBuffer<Type>(); for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) argtypes.append(chk.checkNonVoid( - l.head.pos(), attribTree(l.head, env, VAL, Infer.anyPoly))); + l.head.pos(), types.upperBound(attribTree(l.head, env, VAL, Infer.anyPoly)))); return argtypes.toList(); }
10-05-2006

EVALUATION Probably a side effect of removing the "rvalue conversion" (6359951 and 6227936) and related to bug 6384510. However, this is a new genuine regression.
28-02-2006