JDK-7120669 : 4.9: Clarify well-formedness for intersection types & bounded type variables
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0,7,8
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2011-12-12
  • Updated: 2022-08-02
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.
Other
tbd_majorUnresolved
Related Reports
Blocks :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
This spec bug arose out of an investigation of compiler bug 7111664 (see also 6946211).

At issue is the definition of members of an intersection (and, thus, a type variable) (4.9).  If you squint, you might see an implicit assertion, sometimes enforced by the compiler, that the imaginary class declaration we use to model membership must be well-formed.  If inherited methods clash in certain ways, for example, an error occurs.  (However, some checks, such as the requirement that a subclass make an explicit call to super() if the superclass doesn't have a no-arg constructor, are not enforced.)

If it is our intent that the imaginary class be strictly well-formed, the spec needs to be clear about it.  If not, the spec needs to outline exactly what assertions must be made about the imaginary class (or abandon the imaginary class crutch and just describe the assertions directly).

In my opinion, the rule should be much more forgiving than those for class declarations: unless we can prove that no witness can exist for an intersection, we should assume it does exist, and not complain.  This may mean we have fewer guarantees about membership than we thought, for things like choosing the return type of a method invocation (15.12.2.5).  But these guarantees, like an assumption that there always exists a most-specific return type, are illusory anyway: parameterized types don't have the guarantees that simple classes do, and we can't enforce the guarantees in non-Java class files.  (I ran into this when trying to reason about functional interface members.)

To illustrate:

class TvarAccess {

 /*** Declarations ***/

 static abstract class A {
   protected abstract String foo();
   protected String bar() { return "bar"; }
   protected abstract Object clone();
 }

 interface Foo { public String foo(); }

 interface Bar { public String bar(); }

 interface PublicClone { public Object clone(); }

 // Witness for A&Foo, A&Bar, A&PublicClone, Object&PublicClone
 static class C extends A implements Foo, Bar, PublicClone {
   public String foo() { return "foo"; }
   public String bar() { return "bar"; }
   public Object clone() { return this; }
 }

 interface ReadableFactory {
   Readable make();
 }

 interface CloseableFactory {
   java.io.Closeable make();
 }

 // Witness for ReadableFactory&CloseableFactory
 interface ReaderFactory extends ReadableFactory, CloseableFactory {
   java.io.Reader make();
 }

 class RequiresSuperCall {
   public RequiresSuperCall(boolean arg) {}
 }

 // Witness for T extends RequiresSuperCall
 class D extends RequiresSuperCall {
   public D() { super(true); }
 }

 /*** Tests ***/

 // No error for tvar in javac 7
 public <T extends A & Foo> String testMethod1(T arg) {
   return arg.foo();
 }

 // ERROR for tvar in javac 7
 public <T extends A & Bar> String testMethod2(T arg) {
   return arg.foo();
 }

 // ERROR for tvar in javac 7
 public <T extends A & PublicClone> void testMethod3(T arg) {
   arg.clone();
 }

 // ERROR for tvar in javac 7
 public <T extends Object & PublicClone> void testMethod4(T arg) { // error
   arg.clone();
 }

 // ERROR for tvar in javac 7
 public <T extends ReadableFactory & CloseableFactory> void testMethod5(T arg) {
   arg.make(); // ERROR in javac 7: ambiguous method
 }

 // No error for tvar in javac 7
 public <T extends RequiresSuperCall> void testMethod6(T arg) {
 }

}

Comments
Another StackOverflow post: https://stackoverflow.com/questions/45798233/eclipse-javac-disagree-on-compiling-signature-with-default-method-collision-who
22-08-2017

Should also consider whether a final superclass should be rejected. (See, e.g., JDK-8177716.)
28-03-2017

This report on SO: http://stackoverflow.com/questions/34644237/unrelated-defaults-inheritance-error-for-type-variables-why illustrates another variant of this problem, where the imaginary class has conflicting defaults.
07-01-2016

EVALUATION 6644562 also relates to this part of the spec -- in that case, simplifying the membership definition. It does not address the problem of not having clearly-defined error conditions.
12-12-2011