JDK-8027982 : Compiler infinite recursion when using transitive, recursive generics
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7u21,7u45,8
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • OS: linux
  • Submitted: 2013-11-04
  • Updated: 2013-11-10
  • Resolved: 2013-11-10
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

(bug is reproduced in recent 7u45 as well)

ADDITIONAL OS VERSION INFORMATION :
Linux nvz 3.8.0-25-generic #37-Ubuntu SMP Thu Jun 6 20:47:07 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
Compiler goes to endless recursion when doing unchecked ("??ovariant") typecast with types (type variables) that a transitively and recursively co-dependent;

  Bug was reproduced on Linux 64 bit (jdk7u21), OS X (jdk7u45)

Please consult the code below;




ADDITIONAL REGRESSION INFORMATION:
java version "1.7.0_21"

Most recent javac (**_45) version doesn't work as well

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :

  To reproduce the bug just compile the code below;
javac JavacBug.java;

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
should just compile the code
ACTUAL -
compiler's endless recursion, which results in java.lang.StackOverflowError

ERROR MESSAGES/STACK TRACES THAT OCCUR :
The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
at com.sun.tools.javac.code.Type.contains(Type.java:357)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3564)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3549)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:583)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3564)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3549)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:583)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3564)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3549)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:583)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3593)
at com.sun.tools.javac.code.Types$Rewriter.visitTypeVar(Types.java:3549)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1030)
at com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:3792)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3564)
at com.sun.tools.javac.code.Types$Rewriter.visitClassType(Types.java:3549)
at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:583)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class JavacBug {
    
    interface HolderA<T> {
        
    }

    interface HolderB<T> {
        
    }
    
    // type with "transitive, recursive" generics;
    public static class Demo<T extends T1, T1 extends HolderB<T>> {
        @SuppressWarnings("unchecked") public HolderA<T1> m3(T x) {
            HolderA<T> f = null;
            // this unchecked cast leads to java.lang.StackOverflowError in javac (endless recursion)
            return (HolderA<T1>)f;
        }
    };
  
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround. I could only change type bounds which makes it different from what is semantically intended:
    public static class Demo1<T extends HolderB<T>, T1 extends HolderB<T>> {
        @SuppressWarnings("unchecked") public HolderA<T1> m3(T x) {
            HolderA<T> f = null;
            // this unchecked cast leads to java.lang.StackOverflowError in javac (endless recursion)
            return (HolderA<T1>)f;
        }
    };
Comments
Analysis and further support for deferral: The case presented here represents a decidable instance of this problem. Type parameters without generics can (unless I'm mistaken) be represented as proposition logic with fixed points, which is decidable. However, such a solution would mishandle wildcards, which (unless a number of publications are mistaken) are equivalent to first-order predicate logic, which is not decidable. Even though the example given does not include wildcards, it is arguable that this bug encompasses those cases, in which case is is a duplicate of JDK-6558545. I recommend closing as a duplicate of JDK-6558545.
10-11-2013

This is probably another symptom of type system undecidability, which is reported by JDK-6558545. Expect the fix for this bug to be highly nontrivial.
07-11-2013

reproduced on 7u40.
07-11-2013