src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
changeset 55306 ea43db53de91
parent 54900 e9f5e06a0dd7
child 55561 4c0a7916d3cd
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Sun Jun 09 15:48:57 2019 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Jun 10 05:09:52 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -182,6 +182,8 @@
         this.keepLineMap = keepLineMap;
         this.errorTree = F.Erroneous();
         endPosTable = newEndPosTable(keepEndPositions);
+        this.allowYieldStatement = (!preview.isPreview(Feature.SWITCH_EXPRESSION) || preview.isEnabled()) &&
+                Feature.SWITCH_EXPRESSION.allowedInSource(source);
     }
 
     protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
@@ -211,6 +213,10 @@
      */
     boolean allowThisIdent;
 
+    /** Switch: is yield statement allowed in this source level?
+     */
+    boolean allowYieldStatement;
+
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
     JCVariableDecl receiverParam;
@@ -769,9 +775,10 @@
 
     public JCExpression unannotatedType(boolean allowVar) {
         JCExpression result = term(TYPE);
-
-        if (!allowVar && isRestrictedLocalVarTypeName(result, true)) {
-            syntaxError(result.pos, Errors.VarNotAllowedHere);
+        Name restrictedTypeName;
+
+        if (!allowVar && (restrictedTypeName = restrictedTypeName(result, true)) != null) {
+            syntaxError(result.pos, Errors.RestrictedTypeNotAllowedHere(restrictedTypeName));
         }
 
         return result;
@@ -1377,6 +1384,7 @@
             break;
         case SWITCH:
             checkSourceLevel(Feature.SWITCH_EXPRESSION);
+            allowYieldStatement = true;
             int switchPos = token.pos;
             nextToken();
             JCExpression selector = parExpression();
@@ -1436,7 +1444,7 @@
                     kind = JCCase.RULE;
                 } else {
                     JCExpression value = parseExpression();
-                    stats = List.of(to(F.at(value).Break(value)));
+                    stats = List.of(to(F.at(value).Yield(value)));
                     body = value;
                     kind = JCCase.RULE;
                     accept(SEMI);
@@ -1607,7 +1615,7 @@
         int depth = 0;
         boolean type = false;
         ParensResult defaultResult = ParensResult.PARENS;
-        outer: for (int lookahead = 0 ; ; lookahead++) {
+        outer: for (int lookahead = 0; ; lookahead++) {
             TokenKind tk = S.token(lookahead).kind;
             switch (tk) {
                 case COMMA:
@@ -1782,12 +1790,13 @@
         if (explicitParams) {
             LambdaClassifier lambdaClassifier = new LambdaClassifier();
             for (JCVariableDecl param: params) {
+                Name restrictedTypeName;
                 if (param.vartype != null &&
-                        isRestrictedLocalVarTypeName(param.vartype, false) &&
+                        (restrictedTypeName = restrictedTypeName(param.vartype, false)) != null &&
                         param.vartype.hasTag(TYPEARRAY)) {
                     log.error(DiagnosticFlag.SYNTAX, param.pos,
                         Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS.allowedInSource(source)
-                            ? Errors.VarNotAllowedArray : Errors.VarNotAllowedHere);
+                            ? Errors.RestrictedTypeNotAllowedArray(restrictedTypeName) : Errors.RestrictedTypeNotAllowedHere(restrictedTypeName));
                 }
                 lambdaClassifier.addParameter(param);
                 if (lambdaClassifier.result() == LambdaParameterKind.ERROR) {
@@ -1799,7 +1808,7 @@
             }
             for (JCVariableDecl param: params) {
                 if (param.vartype != null
-                        && isRestrictedLocalVarTypeName(param.vartype, true)) {
+                        && restrictedTypeName(param.vartype, true) != null) {
                     checkSourceLevel(param.pos, Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS);
                     param.startPos = TreeInfo.getStartPos(param.vartype);
                     param.vartype = null;
@@ -1837,7 +1846,7 @@
 
         void addParameter(JCVariableDecl param) {
             if (param.vartype != null && param.name != names.empty) {
-                if (isRestrictedLocalVarTypeName(param.vartype, false)) {
+                if (restrictedTypeName(param.vartype, false) != null) {
                     reduce(LambdaParameterKind.VAR);
                 } else {
                     reduce(LambdaParameterKind.EXPLICIT);
@@ -1944,10 +1953,27 @@
         return args.toList();
     }
 
-    JCMethodInvocation arguments(List<JCExpression> typeArgs, JCExpression t) {
+    JCExpression arguments(List<JCExpression> typeArgs, JCExpression t) {
         int pos = token.pos;
         List<JCExpression> args = arguments();
-        return toP(F.at(pos).Apply(typeArgs, t, args));
+        JCExpression mi = F.at(pos).Apply(typeArgs, t, args);
+        if (t.hasTag(IDENT) && isInvalidUnqualifiedMethodIdentifier(((JCIdent) t).pos,
+                                                                    ((JCIdent) t).name)) {
+            log.error(DiagnosticFlag.SYNTAX, t, Errors.InvalidYield);
+            mi = F.Erroneous(List.of(mi));
+        }
+        return toP(mi);
+    }
+
+    boolean isInvalidUnqualifiedMethodIdentifier(int pos, Name name) {
+        if (name == names.yield) {
+            if (allowYieldStatement) {
+                return true;
+            } else {
+                log.warning(pos, Warnings.InvalidYield);
+            }
+        }
+        return false;
     }
 
     /**  TypeArgumentsOpt = [ TypeArguments ]
@@ -2506,6 +2532,7 @@
 
     /**This method parses a statement appearing inside a block.
      */
+    @SuppressWarnings("fallthrough")
     List<JCStatement> blockStatement() {
         //todo: skip to anchor on error(?)
         int pos = token.pos;
@@ -2543,6 +2570,52 @@
             log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
             dc = token.comment(CommentStyle.JAVADOC);
             return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+        case IDENTIFIER:
+            if (token.name() == names.yield && allowYieldStatement) {
+                Token next = S.token(1);
+                boolean isYieldStatement;
+                switch (next.kind) {
+                    case PLUS: case SUB: case STRINGLITERAL: case CHARLITERAL:
+                    case INTLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
+                    case NULL: case IDENTIFIER: case TRUE: case FALSE:
+                    case NEW: case SWITCH: case THIS: case SUPER:
+                        isYieldStatement = true;
+                        break;
+                    case PLUSPLUS: case SUBSUB:
+                        isYieldStatement = S.token(2).kind != SEMI;
+                        break;
+                    case LPAREN:
+                        int lookahead = 2;
+                        int balance = 1;
+                        boolean hasComma = false;
+                        Token l;
+                        while ((l = S.token(lookahead)).kind != EOF && balance != 0) {
+                            switch (l.kind) {
+                                case LPAREN: balance++; break;
+                                case RPAREN: balance--; break;
+                                case COMMA: if (balance == 1) hasComma = true; break;
+                            }
+                            lookahead++;
+                        }
+                        isYieldStatement = (!hasComma && lookahead != 3) || l.kind == ARROW;
+                        break;
+                    case SEMI: //error recovery - this is not a valid statement:
+                        isYieldStatement = true;
+                        break;
+                    default:
+                        isYieldStatement = false;
+                        break;
+                }
+
+                if (isYieldStatement) {
+                    nextToken();
+                    JCExpression t = term(EXPR);
+                    accept(SEMI);
+                    return List.of(toP(F.at(pos).Yield(t)));
+                }
+
+                //else intentional fall-through
+            }
         default:
             Token prevToken = token;
             JCExpression t = term(EXPR | TYPE);
@@ -2702,9 +2775,9 @@
         }
         case BREAK: {
             nextToken();
-            JCExpression value = token.kind == SEMI ? null : parseExpression();
+            Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;
             accept(SEMI);
-            JCBreak t = toP(F.at(pos).Break(value));
+            JCBreak t = toP(F.at(pos).Break(label));
             return t;
         }
         case CONTINUE: {
@@ -3181,14 +3254,14 @@
         int startPos = Position.NOPOS;
         if (elemType.hasTag(IDENT)) {
             Name typeName = ((JCIdent)elemType).name;
-            if (isRestrictedLocalVarTypeName(typeName, pos, !compound && localDecl)) {
+            if (isRestrictedTypeName(typeName, pos, !compound && localDecl)) {
                 if (type.hasTag(TYPEARRAY) && !compound) {
                     //error - 'var' and arrays
-                    reportSyntaxError(pos, Errors.VarNotAllowedArray);
+                    reportSyntaxError(pos, Errors.RestrictedTypeNotAllowedArray(typeName));
                 } else {
                     if(compound)
                         //error - 'var' in compound local var decl
-                        reportSyntaxError(pos, Errors.VarNotAllowedCompound);
+                        reportSyntaxError(pos, Errors.RestrictedTypeNotAllowedCompound(typeName));
                     startPos = TreeInfo.getStartPos(mods);
                     if (startPos == Position.NOPOS)
                         startPos = TreeInfo.getStartPos(type);
@@ -3204,23 +3277,30 @@
         return result;
     }
 
-    boolean isRestrictedLocalVarTypeName(JCExpression e, boolean shouldWarn) {
+    Name restrictedTypeName(JCExpression e, boolean shouldWarn) {
         switch (e.getTag()) {
             case IDENT:
-                return isRestrictedLocalVarTypeName(((JCIdent)e).name, e.pos, shouldWarn);
+                return isRestrictedTypeName(((JCIdent)e).name, e.pos, shouldWarn) ? ((JCIdent)e).name : null;
             case TYPEARRAY:
-                return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype, shouldWarn);
+                return restrictedTypeName(((JCArrayTypeTree)e).elemtype, shouldWarn);
             default:
-                return false;
+                return null;
         }
     }
 
-    boolean isRestrictedLocalVarTypeName(Name name, int pos, boolean shouldWarn) {
+    boolean isRestrictedTypeName(Name name, int pos, boolean shouldWarn) {
         if (name == names.var) {
             if (Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source)) {
                 return true;
             } else if (shouldWarn) {
-                log.warning(pos, Warnings.VarNotAllowed);
+                log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10));
+            }
+        }
+        if (name == names.yield) {
+            if (allowYieldStatement) {
+                return true;
+            } else if (shouldWarn) {
+                log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK13));
             }
         }
         return false;
@@ -3614,8 +3694,8 @@
     Name typeName() {
         int pos = token.pos;
         Name name = ident();
-        if (isRestrictedLocalVarTypeName(name, pos, true)) {
-            reportSyntaxError(pos, Errors.VarNotAllowed);
+        if (isRestrictedTypeName(name, pos, true)) {
+            reportSyntaxError(pos, Errors.RestrictedTypeNotAllowed(name, name == names.var ? Source.JDK10 : Source.JDK13));
         }
         return name;
     }