--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Nov 03 21:09:57 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Sun Nov 04 10:59:42 2012 +0000
@@ -119,6 +119,9 @@
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 @@
*/
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 @@
} 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 @@
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 @@
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 @@
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 @@
}
}
+ 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) {