JDK-6751514 : Unary post-increment with type variables crash javac during lowering
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6,6u25
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp,windows_7
  • CPU: x86
  • Submitted: 2008-09-23
  • Updated: 2015-03-12
  • Resolved: 2011-05-18
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 7
7 b39Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

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

A DESCRIPTION OF THE PROBLEM :
javac on
import javax.xml.ws.Holder;

public class testclass
{

   private int CompareN( Holder<Integer> nMatch )
   {
      nMatch.value = 0;
      (nMatch.value)++ ;

	return 0;
   }


}

produces
An exception has occurred in the compiler (1.6.0_07). Please file a bug at the Java Developer Connection (http://java.sun.com/webapp
s/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank
 you.
java.lang.AssertionError: (Integer)nMatch.value
        at com.sun.tools.javac.comp.Lower.abstractLval(Lower.java:1873)
        at com.sun.tools.javac.comp.Lower.lowerBoxedPostop(Lower.java:2699)
        at com.sun.tools.javac.comp.Lower.visitUnary(Lower.java:2739)
        at com.sun.tools.javac.tree.JCTree$JCUnary.accept(JCTree.java:1392)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:228)
        at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1074)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:56)
        at com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:146)
        at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:2967)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:739)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:130)
        at com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2290)
        at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2209)
        at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:639)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:2013)
        at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:575)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1921)
        at com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3104)
        at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1199)
        at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1118)
        at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:765)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:730)
        at com.sun.tools.javac.main.Main.compile(Main.java:353)
        at com.sun.tools.javac.main.Main.compile(Main.java:279)
        at com.sun.tools.javac.main.Main.compile(Main.java:270)
        at com.sun.tools.javac.Main.compile(Main.java:69)
        at com.sun.tools.javac.Main.main(Main.java:54)


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac on
import javax.xml.ws.Holder;

public class testclass
{

   private int CompareN( Holder<Integer> nMatch )
   {
      nMatch.value = 0;
      (nMatch.value)++ ;

	return 0;
   }


}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either an error indicating the problem, or successful compilation.
ACTUAL -
failure above

ERROR MESSAGES/STACK TRACES THAT OCCUR :
An exception has occurred in the compiler (1.6.0_07). Please file a bug at the Java Developer Connection (http://java.sun.com/webapp
s/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank
 you.
java.lang.AssertionError: (Integer)nMatch.value
        at com.sun.tools.javac.comp.Lower.abstractLval(Lower.java:1873)
        at com.sun.tools.javac.comp.Lower.lowerBoxedPostop(Lower.java:2699)
        at com.sun.tools.javac.comp.Lower.visitUnary(Lower.java:2739)
        at com.sun.tools.javac.tree.JCTree$JCUnary.accept(JCTree.java:1392)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:228)
        at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1074)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:56)
        at com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:146)
        at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:2967)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:739)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:130)
        at com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2290)
        at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2209)
        at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:639)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:2013)
        at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:575)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:44)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1921)
        at com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3104)
        at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1199)
        at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1118)
        at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:765)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:730)
        at com.sun.tools.javac.main.Main.compile(Main.java:353)
        at com.sun.tools.javac.main.Main.compile(Main.java:279)
        at com.sun.tools.javac.main.Main.compile(Main.java:270)
        at com.sun.tools.javac.Main.compile(Main.java:69)
        at com.sun.tools.javac.Main.main(Main.java:54)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class testclass
{

   private int CompareN( Holder<Integer> nMatch )
   {
      nMatch.value = 0;
      (nMatch.value)++ ;

	return 0;
   }


}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
change (nMatch.value)++ ;
to          nMatch.value = nMatch.value +1 ;

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL http://sa.sfbay.sun.com/projects/langtools_data/7/6751514
09-10-2008

EVALUATION The problem turned out worse than it seemed at first. The code in TransTypes that deals with the translation of unary/binary operator is quite messy and non-uniform. Here is some example of inconsistencies: *) In a binary expression, both arguments are cast to the expected type (if needed) after erasure *) In a compound assigment expression, only the right hand side is cast to the expeced type (if needed) after erasure *) In an unary expression, the argument is cast to the expeced type (if needed) after erasure Let's see some examples: void foo(Foo<Integer> f) { int i = f.x + 2; //erased to: ((Integer)f.x) + 2 int i2 = f.x += 1; //erased to: (f.x) + 2 int i3 = f.x++; //erased to: ((Integer)f.x)++ } The interesting case seems to be the third one (pre/post fix increment operators) as in that case javac is generating a synthetic cast that is not generated for compound assignments; however, since the underlying code dealing with both expression is the same, it turns out that javac can potentially end up in a situation in which the LHS of a pre/postix inc operator is neither a CAST nor a SELECT/IDENT. Consider the following case: int i = (f.x)++; //erased to: (((Integer)f.x))++ In this case the LHS is a parenthesized expression enclosing a cast expression. Since the cast is enclosed in parenthesis, it follows that the code in Lower.lowerBoxedPostop cannot handle it properly. In particular, that method fails to skip the cast expression - usually when the LHS is something of the kind (X)expr, method Lower.abstractLval is invoked only on 'expr'. This, in turn causes the assertion error described in this report, as the code in Lower.abstractLval is not able to cope with AST nodes other than SELECT, IDENT, INDEXED. In this case we have (after skipping parenthesis) a TYPECAST, which is not correct given the current implementation. I think that the implementation of Lower.abstractLval should be made more general. in particular, it should handle type-cast AST nodes; we should avoid checking for type cast AST nodes *before* going inside abstractLval, as this might not always be possible, due to parenthesized expressions. Another important point is that, once we have a better implementation of Lower.abstractLval we can also make the code in TransTypes more uniform than it is now - e.g. we could insert synthetic casts on *all* kinds of operator arguments.
24-09-2008

EVALUATION The following program should compile: class Foo<X> { X x; void test(Foo<Integer> f) { (f.x)++; } } During lowering we end up with a generated tree with an unexpected tag: ((Integer)f.x)++ The cast has been inserted by javac during TransTypes. However Lower.abstractLval only deal with INDEXED, IDENT and SELECT trees; this is the reason of the expection being thrown by the compiler. Deferring other AST nodes to abstractRval (without any additional processing) seems to fix the problem.
23-09-2008