8010822: Intersection type cast for functional expressions does not follow spec EDR
Remove support for marker interfaces; redefine intersection type casts to be order-independent Reviewed-by: jjg
This commit is contained in:
parent
ea55015155
commit
da9dd76b20
langtools
src/share/classes/com/sun/tools/javac
test/tools/javac
diags/examples
lambda
@ -908,6 +908,12 @@ public class Type implements PrimitiveType {
|
|||||||
return interfaces_field.prepend(supertype_field);
|
return interfaces_field.prepend(supertype_field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Type> getExplicitComponents() {
|
||||||
|
return allInterfaces ?
|
||||||
|
interfaces_field :
|
||||||
|
getComponents();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeKind getKind() {
|
public TypeKind getKind() {
|
||||||
return TypeKind.INTERSECTION;
|
return TypeKind.INTERSECTION;
|
||||||
|
@ -610,7 +610,7 @@ public class Types {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope filter used to skip methods that should be ignored (such as methods
|
* Scope filter used to skip methods that should be ignored (such as methods
|
||||||
* overridden by j.l.Object) during function interface conversion/marker interface checks
|
* overridden by j.l.Object) during function interface conversion interface check
|
||||||
*/
|
*/
|
||||||
class DescriptorFilter implements Filter<Symbol> {
|
class DescriptorFilter implements Filter<Symbol> {
|
||||||
|
|
||||||
@ -629,64 +629,6 @@ public class Types {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="isMarker">
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A cache that keeps track of marker interfaces
|
|
||||||
*/
|
|
||||||
class MarkerCache {
|
|
||||||
|
|
||||||
private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>();
|
|
||||||
|
|
||||||
class Entry {
|
|
||||||
final boolean isMarkerIntf;
|
|
||||||
final int prevMark;
|
|
||||||
|
|
||||||
public Entry(boolean isMarkerIntf,
|
|
||||||
int prevMark) {
|
|
||||||
this.isMarkerIntf = isMarkerIntf;
|
|
||||||
this.prevMark = prevMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean matches(int mark) {
|
|
||||||
return this.prevMark == mark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean get(TypeSymbol origin) throws FunctionDescriptorLookupError {
|
|
||||||
Entry e = _map.get(origin);
|
|
||||||
CompoundScope members = membersClosure(origin.type, false);
|
|
||||||
if (e == null ||
|
|
||||||
!e.matches(members.getMark())) {
|
|
||||||
boolean isMarkerIntf = isMarkerInterfaceInternal(origin, members);
|
|
||||||
_map.put(origin, new Entry(isMarkerIntf, members.getMark()));
|
|
||||||
return isMarkerIntf;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return e.isMarkerIntf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is given symbol a marker interface
|
|
||||||
*/
|
|
||||||
public boolean isMarkerInterfaceInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
|
|
||||||
return !origin.isInterface() ?
|
|
||||||
false :
|
|
||||||
!membersCache.getElements(new DescriptorFilter(origin)).iterator().hasNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MarkerCache markerCache = new MarkerCache();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is given type a marker interface?
|
|
||||||
*/
|
|
||||||
public boolean isMarkerInterface(Type site) {
|
|
||||||
return markerCache.get(site.tsym);
|
|
||||||
}
|
|
||||||
// </editor-fold>
|
|
||||||
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="isSubtype">
|
// <editor-fold defaultstate="collapsed" desc="isSubtype">
|
||||||
/**
|
/**
|
||||||
* Is t an unchecked subtype of s?
|
* Is t an unchecked subtype of s?
|
||||||
|
@ -2273,7 +2273,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
|
|
||||||
Type lambdaType;
|
Type lambdaType;
|
||||||
if (pt() != Type.recoveryType) {
|
if (pt() != Type.recoveryType) {
|
||||||
target = checkIntersectionTarget(that, target, resultInfo.checkContext);
|
target = targetChecker.visit(target, that);
|
||||||
lambdaType = types.findDescriptorType(target);
|
lambdaType = types.findDescriptorType(target);
|
||||||
chk.checkFunctionalInterface(that, target);
|
chk.checkFunctionalInterface(that, target);
|
||||||
} else {
|
} else {
|
||||||
@ -2281,7 +2281,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
lambdaType = fallbackDescriptorType(that);
|
lambdaType = fallbackDescriptorType(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFunctionalInfo(that, pt(), lambdaType, resultInfo.checkContext.inferenceContext());
|
setFunctionalInfo(that, pt(), lambdaType, target, resultInfo.checkContext.inferenceContext());
|
||||||
|
|
||||||
if (lambdaType.hasTag(FORALL)) {
|
if (lambdaType.hasTag(FORALL)) {
|
||||||
//lambda expression target desc cannot be a generic method
|
//lambda expression target desc cannot be a generic method
|
||||||
@ -2396,26 +2396,55 @@ public class Attr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type checkIntersectionTarget(DiagnosticPosition pos, Type pt, CheckContext checkContext) {
|
|
||||||
if (pt != Type.recoveryType && pt.isCompound()) {
|
|
||||||
IntersectionClassType ict = (IntersectionClassType)pt;
|
|
||||||
List<Type> bounds = ict.allInterfaces ?
|
|
||||||
ict.getComponents().tail :
|
|
||||||
ict.getComponents();
|
|
||||||
types.findDescriptorType(bounds.head); //propagate exception outwards!
|
|
||||||
for (Type bound : bounds.tail) {
|
|
||||||
if (!types.isMarkerInterface(bound)) {
|
|
||||||
checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//for now (translation doesn't support intersection types)
|
|
||||||
return bounds.head;
|
|
||||||
} else {
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//where
|
//where
|
||||||
|
Types.MapVisitor<DiagnosticPosition> targetChecker = new Types.MapVisitor<DiagnosticPosition>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type visitClassType(ClassType t, DiagnosticPosition pos) {
|
||||||
|
return t.isCompound() ?
|
||||||
|
visitIntersectionClassType((IntersectionClassType)t, pos) : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type visitIntersectionClassType(IntersectionClassType ict, DiagnosticPosition pos) {
|
||||||
|
Symbol desc = types.findDescriptorSymbol(makeNotionalInterface(ict));
|
||||||
|
Type target = null;
|
||||||
|
for (Type bound : ict.getExplicitComponents()) {
|
||||||
|
TypeSymbol boundSym = bound.tsym;
|
||||||
|
if (types.isFunctionalInterface(boundSym) &&
|
||||||
|
types.findDescriptorSymbol(boundSym) == desc) {
|
||||||
|
target = bound;
|
||||||
|
} else if (!boundSym.isInterface() || (boundSym.flags() & ANNOTATION) != 0) {
|
||||||
|
//bound must be an interface
|
||||||
|
reportIntersectionError(pos, "not.an.intf.component", boundSym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target != null ?
|
||||||
|
target :
|
||||||
|
ict.getExplicitComponents().head; //error recovery
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeSymbol makeNotionalInterface(IntersectionClassType ict) {
|
||||||
|
ListBuffer<Type> targs = ListBuffer.lb();
|
||||||
|
ListBuffer<Type> supertypes = ListBuffer.lb();
|
||||||
|
for (Type i : ict.interfaces_field) {
|
||||||
|
if (i.isParameterized()) {
|
||||||
|
targs.appendList(i.tsym.type.allparams());
|
||||||
|
}
|
||||||
|
supertypes.append(i.tsym.type);
|
||||||
|
}
|
||||||
|
IntersectionClassType notionalIntf =
|
||||||
|
(IntersectionClassType)types.makeCompoundType(supertypes.toList());
|
||||||
|
notionalIntf.allparams_field = targs.toList();
|
||||||
|
notionalIntf.tsym.flags_field |= INTERFACE;
|
||||||
|
return notionalIntf.tsym;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportIntersectionError(DiagnosticPosition pos, String key, Object... args) {
|
||||||
|
resultInfo.checkContext.report(pos, diags.fragment("bad.intersection.target.for.functional.expr",
|
||||||
|
diags.fragment(key, args)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private Type fallbackDescriptorType(JCExpression tree) {
|
private Type fallbackDescriptorType(JCExpression tree) {
|
||||||
switch (tree.getTag()) {
|
switch (tree.getTag()) {
|
||||||
case LAMBDA:
|
case LAMBDA:
|
||||||
@ -2586,7 +2615,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
Type target;
|
Type target;
|
||||||
Type desc;
|
Type desc;
|
||||||
if (pt() != Type.recoveryType) {
|
if (pt() != Type.recoveryType) {
|
||||||
target = checkIntersectionTarget(that, pt(), resultInfo.checkContext);
|
target = targetChecker.visit(pt(), that);
|
||||||
desc = types.findDescriptorType(target);
|
desc = types.findDescriptorType(target);
|
||||||
chk.checkFunctionalInterface(that, target);
|
chk.checkFunctionalInterface(that, target);
|
||||||
} else {
|
} else {
|
||||||
@ -2594,7 +2623,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
desc = fallbackDescriptorType(that);
|
desc = fallbackDescriptorType(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFunctionalInfo(that, pt(), desc, resultInfo.checkContext.inferenceContext());
|
setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
|
||||||
List<Type> argtypes = desc.getParameterTypes();
|
List<Type> argtypes = desc.getParameterTypes();
|
||||||
|
|
||||||
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
|
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
|
||||||
@ -2789,20 +2818,25 @@ public class Attr extends JCTree.Visitor {
|
|||||||
* might contain inference variables, we might need to register an hook in the
|
* might contain inference variables, we might need to register an hook in the
|
||||||
* current inference context.
|
* current inference context.
|
||||||
*/
|
*/
|
||||||
private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt, final Type descriptorType, InferenceContext inferenceContext) {
|
private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt,
|
||||||
|
final Type descriptorType, final Type primaryTarget, InferenceContext inferenceContext) {
|
||||||
if (inferenceContext.free(descriptorType)) {
|
if (inferenceContext.free(descriptorType)) {
|
||||||
inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
|
inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
|
||||||
public void typesInferred(InferenceContext inferenceContext) {
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType), inferenceContext);
|
setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType),
|
||||||
|
inferenceContext.asInstType(primaryTarget), inferenceContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ListBuffer<TypeSymbol> targets = ListBuffer.lb();
|
ListBuffer<TypeSymbol> targets = ListBuffer.lb();
|
||||||
if (pt.hasTag(CLASS)) {
|
if (pt.hasTag(CLASS)) {
|
||||||
if (pt.isCompound()) {
|
if (pt.isCompound()) {
|
||||||
|
targets.append(primaryTarget.tsym); //this goes first
|
||||||
for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
|
for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
|
||||||
|
if (t != primaryTarget) {
|
||||||
targets.append(t.tsym);
|
targets.append(t.tsym);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
targets.append(pt.tsym);
|
targets.append(pt.tsym);
|
||||||
}
|
}
|
||||||
|
@ -216,9 +216,14 @@ compiler.misc.descriptor.throws=\
|
|||||||
compiler.misc.no.suitable.functional.intf.inst=\
|
compiler.misc.no.suitable.functional.intf.inst=\
|
||||||
cannot infer functional interface descriptor for {0}
|
cannot infer functional interface descriptor for {0}
|
||||||
|
|
||||||
|
# 0: message segment
|
||||||
|
compiler.misc.bad.intersection.target.for.functional.expr=\
|
||||||
|
bad intersection type target for lambda or method reference\n\
|
||||||
|
{0}
|
||||||
|
|
||||||
# 0: type
|
# 0: type
|
||||||
compiler.misc.secondary.bound.must.be.marker.intf=\
|
compiler.misc.not.an.intf.component=\
|
||||||
secondary bound {0} must be a marker interface
|
component type {0} is not an interface
|
||||||
|
|
||||||
# 0: symbol kind, 1: message segment
|
# 0: symbol kind, 1: message segment
|
||||||
compiler.err.invalid.mref=\
|
compiler.err.invalid.mref=\
|
||||||
|
@ -395,6 +395,9 @@ public class RichDiagnosticFormatter extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitClassSymbol(ClassSymbol s, Locale locale) {
|
public String visitClassSymbol(ClassSymbol s, Locale locale) {
|
||||||
|
if (s.type.isCompound()) {
|
||||||
|
return visit(s.type, locale);
|
||||||
|
}
|
||||||
String name = nameSimplifier.simplify(s);
|
String name = nameSimplifier.simplify(s);
|
||||||
if (name.length() == 0 ||
|
if (name.length() == 0 ||
|
||||||
!getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
|
!getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
|
||||||
@ -583,7 +586,11 @@ public class RichDiagnosticFormatter extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitClassSymbol(ClassSymbol s, Void ignored) {
|
public Void visitClassSymbol(ClassSymbol s, Void ignored) {
|
||||||
|
if (s.type.isCompound()) {
|
||||||
|
typePreprocessor.visit(s.type);
|
||||||
|
} else {
|
||||||
nameSimplifier.addUsage(s);
|
nameSimplifier.addUsage(s);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -22,8 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.err.prob.found.req
|
// key: compiler.err.prob.found.req
|
||||||
// key: compiler.misc.secondary.bound.must.be.marker.intf
|
// key: compiler.misc.bad.intersection.target.for.functional.expr
|
||||||
|
// key: compiler.misc.not.an.intf.component
|
||||||
|
|
||||||
class SecondaryBoundMustBeMarkerInterface {
|
class NotAnInterfaceComponent {
|
||||||
Runnable r = (Runnable & Comparable<?>)()->{};
|
Object o = (Object & Runnable) ()-> { };
|
||||||
}
|
}
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8002099
|
* @bug 8002099
|
||||||
* @summary Add support for intersection types in cast expression
|
* @summary Add support for intersection types in cast expression
|
||||||
* @compile/fail/ref=Intersection01.out -XDrawDiagnostics Intersection01.java
|
* @compile Intersection01.java
|
||||||
*/
|
*/
|
||||||
class Intersection01 {
|
class Intersection01 {
|
||||||
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
Intersection01.java:36:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: java.io.Serializable, (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable))
|
|
||||||
Intersection01.java:38:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: java.io.Serializable, (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable))
|
|
||||||
2 errors
|
|
@ -28,10 +28,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import com.sun.source.util.JavacTask;
|
import com.sun.source.util.JavacTask;
|
||||||
import com.sun.tools.javac.util.List;
|
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
@ -45,37 +46,45 @@ public class IntersectionTargetTypeTest {
|
|||||||
|
|
||||||
enum BoundKind {
|
enum BoundKind {
|
||||||
INTF,
|
INTF,
|
||||||
CLASS,
|
CLASS;
|
||||||
SAM,
|
|
||||||
ZAM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MethodKind {
|
enum MethodKind {
|
||||||
NONE,
|
NONE(false),
|
||||||
ABSTRACT,
|
ABSTRACT_M(true),
|
||||||
DEFAULT;
|
DEFAULT_M(false),
|
||||||
|
ABSTRACT_G(true),
|
||||||
|
DEFAULT_G(false);
|
||||||
|
|
||||||
|
boolean isAbstract;
|
||||||
|
|
||||||
|
MethodKind(boolean isAbstract) {
|
||||||
|
this.isAbstract = isAbstract;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TypeKind {
|
enum TypeKind {
|
||||||
A("interface A { }\n", "A", BoundKind.ZAM),
|
A("interface A { }\n", "A", BoundKind.INTF, MethodKind.NONE),
|
||||||
B("interface B { default void m() { } }\n", "B", BoundKind.ZAM),
|
B("interface B { default void m() { } }\n", "B", BoundKind.INTF, MethodKind.DEFAULT_M),
|
||||||
C("interface C { void m(); }\n", "C", BoundKind.SAM),
|
C("interface C { void m(); }\n", "C", BoundKind.INTF, MethodKind.ABSTRACT_M),
|
||||||
D("interface D extends B { }\n", "D", BoundKind.ZAM),
|
D("interface D extends B { }\n", "D", BoundKind.INTF, MethodKind.DEFAULT_M),
|
||||||
E("interface E extends C { }\n", "E", BoundKind.SAM),
|
E("interface E extends C { }\n", "E", BoundKind.INTF, MethodKind.ABSTRACT_M),
|
||||||
F("interface F extends C { void g(); }\n", "F", BoundKind.INTF),
|
F("interface F extends C { void g(); }\n", "F", BoundKind.INTF, MethodKind.ABSTRACT_G, MethodKind.ABSTRACT_M),
|
||||||
G("interface G extends B { void g(); }\n", "G", BoundKind.SAM),
|
G("interface G extends B { void g(); }\n", "G", BoundKind.INTF, MethodKind.ABSTRACT_G, MethodKind.DEFAULT_M),
|
||||||
H("interface H extends A { void g(); }\n", "H", BoundKind.SAM),
|
H("interface H extends A { void g(); }\n", "H", BoundKind.INTF, MethodKind.ABSTRACT_G),
|
||||||
OBJECT("", "Object", BoundKind.CLASS),
|
OBJECT("", "Object", BoundKind.CLASS),
|
||||||
STRING("", "String", BoundKind.CLASS);
|
STRING("", "String", BoundKind.CLASS);
|
||||||
|
|
||||||
String declStr;
|
String declStr;
|
||||||
String typeStr;
|
String typeStr;
|
||||||
BoundKind boundKind;
|
BoundKind boundKind;
|
||||||
|
MethodKind[] methodKinds;
|
||||||
|
|
||||||
private TypeKind(String declStr, String typeStr, BoundKind boundKind) {
|
private TypeKind(String declStr, String typeStr, BoundKind boundKind, MethodKind... methodKinds) {
|
||||||
this.declStr = declStr;
|
this.declStr = declStr;
|
||||||
this.typeStr = typeStr;
|
this.typeStr = typeStr;
|
||||||
this.boundKind = boundKind;
|
this.boundKind = boundKind;
|
||||||
|
this.methodKinds = methodKinds;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean compatibleSupertype(TypeKind tk) {
|
boolean compatibleSupertype(TypeKind tk) {
|
||||||
@ -263,14 +272,22 @@ public class IntersectionTargetTypeTest {
|
|||||||
boolean errorExpected = !cInfo.wellFormed();
|
boolean errorExpected = !cInfo.wellFormed();
|
||||||
|
|
||||||
if (ek.isFunctional) {
|
if (ek.isFunctional) {
|
||||||
//first bound must be a SAM
|
List<MethodKind> mks = new ArrayList<>();
|
||||||
errorExpected |= cInfo.types[0].boundKind != BoundKind.SAM;
|
for (TypeKind tk : cInfo.types) {
|
||||||
if (cInfo.types.length > 1) {
|
if (tk.boundKind == BoundKind.CLASS) {
|
||||||
//additional bounds must be ZAMs
|
errorExpected = true;
|
||||||
for (int i = 1; i < cInfo.types.length; i++) {
|
break;
|
||||||
errorExpected |= cInfo.types[i].boundKind != BoundKind.ZAM;
|
} else {
|
||||||
|
mks = mergeMethods(mks, Arrays.asList(tk.methodKinds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int abstractCount = 0;
|
||||||
|
for (MethodKind mk : mks) {
|
||||||
|
if (mk.isAbstract) {
|
||||||
|
abstractCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorExpected |= abstractCount != 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorExpected != diagChecker.errorFound) {
|
if (errorExpected != diagChecker.errorFound) {
|
||||||
@ -281,6 +298,32 @@ public class IntersectionTargetTypeTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<MethodKind> mergeMethods(List<MethodKind> l1, List<MethodKind> l2) {
|
||||||
|
List<MethodKind> mergedMethods = new ArrayList<>(l1);
|
||||||
|
for (MethodKind mk2 : l2) {
|
||||||
|
boolean add = !mergedMethods.contains(mk2);
|
||||||
|
switch (mk2) {
|
||||||
|
case ABSTRACT_G:
|
||||||
|
add = add && !mergedMethods.contains(MethodKind.DEFAULT_G);
|
||||||
|
break;
|
||||||
|
case ABSTRACT_M:
|
||||||
|
add = add && !mergedMethods.contains(MethodKind.DEFAULT_M);
|
||||||
|
break;
|
||||||
|
case DEFAULT_G:
|
||||||
|
mergedMethods.remove(MethodKind.ABSTRACT_G);
|
||||||
|
case DEFAULT_M:
|
||||||
|
mergedMethods.remove(MethodKind.ABSTRACT_M);
|
||||||
|
case NONE:
|
||||||
|
add = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
mergedMethods.add(mk2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedMethods;
|
||||||
|
}
|
||||||
|
|
||||||
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||||
|
|
||||||
boolean errorFound;
|
boolean errorFound;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user