1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jan 21 11:16:28 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jan 21 20:13:56 2013 +0000 1.3 @@ -41,6 +41,7 @@ 1.4 import com.sun.tools.javac.tree.*; 1.5 import com.sun.tools.javac.tree.JCTree.*; 1.6 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 1.7 +import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; 1.8 import com.sun.tools.javac.util.*; 1.9 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 1.10 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 1.11 @@ -92,6 +93,7 @@ 1.12 public final boolean varargsEnabled; // = source.allowVarargs(); 1.13 public final boolean allowMethodHandles; 1.14 public final boolean allowDefaultMethods; 1.15 + public final boolean allowStructuralMostSpecific; 1.16 private final boolean debugResolve; 1.17 final EnumSet<VerboseResolutionMode> verboseResolutionMode; 1.18 1.19 @@ -127,6 +129,7 @@ 1.20 Target target = Target.instance(context); 1.21 allowMethodHandles = target.hasMethodHandles(); 1.22 allowDefaultMethods = source.allowDefaultMethods(); 1.23 + allowStructuralMostSpecific = source.allowStructuralMostSpecific(); 1.24 polymorphicSignatureScope = new Scope(syms.noSymbol); 1.25 1.26 inapplicableMethodException = new InapplicableMethodException(diags); 1.27 @@ -835,6 +838,213 @@ 1.28 } 1.29 } 1.30 1.31 + /** 1.32 + * Most specific method applicability routine. Given a list of actual types A, 1.33 + * a list of formal types F1, and a list of formal types F2, the routine determines 1.34 + * as to whether the types in F1 can be considered more specific than those in F2 w.r.t. 1.35 + * argument types A. 1.36 + */ 1.37 + class MostSpecificCheck implements MethodCheck { 1.38 + 1.39 + boolean strict; 1.40 + List<Type> actuals; 1.41 + 1.42 + MostSpecificCheck(boolean strict, List<Type> actuals) { 1.43 + this.strict = strict; 1.44 + this.actuals = actuals; 1.45 + } 1.46 + 1.47 + @Override 1.48 + public void argumentsAcceptable(final Env<AttrContext> env, 1.49 + DeferredAttrContext deferredAttrContext, 1.50 + List<Type> formals1, 1.51 + List<Type> formals2, 1.52 + Warner warn) { 1.53 + formals2 = adjustArgs(formals2, deferredAttrContext.msym, formals1.length(), deferredAttrContext.phase.isVarargsRequired()); 1.54 + while (formals2.nonEmpty()) { 1.55 + ResultInfo mresult = methodCheckResult(formals2.head, deferredAttrContext, warn, actuals.head); 1.56 + mresult.check(null, formals1.head); 1.57 + formals1 = formals1.tail; 1.58 + formals2 = formals2.tail; 1.59 + actuals = actuals.isEmpty() ? actuals : actuals.tail; 1.60 + } 1.61 + } 1.62 + 1.63 + /** 1.64 + * Create a method check context to be used during the most specific applicability check 1.65 + */ 1.66 + ResultInfo methodCheckResult(Type to, DeferredAttr.DeferredAttrContext deferredAttrContext, 1.67 + Warner rsWarner, Type actual) { 1.68 + return attr.new ResultInfo(Kinds.VAL, to, 1.69 + new MostSpecificCheckContext(strict, deferredAttrContext, rsWarner, actual)); 1.70 + } 1.71 + 1.72 + /** 1.73 + * Subclass of method check context class that implements most specific 1.74 + * method conversion. If the actual type under analysis is a deferred type 1.75 + * a full blown structural analysis is carried out. 1.76 + */ 1.77 + class MostSpecificCheckContext extends MethodCheckContext { 1.78 + 1.79 + Type actual; 1.80 + 1.81 + public MostSpecificCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) { 1.82 + super(strict, deferredAttrContext, rsWarner); 1.83 + this.actual = actual; 1.84 + } 1.85 + 1.86 + public boolean compatible(Type found, Type req, Warner warn) { 1.87 + if (!allowStructuralMostSpecific || actual == null) { 1.88 + return super.compatible(found, req, warn); 1.89 + } else { 1.90 + switch (actual.getTag()) { 1.91 + case DEFERRED: 1.92 + DeferredType dt = (DeferredType) actual; 1.93 + DeferredType.SpeculativeCache.Entry e = dt.speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase); 1.94 + return (e == null || e.speculativeTree == deferredAttr.stuckTree) 1.95 + ? false : mostSpecific(found, req, e.speculativeTree, warn); 1.96 + default: 1.97 + return standaloneMostSpecific(found, req, actual, warn); 1.98 + } 1.99 + } 1.100 + } 1.101 + 1.102 + private boolean mostSpecific(Type t, Type s, JCTree tree, Warner warn) { 1.103 + MostSpecificChecker msc = new MostSpecificChecker(t, s, warn); 1.104 + msc.scan(tree); 1.105 + return msc.result; 1.106 + } 1.107 + 1.108 + boolean polyMostSpecific(Type t1, Type t2, Warner warn) { 1.109 + return (!t1.isPrimitive() && t2.isPrimitive()) 1.110 + ? true : super.compatible(t1, t2, warn); 1.111 + } 1.112 + 1.113 + boolean standaloneMostSpecific(Type t1, Type t2, Type exprType, Warner warn) { 1.114 + return (exprType.isPrimitive() == t1.isPrimitive() 1.115 + && exprType.isPrimitive() != t2.isPrimitive()) 1.116 + ? true : super.compatible(t1, t2, warn); 1.117 + } 1.118 + 1.119 + /** 1.120 + * Structural checker for most specific. 1.121 + */ 1.122 + class MostSpecificChecker extends DeferredAttr.PolyScanner { 1.123 + 1.124 + final Type t; 1.125 + final Type s; 1.126 + final Warner warn; 1.127 + boolean result; 1.128 + 1.129 + MostSpecificChecker(Type t, Type s, Warner warn) { 1.130 + this.t = t; 1.131 + this.s = s; 1.132 + this.warn = warn; 1.133 + result = true; 1.134 + } 1.135 + 1.136 + @Override 1.137 + void skip(JCTree tree) { 1.138 + result &= standaloneMostSpecific(t, s, tree.type, warn); 1.139 + } 1.140 + 1.141 + @Override 1.142 + public void visitConditional(JCConditional tree) { 1.143 + if (tree.polyKind == PolyKind.STANDALONE) { 1.144 + result &= standaloneMostSpecific(t, s, tree.type, warn); 1.145 + } else { 1.146 + super.visitConditional(tree); 1.147 + } 1.148 + } 1.149 + 1.150 + @Override 1.151 + public void visitApply(JCMethodInvocation tree) { 1.152 + result &= (tree.polyKind == PolyKind.STANDALONE) 1.153 + ? standaloneMostSpecific(t, s, tree.type, warn) 1.154 + : polyMostSpecific(t, s, warn); 1.155 + } 1.156 + 1.157 + @Override 1.158 + public void visitNewClass(JCNewClass tree) { 1.159 + result &= (tree.polyKind == PolyKind.STANDALONE) 1.160 + ? standaloneMostSpecific(t, s, tree.type, warn) 1.161 + : polyMostSpecific(t, s, warn); 1.162 + } 1.163 + 1.164 + @Override 1.165 + public void visitReference(JCMemberReference tree) { 1.166 + if (types.isFunctionalInterface(t.tsym) && 1.167 + types.isFunctionalInterface(s.tsym) && 1.168 + types.asSuper(t, s.tsym) == null && 1.169 + types.asSuper(s, t.tsym) == null) { 1.170 + Type desc_t = types.findDescriptorType(t); 1.171 + Type desc_s = types.findDescriptorType(s); 1.172 + if (types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) { 1.173 + if (!desc_s.getReturnType().hasTag(VOID)) { 1.174 + //perform structural comparison 1.175 + Type ret_t = desc_t.getReturnType(); 1.176 + Type ret_s = desc_s.getReturnType(); 1.177 + result &= ((tree.refPolyKind == PolyKind.STANDALONE) 1.178 + ? standaloneMostSpecific(ret_t, ret_s, tree.type, warn) 1.179 + : polyMostSpecific(ret_t, ret_s, warn)); 1.180 + } else { 1.181 + return; 1.182 + } 1.183 + } else { 1.184 + result &= false; 1.185 + } 1.186 + } else { 1.187 + result &= MostSpecificCheckContext.super.compatible(t, s, warn); 1.188 + } 1.189 + } 1.190 + 1.191 + @Override 1.192 + public void visitLambda(JCLambda tree) { 1.193 + if (types.isFunctionalInterface(t.tsym) && 1.194 + types.isFunctionalInterface(s.tsym) && 1.195 + types.asSuper(t, s.tsym) == null && 1.196 + types.asSuper(s, t.tsym) == null) { 1.197 + Type desc_t = types.findDescriptorType(t); 1.198 + Type desc_s = types.findDescriptorType(s); 1.199 + if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT 1.200 + || types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) { 1.201 + if (!desc_s.getReturnType().hasTag(VOID)) { 1.202 + //perform structural comparison 1.203 + Type ret_t = desc_t.getReturnType(); 1.204 + Type ret_s = desc_s.getReturnType(); 1.205 + scanLambdaBody(tree, ret_t, ret_s); 1.206 + } else { 1.207 + return; 1.208 + } 1.209 + } else { 1.210 + result &= false; 1.211 + } 1.212 + } else { 1.213 + result &= MostSpecificCheckContext.super.compatible(t, s, warn); 1.214 + } 1.215 + } 1.216 + //where 1.217 + 1.218 + void scanLambdaBody(JCLambda lambda, final Type t, final Type s) { 1.219 + if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { 1.220 + result &= MostSpecificCheckContext.this.mostSpecific(t, s, lambda.body, warn); 1.221 + } else { 1.222 + DeferredAttr.LambdaReturnScanner lambdaScanner = 1.223 + new DeferredAttr.LambdaReturnScanner() { 1.224 + @Override 1.225 + public void visitReturn(JCReturn tree) { 1.226 + if (tree.expr != null) { 1.227 + result &= MostSpecificCheckContext.this.mostSpecific(t, s, tree.expr, warn); 1.228 + } 1.229 + } 1.230 + }; 1.231 + lambdaScanner.scan(lambda.body); 1.232 + } 1.233 + } 1.234 + } 1.235 + } 1.236 + } 1.237 + 1.238 public static class InapplicableMethodException extends RuntimeException { 1.239 private static final long serialVersionUID = 0; 1.240 1.241 @@ -1142,151 +1352,30 @@ 1.242 } 1.243 //where 1.244 private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) { 1.245 - Symbol m12 = adjustVarargs(m1, m2, useVarargs); 1.246 - Symbol m22 = adjustVarargs(m2, m1, useVarargs); 1.247 - Type mtype1 = types.memberType(site, m12); 1.248 - Type mtype2 = types.memberType(site, m22); 1.249 - 1.250 - //check if invocation is more specific 1.251 - if (invocationMoreSpecific(env, site, m22, mtype1.getParameterTypes(), allowBoxing, useVarargs)) { 1.252 - return true; 1.253 + noteWarner.clear(); 1.254 + int maxLength = Math.max( 1.255 + Math.max(m1.type.getParameterTypes().length(), actuals.length()), 1.256 + m2.type.getParameterTypes().length()); 1.257 + Type mst = instantiate(env, site, m2, null, 1.258 + adjustArgs(types.lowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null, 1.259 + allowBoxing, useVarargs, new MostSpecificCheck(!allowBoxing, actuals), noteWarner); 1.260 + return mst != null && 1.261 + !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); 1.262 + } 1.263 + private List<Type> adjustArgs(List<Type> args, Symbol msym, int length, boolean allowVarargs) { 1.264 + if ((msym.flags() & VARARGS) != 0 && allowVarargs) { 1.265 + Type varargsElem = types.elemtype(args.last()); 1.266 + if (varargsElem == null) { 1.267 + Assert.error("Bad varargs = " + args.last() + " " + msym); 1.268 + } 1.269 + List<Type> newArgs = args.reverse().tail.prepend(varargsElem).reverse(); 1.270 + while (newArgs.length() < length) { 1.271 + newArgs = newArgs.append(newArgs.last()); 1.272 + } 1.273 + return newArgs; 1.274 + } else { 1.275 + return args; 1.276 } 1.277 - 1.278 - //perform structural check 1.279 - 1.280 - List<Type> formals1 = mtype1.getParameterTypes(); 1.281 - Type lastFormal1 = formals1.last(); 1.282 - List<Type> formals2 = mtype2.getParameterTypes(); 1.283 - Type lastFormal2 = formals2.last(); 1.284 - ListBuffer<Type> newFormals = ListBuffer.lb(); 1.285 - 1.286 - boolean hasStructuralPoly = false; 1.287 - for (Type actual : actuals) { 1.288 - //perform formal argument adaptation in case actuals > formals (varargs) 1.289 - Type f1 = formals1.isEmpty() ? 1.290 - lastFormal1 : formals1.head; 1.291 - Type f2 = formals2.isEmpty() ? 1.292 - lastFormal2 : formals2.head; 1.293 - 1.294 - //is this a structural actual argument? 1.295 - boolean isStructuralPoly = actual.hasTag(DEFERRED) && 1.296 - (((DeferredType)actual).tree.hasTag(LAMBDA) || 1.297 - ((DeferredType)actual).tree.hasTag(REFERENCE)); 1.298 - 1.299 - Type newFormal = f1; 1.300 - 1.301 - if (isStructuralPoly) { 1.302 - //for structural arguments only - check that corresponding formals 1.303 - //are related - if so replace formal with <null> 1.304 - hasStructuralPoly = true; 1.305 - DeferredType dt = (DeferredType)actual; 1.306 - Type t1 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m1, currentResolutionContext.step).apply(dt); 1.307 - Type t2 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m2, currentResolutionContext.step).apply(dt); 1.308 - if (t1.isErroneous() || t2.isErroneous() || !isStructuralSubtype(t1, t2)) { 1.309 - //not structural subtypes - simply fail 1.310 - return false; 1.311 - } else { 1.312 - newFormal = syms.botType; 1.313 - } 1.314 - } 1.315 - 1.316 - newFormals.append(newFormal); 1.317 - if (newFormals.length() > mtype2.getParameterTypes().length()) { 1.318 - //expand m2's type so as to fit the new formal arity (varargs) 1.319 - m22.type = types.createMethodTypeWithParameters(m22.type, m22.type.getParameterTypes().append(f2)); 1.320 - } 1.321 - 1.322 - formals1 = formals1.isEmpty() ? formals1 : formals1.tail; 1.323 - formals2 = formals2.isEmpty() ? formals2 : formals2.tail; 1.324 - } 1.325 - 1.326 - if (!hasStructuralPoly) { 1.327 - //if no structural actual was found, we're done 1.328 - return false; 1.329 - } 1.330 - //perform additional adaptation if actuals < formals (varargs) 1.331 - for (Type t : formals1) { 1.332 - newFormals.append(t); 1.333 - } 1.334 - //check if invocation (with tweaked args) is more specific 1.335 - return invocationMoreSpecific(env, site, m22, newFormals.toList(), allowBoxing, useVarargs); 1.336 - } 1.337 - //where 1.338 - private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) { 1.339 - MethodResolutionContext prevContext = currentResolutionContext; 1.340 - try { 1.341 - currentResolutionContext = new MethodResolutionContext(); 1.342 - currentResolutionContext.step = allowBoxing ? BOX : BASIC; 1.343 - noteWarner.clear(); 1.344 - Type mst = instantiate(env, site, m2, null, 1.345 - types.lowerBounds(argtypes1), null, 1.346 - allowBoxing, false, resolveMethodCheck, noteWarner); 1.347 - return mst != null && 1.348 - !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); 1.349 - } finally { 1.350 - currentResolutionContext = prevContext; 1.351 - } 1.352 - } 1.353 - //where 1.354 - private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) { 1.355 - List<Type> fromArgs = from.type.getParameterTypes(); 1.356 - List<Type> toArgs = to.type.getParameterTypes(); 1.357 - if (useVarargs && 1.358 - (from.flags() & VARARGS) != 0 && 1.359 - (to.flags() & VARARGS) != 0) { 1.360 - Type varargsTypeFrom = fromArgs.last(); 1.361 - Type varargsTypeTo = toArgs.last(); 1.362 - ListBuffer<Type> args = ListBuffer.lb(); 1.363 - if (toArgs.length() < fromArgs.length()) { 1.364 - //if we are checking a varargs method 'from' against another varargs 1.365 - //method 'to' (where arity of 'to' < arity of 'from') then expand signature 1.366 - //of 'to' to 'fit' arity of 'from' (this means adding fake formals to 'to' 1.367 - //until 'to' signature has the same arity as 'from') 1.368 - while (fromArgs.head != varargsTypeFrom) { 1.369 - args.append(toArgs.head == varargsTypeTo ? types.elemtype(varargsTypeTo) : toArgs.head); 1.370 - fromArgs = fromArgs.tail; 1.371 - toArgs = toArgs.head == varargsTypeTo ? 1.372 - toArgs : 1.373 - toArgs.tail; 1.374 - } 1.375 - } else { 1.376 - //formal argument list is same as original list where last 1.377 - //argument (array type) is removed 1.378 - args.appendList(toArgs.reverse().tail.reverse()); 1.379 - } 1.380 - //append varargs element type as last synthetic formal 1.381 - args.append(types.elemtype(varargsTypeTo)); 1.382 - Type mtype = types.createMethodTypeWithParameters(to.type, args.toList()); 1.383 - return new MethodSymbol(to.flags_field & ~VARARGS, to.name, mtype, to.owner); 1.384 - } else { 1.385 - return to; 1.386 - } 1.387 - } 1.388 - //where 1.389 - boolean isStructuralSubtype(Type s, Type t) { 1.390 - 1.391 - Type ret_s = types.findDescriptorType(s).getReturnType(); 1.392 - Type ret_t = types.findDescriptorType(t).getReturnType(); 1.393 - 1.394 - //covariant most specific check for function descriptor return type 1.395 - if (!types.isSubtype(ret_s, ret_t)) { 1.396 - return false; 1.397 - } 1.398 - 1.399 - List<Type> args_s = types.findDescriptorType(s).getParameterTypes(); 1.400 - List<Type> args_t = types.findDescriptorType(t).getParameterTypes(); 1.401 - 1.402 - //arity must be identical 1.403 - if (args_s.length() != args_t.length()) { 1.404 - return false; 1.405 - } 1.406 - 1.407 - //invariant most specific check for function descriptor parameter types 1.408 - if (!types.isSameTypes(args_t, args_s)) { 1.409 - return false; 1.410 - } 1.411 - 1.412 - return true; 1.413 } 1.414 //where 1.415 Type mostSpecificReturnType(Type mt1, Type mt2) {