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 :
Perhaps I'm reading something into the JLS but it seems pretty clear in the second bullet point of 5.1.10 that the bound of the fresh type variable is an intersection type where the first bound is the wildcard's bound followed by the type variable's bounds in declaration order:
If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable whose upper bound is glb(Bi, Ui[A1:=S1,...,An:=Sn]) and whose lower bound is the null type.
glb(V1,...,Vm) is defined as V1 & ... & Vm.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The sample source is an annotation processor. First compile it. Then compile it again with itself as the annotation processor:
javac CaptureOrder.java
javac -processor CaptureOrder CaptureOrder.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
capture#856 of ? extends I3
java.lang.Object&I3&I2&I1
ACTUAL -
capture#856 of ? extends I3
java.lang.Object&I1&I2&I3
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 I1 {}
interface I2 {}
interface I3 {}
interface IA<A extends I2 & I1> {}
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("*")
public class CaptureOrder extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) test();
return false;
}
IA<? extends I3> field;
private static Element find(Element containing, String name) {
for (Element el : containing.getEnclosedElements()) {
if (el.getSimpleName().toString().equals(name)) return el;
}
return null;
}
void test() {
Elements eu = processingEnv.getElementUtils();
Types tu = processingEnv.getTypeUtils();
TypeElement captureTestEl = eu.getTypeElement(CaptureOrder.class.getName());
VariableElement fieldEl = (VariableElement) find(captureTestEl, "field");
DeclaredType iaOfWildcardExtendsI3 = (DeclaredType) fieldEl.asType();
DeclaredType capture = (DeclaredType) tu.capture(iaOfWildcardExtendsI3);
TypeVariable captureTypeArg = (TypeVariable) capture.getTypeArguments().get(0);
System.out.println(captureTypeArg);
System.out.println(captureTypeArg.getUpperBound());
}
}
---------- END SOURCE ----------