8206986: Compiler support for Switch Expressions (Preview)
8207405: Compiler Tree API support for Switch Expressions (Preview)
Summary: Support for switch expression, switch with rules and multiple constants for cases.
Reviewed-by: jjg, mcimadamore, vromero
--- a/make/langtools/tools/propertiesparser/parser/MessageType.java Tue Aug 28 09:01:54 2018 +0200
+++ b/make/langtools/tools/propertiesparser/parser/MessageType.java Wed Aug 29 09:36:17 2018 +0200
@@ -95,6 +95,7 @@
KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
TARGET("target", "Target", "com.sun.tools.javac.jvm"),
TOKEN("token", "TokenKind", "com.sun.tools.javac.parser.Tokens"),
+ TREE_TAG("tree tag", "Tag", "com.sun.tools.javac.tree.JCTree"),
TYPE("type", "Type", "com.sun.tools.javac.code"),
URL("url", "URL", "java.net"),
SET("set", "Set", "java.util"),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/BreakTree.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BreakTree.java Wed Aug 29 09:36:17 2018 +0200
@@ -35,6 +35,8 @@
* break;
*
* break <em>label</em> ;
+ *
+ * break <em>expression</em> ;
* </pre>
*
* @jls section 14.15
@@ -49,4 +51,18 @@
* @return the label
*/
Name getLabel();
+
+ /**
+ * Returns the expression for this {@code break} statement.
+ *
+ * @return the expression
+ * @since 12
+ *
+ * @deprecated This method is modeling value breaks, which are part of
+ * a preview feature and may be removed if the preview feature
+ * is removed.
+ *
+ */
+ @Deprecated(forRemoval=true, since="12")
+ ExpressionTree getValue();
}
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java Wed Aug 29 09:36:17 2018 +0200
@@ -28,7 +28,7 @@
import java.util.List;
/**
- * A tree node for a {@code case} in a {@code switch} statement.
+ * A tree node for a {@code case} in a {@code switch} statement or expression.
*
* For example:
* <pre>
@@ -49,13 +49,89 @@
/**
* Returns the expression for the case, or
* {@code null} if this is the default case.
+ * If this case has multiple lables, returns the first label.
* @return the expression for the case, or null
*/
ExpressionTree getExpression();
/**
- * Returns the statements labeled by the case.
- * @return the statements labeled by the case
+ * Returns the labels for this case.
+ * For default case, returns an empty list.
+ *
+ * @return labels for this case
+ * @since 12
+ *
+ * @deprecated This method is modeling a case with multiple labels,
+ * which is part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ List<? extends ExpressionTree> getExpressions();
+
+ /**
+ * For case with kind {@linkplain CaseKind#STATEMENT},
+ * returns the statements labeled by the case.
+ * Returns {@code null} for case with kind
+ * {@linkplain CaseKind#RULE}.
+ * @return the statements labeled by the case or null
*/
List<? extends StatementTree> getStatements();
+
+ /**
+ * For case with kind {@linkplain CaseKind#RULE},
+ * returns the statement or expression after the arrow.
+ * Returns {@code null} for case with kind
+ * {@linkplain CaseKind#STATEMENT}.
+ *
+ * @return case value or null
+ * @since 12
+ *
+ * @deprecated This method is modeling a rule case,
+ * which is part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ public default Tree getBody() {
+ return null;
+ }
+
+ /**
+ * Returns the kind of this case.
+ *
+ * @return the kind of this case
+ * @since 12
+ *
+ * @deprecated This method is used to model a rule case,
+ * which is part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ public default CaseKind getCaseKind() {
+ return CaseKind.STATEMENT;
+ }
+
+ /**
+ * The syntatic form of this case:
+ * <ul>
+ * <li>STATEMENT: {@code case <expression>: <statements>}</li>
+ * <li>RULE: {@code case <expression> -> <expression>/<statement>}</li>
+ * </ul>
+ *
+ * @since 12
+ *
+ * @deprecated This enum is used to model a rule case,
+ * which is part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ public enum CaseKind {
+ /**
+ * Case is in the form: {@code case <expression>: <statements>}.
+ */
+ STATEMENT,
+ /**
+ * Case is in the form: {@code case <expression> -> <expression>}.
+ */
+ RULE;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a {@code switch} expression.
+ *
+ * For example:
+ * <pre>
+ * switch ( <em>expression</em> ) {
+ * <em>cases</em>
+ * }
+ * </pre>
+ *
+ * @jls section 15.29
+ *
+ * @since 12
+ *
+ * @deprecated This method is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+@Deprecated(forRemoval=true, since="12")
+public interface SwitchExpressionTree extends ExpressionTree {
+ /**
+ * Returns the expression for the {@code switch} expression.
+ * @return the expression
+ */
+ ExpressionTree getExpression();
+
+ /**
+ * Returns the cases for the {@code switch} expression.
+ * @return the cases
+ */
+ List<? extends CaseTree> getCases();
+}
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java Wed Aug 29 09:36:17 2018 +0200
@@ -240,6 +240,20 @@
SWITCH(SwitchTree.class),
/**
+ * Used for instances of {@link SwitchExpressionTree}.
+ *
+ * @since 12
+ *
+ * @deprecated
+ * This enum constant is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ @SuppressWarnings("removal")
+ SWITCH_EXPRESSION(SwitchExpressionTree.class),
+
+ /**
* Used for instances of {@link SynchronizedTree}.
*/
SYNCHRONIZED(SynchronizedTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java Wed Aug 29 09:36:17 2018 +0200
@@ -354,6 +354,23 @@
R visitSwitch(SwitchTree node, P p);
/**
+ * Visits a SwitchExpressionTree node.
+ *
+ * @param node the node being visited
+ * @param p a parameter value
+ * @return a result value
+ * @since 12
+ *
+ * @deprecated
+ * This method is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Deprecated(forRemoval=true, since="12")
+ @SuppressWarnings("removal")
+ R visitSwitchExpression(SwitchExpressionTree node, P p);
+
+ /**
* Visits a SynchronizedTree node.
* @param node the node being visited
* @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java Wed Aug 29 09:36:17 2018 +0200
@@ -269,6 +269,25 @@
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
+ *
+ * @deprecated
+ * This method is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+ @Override
+ @Deprecated(forRemoval=true, since="12")
+ @SuppressWarnings("removal")
+ public R visitSwitchExpression(SwitchExpressionTree node, P p) {
+ return defaultAction(node, p);
+ }
+
+ /**
+ * {@inheritDoc} This implementation calls {@code defaultAction}.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of {@code defaultAction}
*/
@Override
public R visitCase(CaseTree node, P p) {
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java Wed Aug 29 09:36:17 2018 +0200
@@ -26,6 +26,7 @@
package com.sun.source.util;
import com.sun.source.tree.*;
+import com.sun.source.tree.CaseTree.CaseKind;
/**
* A TreeVisitor that visits all the child tree nodes.
@@ -339,11 +340,36 @@
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
+ *
+ * @deprecated
+ * This method is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
*/
@Override
- public R visitCase(CaseTree node, P p) {
+ @Deprecated(forRemoval=true, since="12")
+ @SuppressWarnings("removal")
+ public R visitSwitchExpression(SwitchExpressionTree node, P p) {
R r = scan(node.getExpression(), p);
- r = scanAndReduce(node.getStatements(), p, r);
+ r = scanAndReduce(node.getCases(), p, r);
+ return r;
+ }
+
+ /**
+ * {@inheritDoc} This implementation scans the children in left to right order.
+ *
+ * @param node {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of scanning
+ */
+ @Override
+ @SuppressWarnings("removal")
+ public R visitCase(CaseTree node, P p) {
+ R r = scan(node.getExpressions(), p);
+ if (node.getCaseKind() == CaseKind.RULE)
+ r = scanAndReduce(node.getBody(), p, r);
+ else
+ r = scanAndReduce(node.getStatements(), p, r);
return r;
}
@@ -441,8 +467,9 @@
* @return the result of scanning
*/
@Override
+ @SuppressWarnings("removal")
public R visitBreak(BreakTree node, P p) {
- return null;
+ return scan(node.getValue(), p);
}
/**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java Wed Aug 29 09:36:17 2018 +0200
@@ -165,6 +165,10 @@
* @return true, if given feature is a preview feature.
*/
public boolean isPreview(Feature feature) {
+ if (feature == Feature.SWITCH_EXPRESSION ||
+ feature == Feature.SWITCH_MULTIPLE_CASE_LABELS ||
+ feature == Feature.SWITCH_RULE)
+ return true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'
//for those selected features, and 'false' for all the others.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Wed Aug 29 09:36:17 2018 +0200
@@ -180,7 +180,10 @@
UNDERSCORE_IDENTIFIER(MIN, JDK8),
PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
- IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES(JDK1_2, JDK8);
+ IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES(JDK1_2, JDK8),
+ SWITCH_MULTIPLE_CASE_LABELS(JDK12, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL),
+ SWITCH_RULE(JDK12, Fragments.FeatureSwitchRules, DiagKind.PLURAL),
+ SWITCH_EXPRESSION(JDK12, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL);
enum DiagKind {
NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Wed Aug 29 09:36:17 2018 +0200
@@ -184,6 +184,7 @@
public final Type noClassDefFoundErrorType;
public final Type noSuchFieldErrorType;
public final Type assertionErrorType;
+ public final Type incompatibleClassChangeErrorType;
public final Type cloneNotSupportedExceptionType;
public final Type annotationType;
public final TypeSymbol enumSym;
@@ -526,6 +527,7 @@
noClassDefFoundErrorType = enterClass("java.lang.NoClassDefFoundError");
noSuchFieldErrorType = enterClass("java.lang.NoSuchFieldError");
assertionErrorType = enterClass("java.lang.AssertionError");
+ incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError");
cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
annotationType = enterClass("java.lang.annotation.Annotation");
classLoaderType = enterClass("java.lang.ClassLoader");
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java Wed Aug 29 09:36:17 2018 +0200
@@ -25,7 +25,6 @@
package com.sun.tools.javac.comp;
-import com.sun.source.tree.LambdaExpressionTree.BodyKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symtab;
@@ -39,10 +38,12 @@
import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
+import com.sun.tools.javac.comp.DeferredAttr.SwitchExpressionScanner;
import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCLambda;
@@ -52,6 +53,7 @@
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCReturn;
+import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Assert;
@@ -145,7 +147,7 @@
* Checks a type in the speculative tree against a given result; the type can be either a plain
* type or an argument type,in which case a more complex check is required.
*/
- Type checkSpeculative(JCExpression expr, ResultInfo resultInfo) {
+ Type checkSpeculative(JCTree expr, ResultInfo resultInfo) {
return checkSpeculative(expr, expr.type, resultInfo);
}
@@ -256,6 +258,11 @@
}
@Override
+ public void visitSwitchExpression(JCSwitchExpression that) {
+ processArg(that, speculativeTree -> new SwitchExpressionType(that, env, speculativeTree));
+ }
+
+ @Override
public void visitReference(JCMemberReference tree) {
//perform arity-based check
Env<AttrContext> localEnv = env.dup(tree);
@@ -456,6 +463,61 @@
}
/**
+ * Argument type for switch expressions.
+ */
+ class SwitchExpressionType extends ArgumentType<JCSwitchExpression> {
+ /** List of break expressions (lazily populated). */
+ Optional<List<JCBreak>> breakExpressions = Optional.empty();
+
+ SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond) {
+ this(tree, env, speculativeCond, new HashMap<>());
+ }
+
+ SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond, Map<ResultInfo, Type> speculativeTypes) {
+ super(tree, env, speculativeCond, speculativeTypes);
+ }
+
+ @Override
+ Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+ ResultInfo localInfo = resultInfo.dup(attr.conditionalContext(resultInfo.checkContext));
+ if (resultInfo.pt.hasTag(VOID)) {
+ //this means we are returning a poly switch expression from void-compatible lambda expression
+ resultInfo.checkContext.report(tree, attr.diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
+ return attr.types.createErrorType(resultInfo.pt);
+ } else {
+ //poly
+ for (JCBreak brk : breakExpressions()) {
+ checkSpeculative(brk.value, brk.value.type, resultInfo);
+ }
+ return localInfo.pt;
+ }
+ }
+
+ /** Compute return expressions (if needed). */
+ List<JCBreak> breakExpressions() {
+ return breakExpressions.orElseGet(() -> {
+ final List<JCBreak> res;
+ ListBuffer<JCBreak> buf = new ListBuffer<>();
+ new SwitchExpressionScanner() {
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.target == speculativeTree)
+ buf.add(tree);
+ }
+ }.scan(speculativeTree.cases);
+ res = buf.toList();
+ breakExpressions = Optional.of(res);
+ return res;
+ });
+ }
+
+ @Override
+ ArgumentType<JCSwitchExpression> dup(JCSwitchExpression tree, Env<AttrContext> env) {
+ return new SwitchExpressionType(tree, env, speculativeTree, speculativeTypes);
+ }
+ }
+
+ /**
* Argument type for explicit lambdas.
*/
class ExplicitLambdaType extends ArgumentType<JCLambda> {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Aug 29 09:36:17 2018 +0200
@@ -26,10 +26,13 @@
package com.sun.tools.javac.comp;
import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
import javax.lang.model.element.ElementKind;
import javax.tools.JavaFileObject;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.MemberSelectTree;
@@ -1395,41 +1398,123 @@
}
public void visitSwitch(JCSwitch tree) {
- Type seltype = attribExpr(tree.selector, env);
+ handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+ attribStats(c.stats, caseEnv);
+ });
+ result = null;
+ }
+
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ tree.polyKind = (pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly) ?
+ PolyKind.STANDALONE : PolyKind.POLY;
+
+ if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
+ //this means we are returning a poly conditional from void-compatible lambda expression
+ resultInfo.checkContext.report(tree, diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
+ result = tree.type = types.createErrorType(resultInfo.pt);
+ return;
+ }
+
+ ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
+ unknownExprInfo :
+ resultInfo.dup(switchExpressionContext(resultInfo.checkContext));
+
+ ListBuffer<DiagnosticPosition> caseTypePositions = new ListBuffer<>();
+ ListBuffer<Type> caseTypes = new ListBuffer<>();
+
+ handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+ caseEnv.info.breakResult = condInfo;
+ attribStats(c.stats, caseEnv);
+ new TreeScanner() {
+ @Override
+ public void visitBreak(JCBreak brk) {
+ if (brk.target == tree) {
+ caseTypePositions.append(brk.value != null ? brk.value.pos() : brk.pos());
+ caseTypes.append(brk.value != null ? brk.value.type : syms.errType);
+ }
+ super.visitBreak(brk);
+ }
+
+ @Override public void visitClassDef(JCClassDecl tree) {}
+ @Override public void visitLambda(JCLambda tree) {}
+ }.scan(c.stats);
+ });
+
+ if (tree.cases.isEmpty()) {
+ log.error(tree.pos(),
+ Errors.SwitchExpressionEmpty);
+ }
+
+ Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(caseTypePositions.toList(), caseTypes.toList()) : pt();
+
+ result = tree.type = check(tree, owntype, KindSelector.VAL, resultInfo);
+ }
+ //where:
+ CheckContext switchExpressionContext(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(Fragments.IncompatibleTypeInSwitchExpression(details)));
+ }
+ };
+ }
+
+ private void handleSwitch(JCTree switchTree,
+ JCExpression selector,
+ List<JCCase> cases,
+ BiConsumer<JCCase, Env<AttrContext>> attribCase) {
+ Type seltype = attribExpr(selector, env);
Env<AttrContext> switchEnv =
- env.dup(tree, env.info.dup(env.info.scope.dup()));
+ env.dup(switchTree, env.info.dup(env.info.scope.dup()));
try {
-
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
boolean stringSwitch = types.isSameType(seltype, syms.stringType);
if (!enumSwitch && !stringSwitch)
- seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
+ seltype = chk.checkType(selector.pos(), seltype, syms.intType);
// Attribute all cases and
// check that there are no duplicate case labels or default clauses.
Set<Object> labels = new HashSet<>(); // The set of case labels.
boolean hasDefault = false; // Is there a default label?
- for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ @SuppressWarnings("removal")
+ CaseKind caseKind = null;
+ boolean wasError = false;
+ for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
JCCase c = l.head;
- if (c.pat != null) {
- if (enumSwitch) {
- Symbol sym = enumConstant(c.pat, seltype);
- if (sym == null) {
- log.error(c.pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
- } else if (!labels.add(sym)) {
- log.error(c.pos(), Errors.DuplicateCaseLabel);
- }
- } else {
- Type pattype = attribExpr(c.pat, switchEnv, seltype);
- if (!pattype.hasTag(ERROR)) {
- if (pattype.constValue() == null) {
- log.error(c.pat.pos(),
- (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
- } else if (!labels.add(pattype.constValue())) {
+ if (caseKind == null) {
+ caseKind = c.caseKind;
+ } else if (caseKind != c.caseKind && !wasError) {
+ log.error(c.pos(),
+ Errors.SwitchMixingCaseTypes);
+ wasError = true;
+ }
+ if (c.getExpressions().nonEmpty()) {
+ for (JCExpression pat : c.getExpressions()) {
+ if (TreeInfo.isNull(pat)) {
+ log.error(pat.pos(),
+ Errors.SwitchNullNotAllowed);
+ } else if (enumSwitch) {
+ Symbol sym = enumConstant(pat, seltype);
+ if (sym == null) {
+ log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
+ } else if (!labels.add(sym)) {
log.error(c.pos(), Errors.DuplicateCaseLabel);
}
+ } else {
+ Type pattype = attribExpr(pat, switchEnv, seltype);
+ if (!pattype.hasTag(ERROR)) {
+ if (pattype.constValue() == null) {
+ log.error(pat.pos(),
+ (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
+ } else if (!labels.add(pattype.constValue())) {
+ log.error(c.pos(), Errors.DuplicateCaseLabel);
+ }
+ }
}
}
} else if (hasDefault) {
@@ -1440,16 +1525,13 @@
Env<AttrContext> caseEnv =
switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
try {
- attribStats(c.stats, caseEnv);
+ attribCase.accept(c, caseEnv);
} finally {
caseEnv.info.scope.leave();
addVars(c.stats, switchEnv.info.scope);
}
}
-
- result = null;
- }
- finally {
+ } finally {
switchEnv.info.scope.leave();
}
}
@@ -1609,7 +1691,9 @@
Type truetype = attribTree(tree.truepart, env, condInfo);
Type falsetype = attribTree(tree.falsepart, env, condInfo);
- Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, truetype, falsetype) : pt();
+ Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
+ condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
+ List.of(truetype, falsetype)) : pt();
if (condtype.constValue() != null &&
truetype.constValue() != null &&
falsetype.constValue() != null &&
@@ -1690,67 +1774,66 @@
* @param thentype The type of the expression's then-part.
* @param elsetype The type of the expression's else-part.
*/
- Type condType(DiagnosticPosition pos,
- Type thentype, Type elsetype) {
+ Type condType(List<DiagnosticPosition> positions, List<Type> condTypes) {
+ if (condTypes.isEmpty()) {
+ return syms.objectType; //TODO: how to handle?
+ }
+ if (condTypes.size() == 1) {
+ return condTypes.head;
+ }
+ Type first = condTypes.head;
// If same type, that is the result
- if (types.isSameType(thentype, elsetype))
- return thentype.baseType();
-
- Type thenUnboxed = (thentype.isPrimitive())
- ? thentype : types.unboxedType(thentype);
- Type elseUnboxed = (elsetype.isPrimitive())
- ? elsetype : types.unboxedType(elsetype);
+ if (condTypes.tail.stream().allMatch(t -> types.isSameType(first, t)))
+ return first.baseType();
+
+ List<Type> unboxedTypes = condTypes.stream()
+ .map(t -> t.isPrimitive() ? t : types.unboxedType(t))
+ .collect(List.collector());
// Otherwise, if both arms can be converted to a numeric
// type, return the least numeric type that fits both arms
// (i.e. return larger of the two, or return int if one
// arm is short, the other is char).
- if (thenUnboxed.isPrimitive() && elseUnboxed.isPrimitive()) {
+ if (unboxedTypes.stream().allMatch(t -> t.isPrimitive())) {
// If one arm has an integer subrange type (i.e., byte,
// short, or char), and the other is an integer constant
// that fits into the subrange, return the subrange type.
- if (thenUnboxed.getTag().isStrictSubRangeOf(INT) &&
- elseUnboxed.hasTag(INT) &&
- types.isAssignable(elseUnboxed, thenUnboxed)) {
- return thenUnboxed.baseType();
- }
- if (elseUnboxed.getTag().isStrictSubRangeOf(INT) &&
- thenUnboxed.hasTag(INT) &&
- types.isAssignable(thenUnboxed, elseUnboxed)) {
- return elseUnboxed.baseType();
+ for (Type type : unboxedTypes) {
+ if (!type.getTag().isStrictSubRangeOf(INT)) {
+ continue;
+ }
+ if (unboxedTypes.stream().filter(t -> t != type).allMatch(t -> t.hasTag(INT) && types.isAssignable(t, type)))
+ return type.baseType();
}
for (TypeTag tag : primitiveTags) {
Type candidate = syms.typeOfTag[tag.ordinal()];
- if (types.isSubtype(thenUnboxed, candidate) &&
- types.isSubtype(elseUnboxed, candidate)) {
+ if (unboxedTypes.stream().allMatch(t -> types.isSubtype(t, candidate))) {
return candidate;
}
}
}
// Those were all the cases that could result in a primitive
- if (thentype.isPrimitive())
- thentype = types.boxedClass(thentype).type;
- if (elsetype.isPrimitive())
- elsetype = types.boxedClass(elsetype).type;
-
- if (types.isSubtype(thentype, elsetype))
- return elsetype.baseType();
- if (types.isSubtype(elsetype, thentype))
- return thentype.baseType();
-
- if (thentype.hasTag(VOID) || elsetype.hasTag(VOID)) {
- log.error(pos,
- Errors.NeitherConditionalSubtype(thentype,
- elsetype));
- return thentype.baseType();
- }
+ condTypes = condTypes.stream()
+ .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
+ .collect(List.collector());
+
+ for (Type type : condTypes) {
+ if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
+ return type.baseType();
+ }
+
+ Iterator<DiagnosticPosition> posIt = positions.iterator();
+
+ condTypes = condTypes.stream()
+ .map(t -> chk.checkNonVoid(posIt.next(), t))
+ .collect(List.collector());
// both are known to be reference types. The result is
// lub(thentype,elsetype). This cannot fail, as it will
// always be possible to infer "Object" if nothing better.
- return types.lub(thentype.baseType(), elsetype.baseType());
+ return types.lub(condTypes.stream().map(t -> t.baseType()).collect(List.collector()));
}
final static TypeTag[] primitiveTags = new TypeTag[]{
@@ -1782,7 +1865,68 @@
}
public void visitBreak(JCBreak tree) {
- tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
+ if (env.info.breakResult != null) {
+ if (tree.value == null) {
+ tree.target = findJumpTarget(tree.pos(), tree.getTag(), null, env);
+ if (tree.target.hasTag(SWITCH_EXPRESSION)) {
+ log.error(tree.pos(), Errors.BreakMissingValue);
+ }
+ } else {
+ if (env.info.breakResult.pt.hasTag(VOID)) {
+ //can happen?
+ env.info.breakResult.checkContext.report(tree.value.pos(),
+ diags.fragment(Fragments.UnexpectedRetVal));
+ }
+ boolean attribute = true;
+ if (tree.value.hasTag(IDENT)) {
+ //disambiguate break <LABEL> and break <ident-as-an-expression>:
+ Name label = ((JCIdent) tree.value).name;
+ Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tree.getTag(), label, env);
+
+ if (jumpTarget.fst != null) {
+ JCTree speculative = deferredAttr.attribSpeculative(tree.value, env, unknownExprInfo);
+ if (!speculative.type.hasTag(ERROR)) {
+ log.error(tree.pos(), Errors.BreakAmbiguousTarget(label));
+ if (jumpTarget.snd == null) {
+ tree.target = jumpTarget.fst;
+ attribute = false;
+ } else {
+ //nothing
+ }
+ } else {
+ if (jumpTarget.snd != null) {
+ log.error(tree.pos(), jumpTarget.snd);
+ }
+ tree.target = jumpTarget.fst;
+ attribute = false;
+ }
+ }
+ }
+ if (attribute) {
+ attribTree(tree.value, env, env.info.breakResult);
+ JCTree immediateTarget = findJumpTarget(tree.pos(), tree.getTag(), null, env);
+ if (immediateTarget.getTag() != SWITCH_EXPRESSION) {
+ log.error(tree.pos(), Errors.BreakExprNotImmediate(immediateTarget.getTag()));
+ Env<AttrContext> env1 = env;
+ while (env1 != null && env1.tree.getTag() != SWITCH_EXPRESSION) {
+ env1 = env1.next;
+ }
+ Assert.checkNonNull(env1);
+ tree.target = env1.tree;
+ } else {
+ tree.target = immediateTarget;
+ }
+ }
+ }
+ } else {
+ if (tree.value == null || tree.value.hasTag(IDENT)) {
+ Name label = tree.value != null ? ((JCIdent) tree.value).name : null;
+ tree.target = findJumpTarget(tree.pos(), tree.getTag(), label, env);
+ } else {
+ log.error(tree.pos(), Errors.BreakComplexValueNoSwitchExpression);
+ attribTree(tree.value, env, unknownExprInfo);
+ }
+ }
result = null;
}
@@ -1805,11 +1949,35 @@
* @param env The environment current at the jump statement.
*/
private JCTree findJumpTarget(DiagnosticPosition pos,
- JCTree.Tag tag,
- Name label,
- Env<AttrContext> env) {
+ JCTree.Tag tag,
+ Name label,
+ Env<AttrContext> env) {
+ Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tag, label, env);
+
+ if (jumpTarget.snd != null) {
+ log.error(pos, jumpTarget.snd);
+ }
+
+ return jumpTarget.fst;
+ }
+ /** Return the target of a break or continue statement, if it exists,
+ * report an error if not.
+ * Note: The target of a labelled break or continue is the
+ * (non-labelled) statement tree referred to by the label,
+ * not the tree representing the labelled statement itself.
+ *
+ * @param tag The tag of the jump statement. This is either
+ * Tree.BREAK or Tree.CONTINUE.
+ * @param label The label of the jump statement, or null if no
+ * label is given.
+ * @param env The environment current at the jump statement.
+ */
+ private Pair<JCTree, JCDiagnostic.Error> findJumpTargetNoError(JCTree.Tag tag,
+ Name label,
+ Env<AttrContext> env) {
// Search environments outwards from the point of jump.
Env<AttrContext> env1 = env;
+ JCDiagnostic.Error pendingError = null;
LOOP:
while (env1 != null) {
switch (env1.tree.getTag()) {
@@ -1821,13 +1989,14 @@
if (!labelled.body.hasTag(DOLOOP) &&
!labelled.body.hasTag(WHILELOOP) &&
!labelled.body.hasTag(FORLOOP) &&
- !labelled.body.hasTag(FOREACHLOOP))
- log.error(pos, Errors.NotLoopLabel(label));
+ !labelled.body.hasTag(FOREACHLOOP)) {
+ pendingError = Errors.NotLoopLabel(label);
+ }
// Found labelled statement target, now go inwards
// to next non-labelled tree.
- return TreeInfo.referencedStatement(labelled);
+ return Pair.of(TreeInfo.referencedStatement(labelled), pendingError);
} else {
- return labelled;
+ return Pair.of(labelled, pendingError);
}
}
break;
@@ -1835,10 +2004,21 @@
case WHILELOOP:
case FORLOOP:
case FOREACHLOOP:
- if (label == null) return env1.tree;
+ if (label == null) return Pair.of(env1.tree, pendingError);
break;
case SWITCH:
- if (label == null && tag == BREAK) return env1.tree;
+ if (label == null && tag == BREAK) return Pair.of(env1.tree, null);
+ break;
+ case SWITCH_EXPRESSION:
+ if (tag == BREAK) {
+ if (label == null) {
+ return Pair.of(env1.tree, null);
+ } else {
+ pendingError = Errors.BreakOutsideSwitchExpression;
+ }
+ } else {
+ pendingError = Errors.ContinueOutsideSwitchExpression;
+ }
break;
case LAMBDA:
case METHODDEF:
@@ -1849,12 +2029,11 @@
env1 = env1.next;
}
if (label != null)
- log.error(pos, Errors.UndefLabel(label));
+ return Pair.of(null, Errors.UndefLabel(label));
else if (tag == CONTINUE)
- log.error(pos, Errors.ContOutsideLoop);
+ return Pair.of(null, Errors.ContOutsideLoop);
else
- log.error(pos, Errors.BreakOutsideSwitchLoop);
- return null;
+ return Pair.of(null, Errors.BreakOutsideSwitchLoop);
}
public void visitReturn(JCReturn tree) {
@@ -1862,6 +2041,8 @@
// nested within than the enclosing class.
if (env.info.returnResult == null) {
log.error(tree.pos(), Errors.RetOutsideMeth);
+ } else if (env.info.breakResult != null) {
+ log.error(tree.pos(), Errors.ReturnOutsideSwitchExpression);
} else {
// Attribute return expression, if it exists, and check that
// it conforms to result type of enclosing method.
@@ -2944,6 +3125,7 @@
} else {
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
}
+ lambdaEnv.info.breakResult = null;
return lambdaEnv;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Wed Aug 29 09:36:17 2018 +0200
@@ -101,6 +101,11 @@
*/
Attr.ResultInfo returnResult = null;
+ /** ResultInfo to be used for attributing 'break' statement expressions
+ * (set by Attr.visitSwitchExpression)
+ */
+ Attr.ResultInfo breakResult = null;
+
/** Symbol corresponding to the site of a qualified default super call
*/
Type defaultSuperCallSite = null;
@@ -124,6 +129,7 @@
info.lint = lint;
info.enclVar = enclVar;
info.returnResult = returnResult;
+ info.breakResult = breakResult;
info.defaultSuperCallSite = defaultSuperCallSite;
info.isSerializable = isSerializable;
info.isLambda = isLambda;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Wed Aug 29 09:36:17 2018 +0200
@@ -1154,6 +1154,18 @@
}
/**
+ * A tree scanner suitable for visiting the target-type dependent nodes nested
+ * within a switch expression body.
+ */
+ static class SwitchExpressionScanner extends FilterScanner {
+
+ SwitchExpressionScanner() {
+ super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
+ FORLOOP, IF, BREAK, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
+ }
+ }
+
+ /**
* This visitor is used to check that structural expressions conform
* to their target - this step is required as inference could end up
* inferring types that make some of the nested expressions incompatible
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Wed Aug 29 09:36:17 2018 +0200
@@ -28,6 +28,8 @@
package com.sun.tools.javac.comp;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
import com.sun.tools.javac.code.*;
@@ -211,7 +213,7 @@
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
- new AssignAnalyzer().analyzeTree(env);
+ new AssignAnalyzer().analyzeTree(env, make);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
@@ -244,7 +246,7 @@
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
- new LambdaAssignAnalyzer(env).analyzeTree(env, that);
+ new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
@@ -396,6 +398,12 @@
public void visitPackageDef(JCPackageDecl tree) {
// Do nothing for PackageDecl
}
+
+ protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
+ JCBreak brk = make.at(Position.NOPOS).Break(null);
+ brk.target = swtch;
+ scan(brk);
+ }
}
/**
@@ -596,11 +604,19 @@
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
alive = true;
JCCase c = l.head;
- if (c.pat == null)
+ if (c.pats.isEmpty())
hasDefault = true;
- else
- scan(c.pat);
+ else {
+ for (JCExpression pat : c.pats) {
+ scan(pat);
+ }
+ }
scanStats(c.stats);
+ c.completesNormally = alive;
+ if (alive && c.caseKind == JCCase.RULE) {
+ scanSyntheticBreak(make, tree);
+ alive = false;
+ }
// Warn about fall-through if lint switch fallthrough enabled.
if (alive &&
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
@@ -615,6 +631,46 @@
alive |= resolveBreaks(tree, prevPendingExits);
}
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ ListBuffer<PendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
+ scan(tree.selector);
+ Set<Object> constants = null;
+ if ((tree.selector.type.tsym.flags() & ENUM) != 0) {
+ constants = new HashSet<>();
+ for (Symbol s : tree.selector.type.tsym.members().getSymbols(s -> (s.flags() & ENUM) != 0)) {
+ constants.add(s.name);
+ }
+ }
+ boolean hasDefault = false;
+ boolean prevAlive = alive;
+ for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ alive = true;
+ JCCase c = l.head;
+ if (c.pats.isEmpty())
+ hasDefault = true;
+ else {
+ for (JCExpression pat : c.pats) {
+ scan(pat);
+ if (constants != null) {
+ if (pat.hasTag(IDENT))
+ constants.remove(((JCIdent) pat).name);
+ if (pat.type != null)
+ constants.remove(pat.type.constValue());
+ }
+ }
+ }
+ scanStats(c.stats);
+ c.completesNormally = alive;
+ }
+ if ((constants == null || !constants.isEmpty()) && !hasDefault) {
+ log.error(tree, Errors.NotExhaustive);
+ }
+ alive = prevAlive;
+ alive |= resolveBreaks(tree, prevPendingExits);
+ }
+
public void visitTry(JCTry tree) {
ListBuffer<PendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
@@ -680,6 +736,8 @@
}
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new PendingExit(tree));
}
@@ -1040,14 +1098,21 @@
}
public void visitSwitch(JCSwitch tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
- scan(tree.selector);
- for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ scan(selector);
+ for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
JCCase c = l.head;
- if (c.pat != null) {
- scan(c.pat);
- }
+ scan(c.pats);
scan(c.stats);
}
resolveBreaks(tree, prevPendingExits);
@@ -1191,6 +1256,8 @@
}
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new FlowPendingExit(tree, null));
}
@@ -2105,27 +2172,40 @@
}
public void visitSwitch(JCSwitch tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
int nextadrPrev = nextadr;
- scanExpr(tree.selector);
+ scanExpr(selector);
final Bits initsSwitch = new Bits(inits);
final Bits uninitsSwitch = new Bits(uninits);
boolean hasDefault = false;
- for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
- if (c.pat == null) {
+ if (c.pats.isEmpty()) {
hasDefault = true;
} else {
- scanExpr(c.pat);
+ for (JCExpression pat : c.pats) {
+ scanExpr(pat);
+ }
}
if (hasDefault) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
}
scan(c.stats);
+ if (c.completesNormally && c.caseKind == JCCase.RULE) {
+ scanSyntheticBreak(make, tree);
+ }
addVars(c.stats, initsSwitch, uninitsSwitch);
if (!hasDefault) {
inits.assign(initsSwitch);
@@ -2301,6 +2381,8 @@
@Override
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new AssignPendingExit(tree, inits, uninits));
}
@@ -2479,11 +2561,11 @@
/** Perform definite assignment/unassignment analysis on a tree.
*/
- public void analyzeTree(Env<?> env) {
- analyzeTree(env, env.tree);
+ public void analyzeTree(Env<?> env, TreeMaker make) {
+ analyzeTree(env, env.tree, make);
}
- public void analyzeTree(Env<?> env, JCTree tree) {
+ public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
try {
startPos = tree.pos().getStartPosition();
@@ -2494,6 +2576,7 @@
vardecls[i] = null;
firstadr = 0;
nextadr = 0;
+ Flow.this.make = make;
pendingExits = new ListBuffer<>();
this.classDef = null;
unrefdResources = WriteableScope.create(env.enclClass.sym);
@@ -2509,6 +2592,7 @@
}
firstadr = 0;
nextadr = 0;
+ Flow.this.make = null;
pendingExits = null;
this.classDef = null;
unrefdResources = null;
@@ -2661,6 +2745,12 @@
super.visitTry(tree);
}
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
+ }
+
public void visitModuleDef(JCModuleDecl tree) {
// Do nothing for modules
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Aug 29 09:36:17 2018 +0200
@@ -715,7 +715,7 @@
JCBreak br = make.Break(null);
breaks.add(br);
List<JCStatement> stmts = entry.getValue().append(br).toList();
- cases.add(make.Case(make.Literal(entry.getKey()), stmts));
+ cases.add(make.Case(JCCase.STATEMENT, List.of(make.Literal(entry.getKey())), stmts, null));
}
JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
for (JCBreak br : breaks) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Wed Aug 29 09:36:17 2018 +0200
@@ -26,7 +26,11 @@
package com.sun.tools.javac.comp;
import java.util.*;
-
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope.WriteableScope;
@@ -54,6 +58,10 @@
import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
import static com.sun.tools.javac.jvm.ByteCodes.*;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
+import com.sun.tools.javac.tree.JCTree.JCCase;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
@@ -263,6 +271,13 @@
}
super.visitApply(tree);
}
+
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
+ }
+
}
/**
@@ -364,6 +379,7 @@
}
super.visitApply(tree);
}
+
}
ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
@@ -3340,6 +3356,45 @@
}
public void visitSwitch(JCSwitch tree) {
+ //expand multiple label cases:
+ ListBuffer<JCCase> cases = new ListBuffer<>();
+
+ for (JCCase c : tree.cases) {
+ switch (c.pats.size()) {
+ case 0: //default
+ case 1: //single label
+ cases.append(c);
+ break;
+ default: //multiple labels, expand:
+ //case C1, C2, C3: ...
+ //=>
+ //case C1:
+ //case C2:
+ //case C3: ...
+ List<JCExpression> patterns = c.pats;
+ while (patterns.tail.nonEmpty()) {
+ cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
+ List.of(patterns.head),
+ List.nil(),
+ null));
+ patterns = patterns.tail;
+ }
+ c.pats = patterns;
+ cases.append(c);
+ break;
+ }
+ }
+
+ for (JCCase c : cases) {
+ if (c.caseKind == JCCase.RULE && c.completesNormally) {
+ JCBreak b = make_at(c.pos()).Break(null);
+ b.target = tree;
+ c.stats = c.stats.append(b);
+ }
+ }
+
+ tree.cases = cases.toList();
+
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
(tree.selector.type.tsym.flags() & ENUM) != 0;
@@ -3371,10 +3426,10 @@
ordinalMethod)));
ListBuffer<JCCase> cases = new ListBuffer<>();
for (JCCase c : tree.cases) {
- if (c.pat != null) {
- VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
+ if (c.pats.nonEmpty()) {
+ VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
JCLiteral pat = map.forConstant(label);
- cases.append(make.Case(pat, c.stats));
+ cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
} else {
cases.append(c);
}
@@ -3442,10 +3497,10 @@
Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
int casePosition = 0;
+
for(JCCase oneCase : caseList) {
- JCExpression expression = oneCase.getExpression();
-
- if (expression != null) { // expression for a "default" case is null
+ if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
+ JCExpression expression = oneCase.pats.head;
String labelExpr = (String) expression.type.constValue();
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
Assert.checkNull(mapping);
@@ -3529,7 +3584,7 @@
breakStmt.target = switch1;
lb.append(elsepart).append(breakStmt);
- caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
+ caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
}
switch1.cases = caseBuffer.toList();
@@ -3546,18 +3601,17 @@
// replacement switch being created.
patchTargets(oneCase, tree, switch2);
- boolean isDefault = (oneCase.getExpression() == null);
+ boolean isDefault = (oneCase.pats.isEmpty());
JCExpression caseExpr;
if (isDefault)
caseExpr = null;
else {
- caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
- getExpression()).
+ caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
type.constValue()));
}
- lb.append(make.Case(caseExpr,
- oneCase.getStatements()));
+ lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
+ oneCase.getStatements(), null));
}
switch2.cases = lb.toList();
@@ -3567,6 +3621,76 @@
}
}
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ //translates switch expression to statement switch:
+ //switch (selector) {
+ // case C: break value;
+ // ...
+ //}
+ //=>
+ //(letexpr T exprswitch$;
+ // switch (selector) {
+ // case C: { exprswitch$ = value; break; }
+ // }
+ // exprswitch$
+ //)
+ VarSymbol dollar_switchexpr = new VarSymbol(Flags.FINAL|Flags.SYNTHETIC,
+ names.fromString("exprswitch" + tree.pos + target.syntheticNameChar()),
+ tree.type,
+ currentMethodSym);
+
+ ListBuffer<JCStatement> stmtList = new ListBuffer<>();
+
+ stmtList.append(make.at(tree.pos()).VarDef(dollar_switchexpr, null).setType(dollar_switchexpr.type));
+ JCSwitch switchStatement = make.Switch(tree.selector, null);
+ switchStatement.cases =
+ tree.cases.stream()
+ .map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c))
+ .collect(List.collector());
+ if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
+ JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
+ List.nil()));
+ JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
+ switchStatement.cases = switchStatement.cases.append(c);
+ }
+
+ stmtList.append(translate(switchStatement));
+
+ result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
+ .setType(dollar_switchexpr.type);
+ }
+ //where:
+ private JCCase convertCase(VarSymbol dollar_switchexpr, JCSwitch switchStatement,
+ JCSwitchExpression switchExpr, JCCase c) {
+ make.at(c.pos());
+ ListBuffer<JCStatement> statements = new ListBuffer<>();
+ statements.addAll(new TreeTranslator() {
+ @Override
+ public void visitLambda(JCLambda tree) {}
+ @Override
+ public void visitClassDef(JCClassDecl tree) {}
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {}
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.target == switchExpr) {
+ tree.target = switchStatement;
+ JCExpressionStatement assignment =
+ make.Exec(make.Assign(make.Ident(dollar_switchexpr),
+ translate(tree.value))
+ .setType(dollar_switchexpr.type));
+ result = make.Block(0, List.of(assignment,
+ tree));
+ tree.value = null;
+ } else {
+ result = tree;
+ }
+ }
+ }.translate(c.stats));
+ return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
+ }
+
public void visitNewArray(JCNewArray tree) {
tree.elemtype = translate(tree.elemtype);
for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
@@ -3602,7 +3726,7 @@
}
public void visitLetExpr(LetExpr tree) {
- tree.defs = translateVarDefs(tree.defs);
+ tree.defs = translate(tree.defs);
tree.expr = translate(tree.expr, tree.type);
result = tree;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java Wed Aug 29 09:36:17 2018 +0200
@@ -48,6 +48,7 @@
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
import static com.sun.tools.javac.code.TypeTag.VOID;
import static com.sun.tools.javac.comp.CompileStates.CompileState;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
/** This pass translates Generic Java to conventional Java.
*
@@ -561,11 +562,22 @@
}
public void visitCase(JCCase tree) {
- tree.pat = translate(tree.pat, null);
+ tree.pats = translate(tree.pats, null);
tree.stats = translate(tree.stats);
result = tree;
}
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ Type selsuper = types.supertype(tree.selector.type);
+ boolean enumSwitch = selsuper != null &&
+ selsuper.tsym == syms.enumSym;
+ Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
+ tree.selector = translate(tree.selector, target);
+ tree.cases = translate(tree.cases);
+ tree.type = erasure(tree.type);
+ result = retype(tree, tree.type, pt);
+ }
+
public void visitSynchronized(JCSynchronized tree) {
tree.lock = translate(tree.lock, erasure(tree.lock.type));
tree.body = translate(tree.body);
@@ -606,6 +618,16 @@
result = tree;
}
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak()) {
+ tree.value = translate(tree.value, erasure(tree.value.type));
+ tree.value.type = erasure(tree.value.type);
+ tree.value = retype(tree.value, tree.value.type, pt);
+ }
+ result = tree;
+ }
+
public void visitThrow(JCThrow tree) {
tree.expr = translate(tree.expr, erasure(tree.expr.type));
result = tree;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java Wed Aug 29 09:36:17 2018 +0200
@@ -259,13 +259,13 @@
@Override
public void visitBreak(JCBreak tree) {
JCBreak that = (JCBreak) parameter;
- result = tree.label == that.label;
+ result = scan(tree.value, that.value);
}
@Override
public void visitCase(JCCase tree) {
JCCase that = (JCCase) parameter;
- result = scan(tree.pat, that.pat) && scan(tree.stats, that.stats);
+ result = scan(tree.pats, that.pats) && scan(tree.stats, that.stats);
}
@Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java Wed Aug 29 09:36:17 2018 +0200
@@ -313,7 +313,7 @@
public void visitCase(JCCase tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
- sr.mergeWith(csp(tree.pat));
+ sr.mergeWith(csp(tree.pats));
sr.mergeWith(csp(tree.stats));
result = sr;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Wed Aug 29 09:36:17 2018 +0200
@@ -183,6 +183,8 @@
final MethodSymbol meth;
+ private int letExprStackPos = 0;
+
/** Construct a code object, given the settings of the fatcode,
* debugging info switches and the CharacterRangeTable.
*/
@@ -382,7 +384,7 @@
}
void postop() {
- Assert.check(alive || state.stacksize == 0);
+ Assert.check(alive || isStatementStart());
}
/** Emit a ldc (or ldc_w) instruction, taking into account operand size
@@ -1211,6 +1213,15 @@
return pc;
}
+ public int setLetExprStackPos(int pos) {
+ int res = letExprStackPos;
+ letExprStackPos = pos;
+ return res;
+ }
+
+ public boolean isStatementStart() {
+ return state.stacksize == letExprStackPos;
+ }
/**************************************************************************
* Stack map generation
@@ -1474,7 +1485,7 @@
State newState = state;
for (; chain != null; chain = chain.next) {
Assert.check(state != chain.state
- && (target > chain.pc || state.stacksize == 0));
+ && (target > chain.pc || isStatementStart()));
if (target >= cp) {
target = cp;
} else if (get1(target) == goto_) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Aug 29 09:36:17 2018 +0200
@@ -81,11 +81,6 @@
*/
private final Type methodType;
- /**
- * Are we presently traversing a let expression ? Yes if depth != 0
- */
- private int letExprDepth;
-
public static Gen instance(Context context) {
Gen instance = context.get(genKey);
if (instance == null)
@@ -1011,10 +1006,10 @@
if (tree.init != null) {
checkStringConstant(tree.init.pos(), v.getConstValue());
if (v.getConstValue() == null || varDebugInfo) {
- Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
genExpr(tree.init, v.erasure(types)).load();
items.makeLocalItem(v).store();
- Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
}
}
checkDimension(tree.pos(), v.type);
@@ -1069,14 +1064,14 @@
CondItem c;
if (cond != null) {
code.statBegin(cond.pos);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
} else {
c = items.makeCondItem(goto_);
}
Chain loopDone = c.jumpFalse();
code.resolve(c.trueJumps);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
code.resolve(loopEnv.info.cont);
genStats(step, loopEnv);
@@ -1090,13 +1085,13 @@
CondItem c;
if (cond != null) {
code.statBegin(cond.pos);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
} else {
c = items.makeCondItem(goto_);
}
code.resolve(c.jumpTrue(), startpc);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
code.resolve(c.falseJumps);
}
}
@@ -1125,7 +1120,7 @@
int limit = code.nextreg;
Assert.check(!tree.selector.type.hasTag(CLASS));
int startpcCrt = genCrt ? code.curCP() : 0;
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
Item sel = genExpr(tree.selector, syms.intType);
List<JCCase> cases = tree.cases;
if (cases.isEmpty()) {
@@ -1154,8 +1149,9 @@
List<JCCase> l = cases;
for (int i = 0; i < labels.length; i++) {
- if (l.head.pat != null) {
- int val = ((Number)l.head.pat.type.constValue()).intValue();
+ if (l.head.pats.nonEmpty()) {
+ Assert.check(l.head.pats.size() == 1);
+ int val = ((Number)l.head.pats.head.type.constValue()).intValue();
labels[i] = val;
if (val < lo) lo = val;
if (hi < val) hi = val;
@@ -1294,7 +1290,7 @@
int limit = code.nextreg;
// Generate code to evaluate lock and save in temporary variable.
final LocalItem lockVar = makeTemp(syms.objectType);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
genExpr(tree.lock, tree.lock.type).load().duplicate();
lockVar.store();
@@ -1556,11 +1552,11 @@
public void visitIf(JCIf tree) {
int limit = code.nextreg;
Chain thenExit = null;
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
CondItem c = genCond(TreeInfo.skipParens(tree.cond),
CRT_FLOW_CONTROLLER);
Chain elseChain = c.jumpFalse();
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
if (!c.isFalse()) {
code.resolve(c.trueJumps);
genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
@@ -1574,7 +1570,7 @@
}
code.resolve(thenExit);
code.endScopes(limit);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
}
public void visitExec(JCExpressionStatement tree) {
@@ -1588,16 +1584,16 @@
((JCUnary) e).setTag(PREDEC);
break;
}
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
genExpr(tree.expr, tree.expr.type).drop();
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
}
public void visitBreak(JCBreak tree) {
int tmpPos = code.pendingStatPos;
Env<GenContext> targetEnv = unwind(tree.target, env);
code.pendingStatPos = tmpPos;
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
targetEnv.info.addExit(code.branch(goto_));
endFinalizerGaps(env, targetEnv);
}
@@ -1606,7 +1602,7 @@
int tmpPos = code.pendingStatPos;
Env<GenContext> targetEnv = unwind(tree.target, env);
code.pendingStatPos = tmpPos;
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
targetEnv.info.addCont(code.branch(goto_));
endFinalizerGaps(env, targetEnv);
}
@@ -1620,7 +1616,7 @@
*/
int tmpPos = code.pendingStatPos;
if (tree.expr != null) {
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
Item r = genExpr(tree.expr, pt).load();
if (hasFinally(env.enclMethod, env)) {
r = makeTemp(pt);
@@ -1640,10 +1636,10 @@
}
public void visitThrow(JCThrow tree) {
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
genExpr(tree.expr, tree.expr.type).load();
code.emitop0(athrow);
- Assert.check(code.state.stacksize == 0);
+ Assert.check(code.isStatementStart());
}
/* ************************************************************************
@@ -2147,12 +2143,15 @@
}
public void visitLetExpr(LetExpr tree) {
- letExprDepth++;
int limit = code.nextreg;
- genStats(tree.defs, env);
+ int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
+ try {
+ genStats(tree.defs, env);
+ } finally {
+ code.setLetExprStackPos(prevLetExprStart);
+ }
result = genExpr(tree.expr, tree.expr.type).load();
code.endScopes(limit);
- letExprDepth--;
}
private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Aug 29 09:36:17 2018 +0200
@@ -26,8 +26,10 @@
package com.sun.tools.javac.parser;
import java.util.*;
+import java.util.function.Function;
import java.util.stream.Collectors;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.ModuleTree.ModuleKind;
@@ -218,12 +220,22 @@
* mode = TYPE : a type
* mode = NOPARAMS : no parameters allowed for type
* mode = TYPEARG : type argument
+ * mode |= NOLAMBDA : lambdas are not allowed
*/
protected static final int EXPR = 0x1;
protected static final int TYPE = 0x2;
protected static final int NOPARAMS = 0x4;
protected static final int TYPEARG = 0x8;
protected static final int DIAMOND = 0x10;
+ protected static final int NOLAMBDA = 0x20;
+
+ protected void selectExprMode() {
+ mode = (mode & NOLAMBDA) | EXPR;
+ }
+
+ protected void selectTypeMode() {
+ mode = (mode & NOLAMBDA) | TYPE;
+ }
/** The current mode.
*/
@@ -427,11 +439,18 @@
* an error.
*/
public void accept(TokenKind tk) {
+ accept(tk, Errors::Expected);
+ }
+
+ /** If next input token matches given token, skip it, otherwise report
+ * an error.
+ */
+ public void accept(TokenKind tk, Function<TokenKind, Error> errorProvider) {
if (token.kind == tk) {
nextToken();
} else {
setErrorEndPos(token.pos);
- reportSyntaxError(S.prevToken().endPos, Errors.Expected(tk));
+ reportSyntaxError(S.prevToken().endPos, errorProvider.apply(tk));
}
}
@@ -796,7 +815,7 @@
case EQ: {
int pos = token.pos;
nextToken();
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term();
return toP(F.at(pos).Assign(t, t1));
}
@@ -814,7 +833,7 @@
int pos = token.pos;
TokenKind tk = token.kind;
nextToken();
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term();
return F.at(pos).Assignop(optag(tk), t, t1);
default:
@@ -829,7 +848,7 @@
JCExpression term1() {
JCExpression t = term2();
if ((mode & EXPR) != 0 && token.kind == QUES) {
- mode = EXPR;
+ selectExprMode();
return term1Rest(t);
} else {
return t;
@@ -858,7 +877,7 @@
JCExpression term2() {
JCExpression t = term3();
if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
- mode = EXPR;
+ selectExprMode();
return term2Rest(t, TreeInfo.orPrec);
} else {
return t;
@@ -1058,7 +1077,7 @@
switch (token.kind) {
case QUES:
if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
- mode = TYPE;
+ selectTypeMode();
return typeArgument();
} else
return illegal();
@@ -1066,11 +1085,11 @@
if (typeArgs == null && (mode & EXPR) != 0) {
TokenKind tk = token.kind;
nextToken();
- mode = EXPR;
+ selectExprMode();
if (tk == SUB &&
(token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
token.radix() == 10) {
- mode = EXPR;
+ selectExprMode();
t = literal(names.hyphen, pos);
} else {
t = term3();
@@ -1084,7 +1103,7 @@
switch (pres) {
case CAST:
accept(LPAREN);
- mode = TYPE;
+ selectTypeMode();
int pos1 = pos;
List<JCExpression> targets = List.of(t = parseType());
while (token.kind == AMP) {
@@ -1096,7 +1115,7 @@
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
}
accept(RPAREN);
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term3();
return F.at(pos).TypeCast(t, t1);
case IMPLICIT_LAMBDA:
@@ -1105,7 +1124,7 @@
break;
default: //PARENS
accept(LPAREN);
- mode = EXPR;
+ selectExprMode();
t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
accept(RPAREN);
t = toP(F.at(pos).Parens(t));
@@ -1117,7 +1136,7 @@
break;
case THIS:
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos).Ident(names._this));
nextToken();
if (typeArgs == null)
@@ -1129,7 +1148,7 @@
break;
case SUPER:
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos).Ident(names._super));
t = superSuffix(typeArgs, t);
typeArgs = null;
@@ -1139,14 +1158,14 @@
case CHARLITERAL: case STRINGLITERAL:
case TRUE: case FALSE: case NULL:
if (typeArgs == null && (mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = literal(names.empty);
} else return illegal();
break;
case NEW:
if (typeArgs != null) return illegal();
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
nextToken();
if (token.kind == LT) typeArgs = typeArguments(false);
t = creator(pos, typeArgs);
@@ -1193,7 +1212,7 @@
break;
case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
if (typeArgs != null) return illegal();
- if ((mode & EXPR) != 0 && peekToken(ARROW)) {
+ if ((mode & EXPR) != 0 && (mode & NOLAMBDA) == 0 && peekToken(ARROW)) {
t = lambdaExpressionOrStatement(false, false, pos);
} else {
t = toP(F.at(token.pos).Ident(ident()));
@@ -1219,7 +1238,7 @@
t = bracketsSuffix(t);
} else {
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term();
if (!annos.isEmpty()) t = illegal(annos.head.pos);
t = to(F.at(pos).Indexed(t, t1));
@@ -1229,7 +1248,7 @@
break loop;
case LPAREN:
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = arguments(typeArgs, t);
if (!annos.isEmpty()) t = illegal(annos.head.pos);
typeArgs = null;
@@ -1248,25 +1267,25 @@
switch (token.kind) {
case CLASS:
if (typeArgs != null) return illegal();
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos).Select(t, names._class));
nextToken();
break loop;
case THIS:
if (typeArgs != null) return illegal();
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos).Select(t, names._this));
nextToken();
break loop;
case SUPER:
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos).Select(t, names._super));
t = superSuffix(typeArgs, t);
typeArgs = null;
break loop;
case NEW:
if (typeArgs != null) return illegal();
- mode = EXPR;
+ selectExprMode();
int pos1 = token.pos;
nextToken();
if (token.kind == LT) typeArgs = typeArguments(false);
@@ -1310,7 +1329,7 @@
t = toP(F.at(pos1).TypeApply(t, args.toList()));
while (token.kind == DOT) {
nextToken();
- mode = TYPE;
+ selectTypeMode();
t = toP(F.at(token.pos).Select(t, ident()));
t = typeArgumentsOpt(t);
}
@@ -1319,7 +1338,7 @@
//method reference expected here
t = illegal();
}
- mode = EXPR;
+ selectExprMode();
return term3Rest(t, typeArgs);
}
break loop;
@@ -1356,12 +1375,82 @@
//return illegal();
}
break;
+ case SWITCH:
+ checkSourceLevel(Feature.SWITCH_EXPRESSION);
+ int switchPos = token.pos;
+ nextToken();
+ JCExpression selector = parExpression();
+ accept(LBRACE);
+ ListBuffer<JCCase> cases = new ListBuffer<>();
+ while (true) {
+ pos = token.pos;
+ switch (token.kind) {
+ case CASE:
+ case DEFAULT:
+ cases.appendList(switchExpressionStatementGroup());
+ break;
+ case RBRACE: case EOF:
+ JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector,
+ cases.toList()));
+ accept(RBRACE);
+ return e;
+ default:
+ nextToken(); // to ensure progress
+ syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
+ }
+ }
default:
return illegal();
}
return term3Rest(t, typeArgs);
}
+ private List<JCCase> switchExpressionStatementGroup() {
+ ListBuffer<JCCase> caseExprs = new ListBuffer<>();
+ int casePos = token.pos;
+ ListBuffer<JCExpression> pats = new ListBuffer<>();
+
+ if (token.kind == DEFAULT) {
+ nextToken();
+ } else {
+ accept(CASE);
+ while (true) {
+ pats.append(term(EXPR | NOLAMBDA));
+ if (token.kind != COMMA) break;
+ checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+ nextToken();
+ };
+ }
+ List<JCStatement> stats = null;
+ JCTree body = null;
+ @SuppressWarnings("removal")
+ CaseKind kind;
+ switch (token.kind) {
+ case ARROW:
+ checkSourceLevel(Feature.SWITCH_RULE);
+ nextToken();
+ if (token.kind == TokenKind.THROW || token.kind == TokenKind.LBRACE) {
+ stats = List.of(parseStatement());
+ body = stats.head;
+ kind = JCCase.RULE;
+ } else {
+ JCExpression value = parseExpression();
+ stats = List.of(to(F.at(value).Break(value)));
+ body = value;
+ kind = JCCase.RULE;
+ accept(SEMI);
+ }
+ break;
+ default:
+ accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+ stats = blockStatements();
+ kind = JCCase.STATEMENT;
+ break;
+ }
+ caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats, body)));
+ return caseExprs.toList();
+ }
+
JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
if (typeArgs != null) illegal();
while (true) {
@@ -1372,13 +1461,13 @@
nextToken();
if ((mode & TYPE) != 0) {
int oldmode = mode;
- mode = TYPE;
+ selectTypeMode();
if (token.kind == RBRACKET) {
nextToken();
t = bracketsOpt(t);
t = toP(F.at(pos1).TypeArray(t));
if (token.kind == COLCOL) {
- mode = EXPR;
+ selectExprMode();
continue;
}
if (annos.nonEmpty()) {
@@ -1389,7 +1478,7 @@
mode = oldmode;
}
if ((mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term();
t = to(F.at(pos1).Indexed(t, t1));
}
@@ -1398,14 +1487,14 @@
nextToken();
typeArgs = typeArgumentsOpt(EXPR);
if (token.kind == SUPER && (mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = to(F.at(pos1).Select(t, names._super));
nextToken();
t = arguments(typeArgs, t);
typeArgs = null;
} else if (token.kind == NEW && (mode & EXPR) != 0) {
if (typeArgs != null) return illegal();
- mode = EXPR;
+ selectExprMode();
int pos2 = token.pos;
nextToken();
if (token.kind == LT) typeArgs = typeArguments(false);
@@ -1425,7 +1514,7 @@
typeArgs = null;
}
} else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
- mode = EXPR;
+ selectExprMode();
if (typeArgs != null) return illegal();
accept(COLCOL);
t = memberReferenceSuffix(pos1, t);
@@ -1440,7 +1529,7 @@
}
}
while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
- mode = EXPR;
+ selectExprMode();
t = to(F.at(token.pos).Unary(
token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
nextToken();
@@ -1580,7 +1669,8 @@
return ParensResult.EXPLICIT_LAMBDA;
} else if (peekToken(lookahead, RPAREN, ARROW)) {
// Identifier, ')' '->' -> implicit lambda
- return ParensResult.IMPLICIT_LAMBDA;
+ return (mode & NOLAMBDA) == 0 ? ParensResult.IMPLICIT_LAMBDA
+ : ParensResult.PARENS;
} else if (depth == 0 && peekToken(lookahead, COMMA)) {
defaultResult = ParensResult.IMPLICIT_LAMBDA;
}
@@ -1818,7 +1908,7 @@
*/
JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
- mode = EXPR;
+ selectExprMode();
return arguments(typeArgs, t);
} else {
return t;
@@ -1857,7 +1947,7 @@
if (token.kind == LT &&
(mode & TYPE) != 0 &&
(mode & NOPARAMS) == 0) {
- mode = TYPE;
+ selectTypeMode();
return typeArguments(t, false);
} else {
return t;
@@ -2019,7 +2109,7 @@
*/
JCExpression bracketsSuffix(JCExpression t) {
if ((mode & EXPR) != 0 && token.kind == DOT) {
- mode = EXPR;
+ selectExprMode();
int pos = token.pos;
nextToken();
accept(CLASS);
@@ -2044,7 +2134,7 @@
}
} else if ((mode & TYPE) != 0) {
if (token.kind != COLCOL) {
- mode = TYPE;
+ selectTypeMode();
}
} else if (token.kind != COLCOL) {
syntaxError(token.pos, Errors.DotClassExpected);
@@ -2064,7 +2154,7 @@
JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
checkSourceLevel(Feature.METHOD_REFERENCES);
- mode = EXPR;
+ selectExprMode();
List<JCExpression> typeArgs = null;
if (token.kind == LT) {
typeArgs = typeArguments(false);
@@ -2103,7 +2193,7 @@
JCExpression t = qualident(true);
int oldmode = mode;
- mode = TYPE;
+ selectTypeMode();
boolean diamondFound = false;
int lastTypeargsPos = -1;
if (token.kind == LT) {
@@ -2617,9 +2707,9 @@
}
case BREAK: {
nextToken();
- Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;
+ JCExpression value = token.kind == SEMI ? null : parseExpression();
accept(SEMI);
- JCBreak t = toP(F.at(pos).Break(label));
+ JCBreak t = toP(F.at(pos).Break(value));
return t;
}
case CONTINUE: {
@@ -2713,7 +2803,7 @@
switch (token.kind) {
case CASE:
case DEFAULT:
- cases.append(switchBlockStatementGroup());
+ cases.appendList(switchBlockStatementGroup());
break;
case RBRACE: case EOF:
return cases.toList();
@@ -2724,28 +2814,69 @@
}
}
- protected JCCase switchBlockStatementGroup() {
+ protected List<JCCase> switchBlockStatementGroup() {
int pos = token.pos;
List<JCStatement> stats;
JCCase c;
+ ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
switch (token.kind) {
- case CASE:
+ case CASE: {
nextToken();
- JCExpression pat = parseExpression();
- accept(COLON);
- stats = blockStatements();
- c = F.at(pos).Case(pat, stats);
+ ListBuffer<JCExpression> pats = new ListBuffer<>();
+ while (true) {
+ pats.append(term(EXPR | NOLAMBDA));
+ if (token.kind != COMMA) break;
+ nextToken();
+ checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+ };
+ @SuppressWarnings("removal")
+ CaseKind caseKind;
+ JCTree body = null;
+ if (token.kind == ARROW) {
+ checkSourceLevel(Feature.SWITCH_RULE);
+ accept(ARROW);
+ caseKind = JCCase.RULE;
+ JCStatement statement = parseStatementAsBlock();
+ if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+ log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+ }
+ stats = List.of(statement);
+ body = stats.head;
+ } else {
+ accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+ caseKind = JCCase.STATEMENT;
+ stats = blockStatements();
+ }
+ c = F.at(pos).Case(caseKind, pats.toList(), stats, body);
if (stats.isEmpty())
storeEnd(c, S.prevToken().endPos);
- return c;
- case DEFAULT:
+ return cases.append(c).toList();
+ }
+ case DEFAULT: {
nextToken();
- accept(COLON);
- stats = blockStatements();
- c = F.at(pos).Case(null, stats);
+ @SuppressWarnings("removal")
+ CaseKind caseKind;
+ JCTree body = null;
+ if (token.kind == ARROW) {
+ checkSourceLevel(Feature.SWITCH_RULE);
+ accept(ARROW);
+ caseKind = JCCase.RULE;
+ JCStatement statement = parseStatementAsBlock();
+ if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+ log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+ }
+ stats = List.of(statement);
+ body = stats.head;
+ } else {
+ accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+ caseKind = JCCase.STATEMENT;
+ stats = blockStatements();
+ }
+ c = F.at(pos).Case(caseKind, List.nil(), stats, body);
if (stats.isEmpty())
storeEnd(c, S.prevToken().endPos);
- return c;
+ return cases.append(c).toList();
+ }
}
throw new AssertionError("should not reach here");
}
@@ -2946,7 +3077,7 @@
*/
JCExpression annotationFieldValue() {
if (LAX_IDENTIFIER.accepts(token.kind)) {
- mode = EXPR;
+ selectExprMode();
JCExpression t1 = term1();
if (t1.hasTag(IDENT) && token.kind == EQ) {
int pos = token.pos;
@@ -2988,7 +3119,7 @@
accept(RBRACE);
return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
default:
- mode = EXPR;
+ selectExprMode();
return term1();
}
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Aug 29 09:36:17 2018 +0200
@@ -49,6 +49,7 @@
# kind name an informative description of the kind of a declaration; see compiler.misc.kindname.*
# target a target version number, such as 1.5, 1.6, 1.7, taken from a com.sun.tools.javac.jvm.Target
# token the name of a non-terminal in source code; see compiler.misc.token.*
+# tree tag the name of a non-terminal in source code; see compiler.misc.token.*
# type a Java type; e.g. int, X, X<T>
# url a URL
# object a Java object (unspecified)
@@ -187,6 +188,33 @@
compiler.err.break.outside.switch.loop=\
break outside switch or loop
+compiler.err.break.missing.value=\
+ missing break value
+
+compiler.err.break.outside.switch.expression=\
+ break outside of enclosing switch expression
+
+compiler.err.continue.outside.switch.expression=\
+ continue outside of enclosing switch expression
+
+compiler.err.return.outside.switch.expression=\
+ return outside of enclosing switch expression
+
+# 0: name
+compiler.err.break.ambiguous.target=\
+ ambiguous reference to ''{0}''\n\
+ (''{0}'' is both a label and an expression)
+
+# 0: tree tag
+compiler.err.break.expr.not.immediate=\
+ value break not supported in ''{0}''
+
+compiler.err.break.complex.value.no.switch.expression=\
+ unexpected value break
+
+compiler.err.switch.expression.empty=\
+ switch expression does not have any case clauses
+
# 0: name
compiler.err.call.must.be.first.stmt.in.ctor=\
call to {0} must be first statement in constructor
@@ -799,12 +827,6 @@
compiler.err.native.meth.cant.have.body=\
native methods cannot have a body
-# 0: type, 1: type
-compiler.err.neither.conditional.subtype=\
- incompatible types for ?: neither is a subtype of the other\n\
- second operand: {0}\n\
- third operand : {1}
-
# 0: message segment
compiler.misc.incompatible.type.in.conditional=\
@@ -814,6 +836,14 @@
compiler.misc.conditional.target.cant.be.void=\
target-type for conditional expression cannot be void
+compiler.misc.switch.expression.target.cant.be.void=\
+ target-type for switch expression cannot be void
+
+# 0: message segment
+compiler.misc.incompatible.type.in.switch.expression=\
+ bad type in switch expression\n\
+ {0}
+
# 0: message segment
compiler.misc.incompatible.ret.type.in.lambda=\
bad return type in lambda expression\n\
@@ -1289,6 +1319,9 @@
compiler.err.unreachable.stmt=\
unreachable statement
+compiler.err.not.exhaustive=\
+ the switch expression does not cover all possible input values
+
compiler.err.initializer.must.be.able.to.complete.normally=\
initializer must be able to complete normally
@@ -2579,6 +2612,22 @@
compiler.misc.kindname.instance.init=\
instance initializer
+# the following are names of tree kinds:
+compiler.misc.tree.tag.forloop=\
+ for
+
+compiler.misc.tree.tag.foreachloop=\
+ for
+
+compiler.misc.tree.tag.whileloop=\
+ while
+
+compiler.misc.tree.tag.doloop=\
+ do
+
+compiler.misc.tree.tag.switch=\
+ switch
+
#####
compiler.misc.no.args=\
@@ -2768,6 +2817,15 @@
compiler.misc.feature.private.intf.methods=\
private interface methods
+compiler.misc.feature.multiple.case.labels=\
+ multiple case labels
+
+compiler.misc.feature.switch.rules=\
+ switch rules
+
+compiler.misc.feature.switch.expressions=\
+ switch expressions
+
compiler.warn.underscore.as.identifier=\
as of release 9, ''_'' is a keyword, and may not be used as an identifier
@@ -3257,6 +3315,14 @@
compiler.err.illegal.argument.for.option=\
illegal argument for {0}: {1}
+compiler.err.switch.null.not.allowed=\
+ null label in case is not allowed
+
+compiler.err.switch.case.unexpected.statement=\
+ unexpected statement in case, expected is an expression, a block or a throw statement
+
+compiler.err.switch.mixing.case.types=\
+ different case kinds used in the switch
############################################
# messages previouly at javac.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Wed Aug 29 09:36:17 2018 +0200
@@ -47,10 +47,12 @@
import javax.tools.JavaFileManager.Location;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.ModuleTree.ModuleKind;
import com.sun.tools.javac.code.Directive.ExportsDirective;
import com.sun.tools.javac.code.Directive.OpensDirective;
import com.sun.tools.javac.code.Type.ModuleType;
+import com.sun.tools.javac.tree.JCTree.JCPolyExpression.PolyKind;
/**
* Root class for abstract syntax tree nodes. It provides definitions
@@ -149,10 +151,14 @@
*/
SWITCH,
- /** Case parts in switch statements, of type Case.
+ /** Case parts in switch statements/expressions, of type Case.
*/
CASE,
+ /** Switch expression statements, of type Switch.
+ */
+ SWITCH_EXPRESSION,
+
/** Synchronized statements, of type Synchonized.
*/
SYNCHRONIZED,
@@ -1238,21 +1244,50 @@
* A "case :" of a switch.
*/
public static class JCCase extends JCStatement implements CaseTree {
- public JCExpression pat;
+ //as CaseKind is deprecated for removal (as it is part of a preview feature),
+ //using indirection through these fields to avoid unnecessary @SuppressWarnings:
+ @SuppressWarnings("removal")
+ public static final CaseKind STATEMENT = CaseKind.STATEMENT;
+ @SuppressWarnings("removal")
+ public static final CaseKind RULE = CaseKind.RULE;
+ @SuppressWarnings("removal")
+ public final CaseKind caseKind;
+ public List<JCExpression> pats;
public List<JCStatement> stats;
- protected JCCase(JCExpression pat, List<JCStatement> stats) {
- this.pat = pat;
+ public JCTree body;
+ public boolean completesNormally;
+ protected JCCase(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+ List<JCStatement> stats, JCTree body) {
+ Assert.checkNonNull(pats);
+ Assert.check(pats.isEmpty() || pats.head != null);
+ this.caseKind = caseKind;
+ this.pats = pats;
this.stats = stats;
+ this.body = body;
}
@Override
public void accept(Visitor v) { v.visitCase(this); }
- @DefinedBy(Api.COMPILER_TREE)
+ @Override @DefinedBy(Api.COMPILER_TREE)
public Kind getKind() { return Kind.CASE; }
- @DefinedBy(Api.COMPILER_TREE)
- public JCExpression getExpression() { return pat; }
- @DefinedBy(Api.COMPILER_TREE)
- public List<JCStatement> getStatements() { return stats; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public JCExpression getExpression() { return pats.head; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public List<JCExpression> getExpressions() { return pats; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public List<JCStatement> getStatements() {
+ return caseKind == CaseKind.STATEMENT ? stats : null;
+ }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public JCTree getBody() { return body; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public CaseKind getCaseKind() {
+ return caseKind;
+ }
@Override @DefinedBy(Api.COMPILER_TREE)
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
return v.visitCase(this, d);
@@ -1264,6 +1299,36 @@
}
/**
+ * A "switch ( ) { }" construction.
+ */
+ @SuppressWarnings("removal")
+ public static class JCSwitchExpression extends JCPolyExpression implements SwitchExpressionTree {
+ public JCExpression selector;
+ public List<JCCase> cases;
+ protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
+ this.selector = selector;
+ this.cases = cases;
+ }
+ @Override
+ public void accept(Visitor v) { v.visitSwitchExpression(this); }
+
+ @DefinedBy(Api.COMPILER_TREE)
+ public Kind getKind() { return Kind.SWITCH_EXPRESSION; }
+ @DefinedBy(Api.COMPILER_TREE)
+ public JCExpression getExpression() { return selector; }
+ @DefinedBy(Api.COMPILER_TREE)
+ public List<JCCase> getCases() { return cases; }
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+ return v.visitSwitchExpression(this, d);
+ }
+ @Override
+ public Tag getTag() {
+ return SWITCH_EXPRESSION;
+ }
+ }
+
+ /**
* A synchronized block.
*/
public static class JCSynchronized extends JCStatement implements SynchronizedTree {
@@ -1484,19 +1549,27 @@
* A break from a loop or switch.
*/
public static class JCBreak extends JCStatement implements BreakTree {
- public Name label;
+ public JCExpression value;
public JCTree target;
- protected JCBreak(Name label, JCTree target) {
- this.label = label;
+ protected JCBreak(JCExpression value, JCTree target) {
+ this.value = value;
this.target = target;
}
@Override
public void accept(Visitor v) { v.visitBreak(this); }
+ public boolean isValueBreak() {
+ return target != null && target.hasTag(SWITCH_EXPRESSION);
+ }
@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() { return Kind.BREAK; }
@DefinedBy(Api.COMPILER_TREE)
- public Name getLabel() { return label; }
+ public Name getLabel() {
+ return value != null && value.getKind() == Kind.IDENTIFIER ? ((JCIdent) value).getName() : null;
+ }
+ @DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public JCExpression getValue() { return value; }
@Override @DefinedBy(Api.COMPILER_TREE)
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
return v.visitBreak(this, d);
@@ -2934,9 +3007,9 @@
/** (let int x = 3; in x+2) */
public static class LetExpr extends JCExpression {
- public List<JCVariableDecl> defs;
+ public List<JCStatement> defs;
public JCExpression expr;
- protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
+ protected LetExpr(List<JCStatement> defs, JCExpression expr) {
this.defs = defs;
this.expr = expr;
}
@@ -2994,7 +3067,9 @@
JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body);
JCLabeledStatement Labelled(Name label, JCStatement body);
JCSwitch Switch(JCExpression selector, List<JCCase> cases);
- JCCase Case(JCExpression pat, List<JCStatement> stats);
+ JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases);
+ JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pat,
+ List<JCStatement> stats, JCTree body);
JCSynchronized Synchronized(JCExpression lock, JCBlock body);
JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
JCTry Try(List<JCTree> resources,
@@ -3007,7 +3082,7 @@
JCExpression elsepart);
JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart);
JCExpressionStatement Exec(JCExpression expr);
- JCBreak Break(Name label);
+ JCBreak Break(JCExpression value);
JCContinue Continue(Name label);
JCReturn Return(JCExpression expr);
JCThrow Throw(JCExpression expr);
@@ -3049,7 +3124,7 @@
JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
JCUses Uses(JCExpression qualId);
- LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr);
+ LetExpr LetExpr(List<JCStatement> defs, JCExpression expr);
}
/** A generic visitor class for trees.
@@ -3070,6 +3145,7 @@
public void visitLabelled(JCLabeledStatement that) { visitTree(that); }
public void visitSwitch(JCSwitch that) { visitTree(that); }
public void visitCase(JCCase that) { visitTree(that); }
+ public void visitSwitchExpression(JCSwitchExpression that) { visitTree(that); }
public void visitSynchronized(JCSynchronized that) { visitTree(that); }
public void visitTry(JCTry that) { visitTree(that); }
public void visitCatch(JCCatch that) { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Aug 29 09:36:17 2018 +0200
@@ -27,6 +27,7 @@
import java.io.*;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.ModuleTree.ModuleKind;
import com.sun.tools.javac.code.*;
@@ -835,18 +836,43 @@
public void visitCase(JCCase tree) {
try {
- if (tree.pat == null) {
+ if (tree.pats.isEmpty()) {
print("default");
} else {
print("case ");
- printExpr(tree.pat);
+ printExprs(tree.pats);
+ }
+ if (tree.caseKind == JCCase.STATEMENT) {
+ print(":");
+ println();
+ indent();
+ printStats(tree.stats);
+ undent();
+ align();
+ } else {
+ print(" -> ");
+ printStat(tree.stats.head);
}
- print(": ");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ try {
+ print("switch ");
+ if (tree.selector.hasTag(PARENS)) {
+ printExpr(tree.selector);
+ } else {
+ print("(");
+ printExpr(tree.selector);
+ print(")");
+ }
+ print(" {");
println();
- indent();
- printStats(tree.stats);
- undent();
+ printStats(tree.cases);
align();
+ print("}");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -956,7 +982,7 @@
public void visitBreak(JCBreak tree) {
try {
print("break");
- if (tree.label != null) print(" " + tree.label);
+ if (tree.value != null) print(" " + tree.value);
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java Wed Aug 29 09:36:17 2018 +0200
@@ -140,15 +140,17 @@
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitBreak(BreakTree node, P p) {
JCBreak t = (JCBreak) node;
- return M.at(t.pos).Break(t.label);
+ JCExpression value = copy(t.value, p);
+ return M.at(t.pos).Break(value);
}
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitCase(CaseTree node, P p) {
JCCase t = (JCCase) node;
- JCExpression pat = copy(t.pat, p);
+ List<JCExpression> pats = copy(t.pats, p);
List<JCStatement> stats = copy(t.stats, p);
- return M.at(t.pos).Case(pat, stats);
+ JCTree body = copy(t.body, p);
+ return M.at(t.pos).Case(t.caseKind, pats, stats, body);
}
@DefinedBy(Api.COMPILER_TREE)
@@ -371,6 +373,15 @@
}
@DefinedBy(Api.COMPILER_TREE)
+ @SuppressWarnings("removal")
+ public JCTree visitSwitchExpression(SwitchExpressionTree node, P p) {
+ JCSwitchExpression t = (JCSwitchExpression) node;
+ JCExpression selector = copy(t.selector, p);
+ List<JCCase> cases = copy(t.cases, p);
+ return M.at(t.pos).SwitchExpression(selector, cases);
+ }
+
+ @DefinedBy(Api.COMPILER_TREE)
public JCTree visitSynchronized(SynchronizedTree node, P p) {
JCSynchronized t = (JCSynchronized) node;
JCExpression lock = copy(t.lock, p);
@@ -559,7 +570,7 @@
switch (tree.getTag()) {
case LETEXPR: {
LetExpr t = (LetExpr) node;
- List<JCVariableDecl> defs = copy(t.defs, p);
+ List<JCStatement> defs = copy(t.defs, p);
JCExpression expr = copy(t.expr, p);
return M.at(t.pos).LetExpr(defs, expr);
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java Wed Aug 29 09:36:17 2018 +0200
@@ -27,6 +27,7 @@
import java.util.Iterator;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.ModuleTree.ModuleKind;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.*;
@@ -273,8 +274,15 @@
return tree;
}
- public JCCase Case(JCExpression pat, List<JCStatement> stats) {
- JCCase tree = new JCCase(pat, stats);
+ public JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+ List<JCStatement> stats, JCTree body) {
+ JCCase tree = new JCCase(caseKind, pats, stats, body);
+ tree.pos = pos;
+ return tree;
+ }
+
+ public JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases) {
+ JCSwitchExpression tree = new JCSwitchExpression(selector, cases);
tree.pos = pos;
return tree;
}
@@ -325,7 +333,7 @@
return tree;
}
- public JCBreak Break(Name label) {
+ public JCBreak Break(JCExpression label) {
JCBreak tree = new JCBreak(label, null);
tree.pos = pos;
return tree;
@@ -599,7 +607,7 @@
return tree;
}
- public LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
+ public LetExpr LetExpr(List<JCStatement> defs, JCExpression expr) {
LetExpr tree = new LetExpr(defs, expr);
tree.pos = pos;
return tree;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java Wed Aug 29 09:36:17 2018 +0200
@@ -176,10 +176,15 @@
}
public void visitCase(JCCase tree) {
- scan(tree.pat);
+ scan(tree.pats);
scan(tree.stats);
}
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ scan(tree.selector);
+ scan(tree.cases);
+ }
+
public void visitSynchronized(JCSynchronized tree) {
scan(tree.lock);
scan(tree.body);
@@ -214,6 +219,7 @@
}
public void visitBreak(JCBreak tree) {
+ scan(tree.value);
}
public void visitContinue(JCContinue tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Wed Aug 29 09:36:17 2018 +0200
@@ -207,11 +207,17 @@
}
public void visitCase(JCCase tree) {
- tree.pat = translate(tree.pat);
+ tree.pats = translate(tree.pats);
tree.stats = translate(tree.stats);
result = tree;
}
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ tree.selector = translate(tree.selector);
+ tree.cases = translateCases(tree.cases);
+ result = tree;
+ }
+
public void visitSynchronized(JCSynchronized tree) {
tree.lock = translate(tree.lock);
tree.body = translate(tree.body);
@@ -252,6 +258,8 @@
}
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ tree.value = translate(tree.value);
result = tree;
}
@@ -419,7 +427,7 @@
}
public void visitLetExpr(LetExpr tree) {
- tree.defs = translateVarDefs(tree.defs);
+ tree.defs = translate(tree.defs);
tree.expr = translate(tree.expr);
result = tree;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Wed Aug 29 09:36:17 2018 +0200
@@ -219,6 +219,10 @@
else if (arg instanceof Source) {
return ((Source)arg).name;
}
+ else if (arg instanceof Tag) {
+ return messages.getLocalizedString(l, "compiler.misc.tree.tag." +
+ StringUtils.toLowerCase(((Tag) arg).name()));
+ }
else {
return String.valueOf(arg);
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Wed Aug 29 09:36:17 2018 +0200
@@ -158,6 +158,8 @@
s = "@" + rawDiagnosticPosHelper.getPosition((JCExpression)arg);
} else if (arg instanceof PathFileObject) {
s = ((PathFileObject) arg).getShortName();
+ } else if (arg instanceof Tag) {
+ s = "compiler.misc.tree.tag." + StringUtils.toLowerCase(((Tag) arg).name());
} else {
s = super.formatArgument(diag, arg, null);
}
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java Wed Aug 29 09:36:17 2018 +0200
@@ -247,7 +247,7 @@
FOR(TokenKind.FOR, XSTMT1|XSTART), // for
IF(TokenKind.IF, XSTMT1|XSTART), // if
RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART), // return
- SWITCH(TokenKind.SWITCH, XSTMT1|XSTART), // switch
+ SWITCH(TokenKind.SWITCH, XSTMT1|XEXPR), // switch
SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL), // synchronized
THROW(TokenKind.THROW, XSTMT1|XSTART), // throw
TRY(TokenKind.TRY, XSTMT1|XSTART), // try
--- a/test/langtools/jdk/jshell/CompletenessTest.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/jdk/jshell/CompletenessTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -185,7 +185,12 @@
"int n,",
"int[] m = {1, 2},",
"int[] m = {1, 2}, n = {3, 4},",
- "Map<String,"
+ "Map<String,",
+ "switch (x) {",
+ "var v = switch (x) {",
+ "var v = switch (x) { case ",
+ "var v = switch (x) { case 0:",
+ "var v = switch (x) { case 0: break 12; ",
};
static final String[] unknown = new String[] {
--- a/test/langtools/lib/combo/tools/javac/combo/Diagnostics.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/lib/combo/tools/javac/combo/Diagnostics.java Wed Aug 29 09:36:17 2018 +0200
@@ -65,6 +65,13 @@
.anyMatch(d -> d.getCode().equals(key));
}
+ /** Do the diagnostics contain the specified warning key? */
+ public boolean containsWarningKey(String key) {
+ return diags.stream()
+ .filter(d -> d.getKind() == Diagnostic.Kind.WARNING)
+ .anyMatch(d -> d.getCode().equals(key));
+ }
+
/** Get the error keys */
public List<String> errorKeys() {
return diags.stream()
--- a/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java Wed Aug 29 09:36:17 2018 +0200
@@ -178,6 +178,14 @@
fail("Expected successful compilation");
}
+ /** Assert that all previous calls to compile() succeeded */
+ protected void assertCompileSucceededWithWarning(String warning) {
+ if (diags.errorsFound())
+ fail("Expected successful compilation");
+ if (!diags.containsWarningKey(warning))
+ fail("Expected compilation warning " + warning);
+ }
+
/**
* If the provided boolean is true, assert all previous compiles succeeded,
* otherwise assert that a compile failed.
@@ -196,9 +204,22 @@
}
/** Assert that a previous call to compile() failed with a specific error key */
- protected void assertCompileFailed(String message) {
+ protected void assertCompileFailed(String key) {
if (!diags.errorsFound())
- fail("Expected failed compilation: " + message);
+ fail("Expected failed compilation: " + key);
+ if (!diags.containsErrorKey(key))
+ fail("Expected compilation error " + key);
+ }
+
+ /** Assert that a previous call to compile() failed with a specific error key */
+ protected void assertCompileFailedOneOf(String... keys) {
+ if (!diags.errorsFound())
+ fail("Expected failed compilation with one of: " + Arrays.asList(keys));
+ boolean found = false;
+ for (String k : keys)
+ if (diags.containsErrorKey(k))
+ found = true;
+ fail(String.format("Expected compilation error with one of %s, found %s", Arrays.asList(keys), diags.keys()));
}
/** Assert that a previous call to compile() failed with all of the specified error keys */
--- a/test/langtools/tools/javac/ConditionalWithVoid.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/ConditionalWithVoid.java Wed Aug 29 09:36:17 2018 +0200
@@ -4,13 +4,17 @@
* @summary The compiler was allowing void types in its parsing of conditional expressions.
* @author tball
*
- * @compile/fail/ref=ConditionalWithVoid.out -XDrawDiagnostics ConditionalWithVoid.java
+ * @compile/fail/ref=ConditionalWithVoid.out --enable-preview -source 12 -XDrawDiagnostics ConditionalWithVoid.java
*/
public class ConditionalWithVoid {
- public void test(Object o) {
+ public void test(Object o, String s) {
// Should fail to compile since Object.wait() has a void return type. Poly case.
System.out.println(o instanceof String ? o.hashCode() : o.wait());
// Should fail to compile since Object.wait() has a void return type. Standalone case.
(o instanceof String ? o.hashCode() : o.wait()).toString();
+ // Should fail to compile since Object.wait() has a void return type. Poly case.
+ System.out.println(switch (s) {case "" -> o.hashCode(); default -> o.wait();});
+ // Should fail to compile since Object.wait() has a void return type. Standalone case.
+ (switch (s) {case "" -> o.hashCode(); default -> o.wait();}).toString();
}
}
--- a/test/langtools/tools/javac/ConditionalWithVoid.out Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/ConditionalWithVoid.out Wed Aug 29 09:36:17 2018 +0200
@@ -1,3 +1,7 @@
ConditionalWithVoid.java:12:71: compiler.err.void.not.allowed.here
-ConditionalWithVoid.java:14:30: compiler.err.neither.conditional.subtype: java.lang.Integer, void
-2 errors
+ConditionalWithVoid.java:14:53: compiler.err.void.not.allowed.here
+ConditionalWithVoid.java:16:82: compiler.err.void.not.allowed.here
+ConditionalWithVoid.java:18:64: compiler.err.void.not.allowed.here
+- compiler.note.preview.filename: ConditionalWithVoid.java
+- compiler.note.preview.recompile
+4 errors
--- a/test/langtools/tools/javac/desugar/BoxingAndSuper.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/desugar/BoxingAndSuper.java Wed Aug 29 09:36:17 2018 +0200
@@ -61,6 +61,7 @@
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.tree.JCTree.Tag;
@@ -327,8 +328,8 @@
if (tree.hasTag(Tag.LETEXPR)) {
LetExpr le = (LetExpr) tree;
- for (JCVariableDecl var : le.defs) {
- letExprRemap.put(var.name.toString(), "$le" + i++);
+ for (JCStatement var : le.defs) {
+ letExprRemap.put(((JCVariableDecl) var).name.toString(), "$le" + i++);
}
}
return super.visitOther(node, p);
--- a/test/langtools/tools/javac/diags/CheckResourceKeys.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/diags/CheckResourceKeys.java Wed Aug 29 09:36:17 2018 +0200
@@ -302,6 +302,7 @@
// prefix/embedded strings
"compiler.",
"compiler.misc.",
+ "compiler.misc.tree.tag.",
"opt.Xlint.desc.",
"count.",
"illegal.",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakAmbiguousTarget.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.break.ambiguous.target
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakAmbiguousTarget {
+ void m(int i, int j) {
+ j: print(switch (i) {
+ default: break j;
+ });
+ }
+ void print(int i) { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakComplexValueNoSwitchExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.break.complex.value.no.switch.expression
+
+class BreakComplexValueNoSwitchExpressions {
+ void t() {
+ while (true) {
+ break 1 + 1;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakExprNotImmediate.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.break.expr.not.immediate
+// key: compiler.misc.tree.tag.doloop
+// key: compiler.misc.tree.tag.foreachloop
+// key: compiler.misc.tree.tag.forloop
+// key: compiler.misc.tree.tag.switch
+// key: compiler.misc.tree.tag.whileloop
+// key: compiler.note.note
+// key: compiler.err.error
+// key: compiler.misc.count.error.plural
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// key: compiler.note.note
+// options: --enable-preview -source 12
+// run: backdoor
+
+class BreakExprNotImmediate {
+ int t(int i) {
+ return switch (i) {
+ case 0:
+ for (; ;) {
+ break 1 + 1;
+ }
+ case 1:
+ for (String s : new String[0]) {
+ break 1 + 1;
+ }
+ case 2:
+ while (true) {
+ break 1 + 1;
+ }
+ case 3:
+ do {
+ break 1 + 1;
+ } while (true);
+ case 4:
+ switch (i) {
+ default: break 1 + 1;
+ }
+ break 0;
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakMissingValue.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.break.missing.value
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakMissingValue {
+ int t(int i) {
+ return switch (i) {
+ default: break;
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakOutsideSwitchExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.break.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakOutsideSwitchExpression {
+ int t(int i) {
+ OUT: while (true) {
+ return switch (i) {
+ default: break OUT;
+ };
+ }
+ return -1;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ContinueOutsideSwitchExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.continue.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ContinueOutsideSwitchExpression {
+ int t(int i) {
+ OUT: while (true) {
+ return switch (i) {
+ default: continue OUT;
+ };
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/IncompatibleTypesInSwitchExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.incompatible.type.in.switch.expression
+// key: compiler.misc.inconvertible.types
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+
+class IncompatibleTypesInSwitchExpression {
+
+ interface A { }
+ interface B { }
+
+ B b = switch (0) { case 0 -> (A)null; default -> (B)null; };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MultipleCaseLabels.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.misc.feature.multiple.case.labels
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class MultipleCaseLabels {
+ void m(int i) {
+ switch (i) {
+ case 0, 1, 2: break;
+ }
+ }
+}
--- a/test/langtools/tools/javac/diags/examples/NeitherConditionalSubtype.java Tue Aug 28 09:01:54 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.err.neither.conditional.subtype
-
-class NeitherConditionalSubtype {
- public int test(boolean cond, Object o) {
- // Should fail to compile since Object.wait() has a void return type.
- (o instanceof String ? o.hashCode() : o.wait()).toString();
- return 0;
- }
-}
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/NotExhaustive.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.not.exhaustive
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class NotExhaustive {
+ int t(int i) {
+ return switch (i) {
+ case 0 -> -1;
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ReturnOutsideSwitchExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.return.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ReturnOutsideSwitchExpression {
+ int t(int i) {
+ return switch (i) {
+ default: return -1;
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchCaseUnexpectedStatement.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.switch.case.unexpected.statement
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ReturnOutsideSwitchExpression {
+ void t(int i) {
+ switch (i) {
+ case 0 -> if (true);
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionEmpty.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.switch.expression.empty
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakOutsideSwitchExpression {
+ String t(E e) {
+ return switch (e) {
+ };
+ }
+ enum E {}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionTargetCantBeVoid.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.incompatible.ret.type.in.lambda
+// key: compiler.misc.switch.expression.target.cant.be.void
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class SwitchExpressionTargetCantBeVoid {
+
+ interface SAM {
+ void m();
+ }
+
+ void test(int cond, Object o1, Object o2, Object o3) {
+ SAM s = ()-> switch (cond) { case 0 -> o1; case 1 -> o2; default -> o3; };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressions.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.misc.feature.switch.expressions
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class SwitchExpressions {
+ int m(int i) {
+ return switch (i) {
+ default: break -1;
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchMixingCaseTypes.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.switch.mixing.case.types
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class SwitchMixingCaseTypes {
+
+ void test(int i) {
+ switch (i) {
+ case 0: break;
+ case 1 -> System.out.println();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchNullNotAllowed.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.switch.null.not.allowed
+
+class SwitchNullNotAllowed {
+
+ void test(Integer i) {
+ switch (i) {
+ case null: break;
+ case 0: break;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchRules.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.misc.feature.switch.rules
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class SwitchExpressions {
+ void m(int i) {
+ switch (i) {
+ default -> { break; }
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.util.List;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import tools.javac.combo.JavacTemplateTestBase;
+
+import static java.util.stream.Collectors.toList;
+
+@Test
+public class ExpSwitchNestingTest extends JavacTemplateTestBase {
+ private static final String RUNNABLE = "Runnable r = () -> { # };";
+ private static final String INT_FN = "java.util.function.IntSupplier r = () -> { # };";
+ private static final String LABEL = "label: #";
+ private static final String DEF_LABEL_VAR = "int label = 0; { # }";
+ private static final String FOR = "for (int i=0; i<10; i++) { # }";
+ private static final String FOR_EACH = "for (int i : new int[] {}) { # }";
+ private static final String WHILE = "while (cond) { # }";
+ private static final String DO = "do { # } while (cond);";
+ private static final String SSWITCH = "switch (x) { case 0: # };";
+ private static final String ESWITCH_Z = "int res = switch (x) { case 0 -> { # } default -> 0; };";
+ private static final String ESWITCH_S = "String res_string = switch (x) { case 0 -> { # } default -> \"default\"; };";
+ private static final String INT_FN_ESWITCH = "java.util.function.IntSupplier r = switch (x) { case 0 -> { # } default -> null; };";
+ private static final String INT_ESWITCH_DEFAULT = "int res = switch (x) { default -> { # } };";
+ private static final String IF = "if (cond) { # }";
+ private static final String BLOCK = "{ # }";
+ private static final String BREAK_Z = "break 0;";
+ private static final String BREAK_S = "break \"hello world\";";
+ private static final String BREAK_INT_FN = "break () -> 0 ;";
+ private static final String BREAK_N = "break;";
+ private static final String BREAK_L = "break label;";
+ private static final String RETURN_Z = "return 0;";
+ private static final String RETURN_N = "return;";
+ private static final String RETURN_S = "return \"Hello\";";
+ private static final String CONTINUE_N = "continue;";
+ private static final String CONTINUE_L = "continue label;";
+ private static final String NOTHING = "System.out.println();";
+
+ // containers that do not require exhaustiveness
+ private static final List<String> CONTAINERS
+ = List.of(RUNNABLE, FOR, WHILE, DO, SSWITCH, IF, BLOCK);
+ // containers that do not require exhaustiveness that are statements
+ private static final List<String> CONTAINER_STATEMENTS
+ = List.of(FOR, WHILE, DO, SSWITCH, IF, BLOCK);
+
+ @AfterMethod
+ public void dumpTemplateIfError(ITestResult result) {
+ // Make sure offending template ends up in log file on failure
+ if (!result.isSuccess()) {
+ System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
+ }
+ }
+
+ private void program(String... constructs) {
+ String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }";
+ for (String c : constructs)
+ s = s.replace("#", c);
+ addSourceFile("C.java", new StringTemplate(s));
+ }
+
+ private void assertOK(String... constructs) {
+ reset();
+ addCompileOptions("--enable-preview", "-source", "12");
+ program(constructs);
+ try {
+ compile();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ assertCompileSucceeded();
+ }
+
+ private void assertOKWithWarning(String warning, String... constructs) {
+ reset();
+ addCompileOptions("--enable-preview", "-source", "12");
+ program(constructs);
+ try {
+ compile();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ assertCompileSucceededWithWarning(warning);
+ }
+
+ private void assertFail(String expectedDiag, String... constructs) {
+ reset();
+ addCompileOptions("--enable-preview", "-source", "12");
+ program(constructs);
+ try {
+ compile();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ assertCompileFailed(expectedDiag);
+ }
+
+ public void testReallySimpleCases() {
+ for (String s : CONTAINERS)
+ assertOK(s, NOTHING);
+ for (String s : CONTAINER_STATEMENTS)
+ assertOK(LABEL, s, NOTHING);
+ }
+
+ public void testLambda() {
+ assertOK(RUNNABLE, RETURN_N);
+ assertOK(RUNNABLE, NOTHING);
+ assertOK(INT_FN, RETURN_Z);
+ assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N);
+ assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z);
+ assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S);
+ assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N);
+ assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z);
+ assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S);
+ assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N);
+ assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L);
+ assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L);
+ assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N);
+ assertFail("compiler.err.undef.label", INT_FN, BREAK_L);
+ assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L);
+ assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L);
+ assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L);
+ assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L);
+ assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L);
+ }
+
+ public void testEswitch() {
+ //Int-valued switch expressions
+ assertOK(ESWITCH_Z, BREAK_Z);
+ assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z);
+ assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N);
+ assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S);
+ assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L);
+ assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L);
+ assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L);
+ assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N);
+ assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N);
+ assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z);
+
+ assertOK(INT_ESWITCH_DEFAULT, BREAK_Z);
+ assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N);
+ assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S);
+ assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L);
+
+
+ // String-valued switch expressions
+ assertOK(ESWITCH_S, BREAK_S);
+ assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S);
+ assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N);
+ assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z);
+ assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L);
+ assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L);
+ assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L);
+ assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N);
+ assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N);
+ assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S);
+ // Function-valued switch expression
+ assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
+ assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N);
+ assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z);
+ assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S);
+
+ assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L);
+ assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L);
+ assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L);
+ assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N);
+ assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N);
+ assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S);
+
+ }
+
+ public void testNestedInExpSwitch() {
+ assertOK(ESWITCH_Z, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, BREAK_Z);
+ //
+ assertOK(ESWITCH_Z, IF, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, IF, BLOCK, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, BLOCK, BREAK_Z);
+ //
+ assertOK(ESWITCH_Z, IF, IF, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, IF, IF, BLOCK, BREAK_Z);
+ assertOK(ESWITCH_Z, IF, BLOCK, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, IF, BLOCK, BLOCK, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, IF, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, IF, BLOCK, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, BLOCK, IF, BREAK_Z);
+ assertOK(ESWITCH_Z, BLOCK, BLOCK, BLOCK, BREAK_Z);
+ //
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z);
+ assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z);
+ assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z);
+ }
+
+ public void testBreakExpressionLabelDisambiguation() {
+ assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
+ assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
+ assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break
+ assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break
+ //
+ }
+
+ public void testFunReturningSwitchExp() {
+ assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
+ }
+
+ public void testContinueLoops() {
+ assertOK(LABEL, FOR, CONTINUE_L);
+ assertOK(LABEL, FOR_EACH, CONTINUE_L);
+ assertOK(LABEL, WHILE, CONTINUE_L);
+ assertOK(LABEL, DO, CONTINUE_L);
+ assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/expswitch/TEST.properties Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
+
+modules = \
+ jdk.compiler/com.sun.tools.javac.util
--- a/test/langtools/tools/javac/failover/CheckAttributedTree.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java Wed Aug 29 09:36:17 2018 +0200
@@ -95,6 +95,7 @@
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.TreeInfo;
@@ -446,6 +447,12 @@
scan(tree.defs);
}
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ super.visitBreak(tree);
+ }
+
JavaFileObject sourcefile;
EndPosTable endPosTable;
Info encl;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Adding switch expressions
+ * @compile/fail/ref=BadSwitchExpressionLambda.out -XDrawDiagnostics --enable-preview -source 12 BadSwitchExpressionLambda.java
+ */
+
+class BadSwitchExpressionLambda {
+
+ interface SAM {
+ void invoke();
+ }
+
+ public static void m() {}
+ public static void r(SAM sam) {}
+
+ void test(int i) {
+ SAM sam1 = () -> m(); //ok
+ SAM sam2 = () -> switch (i) { case 0 -> m(); default -> m(); }; //not ok
+ r(() -> m()); //ok
+ r(() -> switch (i) { case 0 -> m(); default -> m(); }); //not ok
+ return switch (i) { case 0 -> m(); default -> m(); }; //not ok
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+BadSwitchExpressionLambda.java:19:26: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.switch.expression.target.cant.be.void))
+BadSwitchExpressionLambda.java:21:9: compiler.err.cant.apply.symbol: kindname.method, r, BadSwitchExpressionLambda.SAM, @11, kindname.class, BadSwitchExpressionLambda, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.switch.expression.target.cant.be.void)))
+BadSwitchExpressionLambda.java:22:16: compiler.err.prob.found.req: (compiler.misc.unexpected.ret.val)
+- compiler.note.preview.filename: BadSwitchExpressionLambda.java
+- compiler.note.preview.recompile
+3 errors
--- a/test/langtools/tools/javac/lib/DPrinter.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/lib/DPrinter.java Wed Aug 29 09:36:17 2018 +0200
@@ -737,7 +737,7 @@
@Override
public void visitCase(JCCase tree) {
- printTree("pat", tree.pat);
+ printList("pat", tree.pats);
printList("stats", tree.stats);
}
@@ -782,7 +782,7 @@
@Override
public void visitBreak(JCBreak tree) {
- printName("label", tree.label);
+ printTree("value", tree.value);
}
@Override
--- a/test/langtools/tools/javac/parser/JavacParserTest.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/parser/JavacParserTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -82,6 +82,9 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.util.TreePathScanner;
+
public class JavacParserTest extends TestCase {
static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
static final JavaFileManager fm = tool.getStandardFileManager(null, null, null);
@@ -1039,6 +1042,135 @@
}
@Test
+ void testCaseBodyStatements() throws IOException {
+ String code = "class C {" +
+ " void t(int i) {" +
+ " switch (i) {" +
+ " case 0 -> i++;" +
+ " case 1 -> { i++; }" +
+ " case 2 -> throw new RuntimeException();" +
+ " case 3 -> if (true) ;" +
+ " default -> i++;" +
+ " }" +
+ " switch (i) {" +
+ " case 0: i++; break;" +
+ " case 1: { i++; break;}" +
+ " case 2: throw new RuntimeException();" +
+ " case 3: if (true) ; break;" +
+ " default: i++; break;" +
+ " }" +
+ " int j = switch (i) {" +
+ " case 0 -> i + 1;" +
+ " case 1 -> { break i + 1; }" +
+ " default -> throw new RuntimeException();" +
+ " };" +
+ " int k = switch (i) {" +
+ " case 0: break i + 1;" +
+ " case 1: { break i + 1; }" +
+ " default: throw new RuntimeException();" +
+ " };" +
+ " }" +
+ "}";
+ String expectedErrors = "Test.java:1:178: compiler.err.switch.case.unexpected.statement\n";
+ StringWriter out = new StringWriter();
+ JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null,
+ Arrays.asList("-XDrawDiagnostics", "--enable-preview", "-source", "12"),
+ null, Arrays.asList(new MyFileObject(code)));
+
+ CompilationUnitTree cut = ct.parse().iterator().next();
+ Trees trees = Trees.instance(ct);
+ List<String> spans = new ArrayList<>();
+
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitCase(CaseTree tree, Void v) {
+ if (tree.getBody() != null) {
+ int start = (int) trees.getSourcePositions().getStartPosition(cut, tree.getBody());
+ int end = (int) trees.getSourcePositions().getEndPosition(cut, tree.getBody());
+ spans.add(code.substring(start, end));
+ } else {
+ spans.add("<null>");
+ }
+ return super.visitCase(tree, v);
+ }
+ }.scan(cut, null);
+
+ List<String> expectedSpans = List.of(
+ "i++;", "{ i++; }", "throw new RuntimeException();", "if (true) ;", "i++;",
+ "<null>", "<null>", "<null>", "<null>", "<null>",
+ "i + 1"/*TODO semicolon?*/, "{ break i + 1; }", "throw new RuntimeException();",
+ "<null>", "<null>", "<null>");
+ assertEquals("the error spans are not correct; actual:" + spans, expectedSpans, spans);
+ String toString = normalize(cut.toString());
+ String expectedToString =
+ "\n" +
+ "class C {\n" +
+ " \n" +
+ " void t(int i) {\n" +
+ " switch (i) {\n" +
+ " case 0 -> i++;\n" +
+ " case 1 -> {\n" +
+ " i++;\n" +
+ " }\n" +
+ " case 2 -> throw new RuntimeException();\n" +
+ " case 3 -> if (true) ;\n" +
+ " default -> i++;\n" +
+ " }\n" +
+ " switch (i) {\n" +
+ " case 0:\n" +
+ " i++;\n" +
+ " break;\n" +
+ " \n" +
+ " case 1:\n" +
+ " {\n" +
+ " i++;\n" +
+ " break;\n" +
+ " }\n" +
+ " \n" +
+ " case 2:\n" +
+ " throw new RuntimeException();\n" +
+ " \n" +
+ " case 3:\n" +
+ " if (true) ;\n" +
+ " break;\n" +
+ " \n" +
+ " default:\n" +
+ " i++;\n" +
+ " break;\n" +
+ " \n" +
+ " }\n" +
+ " int j = switch (i) {\n" +
+ " case 0 -> break i + 1;\n" +
+ " case 1 -> {\n" +
+ " break i + 1;\n" +
+ " }\n" +
+ " default -> throw new RuntimeException();\n" +
+ " };\n" +
+ " int k = switch (i) {\n" +
+ " case 0:\n" +
+ " break i + 1;\n" +
+ " \n" +
+ " case 1:\n" +
+ " {\n" +
+ " break i + 1;\n" +
+ " }\n" +
+ " \n" +
+ " default:\n" +
+ " throw new RuntimeException();\n" +
+ " \n" +
+ " };\n" +
+ " }\n" +
+ "}";
+ System.err.println("toString:");
+ System.err.println(toString);
+ System.err.println("expectedToString:");
+ System.err.println(expectedToString);
+ assertEquals("the error spans are not correct; actual:" + toString, expectedToString, toString);
+ String actualErrors = normalize(out.toString());
+ assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
+ }
+
+ @Test
void testTypeParamsWithoutMethod() throws IOException {
assert tool != null;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BlockExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify rule cases with expression statements and throw statements work.
+ * @compile --enable-preview -source 12 BlockExpression.java
+ * @run main/othervm --enable-preview BlockExpression
+ */
+
+public class BlockExpression {
+
+ public static void main(String... args) {
+ T t = T.B;
+
+ try {
+ int ii = switch (t) {
+ case A -> 0;
+ default -> throw new IllegalStateException();
+ };
+ throw new AssertionError("Expected exception not thrown.");
+ } catch (IllegalStateException ex) {
+ //OK
+ }
+ }
+
+ enum T {
+ A, B;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify the type of a conditional expression with nested switch expression is computed properly
+ * @compile/fail/ref=BooleanNumericNonNumeric.out -XDrawDiagnostics --enable-preview -source 12 BooleanNumericNonNumeric.java
+ */
+
+public class BooleanNumericNonNumeric {
+
+ private void test(boolean b, int i) {
+ int r1 = 1 + (b ? switch (i) { //boolean, error
+ default -> true;
+ } : false);
+ int r2 = 1 + (b ? switch (i) { //int, ok
+ default -> 0;
+ } : 1);
+ (b ? switch (i) { //int, error
+ default -> 0;
+ } : 1).toString();
+ (b ? switch (i) { //"object", ok
+ case 0 -> true;
+ default -> 0;
+ } : 1).toString();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+BooleanNumericNonNumeric.java:11:20: compiler.err.operator.cant.be.applied.1: +, int, boolean
+BooleanNumericNonNumeric.java:19:15: compiler.err.cant.deref: int
+- compiler.note.preview.filename: BooleanNumericNonNumeric.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BreakTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure BreakTree.getLabel returns reasonable values
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.lang.model.element.Name;
+import javax.tools.*;
+
+import com.sun.source.tree.BreakTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+
+public class BreakTest {
+
+ private static final String CODE =
+ "public class C {" +
+ " void t1(Integer i) {" +
+ " LABEL: switch (i) {" +
+ " case null: i++; break LABEL;" +
+ " default: i++; break;" +
+ " }" +
+ " }" +
+ " int t2(Integer i) {" +
+ " return switch (i) {" +
+ " case null: break LABEL;" +
+ " default: break 2;" +
+ " }" +
+ " }" +
+ "}";
+
+ public static void main(String[] args) throws Exception {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+ StringWriter out = new StringWriter();
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+ Arrays.asList(new MyFileObject(CODE)));
+ List<String> labels = new ArrayList<>();
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitBreak(BreakTree node, Void p) {
+ Name label = node.getLabel();
+ labels.add(label != null ? label.toString() : null);
+ return super.visitBreak(node, p);
+ }
+ }.scan(ct.parse(), null);
+
+ List<String> expected = Arrays.asList("LABEL", null, "LABEL", null);
+
+ if (!expected.equals(labels)) {
+ throw new AssertionError("Unexpected labels found: " + labels);
+ }
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify than an empty switch expression is rejected.
+ * @compile/fail/ref=EmptySwitch.out --enable-preview -source 12 -XDrawDiagnostics EmptySwitch.java
+ */
+
+public class EmptySwitch {
+ private void print(EmptySwitchEnum t) {
+ (switch (t) {
+ }).toString();
+ }
+
+ enum EmptySwitchEnum {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+EmptySwitch.java:33:10: compiler.err.switch.expression.empty
+- compiler.note.preview.filename: EmptySwitch.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitch.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify that an switch expression over enum can be exhaustive without default.
+ * @compile --enable-preview -source 12 ExhaustiveEnumSwitch.java
+ * @compile ExhaustiveEnumSwitchExtra.java
+ * @run main/othervm --enable-preview ExhaustiveEnumSwitch
+ */
+
+public class ExhaustiveEnumSwitch {
+ public static void main(String... args) {
+ new ExhaustiveEnumSwitch().run();
+ }
+
+ private void run() {
+ ExhaustiveEnumSwitchEnum v = ExhaustiveEnumSwitchEnum.valueOf("F");
+
+ try {
+ print(v);
+ throw new AssertionError("Expected exception did not occur.");
+ } catch (IncompatibleClassChangeError err) {
+ //ok
+ }
+ }
+
+ private String print(ExhaustiveEnumSwitchEnum t) {
+ return switch (t) {
+ case A -> "A";
+ case B -> "B";
+ };
+ }
+
+}
+enum ExhaustiveEnumSwitchEnum {
+ A, B;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitchExtra.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+enum ExhaustiveEnumSwitchEnum {
+ A, B, F;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,3 @@
+ExpressionSwitch.java:30:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions)
+ExpressionSwitch.java:31:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,115 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check expression switch works.
+ * @compile/fail/ref=ExpressionSwitch-old.out -source 9 -Xlint:-options -XDrawDiagnostics ExpressionSwitch.java
+ * @compile --enable-preview -source 12 ExpressionSwitch.java
+ * @run main/othervm --enable-preview ExpressionSwitch
+ */
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class ExpressionSwitch {
+ public static void main(String... args) {
+ new ExpressionSwitch().run();
+ }
+
+ private void run() {
+ check(T.A, "A");
+ check(T.B, "B");
+ check(T.C, "other");
+ assertEquals(exhaustive1(T.C), "C");
+ assertEquals(scopesIsolated(T.B), "B");
+ assertEquals(lambdas1(T.B).get(), "B");
+ assertEquals(lambdas2(T.B).get(), "B");
+ localClass(T.A);
+ }
+
+ private String print(T t) {
+ return switch (t) {
+ case A -> "A";
+ case B -> { break "B"; }
+ default -> { break "other"; }
+ };
+ }
+
+ private String exhaustive1(T t) {
+ return switch (t) {
+ case A -> "A";
+ case B -> { break "B"; }
+ case C -> "C";
+ case D -> "D";
+ };
+ }
+
+ private String exhaustive2(T t) {
+ return switch (t) {
+ case A -> "A";
+ case B -> "B";
+ case C -> "C";
+ case D -> "D";
+ };
+ }
+
+ private String scopesIsolated(T t) {
+ return switch (t) {
+ case A -> { String res = "A"; break res;}
+ case B -> { String res = "B"; break res;}
+ default -> { String res = "default"; break res;}
+ };
+ }
+
+ private Supplier<String> lambdas1(T t) {
+ return switch (t) {
+ case A -> () -> "A";
+ case B -> { break () -> "B"; }
+ default -> () -> "default";
+ };
+ }
+
+ private Supplier<String> lambdas2(T t) {
+ return switch (t) {
+ case A: break () -> "A";
+ case B: { break () -> "B"; }
+ default: break () -> "default";
+ };
+ }
+
+ private void localClass(T t) {
+ String good = "good";
+ class L {
+ public String c() {
+ STOP: switch (t) {
+ default: break STOP;
+ }
+ return switch (t) {
+ default: break good;
+ };
+ }
+ }
+ String result = new L().c();
+ if (!Objects.equals(result, good)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ private void check(T t, String expected) {
+ String result = print(t);
+ assertEquals(result, expected);
+ }
+
+ private void assertEquals(Object result, Object expected) {
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B, C, D;
+ }
+ void t() {
+ Runnable r = () -> {};
+ r.run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks1.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify behavior of various kinds of breaks.
+ * @compile --enable-preview -source 12 ExpressionSwitchBreaks1.java
+ * @run main/othervm --enable-preview ExpressionSwitchBreaks1
+ */
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class ExpressionSwitchBreaks1 {
+ public static void main(String... args) {
+ new ExpressionSwitchBreaks1().run();
+ }
+
+ private void run() {
+ check(print1(0, 0), "0-0");
+ check(print1(0, 1), "0-1");
+ check(print1(0, -1), "0-X");
+ check(print1(-1, -1), "X");
+ check(print2(0, 0, 0), "0-0-0");
+ check(print2(0, 0, 1), "0-0-1");
+ check(print2(0, 0, 2), "0-0-2");
+ check(print2(0, 0, -1), "0-0-X");
+ check(print2(0, 1, -1), "0-1");
+ check(print2(0, -1, -1), "0-X");
+ check(print2(1, -1, -1), "1");
+ check(print2(2, 5, 5), "2-X-5");
+ check(print2(-11, -1, -1), "X");
+ }
+
+ private String print1(int i, int j) {
+ switch (i) {
+ case 0:
+ return switch (j) {
+ case 0:
+ if (true) break "0-0";
+ case 1:
+ break "0-1";
+ default:
+ break "0-X";
+ };
+ default: return "X";
+ }
+ }
+
+ private String print2(int i, int j, int k) {
+ return switch (i) {
+ case 0:
+ String r;
+ OUTER: switch (j) {
+ case 0:
+ String res;
+ INNER: switch (k) {
+ case 0: res = "0-0-0"; break;
+ case 1: res = "0-0-1"; break;
+ case 2: res = "0-0-2"; break INNER;
+ default: r = "0-0-X"; break OUTER;
+ }
+ r = res;
+ break;
+ case 1:
+ r = "0-1";
+ break;
+ default:
+ r = "0-X";
+ break;
+ }
+ break r;
+ case 1:
+ break "1";
+ case 2:
+ LOP: while (j-- > 0) {
+ if (k == 5) {
+ k--;
+ continue;
+ }
+ break LOP;
+ }
+ Supplier<String> getter = () -> { return "2-X-5"; };
+ break getter.get();
+ default:
+ break "X";
+ };
+ }
+
+ private void check(String result, String expected) {
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check behavior for invalid breaks.
+ * @compile/fail/ref=ExpressionSwitchBreaks2.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchBreaks2.java
+ */
+
+public class ExpressionSwitchBreaks2 {
+ private String print(int i, int j) {
+ LOOP: while (true) {
+ OUTER: switch (i) {
+ case 0:
+ return switch (j) {
+ case 0:
+ break "0-0";
+ case 1:
+ break ; //error: missing value
+ case 2:
+ break OUTER; //error: jumping outside of the switch expression
+ case 3: {
+ int x = -1;
+ x: switch (i + j) {
+ case 0: break x; //error: cannot disambiguate, wrong type as well
+ }
+ break "X";
+ }
+ case 4: return "X"; //error: no returns from inside of the switch expression
+ case 5: continue; //error: no continue out of the switch expression
+ case 6: continue LOOP; //error: dtto, but with a label
+ case 7: continue UNKNOWN; //error: unknown label
+ default: {
+ String x = "X";
+ x: switch (i + j) {
+ case 0: break ""; //error: cannot break from switch expression that is not immediatelly enclosing
+ }
+ break "X";
+ }
+ };
+ case 1:
+ break "1" + undef; //error: complex value and no switch expression
+ }
+ }
+ j: print(switch (i) {
+ default: break j; //error: "j" is ambiguous (expression/label)
+ }, 0);
+ j2: print(switch (i) {
+ default: break j2;
+ }, 0);
+ return null;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,15 @@
+ExpressionSwitchBreaks2.java:17:25: compiler.err.break.missing.value
+ExpressionSwitchBreaks2.java:19:25: compiler.err.break.outside.switch.expression
+ExpressionSwitchBreaks2.java:23:37: compiler.err.break.ambiguous.target: x
+ExpressionSwitchBreaks2.java:27:29: compiler.err.return.outside.switch.expression
+ExpressionSwitchBreaks2.java:28:29: compiler.err.continue.outside.switch.expression
+ExpressionSwitchBreaks2.java:29:29: compiler.err.continue.outside.switch.expression
+ExpressionSwitchBreaks2.java:30:29: compiler.err.undef.label: UNKNOWN
+ExpressionSwitchBreaks2.java:34:37: compiler.err.break.expr.not.immediate: compiler.misc.tree.tag.switch
+ExpressionSwitchBreaks2.java:40:17: compiler.err.break.complex.value.no.switch.expression
+ExpressionSwitchBreaks2.java:40:29: compiler.err.cant.resolve.location: kindname.variable, undef, , , (compiler.misc.location: kindname.class, ExpressionSwitchBreaks2, null)
+ExpressionSwitchBreaks2.java:44:22: compiler.err.break.ambiguous.target: j
+ExpressionSwitchBreaks2.java:47:22: compiler.err.break.outside.switch.expression
+- compiler.note.preview.filename: ExpressionSwitchBreaks2.java
+- compiler.note.preview.recompile
+12 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify various corner cases with nested switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchBugs.java
+ * @run main/othervm --enable-preview ExpressionSwitchBugs
+ */
+
+public class ExpressionSwitchBugs {
+ public static void main(String... args) {
+ new ExpressionSwitchBugs().testNested();
+ }
+
+ private void testNested() {
+ int i = 0;
+ check(42, id(switch (42) {
+ default: i++; break 42;
+ }));
+ i = 0;
+ check(43, id(switch (42) {
+ case 42: while (i == 0) {
+ i++;
+ }
+ break 42 + i;
+ default: i++; break 42;
+ }));
+ i = 0;
+ check(42, id(switch (42) {
+ case 42: if (i == 0) {
+ break 42;
+ }
+ default: i++; break 43;
+ }));
+ i = 0;
+ check(42, id(switch (42) {
+ case 42: if (i == 0) {
+ break 41 + switch (0) {
+ case 0 -> 1;
+ default -> -1;
+ };
+ }
+ default: i++; break 43;
+ }));
+ }
+
+ private int id(int i) {
+ return i;
+ }
+
+ private int id(Object o) {
+ return -1;
+ }
+
+ private void check(int actual, int expected) {
+ if (actual != expected) {
+ throw new AssertionError("Unexpected result: " + actual);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchCodeFromJLS.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check switch expressions
+ * @compile --enable-preview -source 12 ExpressionSwitchCodeFromJLS.java
+ * @run main/othervm --enable-preview ExpressionSwitchCodeFromJLS
+ */
+
+public class ExpressionSwitchCodeFromJLS {
+ static void howMany(int k) {
+ switch (k) {
+ case 1: System.out.print("one ");
+ case 2: System.out.print("too ");
+ case 3: System.out.println("many");
+ }
+ }
+ static void howManyRule(int k) {
+ switch (k) {
+ case 1 -> System.out.println("one");
+ case 2 -> System.out.println("two");
+ case 3 -> System.out.println("many");
+ }
+ }
+ static void howManyGroup(int k) {
+ switch (k) {
+ case 1: System.out.println("one");
+ break; // exit the switch
+ case 2: System.out.println("two");
+ break; // exit the switch
+ case 3: System.out.println("many");
+ break; // not needed, but good style
+ }
+ }
+ public static void main(String[] args) {
+ howMany(3);
+ howMany(2);
+ howMany(1);
+ howManyRule(1);
+ howManyRule(2);
+ howManyRule(3);
+ howManyGroup(1);
+ howManyGroup(2);
+ howManyGroup(3);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchDA.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check definite (un)assignment for in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchDA.java
+ * @run main/othervm --enable-preview ExpressionSwitchDA
+ */
+
+public class ExpressionSwitchDA {
+ public static void test1() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 : i=42; break;
+ default: i=42;
+ }
+ System.out.println(i);
+ }
+ public static void test2(){
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> i=42;
+ default -> i=42;
+ }
+ System.out.println(i);
+ }
+ public static void test3(){
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> { i=42; }
+ default -> { i=42; }
+ }
+ System.out.println(i);
+ }
+ public static void test4(){
+ int i;
+ int j = 0;
+ int k = switch (j) {
+ case 0 -> i=42;
+ default -> i=42;
+ };
+ System.out.println(i);
+ }
+ public static void test5(){
+ int i;
+ int j = 0;
+ int k = switch (j) {
+ case 0 -> { i=42; break 42; }
+ default -> i=42;
+ };
+ System.out.println(i);
+ }
+ public static void test6(){
+ int i;
+ int j = 0;
+ int k = switch (j) {
+ case 0 -> i=42;
+ default -> { i=42; break 42; }
+ };
+ System.out.println(i);
+ }
+ public static void test7(){
+ int i;
+ int j = 0;
+ int k = switch (j) {
+ case 0 -> { i=42; break 42; }
+ default -> { i=42; break 42; }
+ };
+ System.out.println(i);
+ }
+ public static void test8() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 : i=42; break;
+ default: throw new NullPointerException();
+ }
+ System.out.println(i);
+ }
+ public static void test9() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> i=42;
+ default -> throw new NullPointerException();
+ }
+ System.out.println(i);
+ }
+ public static void test10() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> { i=42; System.out.print(i);}
+ default -> throw new NullPointerException();
+ }
+ System.out.println(i);
+ }
+ public static void test11() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> { i=42; System.out.print(i);}
+ default -> { throw new NullPointerException(); }
+ }
+ System.out.println(i);
+ }
+ public static void test12() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 : i=42; break;
+ default: return;
+ }
+ System.out.println(i);
+ }
+ public static void test13() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> i=42;
+ default -> { return; }
+ }
+ System.out.println(i);
+ }
+ public static void test14() {
+ int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> { i=42; }
+ default -> { return; }
+ }
+ System.out.println(i);
+ }
+ public static void test15() {
+ final int i;
+ int j = 0;
+ switch (j) {
+ case 0 -> { i=42; }
+ default -> { i=42; }
+ }
+ System.out.println(i);
+ }
+ public static void main(String[] args) {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ test6();
+ test7();
+ test8();
+ test9();
+ test10();
+ test11();
+ test12();
+ test13();
+ test14();
+ test15();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check fall through in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchFallThrough.java
+ * @run main/othervm --enable-preview ExpressionSwitchFallThrough
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class ExpressionSwitchFallThrough {
+ public static void main(String... args) {
+ new ExpressionSwitchFallThrough().run();
+ }
+
+ private void run() {
+ runTest(this::expression1);
+ runTest(this::expression2);
+ }
+
+ private void runTest(Function<T, String> print) {
+ check(T.A, print, "ab");
+ check(T.B, print, "b");
+ check(T.C, print, "");
+ }
+
+ private String expression1(T t) {
+ String help = "";
+ return switch (t) {
+ case A: help = "a";
+ case B: help += "b";
+ default: break help;
+ };
+ }
+
+ private String expression2(T t) {
+ String help = "";
+ return switch (t) {
+ case A: help = "a";
+ case B: help += "b";
+ default: break help;
+ };
+ }
+
+ private void check(T t, Function<T, String> print, String expected) {
+ String result = print.apply(t);
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B, C;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check fall through in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchFallThrough1.java
+ * @run main/othervm --enable-preview ExpressionSwitchFallThrough1
+ */
+
+import java.util.Objects;
+
+public class ExpressionSwitchFallThrough1 {
+ public static void main(String... args) {
+ new ExpressionSwitchFallThrough1().test();
+ }
+
+ private void test() {
+ assertEquals("01", printExprFallThrough(0));
+ assertEquals("1", printExprFallThrough(1));
+ assertEquals("other", printExprFallThrough(3));
+ assertEquals("01", printStatementFallThrough(0));
+ assertEquals("1", printStatementFallThrough(1));
+ assertEquals("other", printStatementFallThrough(3));
+ }
+
+ private String printExprFallThrough(Integer p) {
+ String result = "";
+ return switch (p) {
+ case 0: result += "0";
+ case 1: result += "1";
+ break result;
+ default: break "other";
+ };
+ }
+
+ private String printStatementFallThrough(Integer p) {
+ String result = "";
+ switch (p) {
+ case 0: result += "0";
+ case 1: result += "1";
+ break ;
+ default: result = "other";
+ break;
+ }
+ return result;
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (!Objects.equals(actual, expected)) {
+ throw new AssertionError("Unexpected result: " + actual + ", expected: " + expected);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInExpressionSwitch.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check switch expressions embedded in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchInExpressionSwitch.java
+ * @run main/othervm --enable-preview ExpressionSwitchInExpressionSwitch
+ */
+
+public class ExpressionSwitchInExpressionSwitch {
+ public static void main(String[] args) {
+
+ int j = 42;
+ int i = switch (j) {
+ default -> (switch (j) { default -> 0; } )+1;
+ };
+ if (i!=1) {
+ throw new AssertionError("Unexpected result: " + i);
+ }
+ i = switch (j) {
+ default -> {
+ int k = switch (j) {
+ default -> {
+ break 42;
+ }
+ };
+ System.out.println("didn't break to the top level");
+ break 43;
+ }
+ };
+ if (i!=43) {
+ throw new AssertionError("Unexpected result: " + i);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check types inferred for switch expressions.
+ * @compile/fail/ref=ExpressionSwitchInfer.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchInfer.java
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExpressionSwitchInfer {
+
+ private static final String NULL = "null";
+
+ private <T> T test(List<T> l, Class<T> c, String param) {
+ test(param == NULL ? new ArrayList<>() : new ArrayList<>(), CharSequence.class, param).charAt(0);
+ test(param == NULL ? new ArrayList<>() : new ArrayList<>(), CharSequence.class, param).substring(0);
+
+ test(switch (param) {
+ case NULL -> new ArrayList<>();
+ default -> new ArrayList<>();
+ }, CharSequence.class, param).charAt(0);
+ test(switch (param) {
+ case NULL -> new ArrayList<>();
+ default -> new ArrayList<>();
+ }, CharSequence.class, param).substring(0);
+
+ String str = switch (param) {
+ case "" -> {
+ break 0;
+ } default ->"default";
+ };
+
+ return null;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+ExpressionSwitchInfer.java:17:95: compiler.err.cant.resolve.location.args: kindname.method, substring, , int, (compiler.misc.location: kindname.interface, java.lang.CharSequence, null)
+ExpressionSwitchInfer.java:26:38: compiler.err.cant.resolve.location.args: kindname.method, substring, , int, (compiler.misc.location: kindname.interface, java.lang.CharSequence, null)
+ExpressionSwitchInfer.java:30:23: compiler.err.prob.found.req: (compiler.misc.incompatible.type.in.switch.expression: (compiler.misc.inconvertible.types: int, java.lang.String))
+- compiler.note.preview.filename: ExpressionSwitchInfer.java
+- compiler.note.preview.recompile
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchIntersectionTypes.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify behavior when an intersection type is inferred for switch expression.
+ * @compile --enable-preview -source 12 ExpressionSwitchIntersectionTypes.java
+ * @run main/othervm --enable-preview ExpressionSwitchIntersectionTypes
+ */
+
+public class ExpressionSwitchIntersectionTypes<X extends java.io.Serializable & Runnable> {
+
+ void test1(int i, X x) {
+ Runnable r1 = switch (i) {
+ default -> x;
+ };
+ r1.run();
+ }
+
+ void test2(int i, X x) {
+ (switch (i) {
+ default -> x;
+ }).run();
+ }
+
+ public static void main(String[] args) {
+ ExpressionSwitchIntersectionTypes t = new ExpressionSwitchIntersectionTypes();
+ try {
+ t.test1(0, "");
+ throw new AssertionError("Expected exception didn't occur.");
+ } catch (ClassCastException ex) {
+ //good
+ }
+ try {
+ t.test2(0, "");
+ throw new AssertionError("Expected exception didn't occur.");
+ } catch (ClassCastException ex) {
+ //good
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify behavior of not exhaustive switch expressions.
+ * @compile/fail/ref=ExpressionSwitchNotExhaustive.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchNotExhaustive.java
+ */
+
+public class ExpressionSwitchNotExhaustive {
+ private String print(int i) {
+ return switch (i) {
+ case 42 -> "42";
+ case 43 -> "43";
+ };
+ }
+ private String e(E e) {
+ return switch (e) {
+ case A -> "42";
+ };
+ }
+ private String f(int i, E e) {
+ return switch (i) {
+ case 0:
+ String s;
+ switch (e) {
+ case A:
+ s = "42";
+ break;
+ }
+ break s;
+ default:
+ break "43";
+ };
+ }
+ enum E {
+ A, B;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+ExpressionSwitchNotExhaustive.java:10:16: compiler.err.not.exhaustive
+ExpressionSwitchNotExhaustive.java:16:16: compiler.err.not.exhaustive
+ExpressionSwitchNotExhaustive.java:29:23: compiler.err.var.might.not.have.been.initialized: s
+- compiler.note.preview.filename: ExpressionSwitchNotExhaustive.java
+- compiler.note.preview.recompile
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify reachability in switch expressions.
+ * @compile/fail/ref=ExpressionSwitchUnreachable.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchUnreachable.java
+ */
+
+public class ExpressionSwitchUnreachable {
+
+ public static void main(String[] args) {
+ int z = 42;
+ int i = switch (z) {
+ case 0 -> {
+ break 42;
+ System.out.println("Unreachable"); //Unreachable
+ }
+ default -> 0;
+ };
+ i = switch (z) {
+ case 0 -> {
+ break 42;
+ break 42; //Unreachable
+ }
+ default -> 0;
+ };
+ i = switch (z) {
+ case 0:
+ System.out.println("0");
+ break 42;
+ System.out.println("1"); //Unreachable
+ default : break 42;
+ };
+ i = switch (z) {
+ case 0 -> 42;
+ default -> {
+ break 42;
+ System.out.println("Unreachable"); //Unreachable
+ }
+ };
+ i = switch (z) {
+ case 0: break 42;
+ default:
+ System.out.println("0");
+ break 42;
+ System.out.println("1"); //Unreachable
+ };
+ i = switch (z) {
+ case 0:
+ default:
+ System.out.println("0");
+ break 42;
+ System.out.println("1"); //Unreachable
+ };
+ }
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,9 @@
+ExpressionSwitchUnreachable.java:15:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:22:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:30:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:37:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:45:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:52:17: compiler.err.unreachable.stmt
+- compiler.note.preview.filename: ExpressionSwitchUnreachable.java
+- compiler.note.preview.recompile
+6 errors
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParseIncomplete.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure than parser can parse incomplete sources
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.util.JavacTask;
+
+public class ParseIncomplete {
+
+ private static final String CODE =
+ "public class C {" +
+ " void t1(Integer i) {" +
+ " switch (i) {" +
+ " case null: i++; break;" +
+ " case 0, 1: i++; break;" +
+ " default: i++; break;" +
+ " }" +
+ " }" +
+ " int t2(Integer i) {" +
+ " return switch (i) {" +
+ " case null: break 0;" +
+ " case 0, 1: break 1;" +
+ " default: break 2;" +
+ " }" +
+ " }" +
+ "}";
+
+ public static void main(String[] args) throws Exception {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+ for (int i = 0; i < CODE.length(); i++) {
+ String code = CODE.substring(0, i + 1);
+ StringWriter out = new StringWriter();
+ try {
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+ Arrays.asList(new MyFileObject(code)));
+ ct.parse().iterator().next();
+ } catch (Throwable t) {
+ System.err.println("Unexpected exception for code: " + code);
+ System.err.println("output: " + out);
+ throw t;
+ }
+ if (!out.toString().isEmpty()) {
+ System.err.println("Unexpected compiler for code: " + code);
+ System.err.println(out);
+ throw new AssertionError();
+ }
+ }
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParserRecovery.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify the parser handles broken input gracefully.
+ * @compile/fail/ref=ParserRecovery.out -XDrawDiagnostics --enable-preview -source 12 ParserRecovery.java
+ */
+
+public class ParserRecovery {
+ void t1(int e) {
+ int i = switch (e) { case any; };
+ }
+ void t2(int e) {
+ switch (e) { case any; }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParserRecovery.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+ParserRecovery.java:10:39: compiler.err.expected2: :, ->
+ParserRecovery.java:13:31: compiler.err.expected2: :, ->
+- compiler.note.preview.filename: ParserRecovery.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that scopes in rule cases are isolated.
+ * @compile/fail/ref=SwitchExpressionScopesIsolated.out -XDrawDiagnostics --enable-preview -source 12 SwitchExpressionScopesIsolated.java
+ */
+
+public class SwitchExpressionScopesIsolated {
+
+ private String scopesIsolated(int i) {
+ return switch (i) {
+ case 0 -> { String res = ""; break res; }
+ case 1 -> { res = ""; break res; }
+ default -> { res = ""; break res; }
+ };
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,7 @@
+SwitchExpressionScopesIsolated.java:13:25: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:13:41: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:14:26: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:14:42: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+- compiler.note.preview.filename: SwitchExpressionScopesIsolated.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionSimpleVisitorTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure SimpleTreeVisitor.visitSwitchExpression behaves as it should
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.SwitchExpressionTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SimpleTreeVisitor;
+import com.sun.source.util.TreePathScanner;
+
+public class SwitchExpressionSimpleVisitorTest {
+
+ public static void main(String[] args) throws Exception {
+ new SwitchExpressionSimpleVisitorTest().run();
+ }
+
+ void run() throws Exception {
+ String code = "class Test {\n" +
+ " int t(int i) {\n" +
+ " return switch(i) {\n" +
+ " default: break -1;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n";
+ int[] callCount = new int[1];
+ int[] switchExprNodeCount = new int[1];
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitSwitchExpression(SwitchExpressionTree node, Void p) {
+ node.accept(new SimpleTreeVisitor<Void, Void>() {
+ @Override
+ protected Void defaultAction(Tree defaultActionNode, Void p) {
+ callCount[0]++;
+ if (node == defaultActionNode) {
+ switchExprNodeCount[0]++;
+ }
+ return null;
+ }
+ }, null);
+ return super.visitSwitchExpression(node, p);
+ }
+ }.scan(parse(code), null);
+
+ if (callCount[0] != 1 || switchExprNodeCount[0] != 1) {
+ throw new AssertionError("Unexpected counts; callCount=" + callCount[0] +
+ ", switchExprNodeCount=" + switchExprNodeCount[0]);
+ }
+ }
+
+ private CompilationUnitTree parse(String code) throws IOException {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+ StringWriter out = new StringWriter();
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("--enable-preview", "-source", "12"), null,
+ Arrays.asList(new MyFileObject(code)));
+ return ct.parse().iterator().next();
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/CaseTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure CaseTree methods return expected values
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+
+public class CaseTest {
+
+ public static void main(String[] args) throws Exception {
+ new CaseTest().testLabels();
+ new CaseTest().testStatement();
+ new CaseTest().testRule();
+ }
+
+ void testLabels() throws Exception {
+ String code = "class Test {\n" +
+ " void t(int i) {\n" +
+ " switch(i) {\n" +
+ " case 0: break;\n" +
+ " case 1, 2: breal;\n" +
+ " default: breal;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n";
+ List<String> labels = new ArrayList<>();
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitCase(CaseTree node, Void p) {
+ labels.add(String.valueOf(node.getExpression()));
+ labels.add(node.getExpressions().stream()
+ .map(String::valueOf)
+ .collect(Collectors.joining(",", "[", "]")));
+ return super.visitCase(node, p);
+ }
+ }.scan(parse(code), null);
+
+ List<String> expected = Arrays.asList("0", "[0]", "1", "[1,2]", "null", "[]");
+
+ if (!expected.equals(labels)) {
+ throw new AssertionError("Unexpected labels found: " + labels);
+ }
+ }
+
+ void testStatement() throws Exception {
+ String code = "class Test {\n" +
+ " void t(int i) {\n" +
+ " switch(i) {\n" +
+ " case 0:" +
+ " System.err.println();\n" +
+ " break;\n" +
+ " }\n" +
+ " }\n" +
+ "}\n";
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitCase(CaseTree node, Void p) {
+ if (node.getStatements().size() != 2) {
+ throw new AssertionError("Unexpected statements: " + node.getStatements());
+ }
+ if (node.getBody() != null) {
+ throw new AssertionError("Unexpected body: " + node.getBody());
+ }
+ return super.visitCase(node, p);
+ }
+ }.scan(parse(code), null);
+ }
+
+ void testRule() throws Exception {
+ String code = "class Test {\n" +
+ " void t(int i) {\n" +
+ " switch(i) {\n" +
+ " case 0 -> {" +
+ " System.err.println();\n" +
+ " };\n" +
+ " }\n" +
+ " }\n" +
+ "}\n";
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitCase(CaseTree node, Void p) {
+ if (node.getStatements() != null) {
+ throw new AssertionError("Unexpected statements: " + node.getStatements());
+ }
+ if (node.getBody().getKind() != Tree.Kind.BLOCK) {
+ throw new AssertionError("Unexpected body: " + node.getBody());
+ }
+ return super.visitCase(node, p);
+ }
+ }.scan(parse(code), null);
+ }
+
+ private CompilationUnitTree parse(String code) throws IOException {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+ StringWriter out = new StringWriter();
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+ Arrays.asList(new MyFileObject(code)));
+ return ct.parse().iterator().next();
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsExpression-old.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+MultipleLabelsExpression.java:31:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions)
+MultipleLabelsExpression.java:32:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+MultipleLabelsExpression.java:33:19: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify cases with multiple labels work properly.
+ * @compile/fail/ref=MultipleLabelsExpression-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsExpression.java
+ * @compile --enable-preview -source 12 MultipleLabelsExpression.java
+ * @run main/othervm --enable-preview MultipleLabelsExpression
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class MultipleLabelsExpression {
+ public static void main(String... args) {
+ new MultipleLabelsExpression().run();
+ }
+
+ private void run() {
+ runTest(this::expression1);
+ }
+
+ private void runTest(Function<T, String> print) {
+ check(T.A, print, "A");
+ check(T.B, print, "B-C");
+ check(T.C, print, "B-C");
+ check(T.D, print, "D");
+ check(T.E, print, "other");
+ }
+
+ private String expression1(T t) {
+ return switch (t) {
+ case A -> "A";
+ case B, C -> { break "B-C"; }
+ case D -> "D";
+ default -> "other";
+ };
+ }
+
+ private void check(T t, Function<T, String> print, String expected) {
+ String result = print.apply(t);
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B, C, D, E;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsStatement-old.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+MultipleLabelsStatement.java:35:21: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsStatement.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify cases with multiple labels work properly.
+ * @compile/fail/ref=MultipleLabelsStatement-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsStatement.java
+ * @compile --enable-preview -source 12 MultipleLabelsStatement.java
+ * @run main/othervm --enable-preview MultipleLabelsStatement
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class MultipleLabelsStatement {
+ public static void main(String... args) {
+ new MultipleLabelsStatement().run();
+ }
+
+ private void run() {
+ runTest(this::statement1);
+ }
+
+ private void runTest(Function<T, String> print) {
+ check(T.A, print, "A");
+ check(T.B, print, "B-C");
+ check(T.C, print, "B-C");
+ check(T.D, print, "D");
+ check(T.E, print, "other");
+ }
+
+ private String statement1(T t) {
+ String res;
+
+ switch (t) {
+ case A: res = "A"; break;
+ case B, C: res = "B-C"; break;
+ case D: res = "D"; break;
+ default: res = "other"; break;
+ }
+
+ return res;
+ }
+
+ private void check(T t, Function<T, String> print, String expected) {
+ String result = print.apply(t);
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B, C, D, E;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/RuleParsingTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure rule cases can be parsed correctly for complex expressions.
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
+
+public class RuleParsingTest {
+
+ public static void main(String[] args) throws Exception {
+ new RuleParsingTest().testParseComplexExpressions();
+ }
+
+ void testParseComplexExpressions() throws Exception {
+ String[] expressions = {
+ "(a)",
+ "a",
+ "a + a",
+ "~a + a",
+ "a = a",
+ "a += a",
+ "a + (a)",
+ "a + (a) b",
+ "true ? a : b",
+ "m(() -> {})",
+ "m(() -> 1)",
+ "m(a -> 1)",
+ "m((t a) -> 1)",
+ };
+ StringBuilder code = new StringBuilder();
+ List<Entry<Long, Long>> spans = new ArrayList<>();
+ code.append("class Test {\n" +
+ " void t(int i) {\n");
+ for (boolean switchExpr : new boolean[] {false, true}) {
+ if (switchExpr) {
+ code.append(" int j = switch(i) {\n");
+ } else {
+ code.append(" switch(i) {\n");
+ }
+ for (String expr : expressions) {
+ code.append("case ");
+ int start = code.length();
+ code.append(expr);
+ spans.add(new SimpleEntry<>((long) start, (long) code.length()));
+ code.append(" -> {}");
+ }
+ code.append(" };\n");
+ }
+ code.append(" }\n" +
+ "}\n");
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ assert tool != null;
+ DiagnosticListener<JavaFileObject> noErrors = d -> { throw new AssertionError(d.getMessage(null)); };
+
+ StringWriter out = new StringWriter();
+ JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+ List.of("--enable-preview", "-source", "12"), null,
+ Arrays.asList(new MyFileObject(code.toString())));
+ CompilationUnitTree cut = ct.parse().iterator().next();
+ Trees trees = Trees.instance(ct);
+ new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitCase(CaseTree node, Void p) {
+ long start = trees.getSourcePositions().getStartPosition(cut, node.getExpression());
+ long end = trees.getSourcePositions().getEndPosition(cut, node.getExpression());
+ if (!spans.remove(new SimpleEntry<>(start, end))) {
+ throw new AssertionError("Did not find an expression span in expected spans: " +
+ start + "-" + end +
+ " '" + node.getExpression().toString() + "'");
+ }
+ return super.visitCase(node, p);
+ }
+ }.scan(cut, null);
+
+ if (!spans.isEmpty()) {
+ throw new AssertionError("Remaning spans: " + spans);
+ }
+ }
+
+ static class MyFileObject extends SimpleJavaFileObject {
+ private String text;
+
+ public MyFileObject(String text) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ this.text = text;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return text;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * @test /nodymaticcopyright/
+ * @bug 8206986
+ * @summary Verify reasonable errors are produced when neither ':' nor '->'
+ * is found are the expression of a case
+ * @compile/fail/ref=SwitchArrowBrokenConstant.out -source 12 --enable-preview -Xlint:-preview -XDrawDiagnostics SwitchArrowBrokenConstant.java
+ */
+
+public class SwitchArrowBrokenConstant {
+
+ private String likeLambda(int i) {
+ switch (i) {
+ case (a, b) -> {}
+ }
+ return switch (i) {
+ case (a, b) -> {}
+ };
+ switch (i) {
+ case a;
+ }
+ return switch (i) {
+ case a;
+ };
+ switch (i) {
+ default ;
+ }
+ return switch (i) {
+ default ;
+ };
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,11 @@
+SwitchArrowBrokenConstant.java:13:20: compiler.err.expected: ')'
+SwitchArrowBrokenConstant.java:13:23: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:16:20: compiler.err.expected: ')'
+SwitchArrowBrokenConstant.java:16:23: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:19:19: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:22:19: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:25:20: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:28:20: compiler.err.expected2: :, ->
+- compiler.note.preview.filename: SwitchArrowBrokenConstant.java
+- compiler.note.preview.recompile
+8 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify switch over boolean/long/float/double is not allowed.
+ * @compile/fail/ref=SwitchNoExtraTypes.out -XDrawDiagnostics SwitchNoExtraTypes.java
+ */
+
+public class SwitchNoExtraTypes {
+
+ private void switchBoolean(boolean b) {
+ switch (b) {
+ case true: return ;
+ }
+ }
+
+ private void switchLong(long l) {
+ switch (l) {
+ case 0: return ;
+ }
+ }
+
+ private void switchFloat(float f) {
+ switch (f) {
+ case 0: return ;
+ }
+ }
+
+ private void switchDouble(double d) {
+ switch (d) {
+ case 0: return ;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+SwitchNoExtraTypes.java:11:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: boolean, int)
+SwitchNoExtraTypes.java:17:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: long, int)
+SwitchNoExtraTypes.java:23:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: float, int)
+SwitchNoExtraTypes.java:29:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: double, int)
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify switch over Object is not allowed.
+ * @compile/fail/ref=SwitchObject.out -XDrawDiagnostics SwitchObject.java
+ */
+public class SwitchObject {
+
+ private int longSwitch(Object o) {
+ switch (o) {
+ case -1: return 0;
+ case "": return 1;
+ default: return 3;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+SwitchObject.java:10:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int)
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementArrow-old.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,3 @@
+SwitchStatementArrow.java:41:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+SwitchStatementArrow.java:42:21: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementArrow.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * @test /nodymaticcopyright/
+ * @bug 8206986
+ * @summary Verify rule cases work properly.
+ * @compile/fail/ref=SwitchStatementArrow-old.out -source 9 -Xlint:-options -XDrawDiagnostics SwitchStatementArrow.java
+ * @compile --enable-preview -source 12 SwitchStatementArrow.java
+ * @run main/othervm --enable-preview SwitchStatementArrow
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class SwitchStatementArrow {
+ public static void main(String... args) {
+ new SwitchStatementArrow().run();
+ }
+
+ private void run() {
+ runTest(this::statement1);
+ runTest(this::scope);
+ }
+
+ private void runTest(Function<T, String> print) {
+ check(T.A, print, "A");
+ check(T.B, print, "B-C");
+ check(T.C, print, "B-C");
+ try {
+ print.apply(T.D);
+ throw new AssertionError();
+ } catch (IllegalStateException ex) {
+ if (!Objects.equals("D", ex.getMessage()))
+ throw new AssertionError(ex);
+ }
+ check(T.E, print, "other");
+ }
+
+ private String statement1(T t) {
+ String res;
+
+ switch (t) {
+ case A -> { res = "A"; }
+ case B, C -> res = "B-C";
+ case D -> throw new IllegalStateException("D");
+ default -> { res = "other"; break; }
+ }
+
+ return res;
+ }
+
+ private String scope(T t) {
+ String res;
+
+ switch (t) {
+ case A -> { String r = "A"; res = r; }
+ case B, C -> {String r = "B-C"; res = r; }
+ case D -> throw new IllegalStateException("D");
+ default -> { String r = "other"; res = r; break; }
+ }
+
+ return res;
+ }
+
+ private int r;
+
+ private void check(T t, Function<T, String> print, String expected) {
+ String result = print.apply(t);
+ if (!Objects.equals(result, expected)) {
+ throw new AssertionError("Unexpected result: " + result);
+ }
+ }
+
+ enum T {
+ A, B, C, D, E;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that rule and ordinary cases cannot be mixed.
+ * @compile/fail/ref=SwitchStatementBroken.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementBroken.java
+ */
+
+public class SwitchStatementBroken {
+
+ private void statementBroken(int i) {
+ String res;
+
+ switch (i) {
+ case 0 -> { res = "NULL-A"; }
+ case 1: { res = "NULL-A"; break; }
+ case 2: { res = "NULL-A"; break; }
+ default -> { res = "NULL-A"; break; }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+SwitchStatementBroken.java:15:13: compiler.err.switch.mixing.case.types
+- compiler.note.preview.filename: SwitchStatementBroken.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken2.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that not allowed types of statements cannot be used in rule case.
+ * @compile/fail/ref=SwitchStatementBroken2.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementBroken2.java
+ */
+
+public class SwitchStatementBroken2 {
+
+ private void statementArrowNotArbitraryStatements(int i, int j) {
+ String res;
+
+ switch (i) {
+ case 0 -> res = "NULL-A";
+ case 1 -> { res = "NULL-A"; }
+ case 2 -> throw new IllegalStateException();
+ case 3 -> if (j < 0) res = "A"; else res = "B";
+ case 4 -> while (j-- > 0) res += "I";
+ case 5 -> switch (j) {
+ case 0: res = "0"; break;
+ }
+ case 7 -> int i;
+ default -> if (j < 0) res = "A"; else res = "B";
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken2.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,8 @@
+SwitchStatementBroken2.java:17:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:18:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:19:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:22:27: compiler.err.variable.not.allowed
+SwitchStatementBroken2.java:23:24: compiler.err.switch.case.unexpected.statement
+- compiler.note.preview.filename: SwitchStatementBroken2.java
+- compiler.note.preview.recompile
+5 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that scopes in rule cases are isolated.
+ * @compile/fail/ref=SwitchStatementScopesIsolated.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementScopesIsolated.java
+ */
+
+public class SwitchStatementScopesIsolated {
+
+ private void scopesIsolated(int i) {
+ switch (i) {
+ case 0 -> { String res = "NULL-A"; }
+ case 1 -> { res = "NULL-A"; }
+ default -> { res = "NULL-A"; }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+SwitchStatementScopesIsolated.java:13:25: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchStatementScopesIsolated, null)
+SwitchStatementScopesIsolated.java:14:26: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchStatementScopesIsolated, null)
+- compiler.note.preview.filename: SwitchStatementScopesIsolated.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchnull/SwitchNullDisabled.java Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify "case null" is not allowed.
+ * @compile/fail/ref=SwitchNullDisabled.out -XDrawDiagnostics SwitchNullDisabled.java
+ */
+
+public class SwitchNullDisabled {
+ private int switchNull(String str) {
+ switch (str) {
+ case null: return 0;
+ case "": return 1;
+ default: return 2;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchnull/SwitchNullDisabled.out Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+SwitchNullDisabled.java:11:18: compiler.err.switch.null.not.allowed
+1 error
--- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, 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
@@ -47,11 +47,14 @@
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
+
import javax.tools.*;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
@@ -150,6 +153,11 @@
// The modifiers will not found by TreeScanner,
// but the embedded annotations will be.
reflectiveScan(((JCModuleDecl) tree).mods.annotations);
+ } else if (tree instanceof JCCase &&
+ ((JCCase) tree).getCaseKind() == CaseKind.RULE &&
+ f.getName().equals("stats")) {
+ //value case, visit value:
+ reflectiveScan(((JCCase) tree).getBody());
} else {
reflectiveScan(f.get(tree));
}
--- a/test/langtools/tools/javac/tree/TreePosTest.java Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/tree/TreePosTest.java Wed Aug 29 09:36:17 2018 +0200
@@ -69,6 +69,7 @@
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
+import com.sun.source.tree.CaseTree.CaseKind;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.JavacTool;
@@ -76,6 +77,7 @@
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
+import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
@@ -440,6 +442,15 @@
super.visitVarDef(tree);
}
+ @Override
+ public void visitCase(JCCase tree) {
+ if (tree.getCaseKind() == CaseKind.RULE) {
+ scan(tree.getBody());
+ } else {
+ super.visitCase(tree);
+ }
+ }
+
boolean check(Info encl, Info self) {
if (excludeTags.size() > 0) {
if (encl != null && excludeTags.contains(getTagName(encl.tag))