Spec clarification about intersection types

B. Blaser bsrbnd at gmail.com
Tue Nov 7 18:31:40 UTC 2017


Hi,

I would like to request a clarification about intersection types. This
subject was briefly discussed on compiler-dev but it didn't appear
clearly if there was a specification or conformance issue (or
nothing?).

Consider the following example:

class A {
    interface I {}

    I nil1() { return null; }

    <T extends I> T nil2() { return null; }

    static final class Final {}

    void a() {
        // Fails per JLS9 §5.1.6.1 pt (5) + (12)
        Final f1 = (Final & I) nil1();

        // Succeeds as A isn't final
        A a = (A & I) nil1();

        // Should fail per JLS9 §18.4 ?
        Final f2 = nil2();
    }

    // Should fail per JLS9 §4.9 ?
    <U extends Final & I> U nil3() { return null; }
}

Javac currently behaves as follows:

(1) 'Final f1 = (Final & I) nil1()' fails to compile per JLS9 §5.1.6.1
points 5 and 12 which seems to be right:

"A narrowing reference conversion exists from reference type S to
reference type T if all of the following are true:
 ...
• One of the following cases applies:
 ...
5. S is an interface type, T is a class type, and T does not name a final class.
 ...
12. T is an intersection type T1 & ... & Tn, and for all i (1 ≤ i ≤
n), either a widening reference conversion or a narrowing reference
conversion exists from S to Ti."


(2) 'Final f2 = nil2()' succeeds but should probably fail per JLS9 §18.4:

"If the bound set produced in the step above contains the bound false;

then let Y1, ..., Yn be fresh type variables whose bounds are as follows:
 ...
– For all i (1 ≤ i ≤ n), where αi has upper bounds U1, ..., Uk, let
the upper bound of Yi be glb(U1 θ, ..., Uk θ), where θ is the
substitution [α1:=Y1, ..., αn:=Yn].

If the type variables Y1, ..., Yn do not have well-formed bounds (that
is, a lower bound is not a subtype of an upper bound, or an
intersection type is inconsistent), then resolution fails."

In our example, 'T' has the two upper bounds 'T <: I' (from definition
of 'T') and 'T <: Final' (from return type constraint). From §18.4,
the upper bound of 'Y' is 'Final & I' which is an inconsistent
intersection type (but §4.9 isn't absolutely clear about that, see
next) then resolution should fail.


(3) '<U extends Final & I>' succeeds but should probably fail per JLS9 §4.9:

"otherwise, a notional class is induced with direct superclass Ck.
This class or interface has direct superinterfaces T1', ..., Tn' and
is declared in the package in which the intersection type appears."

In our case, it seems to be impossible to have a "notional class
induced with direct superclass" 'Final'.


In conclusion, JLS9 §5.1.6.1 clearly expresses that (1) should fail
but §18.4 and §4.9 are probably not clear enough to establish if (2)
and (3) should really succeed or fail.

I hope I didn't miss anything.

Thanks in advance for any clarification,

Bernard


P.S.

Note for the case 'A a = nil2()' where 'A' isn't 'final', it was
suggested to emit a lint warning because 'nil2()' has no way to know
the expected return type, see:

https://bugs.openjdk.java.net/browse/JDK-8189684


More information about the compiler-dev mailing list