diff -r 352d130c47c5 -r d7d932236fee src/share/classes/com/sun/tools/javac/comp/Check.java --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Nov 03 21:09:57 2012 -0700 +++ b/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 prov = types.interfaceCandidates(site, (MethodSymbol)m); + if (prov.size() > 1) { + ListBuffer abstracts = ListBuffer.lb(); + ListBuffer 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 { + + 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) {