提交 711b54cc 编写于 作者: M mcimadamore

7192246: Add type-checking support for default methods

Summary: Add type-checking support for default methods as per Featherweight-Defender document
Reviewed-by: jjg, dlsmith
上级 45c901d1
......@@ -67,7 +67,6 @@ public class Flags {
if ((mask&NATIVE) != 0) flags.add(Flag.NATIVE);
if ((mask&INTERFACE) != 0) flags.add(Flag.INTERFACE);
if ((mask&ABSTRACT) != 0) flags.add(Flag.ABSTRACT);
if ((mask&DEFAULT) != 0) flags.add(Flag.DEFAULT);
if ((mask&STRICTFP) != 0) flags.add(Flag.STRICTFP);
if ((mask&BRIDGE) != 0) flags.add(Flag.BRIDGE);
if ((mask&SYNTHETIC) != 0) flags.add(Flag.SYNTHETIC);
......
......@@ -206,6 +206,9 @@ public enum Source {
public boolean allowDefaultMethods() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowStrictMethodClashCheck() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowEffectivelyFinalInInnerClasses() {
return compareTo(JDK1_8) >= 0;
}
......
......@@ -1192,9 +1192,9 @@ public abstract class Symbol implements Element {
// check for an inherited implementation
if ((flags() & ABSTRACT) != 0 ||
(other.flags() & ABSTRACT) == 0 ||
!other.isOverridableIn(origin) ||
!this.isMemberOf(origin, types))
(other.flags() & ABSTRACT) == 0 ||
!other.isOverridableIn(origin) ||
!this.isMemberOf(origin, types))
return false;
// assert types.asSuper(origin.type, other.owner) != null;
......
......@@ -75,6 +75,7 @@ public class Types {
final boolean allowBoxing;
final boolean allowCovariantReturns;
final boolean allowObjectToPrimitiveCast;
final boolean allowDefaultMethods;
final ClassReader reader;
final Check chk;
JCDiagnostic.Factory diags;
......@@ -98,6 +99,7 @@ public class Types {
allowBoxing = source.allowBoxing();
allowCovariantReturns = source.allowCovariantReturns();
allowObjectToPrimitiveCast = source.allowObjectToPrimitiveCast();
allowDefaultMethods = source.allowDefaultMethods();
reader = ClassReader.instance(context);
chk = Check.instance(context);
capturedName = names.fromString("<captured wildcard>");
......@@ -2146,6 +2148,13 @@ public class Types {
return List.nil();
}
};
public boolean isDirectSuperInterface(Type t, TypeSymbol tsym) {
for (Type t2 : interfaces(tsym.type)) {
if (isSameType(t, t2)) return true;
}
return false;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="isDerivedRaw">
......@@ -2310,6 +2319,10 @@ public class Types {
return false;
}
public boolean overridesObjectMethod(Symbol msym) {
return ((MethodSymbol)msym).implementation(syms.objectType.tsym, this, true) != null;
}
// <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site">
class ImplementationCache {
......@@ -2455,6 +2468,70 @@ public class Types {
}
// </editor-fold>
//where
public List<MethodSymbol> interfaceCandidates(Type site, MethodSymbol ms) {
return interfaceCandidates(site, ms, false);
}
public List<MethodSymbol> interfaceCandidates(Type site, MethodSymbol ms, boolean intfOnly) {
Filter<Symbol> filter = new MethodFilter(ms, site, intfOnly);
List<MethodSymbol> candidates = List.nil();
for (Symbol s : membersClosure(site, false).getElements(filter)) {
if (!site.tsym.isInterface() && !s.owner.isInterface()) {
return List.of((MethodSymbol)s);
} else if (!candidates.contains(s)) {
candidates = candidates.prepend((MethodSymbol)s);
}
}
return prune(candidates, ownerComparator);
}
public List<MethodSymbol> prune(List<MethodSymbol> methods, Comparator<MethodSymbol> cmp) {
ListBuffer<MethodSymbol> methodsMin = ListBuffer.lb();
for (MethodSymbol m1 : methods) {
boolean isMin_m1 = true;
for (MethodSymbol m2 : methods) {
if (m1 == m2) continue;
if (cmp.compare(m2, m1) < 0) {
isMin_m1 = false;
break;
}
}
if (isMin_m1)
methodsMin.append(m1);
}
return methodsMin.toList();
}
Comparator<MethodSymbol> ownerComparator = new Comparator<MethodSymbol>() {
public int compare(MethodSymbol s1, MethodSymbol s2) {
return s1.owner.isSubClass(s2.owner, Types.this) ? -1 : 1;
}
};
// where
private class MethodFilter implements Filter<Symbol> {
Symbol msym;
Type site;
boolean intfOnly;
MethodFilter(Symbol msym, Type site, boolean intfOnly) {
this.msym = msym;
this.site = site;
this.intfOnly = intfOnly;
}
public boolean accepts(Symbol s) {
return s.kind == Kinds.MTH &&
(!intfOnly || s.owner.isInterface()) &&
s.name == msym.name &&
s.isInheritedIn(site.tsym, Types.this) &&
overrideEquivalent(memberType(site, s), memberType(site, msym));
}
};
// </editor-fold>
/**
* Does t have the same arguments as s? It is assumed that both
* types are (possibly polymorphic) method types. Monomorphic
......
......@@ -135,6 +135,7 @@ public class Attr extends JCTree.Visitor {
allowStringsInSwitch = source.allowStringsInSwitch();
allowPoly = source.allowPoly() && options.isSet("allowPoly");
allowLambda = source.allowLambda();
allowDefaultMethods = source.allowDefaultMethods();
sourceName = source.name;
relax = (options.isSet("-retrofit") ||
options.isSet("-relax"));
......@@ -178,6 +179,10 @@ public class Attr extends JCTree.Visitor {
*/
boolean allowCovariantReturns;
/** Switch: support default methods ?
*/
boolean allowDefaultMethods;
/** Switch: support lambda expressions ?
*/
boolean allowLambda;
......@@ -898,6 +903,10 @@ public class Attr extends JCTree.Visitor {
localEnv.info.lint = lint;
if (isDefaultMethod && types.overridesObjectMethod(m)) {
log.error(tree, "default.overrides.object.member", m.name, Kinds.kindName(m.location()), m.location());
}
// Enter all type parameters into the local method scope.
for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
localEnv.info.scope.enterIfAbsent(l.head.type.tsym);
......@@ -961,10 +970,12 @@ public class Attr extends JCTree.Visitor {
log.error(tree.pos(),
"default.allowed.in.intf.annotation.member");
}
} else if ((owner.flags() & INTERFACE) != 0 && !isDefaultMethod) {
log.error(tree.body.pos(), "intf.meth.cant.have.body");
} else if ((tree.mods.flags & ABSTRACT) != 0) {
log.error(tree.pos(), "abstract.meth.cant.have.body");
} else if ((tree.sym.flags() & ABSTRACT) != 0 && !isDefaultMethod) {
if ((owner.flags() & INTERFACE) != 0) {
log.error(tree.body.pos(), "intf.meth.cant.have.body");
} else {
log.error(tree.pos(), "abstract.meth.cant.have.body");
}
} else if ((tree.mods.flags & NATIVE) != 0) {
log.error(tree.pos(), "native.meth.cant.have.body");
} else {
......@@ -3281,6 +3292,23 @@ public class Attr extends JCTree.Visitor {
}
}
if (env.info.defaultSuperCallSite != null &&
!types.interfaceCandidates(env.enclClass.type, (MethodSymbol)sym, true).contains(sym)) {
Symbol ovSym = null;
for (MethodSymbol msym : types.interfaceCandidates(env.enclClass.type, (MethodSymbol)sym, true)) {
if (msym.overrides(sym, msym.enclClass(), types, true)) {
for (Type i : types.interfaces(env.enclClass.type)) {
if (i.tsym.isSubClass(msym.owner, types)) {
ovSym = i.tsym;
break;
}
}
}
}
log.error(env.tree.pos(), "illegal.default.super.call", env.info.defaultSuperCallSite,
diags.fragment("overridden.default", sym, ovSym));
}
// Compute the identifier's instantiated type.
// For methods, we need to compute the instance type by
// Resolve.instantiate from the symbol's type as well as
......@@ -3700,6 +3728,9 @@ public class Attr extends JCTree.Visitor {
// are compatible (i.e. no two define methods with same arguments
// yet different return types). (JLS 8.4.6.3)
chk.checkCompatibleSupertypes(tree.pos(), c.type);
if (allowDefaultMethods) {
chk.checkDefaultMethodClashes(tree.pos(), c.type);
}
}
// Check that class does not import the same parameterized interface
......
......@@ -72,6 +72,10 @@ public class AttrContext {
*/
Attr.ResultInfo returnResult = null;
/** Symbol corresponding to the site of a qualified default super call
*/
Type defaultSuperCallSite = null;
/** Duplicate this context, replacing scope field and copying all others.
*/
AttrContext dup(Scope scope) {
......@@ -84,6 +88,7 @@ public class AttrContext {
info.lint = lint;
info.enclVar = enclVar;
info.returnResult = returnResult;
info.defaultSuperCallSite = defaultSuperCallSite;
return info;
}
......
......@@ -119,6 +119,9 @@ public class Check {
allowAnnotations = source.allowAnnotations();
allowCovariantReturns = source.allowCovariantReturns();
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
allowDefaultMethods = source.allowDefaultMethods();
allowStrictMethodClashCheck = source.allowStrictMethodClashCheck() &&
options.isSet("strictMethodClashCheck"); //pre-lambda guard
complexInference = options.isSet("complexinference");
warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
......@@ -162,6 +165,14 @@ public class Check {
*/
boolean allowSimplifiedVarargs;
/** Switch: default methods enabled?
*/
boolean allowDefaultMethods;
/** Switch: should unrelated return types trigger a method clash?
*/
boolean allowStrictMethodClashCheck;
/** Switch: -complexinference option set?
*/
boolean complexInference;
......@@ -1114,7 +1125,7 @@ public class Check {
} else if ((sym.owner.flags_field & INTERFACE) != 0) {
if ((flags & DEFAULT) != 0) {
mask = InterfaceDefaultMethodMask;
implicit = PUBLIC;
implicit = PUBLIC | ABSTRACT;
} else {
mask = implicit = InterfaceMethodFlags;
}
......@@ -2047,11 +2058,21 @@ public class Check {
undef == null && e != null;
e = e.sibling) {
if (e.sym.kind == MTH &&
(e.sym.flags() & (ABSTRACT|IPROXY)) == ABSTRACT) {
(e.sym.flags() & (ABSTRACT|IPROXY|DEFAULT)) == ABSTRACT) {
MethodSymbol absmeth = (MethodSymbol)e.sym;
MethodSymbol implmeth = absmeth.implementation(impl, types, true);
if (implmeth == null || implmeth == absmeth)
if (implmeth == null || implmeth == absmeth) {
//look for default implementations
if (allowDefaultMethods) {
MethodSymbol prov = types.interfaceCandidates(impl.type, absmeth).head;
if (prov != null && prov.overrides(absmeth, impl, types, true)) {
implmeth = prov;
}
}
}
if (implmeth == null || implmeth == absmeth) {
undef = absmeth;
}
}
}
if (undef == null) {
......@@ -2354,7 +2375,7 @@ public class Check {
if (m2 == m1) continue;
//if (i) the signature of 'sym' is not a subsignature of m1 (seen as
//a member of 'site') and (ii) m1 has the same erasure as m2, issue an error
if (!types.isSubSignature(sym.type, types.memberType(site, m2), false) &&
if (!types.isSubSignature(sym.type, types.memberType(site, m2), allowStrictMethodClashCheck) &&
types.hasSameArgs(m2.erasure(types), m1.erasure(types))) {
sym.flags_field |= CLASH;
String key = m1 == sym ?
......@@ -2386,7 +2407,7 @@ public class Check {
for (Symbol s : types.membersClosure(site, true).getElementsByName(sym.name, cf)) {
//if (i) the signature of 'sym' is not a subsignature of m1 (seen as
//a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
if (!types.isSubSignature(sym.type, types.memberType(site, s), false) &&
if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck) &&
types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
log.error(pos,
"name.clash.same.erasure.no.hide",
......@@ -2420,6 +2441,62 @@ public class Check {
}
}
void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) {
DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site);
for (Symbol m : types.membersClosure(site, false).getElements(dcf)) {
Assert.check(m.kind == MTH);
List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m);
if (prov.size() > 1) {
ListBuffer<Symbol> abstracts = ListBuffer.lb();
ListBuffer<Symbol> defaults = ListBuffer.lb();
for (MethodSymbol provSym : prov) {
if ((provSym.flags() & DEFAULT) != 0) {
defaults = defaults.append(provSym);
} else if ((provSym.flags() & ABSTRACT) != 0) {
abstracts = abstracts.append(provSym);
}
if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) {
//strong semantics - issue an error if two sibling interfaces
//have two override-equivalent defaults - or if one is abstract
//and the other is default
String errKey;
Symbol s1 = defaults.first();
Symbol s2;
if (defaults.size() > 1) {
errKey = "types.incompatible.unrelated.defaults";
s2 = defaults.toList().tail.head;
} else {
errKey = "types.incompatible.abstract.default";
s2 = abstracts.first();
}
log.error(pos, errKey,
Kinds.kindName(site.tsym), site,
m.name, types.memberType(site, m).getParameterTypes(),
s1.location(), s2.location());
break;
}
}
}
}
}
//where
private class DefaultMethodClashFilter implements Filter<Symbol> {
Type site;
DefaultMethodClashFilter(Type site) {
this.site = site;
}
public boolean accepts(Symbol s) {
return s.kind == MTH &&
(s.flags() & DEFAULT) != 0 &&
s.isInheritedIn(site.tsym, types) &&
!s.isConstructor();
}
}
/** Report a conflict between a user symbol and a synthetic symbol.
*/
private void syntheticError(DiagnosticPosition pos, Symbol sym) {
......
......@@ -3631,15 +3631,26 @@ public class Lower extends TreeTranslator {
public void visitSelect(JCFieldAccess tree) {
// need to special case-access of the form C.super.x
// these will always need an access method.
// these will always need an access method, unless C
// is a default interface subclassed by the current class.
boolean qualifiedSuperAccess =
tree.selected.hasTag(SELECT) &&
TreeInfo.name(tree.selected) == names._super;
TreeInfo.name(tree.selected) == names._super &&
!types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type, currentClass);
tree.selected = translate(tree.selected);
if (tree.name == names._class)
if (tree.name == names._class) {
result = classOf(tree.selected);
else if (tree.name == names._this || tree.name == names._super)
}
else if (tree.name == names._super &&
types.isDirectSuperInterface(tree.selected.type, currentClass)) {
//default super call!! Not a classic qualified super call
TypeSymbol supSym = tree.selected.type.tsym;
Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
result = tree;
}
else if (tree.name == names._this || tree.name == names._super) {
result = makeThis(tree.pos(), tree.selected.type.tsym);
}
else
result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
}
......
......@@ -560,6 +560,12 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
tree.sym = m;
//if this is a default method, add the DEFAULT flag to the enclosing interface
if ((tree.mods.flags & DEFAULT) != 0) {
m.enclClass().flags_field |= DEFAULT;
}
Env<AttrContext> localEnv = methodEnv(tree, env);
DeferredLintHandler prevLintHandler =
......@@ -677,7 +683,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
localEnv.info.scope.owner = tree.sym;
}
if ((tree.mods.flags & STATIC) != 0 ||
(env.enclClass.sym.flags() & INTERFACE) != 0)
((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null))
localEnv.info.staticLevel++;
return localEnv;
}
......@@ -1001,20 +1007,19 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
}
}
// If this is a class, enter symbols for this and super into
// current scope.
if ((c.flags_field & INTERFACE) == 0) {
VarSymbol thisSym =
new VarSymbol(FINAL | HASINIT, names._this, c.type, c);
thisSym.pos = Position.FIRSTPOS;
env.info.scope.enter(thisSym);
if (ct.supertype_field.hasTag(CLASS)) {
VarSymbol superSym =
new VarSymbol(FINAL | HASINIT, names._super,
ct.supertype_field, c);
superSym.pos = Position.FIRSTPOS;
env.info.scope.enter(superSym);
}
// enter symbols for 'this' into current scope.
VarSymbol thisSym =
new VarSymbol(FINAL | HASINIT, names._this, c.type, c);
thisSym.pos = Position.FIRSTPOS;
env.info.scope.enter(thisSym);
// if this is a class, enter symbol for 'super' into current scope.
if ((c.flags_field & INTERFACE) == 0 &&
ct.supertype_field.hasTag(CLASS)) {
VarSymbol superSym =
new VarSymbol(FINAL | HASINIT, names._super,
ct.supertype_field, c);
superSym.pos = Position.FIRSTPOS;
env.info.scope.enter(superSym);
}
// check that no package exists with same fully qualified name,
......
......@@ -52,6 +52,7 @@ import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.ElementVisitor;
......@@ -88,6 +89,7 @@ public class Resolve {
public final boolean boxingEnabled; // = source.allowBoxing();
public final boolean varargsEnabled; // = source.allowVarargs();
public final boolean allowMethodHandles;
public final boolean allowDefaultMethods;
private final boolean debugResolve;
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
......@@ -122,6 +124,7 @@ public class Resolve {
verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
Target target = Target.instance(context);
allowMethodHandles = target.hasMethodHandles();
allowDefaultMethods = source.allowDefaultMethods();
polymorphicSignatureScope = new Scope(syms.noSymbol);
inapplicableMethodException = new InapplicableMethodException(diags);
......@@ -1327,6 +1330,42 @@ public class Resolve {
}
}
Symbol lookupMethod(Env<AttrContext> env,
Type site,
Name name,
List<Type> argtypes,
List<Type> typeargtypes,
Scope sc,
Symbol bestSoFar,
boolean allowBoxing,
boolean useVarargs,
boolean operator,
boolean abstractok) {
for (Symbol s : sc.getElementsByName(name, new LookupFilter(abstractok))) {
bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
bestSoFar, allowBoxing, useVarargs, operator);
}
return bestSoFar;
}
//where
class LookupFilter implements Filter<Symbol> {
boolean abstractOk;
LookupFilter(boolean abstractOk) {
this.abstractOk = abstractOk;
}
public boolean accepts(Symbol s) {
long flags = s.flags();
return s.kind == MTH &&
(flags & SYNTHETIC) == 0 &&
(abstractOk ||
(flags & DEFAULT) != 0 ||
(flags & ABSTRACT) == 0);
}
};
/** Find best qualified method matching given name, type and value
* arguments.
* @param env The current environment.
......@@ -1371,49 +1410,76 @@ public class Resolve {
boolean allowBoxing,
boolean useVarargs,
boolean operator) {
boolean abstractOk = true;
List<Type> itypes = List.nil();
@SuppressWarnings({"unchecked","rawtypes"})
List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
for (TypeSymbol s : superclasses(intype)) {
bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
s.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
//We should not look for abstract methods if receiver is a concrete class
//(as concrete classes are expected to implement all abstracts coming
//from superinterfaces)
abstractOk &= (s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0;
if (abstractOk) {
if (name == names.init) return bestSoFar;
iphase = (iphase == null) ? null : iphase.update(s, this);
if (iphase != null) {
for (Type itype : types.interfaces(s.type)) {
itypes = types.union(types.closure(itype), itypes);
itypes[iphase.ordinal()] = types.union(types.closure(itype), itypes[iphase.ordinal()]);
}
}
if (name == names.init) break;
}
Symbol concrete = bestSoFar.kind < ERR &&
(bestSoFar.flags() & ABSTRACT) == 0 ?
bestSoFar : methodNotFound;
if (name != names.init) {
for (InterfaceLookupPhase iphase2 : InterfaceLookupPhase.values()) {
if (iphase2 == InterfaceLookupPhase.DEFAULT_OK && !allowDefaultMethods) break;
//keep searching for abstract methods
for (Type itype : itypes) {
for (Type itype : itypes[iphase2.ordinal()]) {
if (!itype.isInterface()) continue; //skip j.l.Object (included by Types.closure())
if (iphase2 == InterfaceLookupPhase.DEFAULT_OK &&
(itype.tsym.flags() & DEFAULT) == 0) continue;
bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
if (concrete != bestSoFar &&
concrete.kind < ERR && bestSoFar.kind < ERR &&
types.isSubSignature(concrete.type, bestSoFar.type)) {
//this is an hack - as javac does not do full membership checks
//most specific ends up comparing abstract methods that might have
//been implemented by some concrete method in a subclass and,
//because of raw override, it is possible for an abstract method
//to be more specific than the concrete method - so we need
//to explicitly call that out (see CR 6178365)
bestSoFar = concrete;
}
itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
if (concrete != bestSoFar &&
concrete.kind < ERR && bestSoFar.kind < ERR &&
types.isSubSignature(concrete.type, bestSoFar.type)) {
//this is an hack - as javac does not do full membership checks
//most specific ends up comparing abstract methods that might have
//been implemented by some concrete method in a subclass and,
//because of raw override, it is possible for an abstract method
//to be more specific than the concrete method - so we need
//to explicitly call that out (see CR 6178365)
bestSoFar = concrete;
}
}
}
return bestSoFar;
}
enum InterfaceLookupPhase {
ABSTRACT_OK() {
@Override
InterfaceLookupPhase update(Symbol s, Resolve rs) {
//We should not look for abstract methods if receiver is a concrete class
//(as concrete classes are expected to implement all abstracts coming
//from superinterfaces)
if ((s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0) {
return this;
} else if (rs.allowDefaultMethods) {
return DEFAULT_OK;
} else {
return null;
}
}
},
DEFAULT_OK() {
@Override
InterfaceLookupPhase update(Symbol s, Resolve rs) {
return this;
}
};
abstract InterfaceLookupPhase update(Symbol s, Resolve rs);
}
/**
* Return an Iterable object to scan the superclasses of a given type.
* It's crucial that the scan is done lazily, as we don't want to accidentally
......@@ -1467,34 +1533,6 @@ public class Resolve {
};
}
/**
* Lookup a method with given name and argument types in a given scope
*/
Symbol lookupMethod(Env<AttrContext> env,
Type site,
Name name,
List<Type> argtypes,
List<Type> typeargtypes,
Scope sc,
Symbol bestSoFar,
boolean allowBoxing,
boolean useVarargs,
boolean operator,
boolean abstractok) {
for (Symbol s : sc.getElementsByName(name, lookupFilter)) {
bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
bestSoFar, allowBoxing, useVarargs, operator);
}
return bestSoFar;
}
//where
Filter<Symbol> lookupFilter = new Filter<Symbol>() {
public boolean accepts(Symbol s) {
return s.kind == MTH &&
(s.flags() & SYNTHETIC) == 0;
}
};
/** Find unqualified method matching given name, type and value arguments.
* @param env The current environment.
* @param name The method's name.
......@@ -1920,7 +1958,7 @@ public class Resolve {
/** Check that sym is not an abstract method.
*/
void checkNonAbstract(DiagnosticPosition pos, Symbol sym) {
if ((sym.flags() & ABSTRACT) != 0)
if ((sym.flags() & ABSTRACT) != 0 && (sym.flags() & DEFAULT) == 0)
log.error(pos, "abstract.cant.be.accessed.directly",
kindName(sym), sym, sym.location());
}
......@@ -2744,9 +2782,47 @@ public class Resolve {
if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
env1 = env1.outer;
}
if (allowDefaultMethods && c.isInterface() &&
name == names._super && !isStatic(env) &&
types.isDirectSuperInterface(c.type, env.enclClass.sym)) {
//this might be a default super call if one of the superinterfaces is 'c'
for (Type t : pruneInterfaces(env.enclClass.type)) {
if (t.tsym == c) {
env.info.defaultSuperCallSite = t;
return new VarSymbol(0, names._super,
types.asSuper(env.enclClass.type, c), env.enclClass.sym);
}
}
//find a direct superinterface that is a subtype of 'c'
for (Type i : types.interfaces(env.enclClass.type)) {
if (i.tsym.isSubClass(c, types) && i.tsym != c) {
log.error(pos, "illegal.default.super.call", c,
diags.fragment("redundant.supertype", c, i));
return syms.errSymbol;
}
}
Assert.error();
}
log.error(pos, "not.encl.class", c);
return syms.errSymbol;
}
//where
private List<Type> pruneInterfaces(Type t) {
ListBuffer<Type> result = ListBuffer.lb();
for (Type t1 : types.interfaces(t)) {
boolean shouldAdd = true;
for (Type t2 : types.interfaces(t)) {
if (t1 != t2 && types.isSubtypeNoCapture(t2, t1)) {
shouldAdd = false;
}
}
if (shouldAdd) {
result.append(t1);
}
}
return result.toList();
}
/**
* Resolve `c.this' for an enclosing class c that contains the
......
......@@ -115,6 +115,9 @@ public class ClassReader implements Completer {
*/
boolean lintClassfile;
/** Switch: allow default methods
*/
boolean allowDefaultMethods;
/** Switch: preserve parameter names from the variable table.
*/
......@@ -279,6 +282,7 @@ public class ClassReader implements Completer {
allowVarargs = source.allowVarargs();
allowAnnotations = source.allowAnnotations();
allowSimplifiedVarargs = source.allowSimplifiedVarargs();
allowDefaultMethods = source.allowDefaultMethods();
saveParameterNames = options.isSet("save-parameter-names");
cacheCompletionFailure = options.isUnset("dev");
preferSource = "source".equals(options.get("-Xprefer"));
......@@ -937,6 +941,18 @@ public class ClassReader implements Completer {
new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
if (currentOwner.isInterface() &&
(sym.flags_field & ABSTRACT) == 0 && !name.equals(names.clinit)) {
if (majorVersion > Target.JDK1_8.majorVersion ||
//todo replace with Target.Version when available
(majorVersion == Target.JDK1_8.majorVersion && minorVersion >= Target.JDK1_8.minorVersion)) {
currentOwner.flags_field |= DEFAULT;
sym.flags_field |= DEFAULT | ABSTRACT;
} else {
//protect against ill-formed classfiles
throw new CompletionFailure(currentOwner, "default method found in pre JDK 8 classfile");
}
}
if (readAllOfClassFile || saveParameterNames)
((MethodSymbol)sym).code = readCode(sym);
else
......
......@@ -1540,7 +1540,7 @@ public class ClassWriter extends ClassFile {
List<Type> interfaces = types.interfaces(c.type);
List<Type> typarams = c.type.getTypeArguments();
int flags = adjustFlags(c.flags());
int flags = adjustFlags(c.flags() & ~DEFAULT);
if ((flags & PROTECTED) != 0) flags |= PUBLIC;
flags = flags & ClassFlags & ~STRICTFP;
if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
......@@ -1676,6 +1676,8 @@ public class ClassWriter extends ClassFile {
result |= ACC_BRIDGE;
if ((flags & VARARGS) != 0 && target.useVarargsFlag())
result |= ACC_VARARGS;
if ((flags & DEFAULT) != 0)
result &= ~ABSTRACT;
return result;
}
......
......@@ -523,7 +523,7 @@ public class Items {
Item invoke() {
MethodType mtype = (MethodType)member.externalType(types);
int rescode = Code.typecode(mtype.restype);
if ((member.owner.flags() & Flags.INTERFACE) != 0) {
if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
code.emitInvokeinterface(pool.put(member), mtype);
} else if (nonvirtual) {
code.emitInvokespecial(pool.put(member), mtype);
......
......@@ -574,7 +574,7 @@ compiler.err.intf.expected.here=\
interface expected here
compiler.err.intf.meth.cant.have.body=\
interface methods cannot have body
interface abstract methods cannot have body
compiler.err.invalid.annotation.member.type=\
invalid type for annotation member
......@@ -941,6 +941,31 @@ compiler.err.type.var.more.than.once.in.result=\
compiler.err.types.incompatible.diff.ret=\
types {0} and {1} are incompatible; both define {2}, but with unrelated return types
# 0: kind, 1: type, 2: name, 3: list of type, 4: symbol, 5: symbol
compiler.err.types.incompatible.unrelated.defaults=\
{0} {1} inherits unrelated defaults for {2}({3}) from types {4} and {5}
# 0: kind, 1: type, 2: name, 3: list of type, 4: symbol, 5: symbol
compiler.err.types.incompatible.abstract.default=\
{0} {1} inherits abstract and default for {2}({3}) from types {4} and {5}
# 0: name, 1: kind, 2: symbol
compiler.err.default.overrides.object.member=\
default method {0} in {1} {2} overrides a member of java.lang.Object
# 0: type, 1: message segment
compiler.err.illegal.default.super.call=\
bad type qualifier {0} in default super call\n\
{1}
# 0: symbol, 1: type
compiler.misc.overridden.default=\
method {0} is overridden in {2}
# 0: symbol, 1: symbol
compiler.misc.redundant.supertype=\
redundant interface {0} is extended by {1}
compiler.err.unclosed.char.lit=\
unclosed character literal
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that default methods don't cause ClassReader to complete classes recursively
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods pkg/Foo.java
* @compile ClassReaderTest.java
*/
abstract class ClassReaderTest implements pkg.Foo {}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg;
public interface Foo {
default void m1() { Impl.m1(this); }
default void m2() { Impl.m2(this); }
}
class Impl {
static void m1(Foo f) { }
static void m2(Foo f) { }
}
/*
* @test /nodynamiccopyright/
* @summary negative test for ambiguous defaults
* @compile/fail/ref=Neg01.out -XDallowDefaultMethods -XDrawDiagnostics Neg01.java
*/
class Neg01 {
interface IA { default int m() { return Neg01.m1(this); } }
interface IB { default int m() { return Neg01.m2(this); } }
static class A implements IA {}
static class B implements IB {}
static class AB implements IA, IB {}
static int m1(IA a) { return 0; }
static int m2(IB b) { return 0; }
}
Neg01.java:14:12: compiler.err.types.incompatible.unrelated.defaults: kindname.class, Neg01.AB, m, , Neg01.IA, Neg01.IB
1 error
/*
* @test /nodynamiccopyright/
* @summary check that ill-formed MI hierarchies do not compile
* @compile/fail/ref=Neg02.out -XDallowDefaultMethods -XDrawDiagnostics Neg02.java
*/
class Neg02 {
interface A {
default void m() { Neg02.impl(this); }
}
interface B {
default void m() { Neg02.impl(this); }
}
static class X implements A, B { } //error
void test(X x) {
x.m();
((A)x).m();
((B)x).m();
}
static void impl(A a) { }
static void impl(B b) { }
}
Neg02.java:16:13: compiler.err.types.incompatible.unrelated.defaults: kindname.class, Neg02.X, m, , Neg02.A, Neg02.B
1 error
/*
* @test /nodynamiccopyright/
* @summary check that re-abstraction works properly
* @compile/fail/ref=Neg03.out -XDallowDefaultMethods -XDrawDiagnostics Neg03.java
*/
class Neg03 {
interface A {
default void m() { Neg03.one(this); }
}
interface B {
default void m() { Neg03.two(this); }
}
interface C extends A, B {
default void m() { Neg03.one(this); }
}
static class X implements C, A { } //ok - ignore extraneous remix of A
interface D extends A, B {
void m(); // ok - m() is not reabstracted!
}
static class Y implements D, A { } // invalid - abstract D.m()
interface E extends A {
void m(); // reabstraction of m()
}
static class W implements D, E { } // invalid - abstracts D.m()/E.m()
static class Z implements D, A, B { } // invalid - abstract D.m()
static void one(Object a) { }
static void two(Object a) { }
}
Neg03.java:26:12: compiler.err.does.not.override.abstract: Neg03.Y, m(), Neg03.D
Neg03.java:32:12: compiler.err.does.not.override.abstract: Neg03.W, m(), Neg03.D
Neg03.java:34:12: compiler.err.does.not.override.abstract: Neg03.Z, m(), Neg03.D
3 errors
/*
* @test /nodynamiccopyright/
* @summary check that default method must have most specific return type
* @compile/fail/ref=Neg04.out -XDallowDefaultMethods -XDrawDiagnostics Neg04.java
*/
class Neg04 {
interface IA1 { Integer m(); }
interface IA2 extends IA1 { default Number m() { return Neg04.m(this); } } //error
abstract class C implements IA1, IA2 {}
static int m(IA2 a) { return 0; }
}
Neg04.java:9:48: compiler.err.override.incompatible.ret: (compiler.misc.clashes.with: m(), Neg04.IA2, m(), Neg04.IA1), java.lang.Number, java.lang.Integer
1 error
/*
* @test /nodynamiccopyright/
* @summary check that abstract methods are compatible with inherited defaults
* @compile/fail/ref=Neg05.out -XDallowDefaultMethods -XDrawDiagnostics Neg05.java
*/
class Neg05 {
interface IA1 { default Number m() { return Neg05.m1(this); } }
interface IA2 extends IA1 { default Integer m() { return Neg05.m2(this); } }
interface IA3 extends IA2 { Number m(); } //error
static class C implements IA3{}
static int m1(IA1 a) { return 0; }
static int m2(IA2 b) { return 0; }
}
Neg05.java:10:40: compiler.err.override.incompatible.ret: (compiler.misc.clashes.with: m(), Neg05.IA3, m(), Neg05.IA2), java.lang.Number, java.lang.Integer
Neg05.java:12:12: compiler.err.does.not.override.abstract: Neg05.C, m(), Neg05.IA3
2 errors
/*
* @test /nodynamiccopyright/
* @summary flow analysis is not run on inlined default bodies
* @compile/fail/ref=Neg06.out -XDallowDefaultMethods -XDrawDiagnostics Neg06.java
*/
class Neg06 {
interface A {
default String m() { C.m(); }
}
static class C {
static String m() { return ""; }
}
}
Neg06.java:10:37: compiler.err.missing.ret.stmt
1 error
/*
* @test /nodynamiccopyright/
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg07.out -XDallowDefaultMethods -XDrawDiagnostics Neg07.java
*/
class Neg07 {
interface I {
default int m() { return 1; }
}
static class C1 {
public void m() { } //incompatible return
}
static class C2 extends C1 implements I { }
static class C3 implements I {
public void m() { } //incompatible return
}
}
Neg07.java:16:12: compiler.err.override.incompatible.ret: (compiler.misc.cant.implement: m(), Neg07.C1, m(), Neg07.I), void, int
Neg07.java:19:21: compiler.err.override.incompatible.ret: (compiler.misc.cant.implement: m(), Neg07.C3, m(), Neg07.I), void, int
2 errors
/*
* @test /nodynamiccopyright/
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg08.out -XDallowDefaultMethods -XDrawDiagnostics Neg08.java
*/
class Neg08 {
interface I {
default void m() { }
}
static class C1 {
void m() { } //weaker modifier
}
static class C2 extends C1 implements I { }
static class C3 implements I {
void m() { } //weaker modifier
}
}
Neg08.java:15:12: compiler.err.override.weaker.access: (compiler.misc.cant.implement: m(), Neg08.C1, m(), Neg08.I), public
Neg08.java:18:14: compiler.err.override.weaker.access: (compiler.misc.cant.implement: m(), Neg08.C3, m(), Neg08.I), public
2 errors
/*
* @test /nodynamiccopyright/
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg09.out -Werror -Xlint:unchecked -XDallowDefaultMethods -XDrawDiagnostics Neg09.java
*/
import java.util.List;
class Neg09 {
interface I {
default List<String> m() { return null; }
}
static class C1 {
public List m() { return null; } //unchecked (return) override
}
static class C2 extends C1 implements I { }
static class C3 implements I {
public List m() { return null; } //unchecked (return) override
}
}
Neg09.java:17:12: compiler.warn.override.unchecked.ret: (compiler.misc.unchecked.implement: m(), Neg09.C1, m(), Neg09.I), java.util.List, java.util.List<java.lang.String>
Neg09.java:20:21: compiler.warn.override.unchecked.ret: (compiler.misc.unchecked.implement: m(), Neg09.C3, m(), Neg09.I), java.util.List, java.util.List<java.lang.String>
- compiler.err.warnings.and.werror
1 error
2 warnings
/*
* @test /nodynamiccopyright/
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg10.out -Werror -Xlint:unchecked -XDallowDefaultMethods -XDrawDiagnostics Neg10.java
*/
class Neg10 {
interface I<X extends Exception> {
default void m() throws X { }
}
static class C1 {
public void m() throws Exception { } //unchecked (throws) override
}
static class C2<Z extends Exception> extends C1 implements I<Z> { }
static class C3<Z extends Exception> implements I<Z> {
public void m() throws Exception { } //unchecked (throws) override
}
}
Neg10.java:15:12: compiler.warn.override.unchecked.thrown: (compiler.misc.cant.implement: m(), Neg10.C1, m(), Neg10.I), java.lang.Exception
Neg10.java:18:21: compiler.warn.override.unchecked.thrown: (compiler.misc.cant.implement: m(), Neg10.C3, m(), Neg10.I), java.lang.Exception
- compiler.err.warnings.and.werror
1 error
2 warnings
/*
* @test /nodynamiccopyright/
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg11.out -XDallowDefaultMethods -XDrawDiagnostics Neg11.java
*/
class Neg11 {
interface I {
default void m() { }
}
static class C1 {
public void m() throws Exception { } //bad throws
}
static class C2 extends C1 implements I { }
static class C3 implements I {
public void m() throws Exception { } //bad throws
}
}
Neg11.java:15:12: compiler.err.override.meth.doesnt.throw: (compiler.misc.cant.implement: m(), Neg11.C1, m(), Neg11.I), java.lang.Exception
Neg11.java:18:21: compiler.err.override.meth.doesnt.throw: (compiler.misc.cant.implement: m(), Neg11.C3, m(), Neg11.I), java.lang.Exception
2 errors
/*
* @test /nodynamiccopyright/
* @summary check that abstract methods are discarded in overload resolution diags
* @compile/fail/ref=Neg12.out -XDallowDefaultMethods -XDrawDiagnostics Neg12.java
*/
class Neg12 {
interface I1 {
default void m(String s) {};
}
interface I2 {
void m(String s);
}
static class B {
void m(Integer i) { }
}
static class C extends B implements I1 { }
static class D extends B implements I2 { }
void test(C c, D d) {
c.m();
d.m();
}
}
Neg12.java:21:12: compiler.err.does.not.override.abstract: Neg12.D, m(java.lang.String), Neg12.I2
Neg12.java:24:10: compiler.err.cant.apply.symbols: kindname.method, m, ,{(compiler.misc.inapplicable.method: kindname.method, Neg12.B, m(java.lang.Integer), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, Neg12.I1, m(java.lang.String), (compiler.misc.arg.length.mismatch))}
Neg12.java:25:10: compiler.err.cant.apply.symbol: kindname.method, m, java.lang.Integer, compiler.misc.no.args, kindname.class, Neg12.B, (compiler.misc.arg.length.mismatch)
3 errors
/*
* @test /nodynamiccopyright/
* @summary check that default method overriding object members are flagged as error
* @compile/fail/ref=Neg13.out -XDallowDefaultMethods -XDrawDiagnostics Neg13.java
*/
interface Neg13 {
default protected Object clone() { return null; } //protected not allowed here
default boolean equals(Object obj) { return false; }
default protected void finalize() { } //protected not allowed here
default Class<?> getClass() { return null; }
default int hashCode() { return 0; }
default void notify() { }
default void notifyAll() { }
default String toString() { return null; }
default void wait() { }
default void wait(long timeout) { }
default void wait(long timeout, int nanos) { }
}
Neg13.java:7:30: compiler.err.mod.not.allowed.here: protected
Neg13.java:9:28: compiler.err.mod.not.allowed.here: protected
Neg13.java:8:21: compiler.err.default.overrides.object.member: equals, kindname.interface, Neg13
Neg13.java:10:22: compiler.err.override.meth: (compiler.misc.cant.override: getClass(), Neg13, getClass(), java.lang.Object), final
Neg13.java:11:17: compiler.err.default.overrides.object.member: hashCode, kindname.interface, Neg13
Neg13.java:12:18: compiler.err.override.meth: (compiler.misc.cant.override: notify(), Neg13, notify(), java.lang.Object), final
Neg13.java:13:18: compiler.err.override.meth: (compiler.misc.cant.override: notifyAll(), Neg13, notifyAll(), java.lang.Object), final
Neg13.java:14:20: compiler.err.default.overrides.object.member: toString, kindname.interface, Neg13
Neg13.java:15:18: compiler.err.override.meth: (compiler.misc.cant.override: wait(), Neg13, wait(), java.lang.Object), final
Neg13.java:16:18: compiler.err.override.meth: (compiler.misc.cant.override: wait(long), Neg13, wait(long), java.lang.Object), final
Neg13.java:17:18: compiler.err.override.meth: (compiler.misc.cant.override: wait(long,int), Neg13, wait(long,int), java.lang.Object), final
11 errors
/*
* @test /nodynamiccopyright/
* @summary check that a class cannot have two sibling interfaces with a default and abstract method
* @compile/fail/ref=Neg14.out -XDallowDefaultMethods -XDrawDiagnostics Neg14.java
*/
class Neg14 {
interface IA { int m(); }
interface IB { default int m() { return 1; } }
abstract class AB implements IA, IB {}
}
Neg14.java:10:14: compiler.err.types.incompatible.abstract.default: kindname.class, Neg14.AB, m, , Neg14.IB, Neg14.IA
1 error
/*
* @test /nodynamiccopyright/
* @summary check that level skipping in default super calls is correctly rejected
* @compile/fail/ref=Neg15.out -XDallowDefaultMethods -XDrawDiagnostics Neg15.java
*/
class Neg15 {
interface I { default void m() { } }
interface J extends I { default void m() { } }
interface K extends I {}
static class C implements J, K {
void foo() { K.super.m(); }
}
}
Neg15.java:12:31: compiler.err.illegal.default.super.call: Neg15.K, (compiler.misc.overridden.default: m(), Neg15.J)
1 error
/*
* @test /nodynamiccopyright/
* @summary check that level skipping in default super calls is correctly rejected
* @compile/fail/ref=Neg16.out -XDallowDefaultMethods -XDrawDiagnostics Neg16.java
*/
class Neg16 {
interface I { default void m() { } }
interface J extends I { default void m() { } }
static class C implements I, J {
void foo() { I.super.m(); }
}
}
Neg16.java:11:23: compiler.err.illegal.default.super.call: Neg16.I, (compiler.misc.redundant.supertype: Neg16.I, Neg16.J)
1 error
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary basic test for default methods
* @ignore awaits lambda support
* @author Maurizio Cimadamore
* @compile -XDallowLambda -XDallowPoly -XDallowDefaultMethods Pos01.java
*/
import java.util.*;
class Pos01 {
interface Mapper<T> {
T map(T in);
}
interface ExtendedList<T> extends List<T> {
default List<T> testMap(Mapper<T> r) {
return Pos01.<T>listMapper(this, r);
}
}
static class MyList<E> extends ArrayList<E> implements ExtendedList<E> {}
public static void main(String[] args) {
MyList<Integer> l = new MyList<Integer>();
l.add(1); l.add(2); l.add(3);
l.testMap((Integer x) -> x * x );
}
static <T> List<T> listMapper(List<T> l, Mapper<T> mapper) {
MyList<T> new_list = new MyList<T>();
for (T el : l) {
new_list.add(mapper.map(el));
}
return new_list;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary test for explicit resolution of ambiguous default methods
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos02.java
*/
class Pos02 {
interface IA { default int m() { return Pos02.m1(this); } }
interface IB { default int m() { return Pos02.m2(this); } }
static class A implements IA {}
static class B implements IB {}
static class AB implements IA, IB {
public int m() { return 0; }
void test() {
AB.this.m();
IA.super.m();
}
}
static int m1(IA a) { return 0; }
static int m2(IB b) { return 0; }
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary test for overriding with default method
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos04.java
*/
class Pos04 {
interface A { default int m() { return Pos04.m(this); } }
static abstract class B { public int m() { return 0; } }
static class C extends B implements A {
void test() {
C.this.m();
A.super.m();
}
}
static int m(A a) { return 0; }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that indirectly inherited default methods are discovered during resolution
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos05.java
*/
class Pos05 {
interface A {
default void m() { Pos05.impl(this); }
}
interface B extends A { }
static class E implements B { }
void test(E e) {
e.m();
}
static void impl(A a) { }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that well-formed MI hierarchies behaves well w.r.t. method resolution (i.e. no ambiguities)
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos06.java
*/
class Pos06 {
interface A {
default void m() { Pos06.impl(this); }
}
interface B extends A {
default void m() { Pos06.impl(this); }
}
static class X implements A, B { }
void test(X x) {
x.m();
((A)x).m();
((B)x).m();
}
static void impl(Object a) { }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that compilation order does not matter
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos07.java
*/
class Pos07 {
interface A {
default void foo() { Pos07.impl(this); }
default void bar() { Pos07.impl(this); }
}
static class C implements B, A {}
interface B extends A {
default void foo() { Pos07.impl(this); }
}
static void impl(A a) {}
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that common overrider solves default method conflicts
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos08.java
*/
class Pos08 {
interface A {
default void m() { Pos08.a(this); }
}
interface B {
default void m() { Pos08.b(this); }
}
interface C extends A, B {
default void m() { Pos08.b(this); }
}
static void a(A o) { }
static void b(B o) { }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that type-variables in generic extension decl can be accessed from default impl
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods Pos10.java
*/
class Pos10 {
interface Function<X,Y> {
Y apply(X x);
}
interface A<T> {
default <R> void m(Function<T,R> f) { Impl.<T,R>m(this, f); }
}
static class Impl {
static <T,R> void m(A<T> a, Function<T,R> f) { }
}
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary complex test with conflict resolution via overriding
* @author Brian Goetz
* @compile -XDallowDefaultMethods Pos11.java
*/
class Pos11 {
interface A {
default void get() { Pos11.one(this); }
}
interface B {
default void get() { Pos11.two(this); }
}
interface C extends A {
default void get() { Pos11.two(this); }
}
interface D extends A, B {
default void get() { Pos11.two(this); }
}
static class X implements C { }
static class Y implements C, A { }
static class Z implements D, A, B { }
static void one(Object a) { }
static void two(Object a) { }
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that 'this' can be used from within an extension method
* @compile -XDallowDefaultMethods Pos12.java
*/
interface Pos12 {
default Object m() {
Object o = this;
f(this);
return this;
}
void f(Object o);
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary qualified 'this' inside default method causes StackOverflowException
* @compile -XDallowDefaultMethods Pos13.java
*/
public class Pos13 {
static int assertionCount = 0;
static void assertTrue(boolean cond) {
assertionCount++;
if (!cond)
throw new AssertionError();
}
interface Outer {
abstract void doSomething();
default void m() {
new SubOuter() {
public void doSomething() {
Outer.this.doSomething();
}
}.doSomething();
}
}
interface SubOuter extends Outer { }
static class E implements Outer {
public void doSomething() { assertTrue(true); }
}
public static void main(String[] args) {
new E().m();
assertTrue(assertionCount == 1);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that overload resolution selects most specific signature
* @compile -XDallowDefaultMethods Pos14.java
*/
class Pos14 {
interface A { default Object m() { return null; } }
static abstract class B { abstract public String m(); }
static abstract class C extends B implements A {
void test() {
m().length();
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that overload resolution selects most specific signature
* @compile -XDallowDefaultMethods Pos15.java
*/
class Pos15 {
interface A { default String m() { return null; } }
static abstract class B { abstract public Object m(); }
static abstract class C extends B implements A {
void test() {
m().length();
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary 'class wins' should not short-circuit overload resolution
* @compile -XDallowDefaultMethods Pos16.java
*/
class Pos16 {
interface I {
default String m(Integer i) { return ""; }
}
class C implements I {
Integer m(Object o) { return 1; }
}
void test(C c) {
c.m(1).length();
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @ignore awaits for VM support
* @summary check that code attributed for default methods is correctly generated
* @compile -XDallowDefaultMethods TestDefaultBody.java
* @run main TestDefaultBody
*/
import com.sun.tools.classfile.AccessFlags;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPool.*;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Method;
import com.sun.tools.classfile.Opcode;
import java.io.*;
public class TestDefaultBody {
interface TestInterface {
int no_default(int i);
default int yes_default(int i) { return impl(this, i); }
}
static int impl(TestInterface ti, int i) { return 0; }
static final String TARGET_CLASS_NAME = "TestDefaultBody";
static final String TARGET_NAME = "impl";
static final String TARGET_TYPE = "(LTestDefaultBody$TestInterface;I)I";
static final String SUBTEST_NAME = TestInterface.class.getName() + ".class";
static final String TEST_METHOD_NAME = "yes_default";
public static void main(String... args) throws Exception {
new TestDefaultBody().run();
}
public void run() throws Exception {
String workDir = System.getProperty("test.classes");
File compiledTest = new File(workDir, SUBTEST_NAME);
verifyDefaultBody(compiledTest);
}
void verifyDefaultBody(File f) {
System.err.println("verify: " + f);
try {
ClassFile cf = ClassFile.read(f);
Method testMethod = null;
Code_attribute codeAttr = null;
for (Method m : cf.methods) {
codeAttr = (Code_attribute)m.attributes.get(Attribute.Code);
String mname = m.getName(cf.constant_pool);
if (mname.equals(TEST_METHOD_NAME)) {
testMethod = m;
break;
} else {
codeAttr = null;
}
}
if (testMethod == null) {
throw new Error("Test method not found");
}
if (testMethod.access_flags.is(AccessFlags.ACC_ABSTRACT)) {
throw new Error("Test method is abstract");
}
if (codeAttr == null) {
throw new Error("Code attribute in test method not found");
}
boolean found = false;
for (Instruction instr : codeAttr.getInstructions()) {
if (instr.getOpcode() == Opcode.INVOKESTATIC) {
found = true;
int pc_index = instr.getShort(1);
CONSTANT_Methodref_info mref = (CONSTANT_Methodref_info)cf.constant_pool.get(pc_index);
String className = mref.getClassName();
String targetName = mref.getNameAndTypeInfo().getName();
String targetType = mref.getNameAndTypeInfo().getType();
if (!className.equals(TARGET_CLASS_NAME)) {
throw new Error("unexpected class in default method body " + className);
}
if (!targetName.equals(TARGET_NAME)) {
throw new Error("unexpected method name in default method body " + targetName);
}
if (!targetType.equals(TARGET_TYPE)) {
throw new Error("unexpected method type in default method body " + targetType);
}
break;
}
}
if (!found) {
throw new Error("no invokestatic found in default method body");
}
} catch (Exception e) {
e.printStackTrace();
throw new Error("error reading " + f +": " + e);
}
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @ignore awaits for VM support
* @summary check that javac does not generate bridge methods for defaults
* @compile -XDallowDefaultMethods TestNoBridgeOnDefaults.java
* @run main TestNoBridgeOnDefaults
*/
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPool.*;
import com.sun.tools.classfile.Method;
import java.io.*;
public class TestNoBridgeOnDefaults {
interface A<X> {
default <Y> A<X> m(X x, Y y) { return Impl.<X,Y>m1(this, x, y); }
}
static abstract class B<X> implements A<X> { }
interface C<X> extends A<X> {
default <Y> C<X> m(X x, Y y) { return Impl.<X,Y>m2(this, x, y); }
}
static abstract class D<X> extends B<X> implements C<X> { }
static class Impl {
static <X, Y> A<X> m1(A<X> rec, X x, Y y) { return null; }
static <X, Y> C<X> m2(C<X> rec, X x, Y y) { return null; }
}
static final String[] SUBTEST_NAMES = { B.class.getName() + ".class", D.class.getName() + ".class" };
static final String TEST_METHOD_NAME = "m";
public static void main(String... args) throws Exception {
new TestNoBridgeOnDefaults().run();
}
public void run() throws Exception {
String workDir = System.getProperty("test.classes");
for (int i = 0 ; i < SUBTEST_NAMES.length ; i ++) {
File compiledTest = new File(workDir, SUBTEST_NAMES[i]);
checkNoBridgeOnDefaults(compiledTest);
}
}
void checkNoBridgeOnDefaults(File f) {
System.err.println("check: " + f);
try {
ClassFile cf = ClassFile.read(f);
for (Method m : cf.methods) {
String mname = m.getName(cf.constant_pool);
if (mname.equals(TEST_METHOD_NAME)) {
throw new Error("unexpected bridge method found " + m);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new Error("error reading " + f +": " + e);
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
interface Clinit {
String s = Inner.m();
static class Inner {
static String m() { return ""; }
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check that clinit in interface doesn't cause spurious default method diagnostics
* @compile -source 1.4 -target 1.4 Clinit.java
* @compile CrossCompile.java
*/
class CrossCompile {
void test() {
String s = Clinit.s;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Automatic test for checking correctness of default resolution
*/
import shapegen.*;
import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class FDTest {
enum TestKind {
POSITIVE,
NEGATIVE;
Collection<Hierarchy> getHierarchy(HierarchyGenerator hg) {
return this == POSITIVE ?
hg.getOK() : hg.getErr();
}
}
public static void main(String[] args) throws Exception {
//create default shared JavaCompiler - reused across multiple compilations
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
HierarchyGenerator hg = new HierarchyGenerator();
for (TestKind tk : TestKind.values()) {
for (Hierarchy hs : tk.getHierarchy(hg)) {
new FDTest(tk, hs).run(comp, fm);
}
}
}
TestKind tk;
Hierarchy hs;
DefenderTestSource source;
DiagnosticChecker diagChecker;
FDTest(TestKind tk, Hierarchy hs) {
this.tk = tk;
this.hs = hs;
this.source = new DefenderTestSource();
this.diagChecker = new DiagnosticChecker();
}
void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
Arrays.asList("-XDallowDefaultMethods"), null, Arrays.asList(source));
try {
ct.analyze();
} catch (Throwable ex) {
throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
}
check();
}
void check() {
boolean errorExpected = tk == TestKind.NEGATIVE;
if (errorExpected != diagChecker.errorFound) {
throw new AssertionError("problem in source: \n" +
"\nerror found = " + diagChecker.errorFound +
"\nerror expected = " + errorExpected +
"\n" + dumpHierarchy() +
"\n" + source.getCharContent(true));
}
}
String dumpHierarchy() {
StringBuilder buf = new StringBuilder();
buf.append("root = " + hs.root + "\n");
for (ClassCase cc : hs.all) {
buf.append(" class name = " + cc.getName() + "\n");
buf.append(" class OK = " + cc.get_OK() + "\n");
buf.append(" prov = " + cc.get_mprov() + "\n");
}
return buf.toString();
}
class DefenderTestSource extends SimpleJavaFileObject {
String source;
public DefenderTestSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
StringBuilder buf = new StringBuilder();
List<ClassCase> defaultRef = new ArrayList<>();
for (ClassCase cc : hs.all) {
hs.genClassDef(buf, cc, null, defaultRef);
}
source = buf.toString();
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
boolean errorFound;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
errorFound = true;
}
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author Robert Field
*/
public class ClassCase {
public enum Kind {
IVAC (true, "v"),
IPRESENT (true, "p"),
IDEFAULT (true, "d"),
CNONE (false, "n"),
CABSTRACT (false, "a"),
CCONCRETE (false, "c");
private final String prefix;
public final boolean isInterface;
Kind(boolean isInterface, String prefix) {
this.isInterface = isInterface;
this.prefix = prefix;
}
}
public final Kind kind;
private final ClassCase superclass;
private final List<ClassCase> supertypes;
private String name;
private boolean _OK;
private boolean _HasClassMethod;
private Set<ClassCase> _mprov;
private boolean _IsConcrete;
private boolean _HasDefault;
private ClassCase _mres;
private ClassCase _mdefend;
private Set<RuleGroup> executed = new HashSet<RuleGroup>() {};
public ClassCase(Kind kind, ClassCase superclass, List<ClassCase> interfaces) {
this.kind = kind;
this.superclass = superclass;
// Set supertypes from superclass (if any) and interfaces
List<ClassCase> lc;
if (superclass == null) {
lc = interfaces;
} else {
lc = new ArrayList<>();
lc.add(superclass);
lc.addAll(interfaces);
}
this.supertypes = lc;
}
public final boolean isInterface() { return kind.isInterface; }
public final boolean isClass() { return !kind.isInterface; }
public Set<ClassCase> get_mprov() {
exec(RuleGroup.PROVENENCE);
return _mprov;
}
public void set_mprov(ClassCase cc) {
Set<ClassCase> s = new HashSet<>();
s.add(cc);
_mprov = s;
}
public void set_mprov(Set<ClassCase> s) {
_mprov = s;
}
public ClassCase get_mres() {
exec(RuleGroup.RESOLUTION);
return _mres;
}
public void set_mres(ClassCase cc) {
_mres = cc;
}
public ClassCase get_mdefend() {
exec(RuleGroup.DEFENDER);
return _mdefend;
}
public void set_mdefend(ClassCase cc) {
_mdefend = cc;
}
public boolean get_HasClassMethod() {
exec(RuleGroup.PROVENENCE);
return _HasClassMethod;
}
public void set_HasClassMethod(boolean bool) {
_HasClassMethod = bool;
}
public boolean get_HasDefault() {
exec(RuleGroup.MARKER);
return _HasDefault;
}
public void set_HasDefault(boolean bool) {
_HasDefault = bool;
}
public boolean get_IsConcrete() {
exec(RuleGroup.MARKER);
return _IsConcrete;
}
public void set_IsConcrete(boolean bool) {
_IsConcrete = bool;
}
public boolean get_OK() {
exec(RuleGroup.CHECKING);
return _OK;
}
public void set_OK(boolean bool) {
_OK = bool;
}
public boolean isMethodDefined() {
for (ClassCase cc : supertypes) {
if (cc.isMethodDefined()) {
return true;
}
}
switch (kind) {
case CCONCRETE:
case CABSTRACT:
case IPRESENT:
case IDEFAULT:
return true;
default:
return false;
}
}
public boolean isAbstract() {
return isMethodDefined() && (get_mres()==null);
}
public boolean hasSuperclass() {
return superclass != null;
}
public ClassCase getSuperclass() {
return superclass;
}
public List<ClassCase> getSupertypes() {
return supertypes;
}
public List<ClassCase> getInterfaces() {
if (superclass != null) {
if (supertypes.get(0) != superclass) {
throw new AssertionError("superclass missing from supertypes");
}
return supertypes.subList(1, supertypes.size());
} else {
return supertypes;
}
}
public boolean isSubtypeOf(ClassCase cc) {
// S-Refl
if (cc.equals(this)) {
return true;
}
// S-Def
for (ClassCase sp : getSupertypes()) {
if (cc.equals(sp)) {
return true;
}
}
// _S-Trans
for (ClassCase sp : getSupertypes()) {
if (sp.isSubtypeOf(cc)) {
return true;
}
}
return false;
}
public void init(Map<String, Integer> namingContext) {
if (name != null) {
return; // Already inited
}
for (ClassCase sup : supertypes) {
sup.init(namingContext);
}
// Build name
StringBuilder sb = new StringBuilder();
if (!supertypes.isEmpty()) {
sb.append(isInterface() ? "I" : "C");
for (ClassCase cc : supertypes) {
sb.append(cc.getName());
}
sb.append(kind.isInterface ? "i" : "c");
}
sb.append(kind.prefix);
String pname = sb.toString();
Integer icnt = namingContext.get(pname);
int cnt = icnt == null ? 0 : icnt;
++cnt;
namingContext.put(pname, cnt);
if (cnt > 1) {
sb.append(cnt);
}
this.name = sb.toString();
}
public boolean isa(Kind... kinds) {
for (Kind k : kinds) {
if (kind == k) {
return true;
}
}
return false;
}
private void exec(RuleGroup rg ) {
if (!executed.contains(rg)) {
rg.exec(this);
executed.add(rg);
}
}
public void collectClasses(Set<ClassCase> seen) {
seen.add(this);
for (ClassCase cc : supertypes) {
cc.collectClasses(seen);
}
}
public String getID() {
if (name == null) {
throw new Error("Access to uninitialized ClassCase");
} else {
return name;
}
}
public final String getName() {
if (name == null) {
return "ClassCase uninited@" + hashCode();
} else {
return name;
}
}
@Override
public boolean equals(Object obj) {
return obj instanceof ClassCase && getID().equals(((ClassCase)obj).getID());
}
@Override
public int hashCode() {
return getID().hashCode();
}
@Override
public String toString() {
return getName();
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import static shapegen.ClassCase.Kind.*;
/**
*
* @author Robert Field
*/
public class Hierarchy {
public final ClassCase root;
public final Set<ClassCase> all;
public Hierarchy(ClassCase root) {
this.root = root;
root.init(new HashMap<String,Integer>());
Set<ClassCase> allClasses = new HashSet<>();
root.collectClasses(allClasses);
this.all = allClasses;
}
public boolean anyDefaults() {
for (ClassCase cc : all) {
if (cc.kind == IDEFAULT) {
return true;
}
}
return false;
}
public boolean get_OK() {
return root.get_OK();
}
public String testName() {
return root + "Test";
}
private static void genInterfaceList(StringBuilder buf, String prefix, List<ClassCase> interfaces) {
if (!interfaces.isEmpty()) {
buf.append(" ");
buf.append(prefix);
buf.append(" ");
buf.append(interfaces.get(0));
for (int i = 1; i < interfaces.size(); ++i) {
buf.append(", " + interfaces.get(i));
}
}
}
public static void genClassDef(StringBuilder buf, ClassCase cc, String implClass, List<ClassCase> defaultRef) {
if (cc.isInterface()) {
buf.append("interface ");
buf.append(cc.getName() + " ");
genInterfaceList(buf, "extends", cc.getInterfaces());
buf.append(" {\n");
switch (cc.kind) {
case IDEFAULT:
buf.append(" default String m() { return \"\"; }\n");
defaultRef.add(cc);
break;
case IPRESENT:
buf.append(" String m();\n");
break;
case IVAC:
break;
default:
throw new AssertionError("Unexpected kind");
}
buf.append("}\n\n");
} else {
buf.append((cc.isAbstract()? "abstract " : ""));
buf.append(" class " + cc.getName());
if (cc.getSuperclass() != null) {
buf.append(" extends " + cc.getSuperclass());
}
genInterfaceList(buf, "implements", cc.getInterfaces());
buf.append(" {\n");
switch (cc.kind) {
case CCONCRETE:
buf.append(" public String m() { return \"\"; }\n");
break;
case CABSTRACT:
buf.append(" public abstract String m();\n");
break;
case CNONE:
break;
default:
throw new AssertionError("Unexpected kind");
}
buf.append("}\n\n");
}
}
@Override
public boolean equals(Object obj) {
return obj instanceof Hierarchy && root.getID().equals(((Hierarchy)obj).root.getID());
}
@Override
public int hashCode() {
return root.getID().hashCode();
}
@Override
public String toString() {
return root.getName();
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import shapegen.ClassCase.Kind;
import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import static shapegen.ClassCase.Kind.*;
import static java.lang.Math.pow;
/**
*
* @author Robert Field
*/
public final class HierarchyGenerator {
private static int okcnt = 0;
private static int errcnt = 0;
private static Set<Hierarchy> uniqueOK = new HashSet<>();
private static Set<Hierarchy> uniqueErr = new HashSet<>();
/**
* @param args the command line arguments
*/
public HierarchyGenerator() {
organize("exhaustive interface", iExhaustive(2));
organize("exhaustive class", cExhaustive());
organize("shapes interface", iShapes());
organize("shapes class/interface", ciShapes());
System.out.printf("\nExpect OK: %d -- unique %d", okcnt, uniqueOK.size());
System.out.printf("\nExpect Error: %d -- unique %d\n", errcnt, uniqueErr.size());
}
public Collection<Hierarchy> getOK() {
return uniqueOK;
}
public Collection<Hierarchy> getErr() {
return uniqueErr;
}
private void organize(String tname, List<Hierarchy> totest) {
System.out.printf("\nTesting %s....\n", tname);
int nodefault = 0;
List<Hierarchy> ok = new ArrayList<>();
List<Hierarchy> err = new ArrayList<>();
for (Hierarchy cc : totest) {
if (cc.anyDefaults()) {
//System.out.printf(" %s\n", cc);
if (cc.get_OK()) {
ok.add(cc);
} else {
err.add(cc);
}
} else {
++nodefault;
}
}
errcnt += err.size();
okcnt += ok.size();
uniqueErr.addAll(err);
uniqueOK.addAll(ok);
System.out.printf(" %5d No default\n %5d Error\n %5d OK\n %5d Total\n",
nodefault, err.size(), ok.size(), totest.size());
}
public List<Hierarchy> iExhaustive(int idepth) {
List<ClassCase> current = new ArrayList<>();
for (int i = 0; i < idepth; ++i) {
current = ilayer(current);
}
return wrapInClassAndHierarchy(current);
}
private List<ClassCase> ilayer(List<ClassCase> srcLayer) {
List<ClassCase> lay = new ArrayList<>();
for (int i = (int) pow(2, srcLayer.size()) - 1; i >= 0; --i) {
List<ClassCase> itfs = new ArrayList<>();
for (int b = srcLayer.size() - 1; b >= 0; --b) {
if ((i & (1<<b)) != 0) {
itfs.add(srcLayer.get(b));
}
}
lay.add(new ClassCase(IVAC, null, itfs));
lay.add(new ClassCase(IPRESENT, null, itfs));
lay.add(new ClassCase(IDEFAULT, null, itfs));
lay.add(new ClassCase(IDEFAULT, null, itfs));
}
return lay;
}
public List<Hierarchy> cExhaustive() {
final Kind[] iKinds = new Kind[]{IDEFAULT, IVAC, IPRESENT, null};
final Kind[] cKinds = new Kind[]{CNONE, CABSTRACT, CCONCRETE};
List<Hierarchy> totest = new ArrayList<>();
for (int i1 = 0; i1 < iKinds.length; ++i1) {
for (int i2 = 0; i2 < iKinds.length; ++i2) {
for (int i3 = 0; i3 < iKinds.length; ++i3) {
for (int c1 = 0; c1 < cKinds.length; ++c1) {
for (int c2 = 0; c2 < cKinds.length; ++c2) {
for (int c3 = 0; c3 < cKinds.length; ++c3) {
totest.add( new Hierarchy(
new ClassCase(cKinds[c1],
new ClassCase(cKinds[c2],
new ClassCase(cKinds[c3],
null,
iList(iKinds[i1])
),
iList(iKinds[i2])
),
iList(iKinds[i3])
)));
}
}
}
}
}
}
return totest;
}
private List<ClassCase> iList(Kind kind) {
if (kind == null) {
return Collections.EMPTY_LIST;
} else {
List<ClassCase> itfs = new ArrayList<>();
itfs.add(new ClassCase(kind, null, Collections.EMPTY_LIST));
return itfs;
}
}
public List<Hierarchy> ciShapes() {
return wrapInHierarchy(TTShape.allCases(true));
}
public List<Hierarchy> iShapes() {
return wrapInClassAndHierarchy(TTShape.allCases(false));
}
public List<Hierarchy> wrapInClassAndHierarchy(List<ClassCase> ihs) {
List<Hierarchy> totest = new ArrayList<>();
for (ClassCase cc : ihs) {
List<ClassCase> interfaces = new ArrayList<>();
interfaces.add(cc);
totest.add(new Hierarchy(new ClassCase(CNONE, null, interfaces)));
}
return totest;
}
public List<Hierarchy> wrapInHierarchy(List<ClassCase> ihs) {
List<Hierarchy> totest = new ArrayList<>();
for (ClassCase cc : ihs) {
totest.add(new Hierarchy(cc));
}
return totest;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
/**
*
* @author Robert Field
*/
public abstract class Rule {
public final String name;
public Rule(String name) {
this.name = name;
}
abstract boolean guard(ClassCase cc);
abstract void eval(ClassCase cc);
@Override
public String toString() {
return name;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import java.util.HashSet;
import java.util.Set;
import static shapegen.ClassCase.Kind.*;
/**
*
* @author Robert Field
*/
public class RuleGroup {
final String name;
private final Rule[] rules;
public RuleGroup(String name, Rule[] rules) {
this.name = name;
this.rules = rules;
}
public boolean exec(ClassCase cc) {
boolean found = false;
for (Rule rule : rules) {
if (rule.guard(cc)) {
if (found) {
throw new RuntimeException("Bad rules -- multiple matches " + toString() + " for " + cc);
} else {
rule.eval(cc);
found = true;
}
}
}
return found;
}
@Override
public String toString() {
return name;
}
public static RuleGroup PROVENENCE = new RuleGroup("Provenence", new Rule[] {
new Rule("P-CDeclare") {
boolean guard(ClassCase cc) {
return cc.isa(CCONCRETE, CABSTRACT);
}
void eval(ClassCase cc) {
cc.set_mprov(cc);
cc.set_HasClassMethod(true);
}
},
new Rule("P-IDeclare") {
boolean guard(ClassCase cc) {
return cc.isa(IDEFAULT, IPRESENT);
}
void eval(ClassCase cc) {
cc.set_mprov(cc);
}
},
new Rule("P-IntfInh") {
boolean guard(ClassCase cc) {
return cc.isa(IVAC, CNONE) && !(cc.hasSuperclass() && cc.getSuperclass().get_HasClassMethod());
}
void eval(ClassCase cc) {
Set<ClassCase> _S = new HashSet<>();
for (ClassCase t : cc.getSupertypes()) {
_S.addAll(t.get_mprov());
}
Set<ClassCase> tops = new HashSet<>();
for (ClassCase _W : _S) {
for (ClassCase _V : _S) {
if (_V.equals(_W) || !(_V.isSubtypeOf(_W))) {
tops.add(_W);
}
}
}
cc.set_mprov(tops);
}
},
new Rule("P-ClassInh") {
boolean guard(ClassCase cc) {
return cc.isa(CNONE) && (cc.hasSuperclass() && cc.getSuperclass().get_HasClassMethod());
}
void eval(ClassCase cc) {
cc.set_mprov(cc.getSuperclass());
cc.set_HasClassMethod(true);
}
},
});
public static RuleGroup MARKER = new RuleGroup("Marker", new Rule[] {
new Rule("M-Default") {
boolean guard(ClassCase cc) {
return cc.isa(IDEFAULT);
}
void eval(ClassCase cc) {
cc.set_HasDefault(true);
}
},
new Rule("M-Conc") {
boolean guard(ClassCase cc) {
return cc.isa(CCONCRETE);
}
void eval(ClassCase cc) {
cc.set_IsConcrete(true);
}
},
});
public static RuleGroup RESOLUTION = new RuleGroup("Resolution", new Rule[] {
new Rule("R-Resolve") {
boolean guard(ClassCase cc) {
if (!(cc.isClass() && cc.get_mprov().size() == 1)) {
return false;
}
ClassCase _V = cc.get_mprov().iterator().next();
return _V.get_IsConcrete() || _V.get_HasDefault();
}
void eval(ClassCase cc) {
ClassCase _V = cc.get_mprov().iterator().next();
cc.set_mres(_V);
}
},
});
public static RuleGroup DEFENDER = new RuleGroup("Defender", new Rule[] {
new Rule("D-Defend") {
boolean guard(ClassCase cc) {
ClassCase mresSuper = cc.hasSuperclass() ? cc.getSuperclass().get_mres() : null;
boolean eq = cc.get_mres() == null ? mresSuper == null : cc.get_mres().equals(mresSuper);
return cc.isa(CNONE) && !eq;
}
void eval(ClassCase cc) {
cc.set_mdefend(cc.get_mres());
}
},
});
public static RuleGroup CHECKING = new RuleGroup("Checking", new Rule[] {
new Rule("C-Check") {
boolean guard(ClassCase cc) {
for (ClassCase t : cc.getSupertypes()) {
if (! t.get_OK()) {
return false;
}
}
int defenderCount = 0;
int provCount = 0;
for (ClassCase prov : cc.get_mprov()) {
if (prov.get_HasDefault()) {
defenderCount++;
}
provCount++;
}
return provCount <= 1 || defenderCount == 0;
}
void eval(ClassCase cc) {
cc.set_OK(true);
}
},
});
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import shapegen.ClassCase.Kind;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static shapegen.ClassCase.Kind.*;
/**
* Type Template Node
*
* @author Robert Field
*/
public class TTNode {
final List<TTNode> supertypes;
final boolean canBeClass;
private int currentKindIndex;
private Kind[] kinds;
public TTNode(List<TTNode> subtypes, boolean canBeClass) {
this.supertypes = subtypes;
this.canBeClass = canBeClass;
}
public void start(boolean includeClasses) {
kinds =
supertypes.isEmpty()?
(new Kind[]{IDEFAULT, IPRESENT})
: ((includeClasses && canBeClass)?
new Kind[]{CNONE, IVAC, IDEFAULT, IPRESENT}
: new Kind[]{IVAC, IDEFAULT, IPRESENT});
currentKindIndex = 0;
for (TTNode sub : supertypes) {
sub.start(includeClasses);
}
}
public boolean next() {
++currentKindIndex;
if (currentKindIndex >= kinds.length) {
currentKindIndex = 0;
return false;
} else {
return true;
}
}
public void collectAllSubtypes(Set<TTNode> subs) {
subs.add(this);
for (TTNode n : supertypes) {
n.collectAllSubtypes(subs);
}
}
private Kind getKind() {
return kinds[currentKindIndex];
}
boolean isInterface() {
return getKind().isInterface;
}
boolean isClass() {
return !isInterface();
}
boolean hasDefault() {
return getKind() == IDEFAULT;
}
public boolean isValid() {
for (TTNode n : supertypes) {
if (!n.isValid() || (isInterface() && n.isClass())) {
return false;
}
}
return true;
}
public ClassCase genCase() {
ClassCase subclass;
List<TTNode> ttintfs;
if (isClass() && !supertypes.isEmpty() && supertypes.get(0).isClass()) {
subclass = supertypes.get(0).genCase();
ttintfs = supertypes.subList(1, supertypes.size());
} else {
subclass = null;
ttintfs = supertypes;
}
List<ClassCase> intfs = new ArrayList<>();
for (TTNode node : ttintfs) {
intfs.add(node.genCase());
}
return new ClassCase(getKind(), subclass, intfs);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.io.StringReader;
import static java.lang.Character.isLetter;
import static java.lang.Character.isUpperCase;
import static java.lang.Character.isWhitespace;
/**
* Parse a type template definition string
*
* input :: classDef
* classDef :: letter [ ( classDef* ) ]
*
* @author Robert Field
*/
public class TTParser extends StringReader {
private Map<Character, TTNode> letterMap = new HashMap<>();
private char ch;
private final String def;
public TTParser(String s) {
super(s);
this.def = s;
}
private void advance() throws IOException {
do {
ch = (char)read();
} while (isWhitespace(ch));
}
public TTNode parse() {
try {
advance();
return classDef();
} catch (IOException t) {
throw new RuntimeException(t);
}
}
private TTNode classDef() throws IOException {
if (!isLetter(ch)) {
if (ch == (char)-1) {
throw new IOException("Unexpected end of type template in " + def);
} else {
throw new IOException("Unexpected character in type template: " + (Character)ch + " in " + def);
}
}
char nodeCh = ch;
TTNode node = letterMap.get(nodeCh);
boolean canBeClass = isUpperCase(nodeCh);
advance();
if (node == null) {
List<TTNode> subtypes = new ArrayList<>();
if (ch == '(') {
advance();
while (ch != ')') {
subtypes.add(classDef());
}
advance();
}
node = new TTNode(subtypes, canBeClass);
letterMap.put(nodeCh, node);
}
return node;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package shapegen;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
* @author Robert Field
*/
public class TTShape {
private final TTNode root;
private final TTNode[] nodes;
TTShape(TTNode root) {
this.root = root;
Set<TTNode> subs = new HashSet<>();
root.collectAllSubtypes(subs);
nodes = subs.toArray(new TTNode[subs.size()]);
}
private List<ClassCase> toCases(boolean includeClasses) {
List<ClassCase> ccs = new ArrayList<>();
root.start(includeClasses);
int i;
outer:
while (true) {
if (root.isValid()) {
ClassCase cc = root.genCase();
//System.out.println(cc);
ccs.add(cc);
}
i = 0;
do {
if (i >= nodes.length) {
break outer;
}
} while(!nodes[i++].next());
}
return ccs;
}
public static List<ClassCase> allCases(boolean includeClasses) {
List<ClassCase> ccs = new ArrayList<>();
for (TTShape shape : SHAPES) {
ccs.addAll(shape.toCases(includeClasses));
}
return ccs;
}
public static TTShape parse(String s) {
return new TTShape(new TTParser(s).parse());
}
public static final TTShape[] SHAPES = new TTShape[] {
parse("a"),
parse("a(b)"),
parse("A(bb)"),
parse("A(B(d)c(d))"),
parse("A(b(c))"),
parse("A(B(cd)d)"),
parse("A(B(c)c)"),
parse("A(B(Ce)d(e))"),
parse("A(B(C)d(e))"),
parse("A(Bc(d))"),
parse("A(B(d)dc)"),
parse("A(B(dc)dc)"),
parse("A(B(c(d))d)"),
parse("A(B(C(d))d)"),
parse("A(B(C(e)d(e))e)"),
parse("A(B(c(d))c)"),
parse("A(B(dc(d))c)"),
parse("A(B(C(d))d)"),
};
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary smoke test for separate compilation of default methods
* @author Maurizio Cimadamore
* @compile -XDallowDefaultMethods pkg1/A.java
* @compile -XDallowDefaultMethods Separate.java
*/
import pkg1.A;
class Separate {
interface B extends A.I {
default void m() { A.m(this); }
}
interface C extends A.I, B { }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg1;
public class A {
public interface I {
default void m() { A.m(this); }
}
public static void m(Object o) {}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Automatic test for checking correctness of default super/this resolution
*/
import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class TestDefaultSuperCall {
static int checkCount = 0;
enum InterfaceKind {
DEFAULT("interface A extends B { default void m() { } }"),
ABSTRACT("interface A extends B { void m(); }"),
NONE("interface A extends B { }");
String interfaceStr;
InterfaceKind(String interfaceStr) {
this.interfaceStr = interfaceStr;
}
boolean methodDefined() {
return this == DEFAULT;
}
}
enum PruneKind {
NO_PRUNE("interface C { }"),
PRUNE("interface C extends A { }");
boolean methodDefined(InterfaceKind ik) {
return this == PRUNE &&
ik.methodDefined();
}
String interfaceStr;
PruneKind(String interfaceStr) {
this.interfaceStr = interfaceStr;
}
}
enum QualifierKind {
DIRECT_1("C"),
DIRECT_2("A"),
INDIRECT("B"),
UNRELATED("E"),
ENCLOSING_1(null),
ENCLOSING_2(null);
String qualifierStr;
QualifierKind(String qualifierStr) {
this.qualifierStr = qualifierStr;
}
String getQualifier(Shape sh) {
switch (this) {
case ENCLOSING_1: return sh.enclosingAt(0);
case ENCLOSING_2: return sh.enclosingAt(1);
default:
return qualifierStr;
}
}
boolean isEnclosing() {
return this == ENCLOSING_1 ||
this == ENCLOSING_2;
}
boolean allowSuperCall(InterfaceKind ik, PruneKind pk) {
switch (this) {
case DIRECT_1:
return pk.methodDefined(ik);
case DIRECT_2:
return ik.methodDefined() && pk == PruneKind.NO_PRUNE;
default:
return false;
}
}
}
enum ExprKind {
THIS("this"),
SUPER("super");
String exprStr;
ExprKind(String exprStr) {
this.exprStr = exprStr;
}
}
enum ElementKind {
INTERFACE("interface #N { #B }", true),
INTERFACE_EXTENDS("interface #N extends A, C { #B }", true),
CLASS("class #N { #B }", false),
CLASS_EXTENDS("abstract class #N implements A, C { #B }", false),
STATIC_CLASS("static class #N { #B }", true),
STATIC_CLASS_EXTENDS("abstract static class #N implements A, C { #B }", true),
ANON_CLASS("new Object() { #B };", false),
METHOD("void test() { #B }", false),
STATIC_METHOD("static void test() { #B }", true),
DEFAULT_METHOD("default void test() { #B }", false);
String templateDecl;
boolean isStatic;
ElementKind(String templateDecl, boolean isStatic) {
this.templateDecl = templateDecl;
this.isStatic = isStatic;
}
boolean isClassDecl() {
switch(this) {
case METHOD:
case STATIC_METHOD:
case DEFAULT_METHOD:
return false;
default:
return true;
}
}
boolean isAllowedEnclosing(ElementKind ek, boolean isTop) {
switch (this) {
case CLASS:
case CLASS_EXTENDS:
//class is implicitly static inside interface, so skip this combo
return ek.isClassDecl() &&
ek != INTERFACE && ek != INTERFACE_EXTENDS;
case ANON_CLASS:
return !ek.isClassDecl();
case METHOD:
return ek == CLASS || ek == CLASS_EXTENDS ||
ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS ||
ek == ANON_CLASS;
case INTERFACE:
case INTERFACE_EXTENDS:
case STATIC_CLASS:
case STATIC_CLASS_EXTENDS:
case STATIC_METHOD:
return (isTop && (ek == CLASS || ek == CLASS_EXTENDS)) ||
ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS;
case DEFAULT_METHOD:
return ek == INTERFACE || ek == INTERFACE_EXTENDS;
default:
throw new AssertionError("Bad enclosing element kind" + this);
}
}
boolean isAllowedTop() {
switch (this) {
case CLASS:
case CLASS_EXTENDS:
case INTERFACE:
case INTERFACE_EXTENDS:
return true;
default:
return false;
}
}
boolean hasSuper() {
return this == INTERFACE_EXTENDS ||
this == STATIC_CLASS_EXTENDS ||
this == CLASS_EXTENDS;
}
}
static class Shape {
String shapeStr;
List<ElementKind> enclosingElements;
List<String> enclosingNames;
List<String> elementsWithMethod;
Shape(ElementKind... elements) {
System.err.println("elements = " + Arrays.toString(elements));
enclosingElements = new ArrayList<>();
enclosingNames = new ArrayList<>();
elementsWithMethod = new ArrayList<>();
int count = 0;
String prevName = null;
for (ElementKind ek : elements) {
String name = "name"+count++;
if (ek.isStatic) {
enclosingElements = new ArrayList<>();
enclosingNames = new ArrayList<>();
}
if (ek.isClassDecl()) {
enclosingElements.add(ek);
enclosingNames.add(name);
} else {
elementsWithMethod.add(prevName);
}
String element = ek.templateDecl.replaceAll("#N", name);
shapeStr = shapeStr == null ? element : shapeStr.replaceAll("#B", element);
prevName = name;
}
}
String getShape(QualifierKind qk, ExprKind ek) {
String methName = ek == ExprKind.THIS ? "test" : "m";
String call = qk.getQualifier(this) + "." + ek.exprStr + "." + methName + "();";
return shapeStr.replaceAll("#B", call);
}
String enclosingAt(int index) {
return index < enclosingNames.size() ? enclosingNames.get(index) : "BAD";
}
}
public static void main(String... args) throws Exception {
//create default shared JavaCompiler - reused across multiple compilations
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
for (InterfaceKind ik : InterfaceKind.values()) {
for (PruneKind pk : PruneKind.values()) {
for (ElementKind ek1 : ElementKind.values()) {
if (!ek1.isAllowedTop()) continue;
for (ElementKind ek2 : ElementKind.values()) {
if (!ek2.isAllowedEnclosing(ek1, true)) continue;
for (ElementKind ek3 : ElementKind.values()) {
if (!ek3.isAllowedEnclosing(ek2, false)) continue;
for (ElementKind ek4 : ElementKind.values()) {
if (!ek4.isAllowedEnclosing(ek3, false)) continue;
for (ElementKind ek5 : ElementKind.values()) {
if (!ek5.isAllowedEnclosing(ek4, false) || ek5.isClassDecl()) continue;
for (QualifierKind qk : QualifierKind.values()) {
for (ExprKind ek : ExprKind.values()) {
new TestDefaultSuperCall(ik, pk, new Shape(ek1, ek2, ek3, ek4, ek5), qk, ek).run(comp, fm);
}
}
}
}
}
}
}
}
}
System.out.println("Total check executed: " + checkCount);
}
InterfaceKind ik;
PruneKind pk;
Shape sh;
QualifierKind qk;
ExprKind ek;
JavaSource source;
DiagnosticChecker diagChecker;
TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh, QualifierKind qk, ExprKind ek) {
this.ik = ik;
this.pk = pk;
this.sh = sh;
this.qk = qk;
this.ek = ek;
this.source = new JavaSource();
this.diagChecker = new DiagnosticChecker();
}
class JavaSource extends SimpleJavaFileObject {
String template = "interface E {}\n" +
"interface B { }\n" +
"#I\n" +
"#P\n" +
"#C";
String source;
public JavaSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
source = template.replaceAll("#I", ik.interfaceStr)
.replaceAll("#P", pk.interfaceStr)
.replaceAll("#C", sh.getShape(qk, ek));
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
Arrays.asList("-XDallowDefaultMethods"), null, Arrays.asList(source));
try {
ct.analyze();
} catch (Throwable ex) {
throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
}
check();
}
void check() {
boolean errorExpected = false;
boolean badEnclosing = false;
boolean badThis = false;
boolean badSuper = false;
if (qk == QualifierKind.ENCLOSING_1 &&
sh.enclosingNames.size() < 1) {
errorExpected |= true;
badEnclosing = true;
}
if (qk == QualifierKind.ENCLOSING_2 &&
sh.enclosingNames.size() < 2) {
errorExpected |= true;
badEnclosing = true;
}
if (ek == ExprKind.THIS) {
boolean found = false;
for (int i = 0; i < sh.enclosingElements.size(); i++) {
if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue;
if (sh.enclosingNames.get(i).equals(qk.getQualifier(sh))) {
found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i));
break;
}
}
errorExpected |= !found;
if (!found) {
badThis = true;
}
}
if (ek == ExprKind.SUPER) {
int lastIdx = sh.enclosingElements.size() - 1;
boolean found = lastIdx == -1 ? false :
sh.enclosingElements.get(lastIdx).hasSuper() && qk.allowSuperCall(ik, pk);
errorExpected |= !found;
if (!found) {
badSuper = true;
}
}
checkCount++;
if (diagChecker.errorFound != errorExpected) {
throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
"\nenclosingElems: " + sh.enclosingElements +
"\nenclosingNames: " + sh.enclosingNames +
"\nelementsWithMethod: " + sh.elementsWithMethod +
"\nbad encl: " + badEnclosing +
"\nbad this: " + badThis +
"\nbad super: " + badSuper +
"\nqual kind: " + qk +
"\nfound error: " + diagChecker.errorFound);
}
}
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
boolean errorFound;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
System.err.println(diagnostic.getMessage(Locale.getDefault()));
errorFound = true;
}
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.default.overrides.object.member
// options: -XDallowDefaultMethods
interface DefaultOverridesObjectMember {
default String toString() { return ""; }
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.illegal.default.super.call
// key: compiler.misc.overridden.default
// options: -XDallowDefaultMethods
class OverriddenDefault {
interface I { default void m() { } }
interface J extends I { default void m() { } }
interface K extends I {}
static class C implements J, K {
void foo() { K.super.m(); }
}
}
\ No newline at end of file
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.illegal.default.super.call
// key: compiler.misc.redundant.supertype
// options: -XDallowDefaultMethods
class RedundantSupertype {
interface I { default void m() { } }
interface J extends I { default void m() { } }
static class C implements I, J {
void foo() { I.super.m(); }
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.types.incompatible.abstract.default
// options: -XDallowDefaultMethods
class TypesIncompatibleAbstractDefault {
interface A {
default void m() { }
}
interface B {
void m();
}
interface AB extends A, B { }
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.types.incompatible.unrelated.defaults
// options: -XDallowDefaultMethods
class TypesIncompatibleUnrelatedDefaults {
interface A {
default void m() { }
}
interface B {
default void m() { }
}
interface AB extends A, B { }
}
......@@ -26,7 +26,8 @@
* @bug 7022054
*
* @summary Invalid compiler error on covariant overriding methods with the same erasure
* @compile T7022054pos1.java
* @compile -source 7 T7022054pos1.java
* @compile/fail -XDstrictMethodClashCheck T7022054pos1.java
*
*/
......
......@@ -26,8 +26,8 @@
* @bug 7022054
*
* @summary Invalid compiler error on covariant overriding methods with the same erasure
* @compile T7022054pos2.java
*
* @compile -source 7 T7022054pos2.java
* @compile/fail -XDstrictMethodClashCheck T7022054pos2.java
*/
class T7022054pos2 {
......
......@@ -30,6 +30,7 @@
import java.io.File;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
......@@ -43,13 +44,15 @@ public class EagerInterfaceCompletionTest {
JavaCompiler javacTool;
File testDir;
VersionKind versionKind;
HierarchyKind hierarchyKind;
TestKind testKind;
ActionKind actionKind;
EagerInterfaceCompletionTest(JavaCompiler javacTool, File testDir,
EagerInterfaceCompletionTest(JavaCompiler javacTool, File testDir, VersionKind versionKind,
HierarchyKind hierarchyKind, TestKind testKind, ActionKind actionKind) {
this.javacTool = javacTool;
this.versionKind = versionKind;
this.hierarchyKind = hierarchyKind;
this.testDir = testDir;
this.testKind = testKind;
......@@ -62,7 +65,7 @@ public class EagerInterfaceCompletionTest {
actionKind.doAction(this);
DiagnosticChecker dc = new DiagnosticChecker();
compile(dc, testKind.source);
if (testKind.completionFailure(actionKind, hierarchyKind) != dc.errorFound) {
if (testKind.completionFailure(versionKind, actionKind, hierarchyKind) != dc.errorFound) {
if (dc.errorFound) {
error("Unexpected completion failure" +
"\nhierarhcyKind " + hierarchyKind +
......@@ -80,7 +83,8 @@ public class EagerInterfaceCompletionTest {
void compile(DiagnosticChecker dc, JavaSource... sources) {
try {
CompilationTask ct = javacTool.getTask(null, null, dc,
Arrays.asList("-d", testDir.getAbsolutePath(), "-cp", testDir.getAbsolutePath()),
Arrays.asList("-d", testDir.getAbsolutePath(), "-cp",
testDir.getAbsolutePath(), versionKind.optsArr[0], versionKind.optsArr[1]),
null, Arrays.asList(sources));
ct.call();
}
......@@ -108,12 +112,25 @@ public class EagerInterfaceCompletionTest {
boolean errorFound = false;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
errorFound = true;
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
errorFound = true;
}
}
}
//global declarations
enum VersionKind {
PRE_LAMBDA("-source", "7"),
LAMBDA("-source", "8");
String[] optsArr;
VersionKind(String... optsArr) {
this.optsArr = optsArr;
}
}
enum HierarchyKind {
INTERFACE("interface A { boolean f = false; void m(); }\n" +
"class B implements A { public void m() {} }"),
......@@ -157,13 +174,14 @@ public class EagerInterfaceCompletionTest {
this.source = new JavaSource("Test2.java", code);
}
boolean completionFailure(ActionKind ak, HierarchyKind hk) {
boolean completionFailure(VersionKind vk, ActionKind ak, HierarchyKind hk) {
switch (this) {
case ACCESS_ONLY:
case CONSTR: return ak == ActionKind.REMOVE_B;
case FIELD:
case SUPER: return true;
case METHOD: return hk != HierarchyKind.INTERFACE || ak == ActionKind.REMOVE_B;
case METHOD: return hk != HierarchyKind.INTERFACE || ak == ActionKind.REMOVE_B ||
(hk == HierarchyKind.INTERFACE && ak == ActionKind.REMOVE_A && vk == VersionKind.LAMBDA);
default: throw new AssertionError("Unexpected test kind " + this);
}
}
......@@ -173,12 +191,15 @@ public class EagerInterfaceCompletionTest {
String SCRATCH_DIR = System.getProperty("user.dir");
JavaCompiler javacTool = ToolProvider.getSystemJavaCompiler();
int n = 0;
for (HierarchyKind hierarchyKind : HierarchyKind.values()) {
for (TestKind testKind : TestKind.values()) {
for (ActionKind actionKind : ActionKind.values()) {
File testDir = new File(SCRATCH_DIR, "test"+n);
new EagerInterfaceCompletionTest(javacTool, testDir, hierarchyKind, testKind, actionKind).test();
n++;
for (VersionKind versionKind : VersionKind.values()) {
for (HierarchyKind hierarchyKind : HierarchyKind.values()) {
for (TestKind testKind : TestKind.values()) {
for (ActionKind actionKind : ActionKind.values()) {
File testDir = new File(SCRATCH_DIR, "test"+n);
new EagerInterfaceCompletionTest(javacTool, testDir, versionKind,
hierarchyKind, testKind, actionKind).test();
n++;
}
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册