-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
8u25, 8u40
-
x86_64
-
windows_7
FULL PRODUCT VERSION :
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) Client VM (build 25.25-b02, mixed mode, sharing)
javac 1.8.0_25
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
The example shows a generic type that contains a method that returns another generic type, the latter also containing a method that returns a generic type. The return type of the methods invokes the next generic type using a wildcard bound by the present type's own parameter. The last generic type adds a bound in its declaration. I expected it to produce an intersection type but it produced an error type instead (TypeKind.ERROR). From 5.1.10 it seems that the result should be a fresh type variable bound by the intersection of the previous type variable and the additional type parameter bound. Indeed, this happens if Base1 is introduced earlier in the chain (e.g., as Iy<Y extends Base1>).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached source, then use it as an annotation processor:
javac Demo.java
javac -processor Demo Demo.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Iz<? extends Base2>
DECLARED Iz<capture#527 of ? extends Base2>
TYPEVAR capture#527 of ? extends Base2
bound: DECLARED Base2
Iy<? extends capture#527 of ? extends Base2>
DECLARED Iy<capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#740 of ? extends capture#527 of ? extends Base2
bound: TYPEVAR capture#527 of ? extends Base2
Ix<? extends capture#740 of ? extends capture#527 of ? extends Base2>
DECLARED Ix<capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2
bound: INTERSECTION capture#740 of ? extends capture#527 of ? extends Base2&Base1
ACTUAL -
Iz<? extends Base2>
DECLARED Iz<capture#527 of ? extends Base2>
TYPEVAR capture#527 of ? extends Base2
bound: DECLARED Base2
Iy<? extends capture#527 of ? extends Base2>
DECLARED Iy<capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#740 of ? extends capture#527 of ? extends Base2
bound: TYPEVAR capture#527 of ? extends Base2
Ix<? extends capture#740 of ? extends capture#527 of ? extends Base2>
DECLARED Ix<capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2
bound: ERROR <any>
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
interface Base1 {}
interface Base2 {}
interface Ix<X extends Base1> {}
interface Iy<Y> {
Ix<? extends Y> getInY();
}
interface Iz<Z> {
Iy<? extends Z> getInZ();
}
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("*")
public class Demo extends AbstractProcessor {
public Iz<? extends Base2> rl() { return null; }
// Attempt to determine the type of rl().getInZ().getInY()
void test() {
Elements eu = processingEnv.getElementUtils();
Types tu = processingEnv.getTypeUtils();
// Find return type of rl() and perform capture
ExecutableElement rlel = (ExecutableElement) find(eu.getTypeElement("Demo"), "rl");
DeclaredType izWildExtendsBase2Tm = (DeclaredType) rlel.getReturnType();
System.out.println(izWildExtendsBase2Tm);
DeclaredType capIzWildExtendsBase2Tm = (DeclaredType) tu.capture(izWildExtendsBase2Tm);
print(capIzWildExtendsBase2Tm);
// Find return type of getInZ() when viewed as member of previous method's return; capture
Element getInZ = find(eu.getTypeElement("Iz"), "getInZ");
ExecutableType getInZTm = (ExecutableType) tu.asMemberOf(capIzWildExtendsBase2Tm, getInZ);
DeclaredType iyWildExtendsZ = (DeclaredType) getInZTm.getReturnType();
System.out.println(iyWildExtendsZ);
DeclaredType capIyWildExtendsZ = (DeclaredType) tu.capture(iyWildExtendsZ);
print(capIyWildExtendsZ);
// Find return type of getInY() when viewed as member of previous method's return; capture
Element getInY = find(eu.getTypeElement("Iy"), "getInY");
ExecutableType getInYTm = (ExecutableType) tu.asMemberOf(capIyWildExtendsZ, getInY);
DeclaredType ixWildExtendsY = (DeclaredType) getInYTm.getReturnType();
System.out.println(ixWildExtendsY);
DeclaredType capIxWildExtendsY = (DeclaredType) tu.capture(ixWildExtendsY);
print(capIxWildExtendsY);
}
// Print a type, its first type argument, and the bound thereof
void print(DeclaredType dt) {
System.out.println(dt.getKind() + " " + dt);
TypeMirror arg0 = dt.getTypeArguments().get(0);
System.out.println(" " + arg0.getKind() + ' ' + arg0);
TypeMirror bound = ((TypeVariable) arg0).getUpperBound();
System.out.println(" bound: " + bound.getKind() + ' ' + bound);
}
private static Element find(Element containing, String name) {
for (Element el : containing.getEnclosedElements()) {
if (el.getSimpleName().toString().equals(name)) return el;
}
return null;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) test();
return false;
}
}
---------- END SOURCE ----------
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) Client VM (build 25.25-b02, mixed mode, sharing)
javac 1.8.0_25
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
The example shows a generic type that contains a method that returns another generic type, the latter also containing a method that returns a generic type. The return type of the methods invokes the next generic type using a wildcard bound by the present type's own parameter. The last generic type adds a bound in its declaration. I expected it to produce an intersection type but it produced an error type instead (TypeKind.ERROR). From 5.1.10 it seems that the result should be a fresh type variable bound by the intersection of the previous type variable and the additional type parameter bound. Indeed, this happens if Base1 is introduced earlier in the chain (e.g., as Iy<Y extends Base1>).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached source, then use it as an annotation processor:
javac Demo.java
javac -processor Demo Demo.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Iz<? extends Base2>
DECLARED Iz<capture#527 of ? extends Base2>
TYPEVAR capture#527 of ? extends Base2
bound: DECLARED Base2
Iy<? extends capture#527 of ? extends Base2>
DECLARED Iy<capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#740 of ? extends capture#527 of ? extends Base2
bound: TYPEVAR capture#527 of ? extends Base2
Ix<? extends capture#740 of ? extends capture#527 of ? extends Base2>
DECLARED Ix<capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2
bound: INTERSECTION capture#740 of ? extends capture#527 of ? extends Base2&Base1
ACTUAL -
Iz<? extends Base2>
DECLARED Iz<capture#527 of ? extends Base2>
TYPEVAR capture#527 of ? extends Base2
bound: DECLARED Base2
Iy<? extends capture#527 of ? extends Base2>
DECLARED Iy<capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#740 of ? extends capture#527 of ? extends Base2
bound: TYPEVAR capture#527 of ? extends Base2
Ix<? extends capture#740 of ? extends capture#527 of ? extends Base2>
DECLARED Ix<capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2>
TYPEVAR capture#767 of ? extends capture#740 of ? extends capture#527 of ? extends Base2
bound: ERROR <any>
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
interface Base1 {}
interface Base2 {}
interface Ix<X extends Base1> {}
interface Iy<Y> {
Ix<? extends Y> getInY();
}
interface Iz<Z> {
Iy<? extends Z> getInZ();
}
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("*")
public class Demo extends AbstractProcessor {
public Iz<? extends Base2> rl() { return null; }
// Attempt to determine the type of rl().getInZ().getInY()
void test() {
Elements eu = processingEnv.getElementUtils();
Types tu = processingEnv.getTypeUtils();
// Find return type of rl() and perform capture
ExecutableElement rlel = (ExecutableElement) find(eu.getTypeElement("Demo"), "rl");
DeclaredType izWildExtendsBase2Tm = (DeclaredType) rlel.getReturnType();
System.out.println(izWildExtendsBase2Tm);
DeclaredType capIzWildExtendsBase2Tm = (DeclaredType) tu.capture(izWildExtendsBase2Tm);
print(capIzWildExtendsBase2Tm);
// Find return type of getInZ() when viewed as member of previous method's return; capture
Element getInZ = find(eu.getTypeElement("Iz"), "getInZ");
ExecutableType getInZTm = (ExecutableType) tu.asMemberOf(capIzWildExtendsBase2Tm, getInZ);
DeclaredType iyWildExtendsZ = (DeclaredType) getInZTm.getReturnType();
System.out.println(iyWildExtendsZ);
DeclaredType capIyWildExtendsZ = (DeclaredType) tu.capture(iyWildExtendsZ);
print(capIyWildExtendsZ);
// Find return type of getInY() when viewed as member of previous method's return; capture
Element getInY = find(eu.getTypeElement("Iy"), "getInY");
ExecutableType getInYTm = (ExecutableType) tu.asMemberOf(capIyWildExtendsZ, getInY);
DeclaredType ixWildExtendsY = (DeclaredType) getInYTm.getReturnType();
System.out.println(ixWildExtendsY);
DeclaredType capIxWildExtendsY = (DeclaredType) tu.capture(ixWildExtendsY);
print(capIxWildExtendsY);
}
// Print a type, its first type argument, and the bound thereof
void print(DeclaredType dt) {
System.out.println(dt.getKind() + " " + dt);
TypeMirror arg0 = dt.getTypeArguments().get(0);
System.out.println(" " + arg0.getKind() + ' ' + arg0);
TypeMirror bound = ((TypeVariable) arg0).getUpperBound();
System.out.println(" bound: " + bound.getKind() + ' ' + bound);
}
private static Element find(Element containing, String name) {
for (Element el : containing.getEnclosedElements()) {
if (el.getSimpleName().toString().equals(name)) return el;
}
return null;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) test();
return false;
}
}
---------- END SOURCE ----------
- relates to
-
JDK-8062358 ClassCastException in TransTypes.visitApply
- Closed