langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
changeset 32709 55d136799f79
parent 32164 6c65d5b414bc
child 32912 dd06b5fd9300
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Sep 14 11:26:14 2015 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Sep 15 13:43:44 2015 +0100
@@ -108,6 +108,7 @@
     final TypeEnvs typeEnvs;
     final Dependencies dependencies;
     final Annotate annotate;
+    final ArgumentAttr argumentAttr;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -142,6 +143,7 @@
         deferredLintHandler = DeferredLintHandler.instance(context);
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
+        argumentAttr = ArgumentAttr.instance(context);
 
         Options options = Options.instance(context);
 
@@ -160,7 +162,7 @@
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
         varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
         unknownExprInfo = new ResultInfo(KindSelector.VAL, Type.noType);
-        unknownAnyPolyInfo = new ResultInfo(KindSelector.VAL, Infer.anyPoly);
+        methodAttrInfo = new MethodAttrInfo();
         unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
         unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
@@ -488,6 +490,10 @@
             this.checkMode = checkMode;
         }
 
+        protected void attr(JCTree tree, Env<AttrContext> env) {
+            tree.accept(Attr.this);
+        }
+
         protected Type check(final DiagnosticPosition pos, final Type found) {
             return chk.checkType(pos, found, pt, checkContext);
         }
@@ -522,6 +528,41 @@
         }
     }
 
