JDK-8144123 : Invalid code is compiled by Java without error
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: x86
  • Submitted: 2015-10-06
  • Updated: 2015-12-14
  • Resolved: 2015-11-26
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin da0801a-dhcp85.apple.com 15.0.0 Darwin Kernel Version 15.0.0: Wed Aug 26 16:57:32 PDT 2015; root:xnu-3247.1.106~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
The code found below compiles on javac 1.8.0_60, even though it does not conform to the JLS spec.  (Confirmed by spec author)

The impact is low interoperability between javac and other java compilers, which impacts developer productivity in general.

In reality, though this particular issue is a strange edge-case, this type of issue (different interpretations of JLS, or different quirks in compiler behavior) is fairly common, which has the effect of engineering projects expressly supporting only certain tool chains but not others, which is overall bad for the Java ecosystem.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use javac to compile "CompilerBug" class

$ javac -version
javac 1.8.0_60

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expect a compiler error: Can only iterate over an array or an instance of java.lang.Iterable
ACTUAL -
The class compiles without error and generates 2 .class files.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.Optional;

public class CompilerBug {
    
    static class Wrapper<T> {
        T value;
        public T getValue() {
            return null;
        }
    }
    
    public static Optional<? extends Wrapper<String>[]> optionalArrayOfStringWrappers() {
    	return Optional.empty();
    }
    
    public static <T> Optional<T> findEnglishAttribute(Wrapper<T>[] attributes) {
        return Optional.empty();
    }
    
    public static void main(String[] args) {
        for (Wrapper<String> attribute: optionalArrayOfStringWrappers().get()) {
            // Expect compiler error on for loop:  Can only iterate over an array or an instance of java.lang.Iterable
        }
    }
}
---------- END SOURCE ----------


Comments
Two issues going on here: 1) The type of 'optionalArrayOfStringWrappers()' must be captured, producing an 'Optional<CAP>' where CAP extends 'Wrapper<String>[]'. This is fine, but then javac has a habit of widening capture variables to their bounds at unspecified times, as noted by JDK-8016207, so the for-each statement ends up with a 'Wrapper<String>[]', not a 'CAP'. 2) The specification is not clear about whether array-bounded variables are "array types", per JDK-8013843, so it's not clear whether the capture variable is an acceptable for-each type. I think, for compatibility, we'll probably have to address #2 before addressing #1, and in that case, the actual behavior of javac will be to always be to accept the test program. So while there are some issues of concern here, it's fine to call this report "Not an Issue" and leave the underlying problems to those other bugs.
14-12-2015

Just to add one more point,following code gets compiled properly in eclipse too if Explicitly assigning return of optionalArrayOfStringWrappers().get() to Wrapper<String>[]. without any typecast. Wrapper<String>[] list = optionalArrayOfStringWrappers().get(); for (Wrapper<String> attribute: list) { //for (Wrapper<String> attribute: optionalArrayOfStringWrappers().get()) { // Expect compiler error on for loop: Can only iterate over an array or an instance of java.lang.Iterable }
26-11-2015

This is an issue, Observed in all the builds of Java 8 and 9 ea. Eclipse gives error during compilation. Compilation error - "Can only iterate over an array or an instance of java.lang.Iterable" Whereas Javac executed through windows command prompt and Linux terminal doesn't give any error and generate .class files
26-11-2015

I believe the expectations are wrong here. This method: optionalArrayOfStringWrappers returns a value whose type is: Optional<? extends Wrapper<String>[]> So, when we call get() on the above optional value, we get back a: Wrapper<String>[] Which is an array, after all. Looks like a bug in Eclipse to me.
26-11-2015