1.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Thu Oct 04 13:04:53 2012 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Oct 05 14:35:24 2012 +0100 1.3 @@ -79,8 +79,10 @@ 1.4 final boolean allowObjectToPrimitiveCast; 1.5 final ClassReader reader; 1.6 final Check chk; 1.7 + JCDiagnostic.Factory diags; 1.8 List<Warner> warnStack = List.nil(); 1.9 final Name capturedName; 1.10 + private final FunctionDescriptorLookupError functionDescriptorLookupError; 1.11 1.12 // <editor-fold defaultstate="collapsed" desc="Instantiating"> 1.13 public static Types instance(Context context) { 1.14 @@ -102,6 +104,8 @@ 1.15 chk = Check.instance(context); 1.16 capturedName = names.fromString("<captured wildcard>"); 1.17 messages = JavacMessages.instance(context); 1.18 + diags = JCDiagnostic.Factory.instance(context); 1.19 + functionDescriptorLookupError = new FunctionDescriptorLookupError(); 1.20 } 1.21 // </editor-fold> 1.22 1.23 @@ -296,6 +300,294 @@ 1.24 } 1.25 // </editor-fold> 1.26 1.27 + // <editor-fold defaultstate="collapsed" desc="findSam"> 1.28 + 1.29 + /** 1.30 + * Exception used to report a function descriptor lookup failure. The exception 1.31 + * wraps a diagnostic that can be used to generate more details error 1.32 + * messages. 1.33 + */ 1.34 + public static class FunctionDescriptorLookupError extends RuntimeException { 1.35 + private static final long serialVersionUID = 0; 1.36 + 1.37 + JCDiagnostic diagnostic; 1.38 + 1.39 + FunctionDescriptorLookupError() { 1.40 + this.diagnostic = null; 1.41 + } 1.42 + 1.43 + FunctionDescriptorLookupError setMessage(JCDiagnostic diag) { 1.44 + this.diagnostic = diag; 1.45 + return this; 1.46 + } 1.47 + 1.48 + public JCDiagnostic getDiagnostic() { 1.49 + return diagnostic; 1.50 + } 1.51 + } 1.52 + 1.53 + /** 1.54 + * A cache that keeps track of function descriptors associated with given 1.55 + * functional interfaces. 1.56 + */ 1.57 + class DescriptorCache { 1.58 + 1.59 + private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>(); 1.60 + 1.61 + class FunctionDescriptor { 1.62 + Symbol descSym; 1.63 + 1.64 + FunctionDescriptor(Symbol descSym) { 1.65 + this.descSym = descSym; 1.66 + } 1.67 + 1.68 + public Symbol getSymbol() { 1.69 + return descSym; 1.70 + } 1.71 + 1.72 + public Type getType(Type origin) { 1.73 + return memberType(origin, descSym); 1.74 + } 1.75 + } 1.76 + 1.77 + class Entry { 1.78 + final FunctionDescriptor cachedDescRes; 1.79 + final int prevMark; 1.80 + 1.81 + public Entry(FunctionDescriptor cachedDescRes, 1.82 + int prevMark) { 1.83 + this.cachedDescRes = cachedDescRes; 1.84 + this.prevMark = prevMark; 1.85 + } 1.86 + 1.87 + boolean matches(int mark) { 1.88 + return this.prevMark == mark; 1.89 + } 1.90 + } 1.91 + 1.92 + FunctionDescriptor get(TypeSymbol origin) throws FunctionDescriptorLookupError { 1.93 + Entry e = _map.get(origin); 1.94 + CompoundScope members = membersClosure(origin.type, false); 1.95 + if (e == null || 1.96 + !e.matches(members.getMark())) { 1.97 + FunctionDescriptor descRes = findDescriptorInternal(origin, members); 1.98 + _map.put(origin, new Entry(descRes, members.getMark())); 1.99 + return descRes; 1.100 + } 1.101 + else { 1.102 + return e.cachedDescRes; 1.103 + } 1.104 + } 1.105 + 1.106 + /** 1.107 + * Scope filter used to skip methods that should be ignored during 1.108 + * function interface conversion (such as methods overridden by 1.109 + * j.l.Object) 1.110 + */ 1.111 + class DescriptorFilter implements Filter<Symbol> { 1.112 + 1.113 + TypeSymbol origin; 1.114 + 1.115 + DescriptorFilter(TypeSymbol origin) { 1.116 + this.origin = origin; 1.117 + } 1.118 + 1.119 + @Override 1.120 + public boolean accepts(Symbol sym) { 1.121 + return sym.kind == Kinds.MTH && 1.122 + (sym.flags() & ABSTRACT) != 0 && 1.123 + !overridesObjectMethod(origin, sym) && 1.124 + notOverridden(sym); 1.125 + } 1.126 + 1.127 + private boolean notOverridden(Symbol msym) { 1.128 + Symbol impl = ((MethodSymbol)msym).implementation(origin, Types.this, false); 1.129 + return impl == null || (impl.flags() & ABSTRACT) != 0; 1.130 + } 1.131 + }; 1.132 + 1.133 + /** 1.134 + * Compute the function descriptor associated with a given functional interface 1.135 + */ 1.136 + public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError { 1.137 + if (!origin.isInterface()) { 1.138 + //t must be an interface 1.139 + throw failure("not.a.functional.intf"); 1.140 + } 1.141 + 1.142 + final ListBuffer<Symbol> abstracts = ListBuffer.lb(); 1.143 + for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) { 1.144 + Type mtype = memberType(origin.type, sym); 1.145 + if (abstracts.isEmpty() || 1.146 + (sym.name == abstracts.first().name && 1.147 + overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) { 1.148 + abstracts.append(sym); 1.149 + } else { 1.150 + //the target method(s) should be the only abstract members of t 1.151 + throw failure("not.a.functional.intf.1", 1.152 + diags.fragment("incompatible.abstracts", Kinds.kindName(origin), origin)); 1.153 + } 1.154 + } 1.155 + if (abstracts.isEmpty()) { 1.156 + //t must define a suitable non-generic method 1.157 + throw failure("not.a.functional.intf.1", 1.158 + diags.fragment("no.abstracts", Kinds.kindName(origin), origin)); 1.159 + } else if (abstracts.size() == 1) { 1.160 + if (abstracts.first().type.tag == FORALL) { 1.161 + throw failure("invalid.generic.desc.in.functional.intf", 1.162 + abstracts.first(), 1.163 + Kinds.kindName(origin), 1.164 + origin); 1.165 + } else { 1.166 + return new FunctionDescriptor(abstracts.first()); 1.167 + } 1.168 + } else { // size > 1 1.169 + for (Symbol msym : abstracts) { 1.170 + if (msym.type.tag == FORALL) { 1.171 + throw failure("invalid.generic.desc.in.functional.intf", 1.172 + abstracts.first(), 1.173 + Kinds.kindName(origin), 1.174 + origin); 1.175 + } 1.176 + } 1.177 + FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList()); 1.178 + if (descRes == null) { 1.179 + //we can get here if the functional interface is ill-formed 1.180 + ListBuffer<JCDiagnostic> descriptors = ListBuffer.lb(); 1.181 + for (Symbol desc : abstracts) { 1.182 + String key = desc.type.getThrownTypes().nonEmpty() ? 1.183 + "descriptor.throws" : "descriptor"; 1.184 + descriptors.append(diags.fragment(key, desc.name, 1.185 + desc.type.getParameterTypes(), 1.186 + desc.type.getReturnType(), 1.187 + desc.type.getThrownTypes())); 1.188 + } 1.189 + JCDiagnostic.MultilineDiagnostic incompatibleDescriptors = 1.190 + new JCDiagnostic.MultilineDiagnostic(diags.fragment("incompatible.descs.in.functional.intf", 1.191 + Kinds.kindName(origin), origin), descriptors.toList()); 1.192 + throw failure(incompatibleDescriptors); 1.193 + } 1.194 + return descRes; 1.195 + } 1.196 + } 1.197 + 1.198 + /** 1.199 + * Compute a synthetic type for the target descriptor given a list 1.200 + * of override-equivalent methods in the functional interface type. 1.201 + * The resulting method type is a method type that is override-equivalent 1.202 + * and return-type substitutable with each method in the original list. 1.203 + */ 1.204 + private FunctionDescriptor mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) { 1.205 + //pick argument types - simply take the signature that is a 1.206 + //subsignature of all other signatures in the list (as per JLS 8.4.2) 1.207 + List<Symbol> mostSpecific = List.nil(); 1.208 + outer: for (Symbol msym1 : methodSyms) { 1.209 + Type mt1 = memberType(origin.type, msym1); 1.210 + for (Symbol msym2 : methodSyms) { 1.211 + Type mt2 = memberType(origin.type, msym2); 1.212 + if (!isSubSignature(mt1, mt2)) { 1.213 + continue outer; 1.214 + } 1.215 + } 1.216 + mostSpecific = mostSpecific.prepend(msym1); 1.217 + } 1.218 + if (mostSpecific.isEmpty()) { 1.219 + return null; 1.220 + } 1.221 + 1.222 + 1.223 + //pick return types - this is done in two phases: (i) first, the most 1.224 + //specific return type is chosen using strict subtyping; if this fails, 1.225 + //a second attempt is made using return type substitutability (see JLS 8.4.5) 1.226 + boolean phase2 = false; 1.227 + Symbol bestSoFar = null; 1.228 + while (bestSoFar == null) { 1.229 + outer: for (Symbol msym1 : mostSpecific) { 1.230 + Type mt1 = memberType(origin.type, msym1); 1.231 + for (Symbol msym2 : methodSyms) { 1.232 + Type mt2 = memberType(origin.type, msym2); 1.233 + if (phase2 ? 1.234 + !returnTypeSubstitutable(mt1, mt2) : 1.235 + !isSubtypeInternal(mt1.getReturnType(), mt2.getReturnType())) { 1.236 + continue outer; 1.237 + } 1.238 + } 1.239 + bestSoFar = msym1; 1.240 + } 1.241 + if (phase2) { 1.242 + break; 1.243 + } else { 1.244 + phase2 = true; 1.245 + } 1.246 + } 1.247 + if (bestSoFar == null) return null; 1.248 + 1.249 + //merge thrown types - form the intersection of all the thrown types in 1.250 + //all the signatures in the list 1.251 + List<Type> thrown = null; 1.252 + for (Symbol msym1 : methodSyms) { 1.253 + Type mt1 = memberType(origin.type, msym1); 1.254 + thrown = (thrown == null) ? 1.255 + mt1.getThrownTypes() : 1.256 + chk.intersect(mt1.getThrownTypes(), thrown); 1.257 + } 1.258 + 1.259 + final List<Type> thrown1 = thrown; 1.260 + return new FunctionDescriptor(bestSoFar) { 1.261 + @Override 1.262 + public Type getType(Type origin) { 1.263 + Type mt = memberType(origin, getSymbol()); 1.264 + return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown1, syms.methodClass); 1.265 + } 1.266 + }; 1.267 + } 1.268 + 1.269 + boolean isSubtypeInternal(Type s, Type t) { 1.270 + return (s.isPrimitive() && t.isPrimitive()) ? 1.271 + isSameType(t, s) : 1.272 + isSubtype(s, t); 1.273 + } 1.274 + 1.275 + FunctionDescriptorLookupError failure(String msg, Object... args) { 1.276 + return failure(diags.fragment(msg, args)); 1.277 + } 1.278 + 1.279 + FunctionDescriptorLookupError failure(JCDiagnostic diag) { 1.280 + return functionDescriptorLookupError.setMessage(diag); 1.281 + } 1.282 + } 1.283 + 1.284 + private DescriptorCache descCache = new DescriptorCache(); 1.285 + 1.286 + /** 1.287 + * Find the method descriptor associated to this class symbol - if the 1.288 + * symbol 'origin' is not a functional interface, an exception is thrown. 1.289 + */ 1.290 + public Symbol findDescriptorSymbol(TypeSymbol origin) throws FunctionDescriptorLookupError { 1.291 + return descCache.get(origin).getSymbol(); 1.292 + } 1.293 + 1.294 + /** 1.295 + * Find the type of the method descriptor associated to this class symbol - 1.296 + * if the symbol 'origin' is not a functional interface, an exception is thrown. 1.297 + */ 1.298 + public Type findDescriptorType(Type origin) throws FunctionDescriptorLookupError { 1.299 + return descCache.get(origin.tsym).getType(origin); 1.300 + } 1.301 + 1.302 + /** 1.303 + * Is given type a functional interface? 1.304 + */ 1.305 + public boolean isFunctionalInterface(TypeSymbol tsym) { 1.306 + try { 1.307 + findDescriptorSymbol(tsym); 1.308 + return true; 1.309 + } catch (FunctionDescriptorLookupError ex) { 1.310 + return false; 1.311 + } 1.312 + } 1.313 + // </editor-fold> 1.314 + 1.315 // <editor-fold defaultstate="collapsed" desc="isSubtype"> 1.316 /** 1.317 * Is t an unchecked subtype of s? 1.318 @@ -1215,7 +1507,10 @@ 1.319 * Returns the lower bounds of the formals of a method. 1.320 */ 1.321 public List<Type> lowerBoundArgtypes(Type t) { 1.322 - return map(t.getParameterTypes(), lowerBoundMapping); 1.323 + return lowerBounds(t.getParameterTypes()); 1.324 + } 1.325 + public List<Type> lowerBounds(List<Type> ts) { 1.326 + return map(ts, lowerBoundMapping); 1.327 } 1.328 private final Mapping lowerBoundMapping = new Mapping("lowerBound") { 1.329 public Type apply(Type t) { 1.330 @@ -2007,6 +2302,15 @@ 1.331 hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s); 1.332 } 1.333 1.334 + public boolean overridesObjectMethod(TypeSymbol origin, Symbol msym) { 1.335 + for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) { 1.336 + if (msym.overrides(e.sym, origin, Types.this, true)) { 1.337 + return true; 1.338 + } 1.339 + } 1.340 + return false; 1.341 + } 1.342 + 1.343 // <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site"> 1.344 class ImplementationCache { 1.345