+    class MethodAttrInfo extends ResultInfo {
+        public MethodAttrInfo() {
+            this(chk.basicHandler);
+        }
+
+        public MethodAttrInfo(CheckContext checkContext) {
+            super(KindSelector.VAL, Infer.anyPoly, checkContext);
+        }
+
+        @Override
+        protected void attr(JCTree tree, Env<AttrContext> env) {
+            result = argumentAttr.attribArg(tree, env);
+        }
+
+        protected ResultInfo dup(Type newPt) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(CheckContext newContext) {
+            return new MethodAttrInfo(newContext);
+        }
+
+        protected ResultInfo dup(Type newPt, CheckContext newContext) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(Type newPt, CheckContext newContext, CheckMode newMode) {
+            throw new IllegalStateException();
+        }
+
+        protected ResultInfo dup(CheckMode newMode) {
+            throw new IllegalStateException();
+        }
+    }
+
     class RecoveryInfo extends ResultInfo {
 
         public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext) {
@@ -545,7 +586,7 @@
 
     final ResultInfo statInfo;
     final ResultInfo varAssignmentInfo;
-    final ResultInfo unknownAnyPolyInfo;
+    final ResultInfo methodAttrInfo;
     final ResultInfo unknownExprInfo;
     final ResultInfo unknownTypeInfo;
     final ResultInfo unknownTypeExprInfo;
@@ -588,7 +629,7 @@
         try {
             this.env = env;
             this.resultInfo = resultInfo;
-            tree.accept(this);
+            resultInfo.attr(tree, env);
             if (tree == breakTree &&
                     resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
                 throw new BreakAttr(copyEnv(env));
@@ -684,12 +725,9 @@
     KindSelector attribArgs(KindSelector initialKind, List<JCExpression> trees, Env<AttrContext> env, ListBuffer<Type> argtypes) {
         KindSelector kind = initialKind;
         for (JCExpression arg : trees) {
-            Type argtype;
-            if (allowPoly && deferredAttr.isDeferred(env, arg)) {
-                argtype = deferredAttr.new DeferredType(arg, env);
+            Type argtype = chk.checkNonVoid(arg, attribTree(arg, env, allowPoly ? methodAttrInfo : unknownExprInfo));
+            if (argtype.hasTag(DEFERRED)) {
                 kind = KindSelector.of(KindSelector.POLY, kind);
-            } else {
-                argtype = chk.checkNonVoid(arg, attribTree(arg, env, unknownAnyPolyInfo));
             }
             argtypes.append(argtype);
         }
@@ -1426,12 +1464,12 @@
         Type condtype = attribExpr(tree.cond, env, syms.booleanType);
 
         tree.polyKind = (!allowPoly ||
-                pt().hasTag(NONE) && pt() != Type.recoveryType ||
+                pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
                 isBooleanOrNumeric(env, tree)) ?
                 PolyKind.STANDALONE : PolyKind.POLY;
 
         if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
-            //cannot get here (i.e. it means we are returning from void method - which is already an error)
+            //this means we are returning a poly conditional from void-compatible lambda expression
             resultInfo.checkContext.report(tree, diags.fragment("conditional.target.cant.be.void"));
             result = tree.type = types.createErrorType(resultInfo.pt);
             return;
@@ -1439,15 +1477,7 @@
 
         ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
                 unknownExprInfo :
-                resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
-                    //this will use enclosing check context to check compatibility of
-                    //subexpression against target type; if we are in a method check context,
-                    //depending on whether boxing is allowed, we could have incompatibilities
-                    @Override
-                    public void report(DiagnosticPosition pos, JCDiagnostic details) {
-                        enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
-                    }
-                });
+                resultInfo.dup(conditionalContext(resultInfo.checkContext));
 
         Type truetype = attribTree(tree.truepart, env, condInfo);
         Type falsetype = attribTree(tree.falsepart, env, condInfo);
@@ -1506,6 +1536,18 @@
                 }
             };
 
+        CheckContext conditionalContext(CheckContext checkContext) {
+            return new Check.NestedCheckContext(checkContext) {
+                //this will use enclosing check context to check compatibility of
+                //subexpression against target type; if we are in a method check context,
+                //depending on whether boxing is allowed, we could have incompatibilities
+                @Override
+                public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                    enclosingContext.report(pos, diags.fragment("incompatible.type.in.conditional", details));
+                }
+            };
+        }
+
         /** Compute the type of a conditional expression, after
          *  checking that it exists.  See JLS 15.25. Does not take into
          *  account the special case where condition and both arms
@@ -2070,13 +2112,8 @@
                 tree.constructor = constructor.baseSymbol();
 
                 final TypeSymbol csym = clazztype.tsym;
-                ResultInfo diamondResult = new ResultInfo(pkind, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {
-                    @Override
-                    public void report(DiagnosticPosition _unused, JCDiagnostic details) {
-                        enclosingContext.report(tree.clazz,
-                                diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", csym), details));
-                    }
-                }, CheckMode.NO_TREE_UPDATE);
+                ResultInfo diamondResult = new ResultInfo(pkind, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes),
+                        diamondContext(tree, csym, resultInfo.checkContext), CheckMode.NO_TREE_UPDATE);
                 Type constructorType = tree.constructorType = types.createErrorType(clazztype);
                 constructorType = checkId(tree, site,
                         constructor,
@@ -2261,6 +2298,16 @@
             chk.validate(tree.typeargs, localEnv);
         }
 
+        CheckContext diamondContext(JCNewClass clazz, TypeSymbol tsym, CheckContext checkContext) {
+            return new Check.NestedCheckContext(checkContext) {
+                @Override
+                public void report(DiagnosticPosition _unused, JCDiagnostic details) {
+                    enclosingContext.report(clazz.clazz,
+                            diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", tsym), details));
+                }
+            };
+        }
+
     /** Make an attributed null check tree.
      */
     public JCExpression makeNullCheck(JCExpression arg) {
@@ -2330,8 +2377,7 @@
         boolean needsRecovery =
                 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
         try {
-            Type currentTarget = pt();
-            if (needsRecovery && isSerializable(currentTarget)) {
+            if (needsRecovery && isSerializable(pt())) {
                 localEnv.info.isSerializable = true;
             }
             List<Type> explicitParamTypes = null;
@@ -2341,22 +2387,13 @@
                 explicitParamTypes = TreeInfo.types(that.params);
             }
 
-            Type lambdaType;
-            if (pt() != Type.recoveryType) {
-                /* We need to adjust the target. If the target is an
-                 * intersection type, for example: SAM & I1 & I2 ...
-                 * the target will be updated to SAM
-                 */
-                currentTarget = targetChecker.visit(currentTarget, that);
-                if (explicitParamTypes != null) {
-                    currentTarget = infer.instantiateFunctionalInterface(that,
-                            currentTarget, explicitParamTypes, resultInfo.checkContext);
-                }
-                currentTarget = types.removeWildcards(currentTarget);
-                lambdaType = types.findDescriptorType(currentTarget);
-            } else {
-                currentTarget = Type.recoveryType;
-                lambdaType = fallbackDescriptorType(that);
+            TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
+            Type currentTarget = targetInfo.target;
+            Type lambdaType = targetInfo.descriptor;
+
+            if (currentTarget.isErroneous()) {
+                result = that.type = currentTarget;
+                return;
             }
 
             setFunctionalInfo(localEnv, that, pt(), lambdaType, currentTarget, resultInfo.checkContext);
@@ -2409,15 +2446,8 @@
             //with the target-type, it will be recovered anyway in Attr.checkId
             needsRecovery = false;
 
-            FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
-                    new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
-                    new FunctionalReturnContext(resultInfo.checkContext);
-
-            ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
-                recoveryInfo :
-                new ResultInfo(KindSelector.VAL,
-                               lambdaType.getReturnType(), funcContext);
-            localEnv.info.returnResult = bodyResultInfo;
+            ResultInfo bodyResultInfo = localEnv.info.returnResult =
+                    lambdaBodyResult(that, lambdaType, resultInfo);
 
             if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
                 attribTree(that.getBody(), localEnv, bodyResultInfo);
@@ -2467,6 +2497,44 @@
         }
     }
     //where
+        class TargetInfo {
+            Type target;
+            Type descriptor;
+
+            public TargetInfo(Type target, Type descriptor) {
+                this.target = target;
+                this.descriptor = descriptor;
+            }
+        }
+
+        TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
+            Type lambdaType;
+            Type currentTarget = resultInfo.pt;
+            if (resultInfo.pt != Type.recoveryType) {
+                /* We need to adjust the target. If the target is an
+                 * intersection type, for example: SAM & I1 & I2 ...
+                 * the target will be updated to SAM
+                 */
+                currentTarget = targetChecker.visit(currentTarget, that);
+                if (explicitParamTypes != null) {
+                    currentTarget = infer.instantiateFunctionalInterface(that,
+                            currentTarget, explicitParamTypes, resultInfo.checkContext);
+                }
+                currentTarget = types.removeWildcards(currentTarget);
+                lambdaType = types.findDescriptorType(currentTarget);
+            } else {
+                currentTarget = Type.recoveryType;
+                lambdaType = fallbackDescriptorType(that);
+            }
+            if (that.hasTag(LAMBDA) && lambdaType.hasTag(FORALL)) {
+                //lambda expression target desc cannot be a generic method
+                resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
+                        lambdaType, kindName(currentTarget.tsym), currentTarget.tsym));
+                currentTarget = types.createErrorType(pt());
+            }
+            return new TargetInfo(currentTarget, lambdaType);
+        }
+
         void preFlow(JCLambda tree) {
             new PostAttrAnalyzer() {
                 @Override
@@ -2612,13 +2680,24 @@
             }
         }
 
