1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Nov 03 21:09:57 2012 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Sun Nov 04 10:59:42 2012 +0000 1.3 @@ -119,6 +119,9 @@ 1.4 allowAnnotations = source.allowAnnotations(); 1.5 allowCovariantReturns = source.allowCovariantReturns(); 1.6 allowSimplifiedVarargs = source.allowSimplifiedVarargs(); 1.7 + allowDefaultMethods = source.allowDefaultMethods(); 1.8 + allowStrictMethodClashCheck = source.allowStrictMethodClashCheck() && 1.9 + options.isSet("strictMethodClashCheck"); //pre-lambda guard 1.10 complexInference = options.isSet("complexinference"); 1.11 warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts"); 1.12 suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile"); 1.13 @@ -162,6 +165,14 @@ 1.14 */ 1.15 boolean allowSimplifiedVarargs; 1.16 1.17 + /** Switch: default methods enabled? 1.18 + */ 1.19 + boolean allowDefaultMethods; 1.20 + 1.21 + /** Switch: should unrelated return types trigger a method clash? 1.22 + */ 1.23 + boolean allowStrictMethodClashCheck; 1.24 + 1.25 /** Switch: -complexinference option set? 1.26 */ 1.27 boolean complexInference; 1.28 @@ -1114,7 +1125,7 @@ 1.29 } else if ((sym.owner.flags_field & INTERFACE) != 0) { 1.30 if ((flags & DEFAULT) != 0) { 1.31 mask = InterfaceDefaultMethodMask; 1.32 - implicit = PUBLIC; 1.33 + implicit = PUBLIC | ABSTRACT; 1.34 } else { 1.35 mask = implicit = InterfaceMethodFlags; 1.36 } 1.37 @@ -2047,11 +2058,21 @@ 1.38 undef == null && e != null; 1.39 e = e.sibling) { 1.40 if (e.sym.kind == MTH && 1.41 - (e.sym.flags() & (ABSTRACT|IPROXY)) == ABSTRACT) { 1.42 + (e.sym.flags() & (ABSTRACT|IPROXY|DEFAULT)) == ABSTRACT) { 1.43 MethodSymbol absmeth = (MethodSymbol)e.sym; 1.44 MethodSymbol implmeth = absmeth.implementation(impl, types, true); 1.45 - if (implmeth == null || implmeth == absmeth) 1.46 + if (implmeth == null || implmeth == absmeth) { 1.47 + //look for default implementations 1.48 + if (allowDefaultMethods) { 1.49 + MethodSymbol prov = types.interfaceCandidates(impl.type, absmeth).head; 1.50 + if (prov != null && prov.overrides(absmeth, impl, types, true)) { 1.51 + implmeth = prov; 1.52 + } 1.53 + } 1.54 + } 1.55 + if (implmeth == null || implmeth == absmeth) { 1.56 undef = absmeth; 1.57 + } 1.58 } 1.59 } 1.60 if (undef == null) { 1.61 @@ -2354,7 +2375,7 @@ 1.62 if (m2 == m1) continue; 1.63 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 1.64 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error 1.65 - if (!types.isSubSignature(sym.type, types.memberType(site, m2), false) && 1.66 + if (!types.isSubSignature(sym.type, types.memberType(site, m2), allowStrictMethodClashCheck) && 1.67 types.hasSameArgs(m2.erasure(types), m1.erasure(types))) { 1.68 sym.flags_field |= CLASH; 1.69 String key = m1 == sym ? 1.70 @@ -2386,7 +2407,7 @@ 1.71 for (Symbol s : types.membersClosure(site, true).getElementsByName(sym.name, cf)) { 1.72 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 1.73 //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error 1.74 - if (!types.isSubSignature(sym.type, types.memberType(site, s), false) && 1.75 + if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck) && 1.76 types.hasSameArgs(s.erasure(types), sym.erasure(types))) { 1.77 log.error(pos, 1.78 "name.clash.same.erasure.no.hide", 1.79 @@ -2420,6 +2441,62 @@ 1.80 } 1.81 } 1.82 1.83 + void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) { 1.84 + DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site); 1.85 + for (Symbol m : types.membersClosure(site, false).getElements(dcf)) { 1.86 + Assert.check(m.kind == MTH); 1.87 + List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m); 1.88 + if (prov.size() > 1) { 1.89 + ListBuffer<Symbol> abstracts = ListBuffer.lb(); 1.90 + ListBuffer<Symbol> defaults = ListBuffer.lb(); 1.91 + for (MethodSymbol provSym : prov) { 1.92 + if ((provSym.flags() & DEFAULT) != 0) { 1.93 + defaults = defaults.append(provSym); 1.94 + } else if ((provSym.flags() & ABSTRACT) != 0) { 1.95 + abstracts = abstracts.append(provSym); 1.96 + } 1.97 + if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) { 1.98 + //strong semantics - issue an error if two sibling interfaces 1.99 + //have two override-equivalent defaults - or if one is abstract 1.100 + //and the other is default 1.101 + String errKey; 1.102 + Symbol s1 = defaults.first(); 1.103 + Symbol s2; 1.104 + if (defaults.size() > 1) { 1.105 + errKey = "types.incompatible.unrelated.defaults"; 1.106 + s2 = defaults.toList().tail.head; 1.107 + } else { 1.108 + errKey = "types.incompatible.abstract.default"; 1.109 + s2 = abstracts.first(); 1.110 + } 1.111 + log.error(pos, errKey, 1.112 + Kinds.kindName(site.tsym), site, 1.113 + m.name, types.memberType(site, m).getParameterTypes(), 1.114 + s1.location(), s2.location()); 1.115 + break; 1.116 + } 1.117 + } 1.118 + } 1.119 + } 1.120 + } 1.121 + 1.122 + //where 1.123 + private class DefaultMethodClashFilter implements Filter<Symbol> { 1.124 + 1.125 + Type site; 1.126 + 1.127 + DefaultMethodClashFilter(Type site) { 1.128 + this.site = site; 1.129 + } 1.130 + 1.131 + public boolean accepts(Symbol s) { 1.132 + return s.kind == MTH && 1.133 + (s.flags() & DEFAULT) != 0 && 1.134 + s.isInheritedIn(site.tsym, types) && 1.135 + !s.isConstructor(); 1.136 + } 1.137 + } 1.138 + 1.139 /** Report a conflict between a user symbol and a synthetic symbol. 1.140 */ 1.141 private void syntheticError(DiagnosticPosition pos, Symbol sym) {