JDK-8177716 : Type inference broken with Interfaces
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7,8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2017-03-28
  • Updated: 2017-06-12
  • Resolved: 2017-03-28
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :


A DESCRIPTION OF THE PROBLEM :
    public static <T extends List> T newList() {
        return null;
    }

    public static void main(String[] args) {
        String s = newList();
    }
following code works fine while it should not compile. 

         0: invokestatic  #4                  // Method newList:()Ljava/util/List;
         3: checkcast     #5                  // class java/lang/String
 the type is inferred correctly but the assignment of a List to String is permitted.

Only happens to interfaces. changing to a concrete class no longer compiles.

REGRESSION.  Last worked in version 6u45


REPRODUCIBILITY :
This bug can be reproduced always.


Comments
I've added a note to JDK-7120669 in case we want to improve the specification here in a future version.
28-03-2017

This is not an issue - JLS says that in this case the inferred return type is an intersection type of the kind String & List. The rationale behind this is that you could have a subclass of both String and List - of course in this case this is not possible because String is final, but the JLS has never been enhanced to detect this particular case. This discussion is very related: http://mail.openjdk.java.net/pipermail/compiler-dev/2017-January/010647.html The conclusion of that discussion is that, rather than having complex logic to ban cases where an intersection type with 'final' components is inferred, we instead emit Lint warnings for when a method type is inferred w/o any input from the actual arguments (as in this case) - which is generally considered as a bad practice.
28-03-2017

This issue exists from quite a long time, reproducible in 7 8 and 9 latest versions List is silently typecasted to String without any errors, which was not the case in 6u43 (Verified on 6u43) javap output shows type is inferred correctly but assignment is wrongly done == 0: invokestatic #2 // Method newList:()Ljava/util/List; 3: checkcast #3 // class java/lang/String == Changing <T extends List> to concrete class such as <T extends ArrayList> gives expected error == jdk/9/ea/162/binaries/linux-x64/bin/javac Test.java Test.java:9: error: incompatible types: no unique maximal instance exists for type variable T with upper bounds String,ArrayList String s = newList(); ^ where T is a type-variable: T extends ArrayList declared in method <T>newList() 1 error ==
28-03-2017