+        ResultInfo lambdaBodyResult(JCLambda that, Type descriptor, ResultInfo resultInfo) {
+            FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+                    new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
+                    new FunctionalReturnContext(resultInfo.checkContext);
+
+            return descriptor.getReturnType() == Type.recoveryType ?
+                    recoveryInfo :
+                    new ResultInfo(KindSelector.VAL,
+                            descriptor.getReturnType(), funcContext);
+        }
+
         /**
         * Lambda compatibility. Check that given return types, thrown types, parameter types
         * are compatible with the expected functional interface descriptor. This means that:
         * (i) parameter types must be identical to those of the target descriptor; (ii) return
         * types must be compatible with the return type of the expected descriptor.
         */
-        private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) {
+        void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) {
             Type returnType = checkContext.inferenceContext().asUndetVar(descriptor.getReturnType());
 
             //return values have already been checked - but if lambda has no return
@@ -2746,18 +2825,12 @@
                 typeargtypes = attribTypes(that.typeargs, localEnv);
             }
 
-            Type desc;
-            Type currentTarget = pt();
             boolean isTargetSerializable =
                     resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
-                    isSerializable(currentTarget);
-            if (currentTarget != Type.recoveryType) {
-                currentTarget = types.removeWildcards(targetChecker.visit(currentTarget, that));
-                desc = types.findDescriptorType(currentTarget);
-            } else {
-                currentTarget = Type.recoveryType;
-                desc = fallbackDescriptorType(that);
-            }
+                    isSerializable(pt());
+            TargetInfo targetInfo = getTargetInfo(that, resultInfo, null);
+            Type currentTarget = targetInfo.target;
+            Type desc = targetInfo.descriptor;
 
             setFunctionalInfo(localEnv, that, pt(), desc, currentTarget, resultInfo.checkContext);
             List<Type> argtypes = desc.getParameterTypes();
@@ -3279,7 +3352,7 @@
         }
 
         // Attribute the qualifier expression, and determine its symbol (if any).
-        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Infer.anyPoly));
+        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.noType));
         if (!pkind().contains(KindSelector.TYP_PCK))
             site = capture(site); // Capture field access
 
@@ -3884,8 +3957,15 @@
                        syms.methodClass);
             }
 
-            return chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
-                    resultInfo.checkContext.inferenceContext());
+            PolyKind pkind = (sym.type.hasTag(FORALL) &&
+                 sym.type.getReturnType().containsAny(((ForAll)sym.type).tvars)) ?
+                 PolyKind.POLY : PolyKind.STANDALONE;
+            TreeInfo.setPolyKind(env.tree, pkind);
+
+            return (resultInfo.pt == Infer.anyPoly) ?
+                    owntype :
+                    chk.checkMethod(owntype, sym, env, argtrees, argtypes, env.info.lastResolveVarargs(),
+                            resultInfo.checkContext.inferenceContext());
         } catch (Infer.InferenceException ex) {
             //invalid target type - propagate exception outwards or report error
             //depending on the current check context