src/share/classes/com/sun/tools/javac/comp/Resolve.java

changeset 1510
7873d37f5b37
parent 1498
1afdf1f1472b
child 1521
71f35e4b93a5
     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) {

mercurial