8206986: Compiler support for Switch Expressions (Preview)
8207405: Compiler Tree API support for Switch Expressions (Preview) Support for switch expression, switch with rules and multiple constants for cases. Reviewed-by: jjg, mcimadamore, vromero
This commit is contained in:
parent
3f4b55c4df
commit
b3b644438e
@ -95,6 +95,7 @@ public interface MessageType {
|
|||||||
KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
|
KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
|
||||||
TARGET("target", "Target", "com.sun.tools.javac.jvm"),
|
TARGET("target", "Target", "com.sun.tools.javac.jvm"),
|
||||||
TOKEN("token", "TokenKind", "com.sun.tools.javac.parser.Tokens"),
|
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"),
|
TYPE("type", "Type", "com.sun.tools.javac.code"),
|
||||||
URL("url", "URL", "java.net"),
|
URL("url", "URL", "java.net"),
|
||||||
SET("set", "Set", "java.util"),
|
SET("set", "Set", "java.util"),
|
||||||
|
@ -35,6 +35,8 @@ import javax.lang.model.element.Name;
|
|||||||
* break;
|
* break;
|
||||||
*
|
*
|
||||||
* break <em>label</em> ;
|
* break <em>label</em> ;
|
||||||
|
*
|
||||||
|
* break <em>expression</em> ;
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @jls section 14.15
|
* @jls section 14.15
|
||||||
@ -49,4 +51,18 @@ public interface BreakTree extends StatementTree {
|
|||||||
* @return the label
|
* @return the label
|
||||||
*/
|
*/
|
||||||
Name getLabel();
|
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();
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ package com.sun.source.tree;
|
|||||||
import java.util.List;
|
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:
|
* For example:
|
||||||
* <pre>
|
* <pre>
|
||||||
@ -49,13 +49,89 @@ public interface CaseTree extends Tree {
|
|||||||
/**
|
/**
|
||||||
* Returns the expression for the case, or
|
* Returns the expression for the case, or
|
||||||
* {@code null} if this is the default case.
|
* {@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
|
* @return the expression for the case, or null
|
||||||
*/
|
*/
|
||||||
ExpressionTree getExpression();
|
ExpressionTree getExpression();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the statements labeled by the case.
|
* Returns the labels for this case.
|
||||||
* @return the statements labeled by the 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();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
@ -239,6 +239,20 @@ public interface Tree {
|
|||||||
*/
|
*/
|
||||||
SWITCH(SwitchTree.class),
|
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}.
|
* Used for instances of {@link SynchronizedTree}.
|
||||||
*/
|
*/
|
||||||
|
@ -353,6 +353,23 @@ public interface TreeVisitor<R,P> {
|
|||||||
*/
|
*/
|
||||||
R visitSwitch(SwitchTree node, P p);
|
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.
|
* Visits a SynchronizedTree node.
|
||||||
* @param node the node being visited
|
* @param node the node being visited
|
||||||
|
@ -263,6 +263,25 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
|
|||||||
return defaultAction(node, p);
|
return defaultAction(node, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc} This implementation calls {@code defaultAction}.
|
||||||
|
*
|
||||||
|
* @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}.
|
* {@inheritDoc} This implementation calls {@code defaultAction}.
|
||||||
*
|
*
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
package com.sun.source.util;
|
package com.sun.source.util;
|
||||||
|
|
||||||
import com.sun.source.tree.*;
|
import com.sun.source.tree.*;
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A TreeVisitor that visits all the child tree nodes.
|
* A TreeVisitor that visits all the child tree nodes.
|
||||||
@ -339,10 +340,35 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
|||||||
* @param node {@inheritDoc}
|
* @param node {@inheritDoc}
|
||||||
* @param p {@inheritDoc}
|
* @param p {@inheritDoc}
|
||||||
* @return the result of scanning
|
* @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
|
@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 r = scan(node.getExpression(), p);
|
||||||
|
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);
|
r = scanAndReduce(node.getStatements(), p, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -441,8 +467,9 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
|||||||
* @return the result of scanning
|
* @return the result of scanning
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("removal")
|
||||||
public R visitBreak(BreakTree node, P p) {
|
public R visitBreak(BreakTree node, P p) {
|
||||||
return null;
|
return scan(node.getValue(), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,6 +165,10 @@ public class Preview {
|
|||||||
* @return true, if given feature is a preview feature.
|
* @return true, if given feature is a preview feature.
|
||||||
*/
|
*/
|
||||||
public boolean isPreview(Feature 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).
|
//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'
|
//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.
|
//for those selected features, and 'false' for all the others.
|
||||||
|
@ -180,7 +180,10 @@ public enum Source {
|
|||||||
UNDERSCORE_IDENTIFIER(MIN, JDK8),
|
UNDERSCORE_IDENTIFIER(MIN, JDK8),
|
||||||
PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
|
PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
|
||||||
LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
|
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 {
|
enum DiagKind {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
|
@ -184,6 +184,7 @@ public class Symtab {
|
|||||||
public final Type noClassDefFoundErrorType;
|
public final Type noClassDefFoundErrorType;
|
||||||
public final Type noSuchFieldErrorType;
|
public final Type noSuchFieldErrorType;
|
||||||
public final Type assertionErrorType;
|
public final Type assertionErrorType;
|
||||||
|
public final Type incompatibleClassChangeErrorType;
|
||||||
public final Type cloneNotSupportedExceptionType;
|
public final Type cloneNotSupportedExceptionType;
|
||||||
public final Type annotationType;
|
public final Type annotationType;
|
||||||
public final TypeSymbol enumSym;
|
public final TypeSymbol enumSym;
|
||||||
@ -526,6 +527,7 @@ public class Symtab {
|
|||||||
noClassDefFoundErrorType = enterClass("java.lang.NoClassDefFoundError");
|
noClassDefFoundErrorType = enterClass("java.lang.NoClassDefFoundError");
|
||||||
noSuchFieldErrorType = enterClass("java.lang.NoSuchFieldError");
|
noSuchFieldErrorType = enterClass("java.lang.NoSuchFieldError");
|
||||||
assertionErrorType = enterClass("java.lang.AssertionError");
|
assertionErrorType = enterClass("java.lang.AssertionError");
|
||||||
|
incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError");
|
||||||
cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
|
cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
|
||||||
annotationType = enterClass("java.lang.annotation.Annotation");
|
annotationType = enterClass("java.lang.annotation.Annotation");
|
||||||
classLoaderType = enterClass("java.lang.ClassLoader");
|
classLoaderType = enterClass("java.lang.ClassLoader");
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package com.sun.tools.javac.comp;
|
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.Flags;
|
||||||
import com.sun.tools.javac.code.Symbol;
|
import com.sun.tools.javac.code.Symbol;
|
||||||
import com.sun.tools.javac.code.Symtab;
|
import com.sun.tools.javac.code.Symtab;
|
||||||
@ -39,10 +38,12 @@ import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
|
|||||||
import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
|
import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
|
||||||
import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
|
import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
|
||||||
import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
|
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.Infer.PartiallyInferredMethodType;
|
||||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
||||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
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.JCConditional;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
||||||
@ -52,6 +53,7 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
|||||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCParens;
|
import com.sun.tools.javac.tree.JCTree.JCParens;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCReturn;
|
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.TreeCopier;
|
||||||
import com.sun.tools.javac.tree.TreeInfo;
|
import com.sun.tools.javac.tree.TreeInfo;
|
||||||
import com.sun.tools.javac.util.Assert;
|
import com.sun.tools.javac.util.Assert;
|
||||||
@ -145,7 +147,7 @@ public class ArgumentAttr extends JCTree.Visitor {
|
|||||||
* Checks a type in the speculative tree against a given result; the type can be either a plain
|
* 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 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);
|
return checkSpeculative(expr, expr.type, resultInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +257,11 @@ public class ArgumentAttr extends JCTree.Visitor {
|
|||||||
processArg(that, speculativeTree -> new ConditionalType(that, env, speculativeTree));
|
processArg(that, speculativeTree -> new ConditionalType(that, env, speculativeTree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitSwitchExpression(JCSwitchExpression that) {
|
||||||
|
processArg(that, speculativeTree -> new SwitchExpressionType(that, env, speculativeTree));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitReference(JCMemberReference tree) {
|
public void visitReference(JCMemberReference tree) {
|
||||||
//perform arity-based check
|
//perform arity-based check
|
||||||
@ -455,6 +462,61 @@ public class ArgumentAttr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Argument type for explicit lambdas.
|
||||||
*/
|
*/
|
||||||
|
@ -26,10 +26,13 @@
|
|||||||
package com.sun.tools.javac.comp;
|
package com.sun.tools.javac.comp;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
import com.sun.source.tree.IdentifierTree;
|
import com.sun.source.tree.IdentifierTree;
|
||||||
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
||||||
import com.sun.source.tree.MemberSelectTree;
|
import com.sun.source.tree.MemberSelectTree;
|
||||||
@ -1395,43 +1398,125 @@ public class Attr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitSwitch(JCSwitch tree) {
|
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<AttrContext> switchEnv =
|
||||||
env.dup(tree, env.info.dup(env.info.scope.dup()));
|
env.dup(switchTree, env.info.dup(env.info.scope.dup()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
|
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
|
||||||
boolean stringSwitch = types.isSameType(seltype, syms.stringType);
|
boolean stringSwitch = types.isSameType(seltype, syms.stringType);
|
||||||
if (!enumSwitch && !stringSwitch)
|
if (!enumSwitch && !stringSwitch)
|
||||||
seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
|
seltype = chk.checkType(selector.pos(), seltype, syms.intType);
|
||||||
|
|
||||||
// Attribute all cases and
|
// Attribute all cases and
|
||||||
// check that there are no duplicate case labels or default clauses.
|
// check that there are no duplicate case labels or default clauses.
|
||||||
Set<Object> labels = new HashSet<>(); // The set of case labels.
|
Set<Object> labels = new HashSet<>(); // The set of case labels.
|
||||||
boolean hasDefault = false; // Is there a default label?
|
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;
|
JCCase c = l.head;
|
||||||
if (c.pat != null) {
|
if (caseKind == null) {
|
||||||
if (enumSwitch) {
|
caseKind = c.caseKind;
|
||||||
Symbol sym = enumConstant(c.pat, seltype);
|
} 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) {
|
if (sym == null) {
|
||||||
log.error(c.pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
|
log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
|
||||||
} else if (!labels.add(sym)) {
|
} else if (!labels.add(sym)) {
|
||||||
log.error(c.pos(), Errors.DuplicateCaseLabel);
|
log.error(c.pos(), Errors.DuplicateCaseLabel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Type pattype = attribExpr(c.pat, switchEnv, seltype);
|
Type pattype = attribExpr(pat, switchEnv, seltype);
|
||||||
if (!pattype.hasTag(ERROR)) {
|
if (!pattype.hasTag(ERROR)) {
|
||||||
if (pattype.constValue() == null) {
|
if (pattype.constValue() == null) {
|
||||||
log.error(c.pat.pos(),
|
log.error(pat.pos(),
|
||||||
(stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
|
(stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
|
||||||
} else if (!labels.add(pattype.constValue())) {
|
} else if (!labels.add(pattype.constValue())) {
|
||||||
log.error(c.pos(), Errors.DuplicateCaseLabel);
|
log.error(c.pos(), Errors.DuplicateCaseLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (hasDefault) {
|
} else if (hasDefault) {
|
||||||
log.error(c.pos(), Errors.DuplicateDefaultLabel);
|
log.error(c.pos(), Errors.DuplicateDefaultLabel);
|
||||||
} else {
|
} else {
|
||||||
@ -1440,16 +1525,13 @@ public class Attr extends JCTree.Visitor {
|
|||||||
Env<AttrContext> caseEnv =
|
Env<AttrContext> caseEnv =
|
||||||
switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
|
switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
|
||||||
try {
|
try {
|
||||||
attribStats(c.stats, caseEnv);
|
attribCase.accept(c, caseEnv);
|
||||||
} finally {
|
} finally {
|
||||||
caseEnv.info.scope.leave();
|
caseEnv.info.scope.leave();
|
||||||
addVars(c.stats, switchEnv.info.scope);
|
addVars(c.stats, switchEnv.info.scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
switchEnv.info.scope.leave();
|
switchEnv.info.scope.leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1609,7 +1691,9 @@ public class Attr extends JCTree.Visitor {
|
|||||||
Type truetype = attribTree(tree.truepart, env, condInfo);
|
Type truetype = attribTree(tree.truepart, env, condInfo);
|
||||||
Type falsetype = attribTree(tree.falsepart, 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 &&
|
if (condtype.constValue() != null &&
|
||||||
truetype.constValue() != null &&
|
truetype.constValue() != null &&
|
||||||
falsetype.constValue() != null &&
|
falsetype.constValue() != null &&
|
||||||
@ -1690,67 +1774,66 @@ public class Attr extends JCTree.Visitor {
|
|||||||
* @param thentype The type of the expression's then-part.
|
* @param thentype The type of the expression's then-part.
|
||||||
* @param elsetype The type of the expression's else-part.
|
* @param elsetype The type of the expression's else-part.
|
||||||
*/
|
*/
|
||||||
Type condType(DiagnosticPosition pos,
|
Type condType(List<DiagnosticPosition> positions, List<Type> condTypes) {
|
||||||
Type thentype, Type elsetype) {
|
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 same type, that is the result
|
||||||
if (types.isSameType(thentype, elsetype))
|
if (condTypes.tail.stream().allMatch(t -> types.isSameType(first, t)))
|
||||||
return thentype.baseType();
|
return first.baseType();
|
||||||
|
|
||||||
Type thenUnboxed = (thentype.isPrimitive())
|
List<Type> unboxedTypes = condTypes.stream()
|
||||||
? thentype : types.unboxedType(thentype);
|
.map(t -> t.isPrimitive() ? t : types.unboxedType(t))
|
||||||
Type elseUnboxed = (elsetype.isPrimitive())
|
.collect(List.collector());
|
||||||
? elsetype : types.unboxedType(elsetype);
|
|
||||||
|
|
||||||
// Otherwise, if both arms can be converted to a numeric
|
// Otherwise, if both arms can be converted to a numeric
|
||||||
// type, return the least numeric type that fits both arms
|
// type, return the least numeric type that fits both arms
|
||||||
// (i.e. return larger of the two, or return int if one
|
// (i.e. return larger of the two, or return int if one
|
||||||
// arm is short, the other is char).
|
// 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,
|
// If one arm has an integer subrange type (i.e., byte,
|
||||||
// short, or char), and the other is an integer constant
|
// short, or char), and the other is an integer constant
|
||||||
// that fits into the subrange, return the subrange type.
|
// that fits into the subrange, return the subrange type.
|
||||||
if (thenUnboxed.getTag().isStrictSubRangeOf(INT) &&
|
for (Type type : unboxedTypes) {
|
||||||
elseUnboxed.hasTag(INT) &&
|
if (!type.getTag().isStrictSubRangeOf(INT)) {
|
||||||
types.isAssignable(elseUnboxed, thenUnboxed)) {
|
continue;
|
||||||
return thenUnboxed.baseType();
|
|
||||||
}
|
}
|
||||||
if (elseUnboxed.getTag().isStrictSubRangeOf(INT) &&
|
if (unboxedTypes.stream().filter(t -> t != type).allMatch(t -> t.hasTag(INT) && types.isAssignable(t, type)))
|
||||||
thenUnboxed.hasTag(INT) &&
|
return type.baseType();
|
||||||
types.isAssignable(thenUnboxed, elseUnboxed)) {
|
|
||||||
return elseUnboxed.baseType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TypeTag tag : primitiveTags) {
|
for (TypeTag tag : primitiveTags) {
|
||||||
Type candidate = syms.typeOfTag[tag.ordinal()];
|
Type candidate = syms.typeOfTag[tag.ordinal()];
|
||||||
if (types.isSubtype(thenUnboxed, candidate) &&
|
if (unboxedTypes.stream().allMatch(t -> types.isSubtype(t, candidate))) {
|
||||||
types.isSubtype(elseUnboxed, candidate)) {
|
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Those were all the cases that could result in a primitive
|
// Those were all the cases that could result in a primitive
|
||||||
if (thentype.isPrimitive())
|
condTypes = condTypes.stream()
|
||||||
thentype = types.boxedClass(thentype).type;
|
.map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
|
||||||
if (elsetype.isPrimitive())
|
.collect(List.collector());
|
||||||
elsetype = types.boxedClass(elsetype).type;
|
|
||||||
|
|
||||||
if (types.isSubtype(thentype, elsetype))
|
for (Type type : condTypes) {
|
||||||
return elsetype.baseType();
|
if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
|
||||||
if (types.isSubtype(elsetype, thentype))
|
return type.baseType();
|
||||||
return thentype.baseType();
|
|
||||||
|
|
||||||
if (thentype.hasTag(VOID) || elsetype.hasTag(VOID)) {
|
|
||||||
log.error(pos,
|
|
||||||
Errors.NeitherConditionalSubtype(thentype,
|
|
||||||
elsetype));
|
|
||||||
return thentype.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
|
// both are known to be reference types. The result is
|
||||||
// lub(thentype,elsetype). This cannot fail, as it will
|
// lub(thentype,elsetype). This cannot fail, as it will
|
||||||
// always be possible to infer "Object" if nothing better.
|
// 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[]{
|
final static TypeTag[] primitiveTags = new TypeTag[]{
|
||||||
@ -1782,7 +1865,68 @@ public class Attr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
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;
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1808,8 +1952,32 @@ public class Attr extends JCTree.Visitor {
|
|||||||
JCTree.Tag tag,
|
JCTree.Tag tag,
|
||||||
Name label,
|
Name label,
|
||||||
Env<AttrContext> env) {
|
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.
|
// Search environments outwards from the point of jump.
|
||||||
Env<AttrContext> env1 = env;
|
Env<AttrContext> env1 = env;
|
||||||
|
JCDiagnostic.Error pendingError = null;
|
||||||
LOOP:
|
LOOP:
|
||||||
while (env1 != null) {
|
while (env1 != null) {
|
||||||
switch (env1.tree.getTag()) {
|
switch (env1.tree.getTag()) {
|
||||||
@ -1821,13 +1989,14 @@ public class Attr extends JCTree.Visitor {
|
|||||||
if (!labelled.body.hasTag(DOLOOP) &&
|
if (!labelled.body.hasTag(DOLOOP) &&
|
||||||
!labelled.body.hasTag(WHILELOOP) &&
|
!labelled.body.hasTag(WHILELOOP) &&
|
||||||
!labelled.body.hasTag(FORLOOP) &&
|
!labelled.body.hasTag(FORLOOP) &&
|
||||||
!labelled.body.hasTag(FOREACHLOOP))
|
!labelled.body.hasTag(FOREACHLOOP)) {
|
||||||
log.error(pos, Errors.NotLoopLabel(label));
|
pendingError = Errors.NotLoopLabel(label);
|
||||||
|
}
|
||||||
// Found labelled statement target, now go inwards
|
// Found labelled statement target, now go inwards
|
||||||
// to next non-labelled tree.
|
// to next non-labelled tree.
|
||||||
return TreeInfo.referencedStatement(labelled);
|
return Pair.of(TreeInfo.referencedStatement(labelled), pendingError);
|
||||||
} else {
|
} else {
|
||||||
return labelled;
|
return Pair.of(labelled, pendingError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1835,10 +2004,21 @@ public class Attr extends JCTree.Visitor {
|
|||||||
case WHILELOOP:
|
case WHILELOOP:
|
||||||
case FORLOOP:
|
case FORLOOP:
|
||||||
case FOREACHLOOP:
|
case FOREACHLOOP:
|
||||||
if (label == null) return env1.tree;
|
if (label == null) return Pair.of(env1.tree, pendingError);
|
||||||
break;
|
break;
|
||||||
case SWITCH:
|
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;
|
break;
|
||||||
case LAMBDA:
|
case LAMBDA:
|
||||||
case METHODDEF:
|
case METHODDEF:
|
||||||
@ -1849,12 +2029,11 @@ public class Attr extends JCTree.Visitor {
|
|||||||
env1 = env1.next;
|
env1 = env1.next;
|
||||||
}
|
}
|
||||||
if (label != null)
|
if (label != null)
|
||||||
log.error(pos, Errors.UndefLabel(label));
|
return Pair.of(null, Errors.UndefLabel(label));
|
||||||
else if (tag == CONTINUE)
|
else if (tag == CONTINUE)
|
||||||
log.error(pos, Errors.ContOutsideLoop);
|
return Pair.of(null, Errors.ContOutsideLoop);
|
||||||
else
|
else
|
||||||
log.error(pos, Errors.BreakOutsideSwitchLoop);
|
return Pair.of(null, Errors.BreakOutsideSwitchLoop);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitReturn(JCReturn tree) {
|
public void visitReturn(JCReturn tree) {
|
||||||
@ -1862,6 +2041,8 @@ public class Attr extends JCTree.Visitor {
|
|||||||
// nested within than the enclosing class.
|
// nested within than the enclosing class.
|
||||||
if (env.info.returnResult == null) {
|
if (env.info.returnResult == null) {
|
||||||
log.error(tree.pos(), Errors.RetOutsideMeth);
|
log.error(tree.pos(), Errors.RetOutsideMeth);
|
||||||
|
} else if (env.info.breakResult != null) {
|
||||||
|
log.error(tree.pos(), Errors.ReturnOutsideSwitchExpression);
|
||||||
} else {
|
} else {
|
||||||
// Attribute return expression, if it exists, and check that
|
// Attribute return expression, if it exists, and check that
|
||||||
// it conforms to result type of enclosing method.
|
// it conforms to result type of enclosing method.
|
||||||
@ -2944,6 +3125,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
} else {
|
} else {
|
||||||
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
|
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
|
||||||
}
|
}
|
||||||
|
lambdaEnv.info.breakResult = null;
|
||||||
return lambdaEnv;
|
return lambdaEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +101,11 @@ public class AttrContext {
|
|||||||
*/
|
*/
|
||||||
Attr.ResultInfo returnResult = null;
|
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
|
/** Symbol corresponding to the site of a qualified default super call
|
||||||
*/
|
*/
|
||||||
Type defaultSuperCallSite = null;
|
Type defaultSuperCallSite = null;
|
||||||
@ -124,6 +129,7 @@ public class AttrContext {
|
|||||||
info.lint = lint;
|
info.lint = lint;
|
||||||
info.enclVar = enclVar;
|
info.enclVar = enclVar;
|
||||||
info.returnResult = returnResult;
|
info.returnResult = returnResult;
|
||||||
|
info.breakResult = breakResult;
|
||||||
info.defaultSuperCallSite = defaultSuperCallSite;
|
info.defaultSuperCallSite = defaultSuperCallSite;
|
||||||
info.isSerializable = isSerializable;
|
info.isSerializable = isSerializable;
|
||||||
info.isLambda = isLambda;
|
info.isLambda = isLambda;
|
||||||
|
@ -1153,6 +1153,18 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* This visitor is used to check that structural expressions conform
|
||||||
* to their target - this step is required as inference could end up
|
* to their target - this step is required as inference could end up
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
package com.sun.tools.javac.comp;
|
package com.sun.tools.javac.comp;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
|
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
|
||||||
import com.sun.tools.javac.code.*;
|
import com.sun.tools.javac.code.*;
|
||||||
@ -211,7 +213,7 @@ public class Flow {
|
|||||||
|
|
||||||
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
||||||
new AliveAnalyzer().analyzeTree(env, make);
|
new AliveAnalyzer().analyzeTree(env, make);
|
||||||
new AssignAnalyzer().analyzeTree(env);
|
new AssignAnalyzer().analyzeTree(env, make);
|
||||||
new FlowAnalyzer().analyzeTree(env, make);
|
new FlowAnalyzer().analyzeTree(env, make);
|
||||||
new CaptureAnalyzer().analyzeTree(env, make);
|
new CaptureAnalyzer().analyzeTree(env, make);
|
||||||
}
|
}
|
||||||
@ -244,7 +246,7 @@ public class Flow {
|
|||||||
//related errors, which will allow for more errors to be detected
|
//related errors, which will allow for more errors to be detected
|
||||||
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
|
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
|
||||||
try {
|
try {
|
||||||
new LambdaAssignAnalyzer(env).analyzeTree(env, that);
|
new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
|
||||||
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
|
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
|
||||||
flowAnalyzer.analyzeTree(env, that, make);
|
flowAnalyzer.analyzeTree(env, that, make);
|
||||||
return flowAnalyzer.inferredThrownTypes;
|
return flowAnalyzer.inferredThrownTypes;
|
||||||
@ -396,6 +398,12 @@ public class Flow {
|
|||||||
public void visitPackageDef(JCPackageDecl tree) {
|
public void visitPackageDef(JCPackageDecl tree) {
|
||||||
// Do nothing for PackageDecl
|
// 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 @@ public class Flow {
|
|||||||
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
|
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
|
||||||
alive = true;
|
alive = true;
|
||||||
JCCase c = l.head;
|
JCCase c = l.head;
|
||||||
if (c.pat == null)
|
if (c.pats.isEmpty())
|
||||||
hasDefault = true;
|
hasDefault = true;
|
||||||
else
|
else {
|
||||||
scan(c.pat);
|
for (JCExpression pat : c.pats) {
|
||||||
|
scan(pat);
|
||||||
|
}
|
||||||
|
}
|
||||||
scanStats(c.stats);
|
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.
|
// Warn about fall-through if lint switch fallthrough enabled.
|
||||||
if (alive &&
|
if (alive &&
|
||||||
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
|
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
|
||||||
@ -615,6 +631,46 @@ public class Flow {
|
|||||||
alive |= resolveBreaks(tree, prevPendingExits);
|
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) {
|
public void visitTry(JCTry tree) {
|
||||||
ListBuffer<PendingExit> prevPendingExits = pendingExits;
|
ListBuffer<PendingExit> prevPendingExits = pendingExits;
|
||||||
pendingExits = new ListBuffer<>();
|
pendingExits = new ListBuffer<>();
|
||||||
@ -680,6 +736,8 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
scan(tree.value);
|
||||||
recordExit(new PendingExit(tree));
|
recordExit(new PendingExit(tree));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1040,14 +1098,21 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitSwitch(JCSwitch tree) {
|
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;
|
ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
|
||||||
pendingExits = new ListBuffer<>();
|
pendingExits = new ListBuffer<>();
|
||||||
scan(tree.selector);
|
scan(selector);
|
||||||
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
|
for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
|
||||||
JCCase c = l.head;
|
JCCase c = l.head;
|
||||||
if (c.pat != null) {
|
scan(c.pats);
|
||||||
scan(c.pat);
|
|
||||||
}
|
|
||||||
scan(c.stats);
|
scan(c.stats);
|
||||||
}
|
}
|
||||||
resolveBreaks(tree, prevPendingExits);
|
resolveBreaks(tree, prevPendingExits);
|
||||||
@ -1191,6 +1256,8 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
scan(tree.value);
|
||||||
recordExit(new FlowPendingExit(tree, null));
|
recordExit(new FlowPendingExit(tree, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2105,27 +2172,40 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitSwitch(JCSwitch tree) {
|
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;
|
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
|
||||||
pendingExits = new ListBuffer<>();
|
pendingExits = new ListBuffer<>();
|
||||||
int nextadrPrev = nextadr;
|
int nextadrPrev = nextadr;
|
||||||
scanExpr(tree.selector);
|
scanExpr(selector);
|
||||||
final Bits initsSwitch = new Bits(inits);
|
final Bits initsSwitch = new Bits(inits);
|
||||||
final Bits uninitsSwitch = new Bits(uninits);
|
final Bits uninitsSwitch = new Bits(uninits);
|
||||||
boolean hasDefault = false;
|
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);
|
inits.assign(initsSwitch);
|
||||||
uninits.assign(uninits.andSet(uninitsSwitch));
|
uninits.assign(uninits.andSet(uninitsSwitch));
|
||||||
JCCase c = l.head;
|
JCCase c = l.head;
|
||||||
if (c.pat == null) {
|
if (c.pats.isEmpty()) {
|
||||||
hasDefault = true;
|
hasDefault = true;
|
||||||
} else {
|
} else {
|
||||||
scanExpr(c.pat);
|
for (JCExpression pat : c.pats) {
|
||||||
|
scanExpr(pat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hasDefault) {
|
if (hasDefault) {
|
||||||
inits.assign(initsSwitch);
|
inits.assign(initsSwitch);
|
||||||
uninits.assign(uninits.andSet(uninitsSwitch));
|
uninits.assign(uninits.andSet(uninitsSwitch));
|
||||||
}
|
}
|
||||||
scan(c.stats);
|
scan(c.stats);
|
||||||
|
if (c.completesNormally && c.caseKind == JCCase.RULE) {
|
||||||
|
scanSyntheticBreak(make, tree);
|
||||||
|
}
|
||||||
addVars(c.stats, initsSwitch, uninitsSwitch);
|
addVars(c.stats, initsSwitch, uninitsSwitch);
|
||||||
if (!hasDefault) {
|
if (!hasDefault) {
|
||||||
inits.assign(initsSwitch);
|
inits.assign(initsSwitch);
|
||||||
@ -2301,6 +2381,8 @@ public class Flow {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
scan(tree.value);
|
||||||
recordExit(new AssignPendingExit(tree, inits, uninits));
|
recordExit(new AssignPendingExit(tree, inits, uninits));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2479,11 +2561,11 @@ public class Flow {
|
|||||||
|
|
||||||
/** Perform definite assignment/unassignment analysis on a tree.
|
/** Perform definite assignment/unassignment analysis on a tree.
|
||||||
*/
|
*/
|
||||||
public void analyzeTree(Env<?> env) {
|
public void analyzeTree(Env<?> env, TreeMaker make) {
|
||||||
analyzeTree(env, env.tree);
|
analyzeTree(env, env.tree, make);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void analyzeTree(Env<?> env, JCTree tree) {
|
public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
|
||||||
try {
|
try {
|
||||||
startPos = tree.pos().getStartPosition();
|
startPos = tree.pos().getStartPosition();
|
||||||
|
|
||||||
@ -2494,6 +2576,7 @@ public class Flow {
|
|||||||
vardecls[i] = null;
|
vardecls[i] = null;
|
||||||
firstadr = 0;
|
firstadr = 0;
|
||||||
nextadr = 0;
|
nextadr = 0;
|
||||||
|
Flow.this.make = make;
|
||||||
pendingExits = new ListBuffer<>();
|
pendingExits = new ListBuffer<>();
|
||||||
this.classDef = null;
|
this.classDef = null;
|
||||||
unrefdResources = WriteableScope.create(env.enclClass.sym);
|
unrefdResources = WriteableScope.create(env.enclClass.sym);
|
||||||
@ -2509,6 +2592,7 @@ public class Flow {
|
|||||||
}
|
}
|
||||||
firstadr = 0;
|
firstadr = 0;
|
||||||
nextadr = 0;
|
nextadr = 0;
|
||||||
|
Flow.this.make = null;
|
||||||
pendingExits = null;
|
pendingExits = null;
|
||||||
this.classDef = null;
|
this.classDef = null;
|
||||||
unrefdResources = null;
|
unrefdResources = null;
|
||||||
@ -2661,6 +2745,12 @@ public class Flow {
|
|||||||
super.visitTry(tree);
|
super.visitTry(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
scan(tree.value);
|
||||||
|
}
|
||||||
|
|
||||||
public void visitModuleDef(JCModuleDecl tree) {
|
public void visitModuleDef(JCModuleDecl tree) {
|
||||||
// Do nothing for modules
|
// Do nothing for modules
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,7 @@ public class LambdaToMethod extends TreeTranslator {
|
|||||||
JCBreak br = make.Break(null);
|
JCBreak br = make.Break(null);
|
||||||
breaks.add(br);
|
breaks.add(br);
|
||||||
List<JCStatement> stmts = entry.getValue().append(br).toList();
|
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());
|
JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
|
||||||
for (JCBreak br : breaks) {
|
for (JCBreak br : breaks) {
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
package com.sun.tools.javac.comp;
|
package com.sun.tools.javac.comp;
|
||||||
|
|
||||||
import java.util.*;
|
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.*;
|
||||||
import com.sun.tools.javac.code.Kinds.KindSelector;
|
import com.sun.tools.javac.code.Kinds.KindSelector;
|
||||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||||
@ -54,6 +58,10 @@ import static com.sun.tools.javac.code.TypeTag.*;
|
|||||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
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.code.Symbol.OperatorSymbol.AccessCode.DEREF;
|
||||||
import static com.sun.tools.javac.jvm.ByteCodes.*;
|
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.JCOperatorExpression.OperandPos.LEFT;
|
||||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||||
|
|
||||||
@ -263,6 +271,13 @@ public class Lower extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
super.visitApply(tree);
|
super.visitApply(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
scan(tree.value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,6 +379,7 @@ public class Lower extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
super.visitApply(tree);
|
super.visitApply(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
|
ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
|
||||||
@ -3340,6 +3356,45 @@ public class Lower extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitSwitch(JCSwitch tree) {
|
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);
|
Type selsuper = types.supertype(tree.selector.type);
|
||||||
boolean enumSwitch = selsuper != null &&
|
boolean enumSwitch = selsuper != null &&
|
||||||
(tree.selector.type.tsym.flags() & ENUM) != 0;
|
(tree.selector.type.tsym.flags() & ENUM) != 0;
|
||||||
@ -3371,10 +3426,10 @@ public class Lower extends TreeTranslator {
|
|||||||
ordinalMethod)));
|
ordinalMethod)));
|
||||||
ListBuffer<JCCase> cases = new ListBuffer<>();
|
ListBuffer<JCCase> cases = new ListBuffer<>();
|
||||||
for (JCCase c : tree.cases) {
|
for (JCCase c : tree.cases) {
|
||||||
if (c.pat != null) {
|
if (c.pats.nonEmpty()) {
|
||||||
VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
|
VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
|
||||||
JCLiteral pat = map.forConstant(label);
|
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 {
|
} else {
|
||||||
cases.append(c);
|
cases.append(c);
|
||||||
}
|
}
|
||||||
@ -3442,10 +3497,10 @@ public class Lower extends TreeTranslator {
|
|||||||
Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
|
Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
|
||||||
|
|
||||||
int casePosition = 0;
|
int casePosition = 0;
|
||||||
for(JCCase oneCase : caseList) {
|
|
||||||
JCExpression expression = oneCase.getExpression();
|
|
||||||
|
|
||||||
if (expression != null) { // expression for a "default" case is null
|
for(JCCase oneCase : caseList) {
|
||||||
|
if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
|
||||||
|
JCExpression expression = oneCase.pats.head;
|
||||||
String labelExpr = (String) expression.type.constValue();
|
String labelExpr = (String) expression.type.constValue();
|
||||||
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
|
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
|
||||||
Assert.checkNull(mapping);
|
Assert.checkNull(mapping);
|
||||||
@ -3529,7 +3584,7 @@ public class Lower extends TreeTranslator {
|
|||||||
breakStmt.target = switch1;
|
breakStmt.target = switch1;
|
||||||
lb.append(elsepart).append(breakStmt);
|
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();
|
switch1.cases = caseBuffer.toList();
|
||||||
@ -3546,18 +3601,17 @@ public class Lower extends TreeTranslator {
|
|||||||
// replacement switch being created.
|
// replacement switch being created.
|
||||||
patchTargets(oneCase, tree, switch2);
|
patchTargets(oneCase, tree, switch2);
|
||||||
|
|
||||||
boolean isDefault = (oneCase.getExpression() == null);
|
boolean isDefault = (oneCase.pats.isEmpty());
|
||||||
JCExpression caseExpr;
|
JCExpression caseExpr;
|
||||||
if (isDefault)
|
if (isDefault)
|
||||||
caseExpr = null;
|
caseExpr = null;
|
||||||
else {
|
else {
|
||||||
caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
|
caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
|
||||||
getExpression()).
|
|
||||||
type.constValue()));
|
type.constValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
lb.append(make.Case(caseExpr,
|
lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
|
||||||
oneCase.getStatements()));
|
oneCase.getStatements(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch2.cases = lb.toList();
|
switch2.cases = lb.toList();
|
||||||
@ -3567,6 +3621,76 @@ public class Lower extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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) {
|
public void visitNewArray(JCNewArray tree) {
|
||||||
tree.elemtype = translate(tree.elemtype);
|
tree.elemtype = translate(tree.elemtype);
|
||||||
for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
|
for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
|
||||||
@ -3602,7 +3726,7 @@ public class Lower extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitLetExpr(LetExpr tree) {
|
public void visitLetExpr(LetExpr tree) {
|
||||||
tree.defs = translateVarDefs(tree.defs);
|
tree.defs = translate(tree.defs);
|
||||||
tree.expr = translate(tree.expr, tree.type);
|
tree.expr = translate(tree.expr, tree.type);
|
||||||
result = tree;
|
result = tree;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ import static com.sun.tools.javac.code.TypeTag.CLASS;
|
|||||||
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
||||||
import static com.sun.tools.javac.code.TypeTag.VOID;
|
import static com.sun.tools.javac.code.TypeTag.VOID;
|
||||||
import static com.sun.tools.javac.comp.CompileStates.CompileState;
|
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.
|
/** This pass translates Generic Java to conventional Java.
|
||||||
*
|
*
|
||||||
@ -561,11 +562,22 @@ public class TransTypes extends TreeTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
tree.pat = translate(tree.pat, null);
|
tree.pats = translate(tree.pats, null);
|
||||||
tree.stats = translate(tree.stats);
|
tree.stats = translate(tree.stats);
|
||||||
result = tree;
|
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) {
|
public void visitSynchronized(JCSynchronized tree) {
|
||||||
tree.lock = translate(tree.lock, erasure(tree.lock.type));
|
tree.lock = translate(tree.lock, erasure(tree.lock.type));
|
||||||
tree.body = translate(tree.body);
|
tree.body = translate(tree.body);
|
||||||
@ -606,6 +618,16 @@ public class TransTypes extends TreeTranslator {
|
|||||||
result = tree;
|
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) {
|
public void visitThrow(JCThrow tree) {
|
||||||
tree.expr = translate(tree.expr, erasure(tree.expr.type));
|
tree.expr = translate(tree.expr, erasure(tree.expr.type));
|
||||||
result = tree;
|
result = tree;
|
||||||
|
@ -259,13 +259,13 @@ public class TreeDiffer extends TreeScanner {
|
|||||||
@Override
|
@Override
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
JCBreak that = (JCBreak) parameter;
|
JCBreak that = (JCBreak) parameter;
|
||||||
result = tree.label == that.label;
|
result = scan(tree.value, that.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
JCCase that = (JCCase) parameter;
|
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
|
@Override
|
||||||
|
@ -313,7 +313,7 @@ implements CRTFlags {
|
|||||||
|
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
|
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
|
||||||
sr.mergeWith(csp(tree.pat));
|
sr.mergeWith(csp(tree.pats));
|
||||||
sr.mergeWith(csp(tree.stats));
|
sr.mergeWith(csp(tree.stats));
|
||||||
result = sr;
|
result = sr;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,8 @@ public class Code {
|
|||||||
|
|
||||||
final MethodSymbol meth;
|
final MethodSymbol meth;
|
||||||
|
|
||||||
|
private int letExprStackPos = 0;
|
||||||
|
|
||||||
/** Construct a code object, given the settings of the fatcode,
|
/** Construct a code object, given the settings of the fatcode,
|
||||||
* debugging info switches and the CharacterRangeTable.
|
* debugging info switches and the CharacterRangeTable.
|
||||||
*/
|
*/
|
||||||
@ -382,7 +384,7 @@ public class Code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void postop() {
|
void postop() {
|
||||||
Assert.check(alive || state.stacksize == 0);
|
Assert.check(alive || isStatementStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Emit a ldc (or ldc_w) instruction, taking into account operand size
|
/** Emit a ldc (or ldc_w) instruction, taking into account operand size
|
||||||
@ -1211,6 +1213,15 @@ public class Code {
|
|||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int setLetExprStackPos(int pos) {
|
||||||
|
int res = letExprStackPos;
|
||||||
|
letExprStackPos = pos;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatementStart() {
|
||||||
|
return state.stacksize == letExprStackPos;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Stack map generation
|
* Stack map generation
|
||||||
@ -1474,7 +1485,7 @@ public class Code {
|
|||||||
State newState = state;
|
State newState = state;
|
||||||
for (; chain != null; chain = chain.next) {
|
for (; chain != null; chain = chain.next) {
|
||||||
Assert.check(state != chain.state
|
Assert.check(state != chain.state
|
||||||
&& (target > chain.pc || state.stacksize == 0));
|
&& (target > chain.pc || isStatementStart()));
|
||||||
if (target >= cp) {
|
if (target >= cp) {
|
||||||
target = cp;
|
target = cp;
|
||||||
} else if (get1(target) == goto_) {
|
} else if (get1(target) == goto_) {
|
||||||
|
@ -81,11 +81,6 @@ public class Gen extends JCTree.Visitor {
|
|||||||
*/
|
*/
|
||||||
private final Type methodType;
|
private final Type methodType;
|
||||||
|
|
||||||
/**
|
|
||||||
* Are we presently traversing a let expression ? Yes if depth != 0
|
|
||||||
*/
|
|
||||||
private int letExprDepth;
|
|
||||||
|
|
||||||
public static Gen instance(Context context) {
|
public static Gen instance(Context context) {
|
||||||
Gen instance = context.get(genKey);
|
Gen instance = context.get(genKey);
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
@ -1011,10 +1006,10 @@ public class Gen extends JCTree.Visitor {
|
|||||||
if (tree.init != null) {
|
if (tree.init != null) {
|
||||||
checkStringConstant(tree.init.pos(), v.getConstValue());
|
checkStringConstant(tree.init.pos(), v.getConstValue());
|
||||||
if (v.getConstValue() == null || varDebugInfo) {
|
if (v.getConstValue() == null || varDebugInfo) {
|
||||||
Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
genExpr(tree.init, v.erasure(types)).load();
|
genExpr(tree.init, v.erasure(types)).load();
|
||||||
items.makeLocalItem(v).store();
|
items.makeLocalItem(v).store();
|
||||||
Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkDimension(tree.pos(), v.type);
|
checkDimension(tree.pos(), v.type);
|
||||||
@ -1069,14 +1064,14 @@ public class Gen extends JCTree.Visitor {
|
|||||||
CondItem c;
|
CondItem c;
|
||||||
if (cond != null) {
|
if (cond != null) {
|
||||||
code.statBegin(cond.pos);
|
code.statBegin(cond.pos);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
|
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
|
||||||
} else {
|
} else {
|
||||||
c = items.makeCondItem(goto_);
|
c = items.makeCondItem(goto_);
|
||||||
}
|
}
|
||||||
Chain loopDone = c.jumpFalse();
|
Chain loopDone = c.jumpFalse();
|
||||||
code.resolve(c.trueJumps);
|
code.resolve(c.trueJumps);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
|
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
|
||||||
code.resolve(loopEnv.info.cont);
|
code.resolve(loopEnv.info.cont);
|
||||||
genStats(step, loopEnv);
|
genStats(step, loopEnv);
|
||||||
@ -1090,13 +1085,13 @@ public class Gen extends JCTree.Visitor {
|
|||||||
CondItem c;
|
CondItem c;
|
||||||
if (cond != null) {
|
if (cond != null) {
|
||||||
code.statBegin(cond.pos);
|
code.statBegin(cond.pos);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
|
c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
|
||||||
} else {
|
} else {
|
||||||
c = items.makeCondItem(goto_);
|
c = items.makeCondItem(goto_);
|
||||||
}
|
}
|
||||||
code.resolve(c.jumpTrue(), startpc);
|
code.resolve(c.jumpTrue(), startpc);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
code.resolve(c.falseJumps);
|
code.resolve(c.falseJumps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1125,7 +1120,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
int limit = code.nextreg;
|
int limit = code.nextreg;
|
||||||
Assert.check(!tree.selector.type.hasTag(CLASS));
|
Assert.check(!tree.selector.type.hasTag(CLASS));
|
||||||
int startpcCrt = genCrt ? code.curCP() : 0;
|
int startpcCrt = genCrt ? code.curCP() : 0;
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
Item sel = genExpr(tree.selector, syms.intType);
|
Item sel = genExpr(tree.selector, syms.intType);
|
||||||
List<JCCase> cases = tree.cases;
|
List<JCCase> cases = tree.cases;
|
||||||
if (cases.isEmpty()) {
|
if (cases.isEmpty()) {
|
||||||
@ -1154,8 +1149,9 @@ public class Gen extends JCTree.Visitor {
|
|||||||
|
|
||||||
List<JCCase> l = cases;
|
List<JCCase> l = cases;
|
||||||
for (int i = 0; i < labels.length; i++) {
|
for (int i = 0; i < labels.length; i++) {
|
||||||
if (l.head.pat != null) {
|
if (l.head.pats.nonEmpty()) {
|
||||||
int val = ((Number)l.head.pat.type.constValue()).intValue();
|
Assert.check(l.head.pats.size() == 1);
|
||||||
|
int val = ((Number)l.head.pats.head.type.constValue()).intValue();
|
||||||
labels[i] = val;
|
labels[i] = val;
|
||||||
if (val < lo) lo = val;
|
if (val < lo) lo = val;
|
||||||
if (hi < val) hi = val;
|
if (hi < val) hi = val;
|
||||||
@ -1294,7 +1290,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
int limit = code.nextreg;
|
int limit = code.nextreg;
|
||||||
// Generate code to evaluate lock and save in temporary variable.
|
// Generate code to evaluate lock and save in temporary variable.
|
||||||
final LocalItem lockVar = makeTemp(syms.objectType);
|
final LocalItem lockVar = makeTemp(syms.objectType);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
genExpr(tree.lock, tree.lock.type).load().duplicate();
|
genExpr(tree.lock, tree.lock.type).load().duplicate();
|
||||||
lockVar.store();
|
lockVar.store();
|
||||||
|
|
||||||
@ -1556,11 +1552,11 @@ public class Gen extends JCTree.Visitor {
|
|||||||
public void visitIf(JCIf tree) {
|
public void visitIf(JCIf tree) {
|
||||||
int limit = code.nextreg;
|
int limit = code.nextreg;
|
||||||
Chain thenExit = null;
|
Chain thenExit = null;
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
CondItem c = genCond(TreeInfo.skipParens(tree.cond),
|
CondItem c = genCond(TreeInfo.skipParens(tree.cond),
|
||||||
CRT_FLOW_CONTROLLER);
|
CRT_FLOW_CONTROLLER);
|
||||||
Chain elseChain = c.jumpFalse();
|
Chain elseChain = c.jumpFalse();
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
if (!c.isFalse()) {
|
if (!c.isFalse()) {
|
||||||
code.resolve(c.trueJumps);
|
code.resolve(c.trueJumps);
|
||||||
genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
|
genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
|
||||||
@ -1574,7 +1570,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
code.resolve(thenExit);
|
code.resolve(thenExit);
|
||||||
code.endScopes(limit);
|
code.endScopes(limit);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitExec(JCExpressionStatement tree) {
|
public void visitExec(JCExpressionStatement tree) {
|
||||||
@ -1588,16 +1584,16 @@ public class Gen extends JCTree.Visitor {
|
|||||||
((JCUnary) e).setTag(PREDEC);
|
((JCUnary) e).setTag(PREDEC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
genExpr(tree.expr, tree.expr.type).drop();
|
genExpr(tree.expr, tree.expr.type).drop();
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
int tmpPos = code.pendingStatPos;
|
int tmpPos = code.pendingStatPos;
|
||||||
Env<GenContext> targetEnv = unwind(tree.target, env);
|
Env<GenContext> targetEnv = unwind(tree.target, env);
|
||||||
code.pendingStatPos = tmpPos;
|
code.pendingStatPos = tmpPos;
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
targetEnv.info.addExit(code.branch(goto_));
|
targetEnv.info.addExit(code.branch(goto_));
|
||||||
endFinalizerGaps(env, targetEnv);
|
endFinalizerGaps(env, targetEnv);
|
||||||
}
|
}
|
||||||
@ -1606,7 +1602,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
int tmpPos = code.pendingStatPos;
|
int tmpPos = code.pendingStatPos;
|
||||||
Env<GenContext> targetEnv = unwind(tree.target, env);
|
Env<GenContext> targetEnv = unwind(tree.target, env);
|
||||||
code.pendingStatPos = tmpPos;
|
code.pendingStatPos = tmpPos;
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
targetEnv.info.addCont(code.branch(goto_));
|
targetEnv.info.addCont(code.branch(goto_));
|
||||||
endFinalizerGaps(env, targetEnv);
|
endFinalizerGaps(env, targetEnv);
|
||||||
}
|
}
|
||||||
@ -1620,7 +1616,7 @@ public class Gen extends JCTree.Visitor {
|
|||||||
*/
|
*/
|
||||||
int tmpPos = code.pendingStatPos;
|
int tmpPos = code.pendingStatPos;
|
||||||
if (tree.expr != null) {
|
if (tree.expr != null) {
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
Item r = genExpr(tree.expr, pt).load();
|
Item r = genExpr(tree.expr, pt).load();
|
||||||
if (hasFinally(env.enclMethod, env)) {
|
if (hasFinally(env.enclMethod, env)) {
|
||||||
r = makeTemp(pt);
|
r = makeTemp(pt);
|
||||||
@ -1640,10 +1636,10 @@ public class Gen extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitThrow(JCThrow tree) {
|
public void visitThrow(JCThrow tree) {
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
genExpr(tree.expr, tree.expr.type).load();
|
genExpr(tree.expr, tree.expr.type).load();
|
||||||
code.emitop0(athrow);
|
code.emitop0(athrow);
|
||||||
Assert.check(code.state.stacksize == 0);
|
Assert.check(code.isStatementStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************
|
/* ************************************************************************
|
||||||
@ -2147,12 +2143,15 @@ public class Gen extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitLetExpr(LetExpr tree) {
|
public void visitLetExpr(LetExpr tree) {
|
||||||
letExprDepth++;
|
|
||||||
int limit = code.nextreg;
|
int limit = code.nextreg;
|
||||||
|
int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
|
||||||
|
try {
|
||||||
genStats(tree.defs, env);
|
genStats(tree.defs, env);
|
||||||
|
} finally {
|
||||||
|
code.setLetExprStackPos(prevLetExprStart);
|
||||||
|
}
|
||||||
result = genExpr(tree.expr, tree.expr.type).load();
|
result = genExpr(tree.expr, tree.expr.type).load();
|
||||||
code.endScopes(limit);
|
code.endScopes(limit);
|
||||||
letExprDepth--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
|
private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
|
||||||
|
@ -26,8 +26,10 @@
|
|||||||
package com.sun.tools.javac.parser;
|
package com.sun.tools.javac.parser;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
||||||
import com.sun.source.tree.ModuleTree.ModuleKind;
|
import com.sun.source.tree.ModuleTree.ModuleKind;
|
||||||
|
|
||||||
@ -218,12 +220,22 @@ public class JavacParser implements Parser {
|
|||||||
* mode = TYPE : a type
|
* mode = TYPE : a type
|
||||||
* mode = NOPARAMS : no parameters allowed for type
|
* mode = NOPARAMS : no parameters allowed for type
|
||||||
* mode = TYPEARG : type argument
|
* mode = TYPEARG : type argument
|
||||||
|
* mode |= NOLAMBDA : lambdas are not allowed
|
||||||
*/
|
*/
|
||||||
protected static final int EXPR = 0x1;
|
protected static final int EXPR = 0x1;
|
||||||
protected static final int TYPE = 0x2;
|
protected static final int TYPE = 0x2;
|
||||||
protected static final int NOPARAMS = 0x4;
|
protected static final int NOPARAMS = 0x4;
|
||||||
protected static final int TYPEARG = 0x8;
|
protected static final int TYPEARG = 0x8;
|
||||||
protected static final int DIAMOND = 0x10;
|
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.
|
/** The current mode.
|
||||||
*/
|
*/
|
||||||
@ -427,11 +439,18 @@ public class JavacParser implements Parser {
|
|||||||
* an error.
|
* an error.
|
||||||
*/
|
*/
|
||||||
public void accept(TokenKind tk) {
|
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) {
|
if (token.kind == tk) {
|
||||||
nextToken();
|
nextToken();
|
||||||
} else {
|
} else {
|
||||||
setErrorEndPos(token.pos);
|
setErrorEndPos(token.pos);
|
||||||
reportSyntaxError(S.prevToken().endPos, Errors.Expected(tk));
|
reportSyntaxError(S.prevToken().endPos, errorProvider.apply(tk));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,7 +815,7 @@ public class JavacParser implements Parser {
|
|||||||
case EQ: {
|
case EQ: {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
nextToken();
|
nextToken();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term();
|
JCExpression t1 = term();
|
||||||
return toP(F.at(pos).Assign(t, t1));
|
return toP(F.at(pos).Assign(t, t1));
|
||||||
}
|
}
|
||||||
@ -814,7 +833,7 @@ public class JavacParser implements Parser {
|
|||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
TokenKind tk = token.kind;
|
TokenKind tk = token.kind;
|
||||||
nextToken();
|
nextToken();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term();
|
JCExpression t1 = term();
|
||||||
return F.at(pos).Assignop(optag(tk), t, t1);
|
return F.at(pos).Assignop(optag(tk), t, t1);
|
||||||
default:
|
default:
|
||||||
@ -829,7 +848,7 @@ public class JavacParser implements Parser {
|
|||||||
JCExpression term1() {
|
JCExpression term1() {
|
||||||
JCExpression t = term2();
|
JCExpression t = term2();
|
||||||
if ((mode & EXPR) != 0 && token.kind == QUES) {
|
if ((mode & EXPR) != 0 && token.kind == QUES) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
return term1Rest(t);
|
return term1Rest(t);
|
||||||
} else {
|
} else {
|
||||||
return t;
|
return t;
|
||||||
@ -858,7 +877,7 @@ public class JavacParser implements Parser {
|
|||||||
JCExpression term2() {
|
JCExpression term2() {
|
||||||
JCExpression t = term3();
|
JCExpression t = term3();
|
||||||
if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
|
if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
return term2Rest(t, TreeInfo.orPrec);
|
return term2Rest(t, TreeInfo.orPrec);
|
||||||
} else {
|
} else {
|
||||||
return t;
|
return t;
|
||||||
@ -1058,7 +1077,7 @@ public class JavacParser implements Parser {
|
|||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case QUES:
|
case QUES:
|
||||||
if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
|
if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
return typeArgument();
|
return typeArgument();
|
||||||
} else
|
} else
|
||||||
return illegal();
|
return illegal();
|
||||||
@ -1066,11 +1085,11 @@ public class JavacParser implements Parser {
|
|||||||
if (typeArgs == null && (mode & EXPR) != 0) {
|
if (typeArgs == null && (mode & EXPR) != 0) {
|
||||||
TokenKind tk = token.kind;
|
TokenKind tk = token.kind;
|
||||||
nextToken();
|
nextToken();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
if (tk == SUB &&
|
if (tk == SUB &&
|
||||||
(token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
|
(token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
|
||||||
token.radix() == 10) {
|
token.radix() == 10) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = literal(names.hyphen, pos);
|
t = literal(names.hyphen, pos);
|
||||||
} else {
|
} else {
|
||||||
t = term3();
|
t = term3();
|
||||||
@ -1084,7 +1103,7 @@ public class JavacParser implements Parser {
|
|||||||
switch (pres) {
|
switch (pres) {
|
||||||
case CAST:
|
case CAST:
|
||||||
accept(LPAREN);
|
accept(LPAREN);
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
int pos1 = pos;
|
int pos1 = pos;
|
||||||
List<JCExpression> targets = List.of(t = parseType());
|
List<JCExpression> targets = List.of(t = parseType());
|
||||||
while (token.kind == AMP) {
|
while (token.kind == AMP) {
|
||||||
@ -1096,7 +1115,7 @@ public class JavacParser implements Parser {
|
|||||||
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
||||||
}
|
}
|
||||||
accept(RPAREN);
|
accept(RPAREN);
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term3();
|
JCExpression t1 = term3();
|
||||||
return F.at(pos).TypeCast(t, t1);
|
return F.at(pos).TypeCast(t, t1);
|
||||||
case IMPLICIT_LAMBDA:
|
case IMPLICIT_LAMBDA:
|
||||||
@ -1105,7 +1124,7 @@ public class JavacParser implements Parser {
|
|||||||
break;
|
break;
|
||||||
default: //PARENS
|
default: //PARENS
|
||||||
accept(LPAREN);
|
accept(LPAREN);
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
|
t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
|
||||||
accept(RPAREN);
|
accept(RPAREN);
|
||||||
t = toP(F.at(pos).Parens(t));
|
t = toP(F.at(pos).Parens(t));
|
||||||
@ -1117,7 +1136,7 @@ public class JavacParser implements Parser {
|
|||||||
break;
|
break;
|
||||||
case THIS:
|
case THIS:
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos).Ident(names._this));
|
t = to(F.at(pos).Ident(names._this));
|
||||||
nextToken();
|
nextToken();
|
||||||
if (typeArgs == null)
|
if (typeArgs == null)
|
||||||
@ -1129,7 +1148,7 @@ public class JavacParser implements Parser {
|
|||||||
break;
|
break;
|
||||||
case SUPER:
|
case SUPER:
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos).Ident(names._super));
|
t = to(F.at(pos).Ident(names._super));
|
||||||
t = superSuffix(typeArgs, t);
|
t = superSuffix(typeArgs, t);
|
||||||
typeArgs = null;
|
typeArgs = null;
|
||||||
@ -1139,14 +1158,14 @@ public class JavacParser implements Parser {
|
|||||||
case CHARLITERAL: case STRINGLITERAL:
|
case CHARLITERAL: case STRINGLITERAL:
|
||||||
case TRUE: case FALSE: case NULL:
|
case TRUE: case FALSE: case NULL:
|
||||||
if (typeArgs == null && (mode & EXPR) != 0) {
|
if (typeArgs == null && (mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = literal(names.empty);
|
t = literal(names.empty);
|
||||||
} else return illegal();
|
} else return illegal();
|
||||||
break;
|
break;
|
||||||
case NEW:
|
case NEW:
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
nextToken();
|
nextToken();
|
||||||
if (token.kind == LT) typeArgs = typeArguments(false);
|
if (token.kind == LT) typeArgs = typeArguments(false);
|
||||||
t = creator(pos, typeArgs);
|
t = creator(pos, typeArgs);
|
||||||
@ -1193,7 +1212,7 @@ public class JavacParser implements Parser {
|
|||||||
break;
|
break;
|
||||||
case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
|
case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
|
||||||
if (typeArgs != null) return illegal();
|
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);
|
t = lambdaExpressionOrStatement(false, false, pos);
|
||||||
} else {
|
} else {
|
||||||
t = toP(F.at(token.pos).Ident(ident()));
|
t = toP(F.at(token.pos).Ident(ident()));
|
||||||
@ -1219,7 +1238,7 @@ public class JavacParser implements Parser {
|
|||||||
t = bracketsSuffix(t);
|
t = bracketsSuffix(t);
|
||||||
} else {
|
} else {
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term();
|
JCExpression t1 = term();
|
||||||
if (!annos.isEmpty()) t = illegal(annos.head.pos);
|
if (!annos.isEmpty()) t = illegal(annos.head.pos);
|
||||||
t = to(F.at(pos).Indexed(t, t1));
|
t = to(F.at(pos).Indexed(t, t1));
|
||||||
@ -1229,7 +1248,7 @@ public class JavacParser implements Parser {
|
|||||||
break loop;
|
break loop;
|
||||||
case LPAREN:
|
case LPAREN:
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = arguments(typeArgs, t);
|
t = arguments(typeArgs, t);
|
||||||
if (!annos.isEmpty()) t = illegal(annos.head.pos);
|
if (!annos.isEmpty()) t = illegal(annos.head.pos);
|
||||||
typeArgs = null;
|
typeArgs = null;
|
||||||
@ -1248,25 +1267,25 @@ public class JavacParser implements Parser {
|
|||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case CLASS:
|
case CLASS:
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos).Select(t, names._class));
|
t = to(F.at(pos).Select(t, names._class));
|
||||||
nextToken();
|
nextToken();
|
||||||
break loop;
|
break loop;
|
||||||
case THIS:
|
case THIS:
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos).Select(t, names._this));
|
t = to(F.at(pos).Select(t, names._this));
|
||||||
nextToken();
|
nextToken();
|
||||||
break loop;
|
break loop;
|
||||||
case SUPER:
|
case SUPER:
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos).Select(t, names._super));
|
t = to(F.at(pos).Select(t, names._super));
|
||||||
t = superSuffix(typeArgs, t);
|
t = superSuffix(typeArgs, t);
|
||||||
typeArgs = null;
|
typeArgs = null;
|
||||||
break loop;
|
break loop;
|
||||||
case NEW:
|
case NEW:
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
int pos1 = token.pos;
|
int pos1 = token.pos;
|
||||||
nextToken();
|
nextToken();
|
||||||
if (token.kind == LT) typeArgs = typeArguments(false);
|
if (token.kind == LT) typeArgs = typeArguments(false);
|
||||||
@ -1310,7 +1329,7 @@ public class JavacParser implements Parser {
|
|||||||
t = toP(F.at(pos1).TypeApply(t, args.toList()));
|
t = toP(F.at(pos1).TypeApply(t, args.toList()));
|
||||||
while (token.kind == DOT) {
|
while (token.kind == DOT) {
|
||||||
nextToken();
|
nextToken();
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
t = toP(F.at(token.pos).Select(t, ident()));
|
t = toP(F.at(token.pos).Select(t, ident()));
|
||||||
t = typeArgumentsOpt(t);
|
t = typeArgumentsOpt(t);
|
||||||
}
|
}
|
||||||
@ -1319,7 +1338,7 @@ public class JavacParser implements Parser {
|
|||||||
//method reference expected here
|
//method reference expected here
|
||||||
t = illegal();
|
t = illegal();
|
||||||
}
|
}
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
return term3Rest(t, typeArgs);
|
return term3Rest(t, typeArgs);
|
||||||
}
|
}
|
||||||
break loop;
|
break loop;
|
||||||
@ -1356,12 +1375,82 @@ public class JavacParser implements Parser {
|
|||||||
//return illegal();
|
//return illegal();
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
return illegal();
|
return illegal();
|
||||||
}
|
}
|
||||||
return term3Rest(t, typeArgs);
|
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) {
|
JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
|
||||||
if (typeArgs != null) illegal();
|
if (typeArgs != null) illegal();
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -1372,13 +1461,13 @@ public class JavacParser implements Parser {
|
|||||||
nextToken();
|
nextToken();
|
||||||
if ((mode & TYPE) != 0) {
|
if ((mode & TYPE) != 0) {
|
||||||
int oldmode = mode;
|
int oldmode = mode;
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
if (token.kind == RBRACKET) {
|
if (token.kind == RBRACKET) {
|
||||||
nextToken();
|
nextToken();
|
||||||
t = bracketsOpt(t);
|
t = bracketsOpt(t);
|
||||||
t = toP(F.at(pos1).TypeArray(t));
|
t = toP(F.at(pos1).TypeArray(t));
|
||||||
if (token.kind == COLCOL) {
|
if (token.kind == COLCOL) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (annos.nonEmpty()) {
|
if (annos.nonEmpty()) {
|
||||||
@ -1389,7 +1478,7 @@ public class JavacParser implements Parser {
|
|||||||
mode = oldmode;
|
mode = oldmode;
|
||||||
}
|
}
|
||||||
if ((mode & EXPR) != 0) {
|
if ((mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term();
|
JCExpression t1 = term();
|
||||||
t = to(F.at(pos1).Indexed(t, t1));
|
t = to(F.at(pos1).Indexed(t, t1));
|
||||||
}
|
}
|
||||||
@ -1398,14 +1487,14 @@ public class JavacParser implements Parser {
|
|||||||
nextToken();
|
nextToken();
|
||||||
typeArgs = typeArgumentsOpt(EXPR);
|
typeArgs = typeArgumentsOpt(EXPR);
|
||||||
if (token.kind == SUPER && (mode & EXPR) != 0) {
|
if (token.kind == SUPER && (mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(pos1).Select(t, names._super));
|
t = to(F.at(pos1).Select(t, names._super));
|
||||||
nextToken();
|
nextToken();
|
||||||
t = arguments(typeArgs, t);
|
t = arguments(typeArgs, t);
|
||||||
typeArgs = null;
|
typeArgs = null;
|
||||||
} else if (token.kind == NEW && (mode & EXPR) != 0) {
|
} else if (token.kind == NEW && (mode & EXPR) != 0) {
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
int pos2 = token.pos;
|
int pos2 = token.pos;
|
||||||
nextToken();
|
nextToken();
|
||||||
if (token.kind == LT) typeArgs = typeArguments(false);
|
if (token.kind == LT) typeArgs = typeArguments(false);
|
||||||
@ -1425,7 +1514,7 @@ public class JavacParser implements Parser {
|
|||||||
typeArgs = null;
|
typeArgs = null;
|
||||||
}
|
}
|
||||||
} else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
|
} else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
if (typeArgs != null) return illegal();
|
if (typeArgs != null) return illegal();
|
||||||
accept(COLCOL);
|
accept(COLCOL);
|
||||||
t = memberReferenceSuffix(pos1, t);
|
t = memberReferenceSuffix(pos1, t);
|
||||||
@ -1440,7 +1529,7 @@ public class JavacParser implements Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
|
while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
t = to(F.at(token.pos).Unary(
|
t = to(F.at(token.pos).Unary(
|
||||||
token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
|
token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
|
||||||
nextToken();
|
nextToken();
|
||||||
@ -1580,7 +1669,8 @@ public class JavacParser implements Parser {
|
|||||||
return ParensResult.EXPLICIT_LAMBDA;
|
return ParensResult.EXPLICIT_LAMBDA;
|
||||||
} else if (peekToken(lookahead, RPAREN, ARROW)) {
|
} else if (peekToken(lookahead, RPAREN, ARROW)) {
|
||||||
// Identifier, ')' '->' -> implicit lambda
|
// Identifier, ')' '->' -> implicit lambda
|
||||||
return ParensResult.IMPLICIT_LAMBDA;
|
return (mode & NOLAMBDA) == 0 ? ParensResult.IMPLICIT_LAMBDA
|
||||||
|
: ParensResult.PARENS;
|
||||||
} else if (depth == 0 && peekToken(lookahead, COMMA)) {
|
} else if (depth == 0 && peekToken(lookahead, COMMA)) {
|
||||||
defaultResult = ParensResult.IMPLICIT_LAMBDA;
|
defaultResult = ParensResult.IMPLICIT_LAMBDA;
|
||||||
}
|
}
|
||||||
@ -1818,7 +1908,7 @@ public class JavacParser implements Parser {
|
|||||||
*/
|
*/
|
||||||
JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
|
JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
|
||||||
if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
|
if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
return arguments(typeArgs, t);
|
return arguments(typeArgs, t);
|
||||||
} else {
|
} else {
|
||||||
return t;
|
return t;
|
||||||
@ -1857,7 +1947,7 @@ public class JavacParser implements Parser {
|
|||||||
if (token.kind == LT &&
|
if (token.kind == LT &&
|
||||||
(mode & TYPE) != 0 &&
|
(mode & TYPE) != 0 &&
|
||||||
(mode & NOPARAMS) == 0) {
|
(mode & NOPARAMS) == 0) {
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
return typeArguments(t, false);
|
return typeArguments(t, false);
|
||||||
} else {
|
} else {
|
||||||
return t;
|
return t;
|
||||||
@ -2019,7 +2109,7 @@ public class JavacParser implements Parser {
|
|||||||
*/
|
*/
|
||||||
JCExpression bracketsSuffix(JCExpression t) {
|
JCExpression bracketsSuffix(JCExpression t) {
|
||||||
if ((mode & EXPR) != 0 && token.kind == DOT) {
|
if ((mode & EXPR) != 0 && token.kind == DOT) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
nextToken();
|
nextToken();
|
||||||
accept(CLASS);
|
accept(CLASS);
|
||||||
@ -2044,7 +2134,7 @@ public class JavacParser implements Parser {
|
|||||||
}
|
}
|
||||||
} else if ((mode & TYPE) != 0) {
|
} else if ((mode & TYPE) != 0) {
|
||||||
if (token.kind != COLCOL) {
|
if (token.kind != COLCOL) {
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
}
|
}
|
||||||
} else if (token.kind != COLCOL) {
|
} else if (token.kind != COLCOL) {
|
||||||
syntaxError(token.pos, Errors.DotClassExpected);
|
syntaxError(token.pos, Errors.DotClassExpected);
|
||||||
@ -2064,7 +2154,7 @@ public class JavacParser implements Parser {
|
|||||||
|
|
||||||
JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
|
JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
|
||||||
checkSourceLevel(Feature.METHOD_REFERENCES);
|
checkSourceLevel(Feature.METHOD_REFERENCES);
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
List<JCExpression> typeArgs = null;
|
List<JCExpression> typeArgs = null;
|
||||||
if (token.kind == LT) {
|
if (token.kind == LT) {
|
||||||
typeArgs = typeArguments(false);
|
typeArgs = typeArguments(false);
|
||||||
@ -2103,7 +2193,7 @@ public class JavacParser implements Parser {
|
|||||||
JCExpression t = qualident(true);
|
JCExpression t = qualident(true);
|
||||||
|
|
||||||
int oldmode = mode;
|
int oldmode = mode;
|
||||||
mode = TYPE;
|
selectTypeMode();
|
||||||
boolean diamondFound = false;
|
boolean diamondFound = false;
|
||||||
int lastTypeargsPos = -1;
|
int lastTypeargsPos = -1;
|
||||||
if (token.kind == LT) {
|
if (token.kind == LT) {
|
||||||
@ -2617,9 +2707,9 @@ public class JavacParser implements Parser {
|
|||||||
}
|
}
|
||||||
case BREAK: {
|
case BREAK: {
|
||||||
nextToken();
|
nextToken();
|
||||||
Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;
|
JCExpression value = token.kind == SEMI ? null : parseExpression();
|
||||||
accept(SEMI);
|
accept(SEMI);
|
||||||
JCBreak t = toP(F.at(pos).Break(label));
|
JCBreak t = toP(F.at(pos).Break(value));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
case CONTINUE: {
|
case CONTINUE: {
|
||||||
@ -2713,7 +2803,7 @@ public class JavacParser implements Parser {
|
|||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case CASE:
|
case CASE:
|
||||||
case DEFAULT:
|
case DEFAULT:
|
||||||
cases.append(switchBlockStatementGroup());
|
cases.appendList(switchBlockStatementGroup());
|
||||||
break;
|
break;
|
||||||
case RBRACE: case EOF:
|
case RBRACE: case EOF:
|
||||||
return cases.toList();
|
return cases.toList();
|
||||||
@ -2724,28 +2814,69 @@ public class JavacParser implements Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JCCase switchBlockStatementGroup() {
|
protected List<JCCase> switchBlockStatementGroup() {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
List<JCStatement> stats;
|
List<JCStatement> stats;
|
||||||
JCCase c;
|
JCCase c;
|
||||||
|
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
|
||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case CASE:
|
case CASE: {
|
||||||
nextToken();
|
nextToken();
|
||||||
JCExpression pat = parseExpression();
|
ListBuffer<JCExpression> pats = new ListBuffer<>();
|
||||||
accept(COLON);
|
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();
|
stats = blockStatements();
|
||||||
c = F.at(pos).Case(pat, stats);
|
}
|
||||||
|
c = F.at(pos).Case(caseKind, pats.toList(), stats, body);
|
||||||
if (stats.isEmpty())
|
if (stats.isEmpty())
|
||||||
storeEnd(c, S.prevToken().endPos);
|
storeEnd(c, S.prevToken().endPos);
|
||||||
return c;
|
return cases.append(c).toList();
|
||||||
case DEFAULT:
|
}
|
||||||
|
case DEFAULT: {
|
||||||
nextToken();
|
nextToken();
|
||||||
accept(COLON);
|
@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();
|
stats = blockStatements();
|
||||||
c = F.at(pos).Case(null, stats);
|
}
|
||||||
|
c = F.at(pos).Case(caseKind, List.nil(), stats, body);
|
||||||
if (stats.isEmpty())
|
if (stats.isEmpty())
|
||||||
storeEnd(c, S.prevToken().endPos);
|
storeEnd(c, S.prevToken().endPos);
|
||||||
return c;
|
return cases.append(c).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new AssertionError("should not reach here");
|
throw new AssertionError("should not reach here");
|
||||||
}
|
}
|
||||||
@ -2946,7 +3077,7 @@ public class JavacParser implements Parser {
|
|||||||
*/
|
*/
|
||||||
JCExpression annotationFieldValue() {
|
JCExpression annotationFieldValue() {
|
||||||
if (LAX_IDENTIFIER.accepts(token.kind)) {
|
if (LAX_IDENTIFIER.accepts(token.kind)) {
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
JCExpression t1 = term1();
|
JCExpression t1 = term1();
|
||||||
if (t1.hasTag(IDENT) && token.kind == EQ) {
|
if (t1.hasTag(IDENT) && token.kind == EQ) {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
@ -2988,7 +3119,7 @@ public class JavacParser implements Parser {
|
|||||||
accept(RBRACE);
|
accept(RBRACE);
|
||||||
return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
|
return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
|
||||||
default:
|
default:
|
||||||
mode = EXPR;
|
selectExprMode();
|
||||||
return term1();
|
return term1();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
# kind name an informative description of the kind of a declaration; see compiler.misc.kindname.*
|
# 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
|
# 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.*
|
# 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>
|
# type a Java type; e.g. int, X, X<T>
|
||||||
# url a URL
|
# url a URL
|
||||||
# object a Java object (unspecified)
|
# object a Java object (unspecified)
|
||||||
@ -187,6 +188,33 @@ compiler.err.bad.initializer=\
|
|||||||
compiler.err.break.outside.switch.loop=\
|
compiler.err.break.outside.switch.loop=\
|
||||||
break outside switch or 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
|
# 0: name
|
||||||
compiler.err.call.must.be.first.stmt.in.ctor=\
|
compiler.err.call.must.be.first.stmt.in.ctor=\
|
||||||
call to {0} must be first statement in constructor
|
call to {0} must be first statement in constructor
|
||||||
@ -799,12 +827,6 @@ compiler.err.name.reserved.for.internal.use=\
|
|||||||
compiler.err.native.meth.cant.have.body=\
|
compiler.err.native.meth.cant.have.body=\
|
||||||
native methods cannot have a 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
|
# 0: message segment
|
||||||
compiler.misc.incompatible.type.in.conditional=\
|
compiler.misc.incompatible.type.in.conditional=\
|
||||||
@ -814,6 +836,14 @@ compiler.misc.incompatible.type.in.conditional=\
|
|||||||
compiler.misc.conditional.target.cant.be.void=\
|
compiler.misc.conditional.target.cant.be.void=\
|
||||||
target-type for conditional expression cannot 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
|
# 0: message segment
|
||||||
compiler.misc.incompatible.ret.type.in.lambda=\
|
compiler.misc.incompatible.ret.type.in.lambda=\
|
||||||
bad return type in lambda expression\n\
|
bad return type in lambda expression\n\
|
||||||
@ -1289,6 +1319,9 @@ compiler.misc.cant.apply.diamond.1=\
|
|||||||
compiler.err.unreachable.stmt=\
|
compiler.err.unreachable.stmt=\
|
||||||
unreachable statement
|
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=\
|
compiler.err.initializer.must.be.able.to.complete.normally=\
|
||||||
initializer must be able to complete normally
|
initializer must be able to complete normally
|
||||||
|
|
||||||
@ -2579,6 +2612,22 @@ compiler.misc.kindname.static.init=\
|
|||||||
compiler.misc.kindname.instance.init=\
|
compiler.misc.kindname.instance.init=\
|
||||||
instance initializer
|
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=\
|
compiler.misc.no.args=\
|
||||||
@ -2768,6 +2817,15 @@ compiler.misc.feature.static.intf.method.invoke=\
|
|||||||
compiler.misc.feature.private.intf.methods=\
|
compiler.misc.feature.private.intf.methods=\
|
||||||
private interface 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=\
|
compiler.warn.underscore.as.identifier=\
|
||||||
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
||||||
|
|
||||||
@ -3257,6 +3315,14 @@ compiler.warn.leaks.not.accessible.unexported.qualified=\
|
|||||||
compiler.err.illegal.argument.for.option=\
|
compiler.err.illegal.argument.for.option=\
|
||||||
illegal argument for {0}: {1}
|
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
|
# messages previouly at javac.properties
|
||||||
|
@ -47,10 +47,12 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
|||||||
|
|
||||||
import javax.tools.JavaFileManager.Location;
|
import javax.tools.JavaFileManager.Location;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
import com.sun.source.tree.ModuleTree.ModuleKind;
|
import com.sun.source.tree.ModuleTree.ModuleKind;
|
||||||
import com.sun.tools.javac.code.Directive.ExportsDirective;
|
import com.sun.tools.javac.code.Directive.ExportsDirective;
|
||||||
import com.sun.tools.javac.code.Directive.OpensDirective;
|
import com.sun.tools.javac.code.Directive.OpensDirective;
|
||||||
import com.sun.tools.javac.code.Type.ModuleType;
|
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
|
* Root class for abstract syntax tree nodes. It provides definitions
|
||||||
@ -149,10 +151,14 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
*/
|
*/
|
||||||
SWITCH,
|
SWITCH,
|
||||||
|
|
||||||
/** Case parts in switch statements, of type Case.
|
/** Case parts in switch statements/expressions, of type Case.
|
||||||
*/
|
*/
|
||||||
CASE,
|
CASE,
|
||||||
|
|
||||||
|
/** Switch expression statements, of type Switch.
|
||||||
|
*/
|
||||||
|
SWITCH_EXPRESSION,
|
||||||
|
|
||||||
/** Synchronized statements, of type Synchonized.
|
/** Synchronized statements, of type Synchonized.
|
||||||
*/
|
*/
|
||||||
SYNCHRONIZED,
|
SYNCHRONIZED,
|
||||||
@ -1238,21 +1244,50 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
* A "case :" of a switch.
|
* A "case :" of a switch.
|
||||||
*/
|
*/
|
||||||
public static class JCCase extends JCStatement implements CaseTree {
|
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;
|
public List<JCStatement> stats;
|
||||||
protected JCCase(JCExpression pat, List<JCStatement> stats) {
|
public JCTree body;
|
||||||
this.pat = pat;
|
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.stats = stats;
|
||||||
|
this.body = body;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void accept(Visitor v) { v.visitCase(this); }
|
public void accept(Visitor v) { v.visitCase(this); }
|
||||||
|
|
||||||
@DefinedBy(Api.COMPILER_TREE)
|
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||||
public Kind getKind() { return Kind.CASE; }
|
public Kind getKind() { return Kind.CASE; }
|
||||||
@DefinedBy(Api.COMPILER_TREE)
|
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||||
public JCExpression getExpression() { return pat; }
|
public JCExpression getExpression() { return pats.head; }
|
||||||
@DefinedBy(Api.COMPILER_TREE)
|
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||||
public List<JCStatement> getStatements() { return stats; }
|
@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)
|
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||||
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
|
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
|
||||||
return v.visitCase(this, d);
|
return v.visitCase(this, d);
|
||||||
@ -1263,6 +1298,36 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* A synchronized block.
|
||||||
*/
|
*/
|
||||||
@ -1484,19 +1549,27 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
* A break from a loop or switch.
|
* A break from a loop or switch.
|
||||||
*/
|
*/
|
||||||
public static class JCBreak extends JCStatement implements BreakTree {
|
public static class JCBreak extends JCStatement implements BreakTree {
|
||||||
public Name label;
|
public JCExpression value;
|
||||||
public JCTree target;
|
public JCTree target;
|
||||||
protected JCBreak(Name label, JCTree target) {
|
protected JCBreak(JCExpression value, JCTree target) {
|
||||||
this.label = label;
|
this.value = value;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void accept(Visitor v) { v.visitBreak(this); }
|
public void accept(Visitor v) { v.visitBreak(this); }
|
||||||
|
public boolean isValueBreak() {
|
||||||
|
return target != null && target.hasTag(SWITCH_EXPRESSION);
|
||||||
|
}
|
||||||
|
|
||||||
@DefinedBy(Api.COMPILER_TREE)
|
@DefinedBy(Api.COMPILER_TREE)
|
||||||
public Kind getKind() { return Kind.BREAK; }
|
public Kind getKind() { return Kind.BREAK; }
|
||||||
@DefinedBy(Api.COMPILER_TREE)
|
@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)
|
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||||
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
|
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
|
||||||
return v.visitBreak(this, d);
|
return v.visitBreak(this, d);
|
||||||
@ -2934,9 +3007,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
|
|
||||||
/** (let int x = 3; in x+2) */
|
/** (let int x = 3; in x+2) */
|
||||||
public static class LetExpr extends JCExpression {
|
public static class LetExpr extends JCExpression {
|
||||||
public List<JCVariableDecl> defs;
|
public List<JCStatement> defs;
|
||||||
public JCExpression expr;
|
public JCExpression expr;
|
||||||
protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
|
protected LetExpr(List<JCStatement> defs, JCExpression expr) {
|
||||||
this.defs = defs;
|
this.defs = defs;
|
||||||
this.expr = expr;
|
this.expr = expr;
|
||||||
}
|
}
|
||||||
@ -2994,7 +3067,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body);
|
JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body);
|
||||||
JCLabeledStatement Labelled(Name label, JCStatement body);
|
JCLabeledStatement Labelled(Name label, JCStatement body);
|
||||||
JCSwitch Switch(JCExpression selector, List<JCCase> cases);
|
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);
|
JCSynchronized Synchronized(JCExpression lock, JCBlock body);
|
||||||
JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
|
JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
|
||||||
JCTry Try(List<JCTree> resources,
|
JCTry Try(List<JCTree> resources,
|
||||||
@ -3007,7 +3082,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
JCExpression elsepart);
|
JCExpression elsepart);
|
||||||
JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart);
|
JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart);
|
||||||
JCExpressionStatement Exec(JCExpression expr);
|
JCExpressionStatement Exec(JCExpression expr);
|
||||||
JCBreak Break(Name label);
|
JCBreak Break(JCExpression value);
|
||||||
JCContinue Continue(Name label);
|
JCContinue Continue(Name label);
|
||||||
JCReturn Return(JCExpression expr);
|
JCReturn Return(JCExpression expr);
|
||||||
JCThrow Throw(JCExpression expr);
|
JCThrow Throw(JCExpression expr);
|
||||||
@ -3049,7 +3124,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
|
JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
|
||||||
JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
|
JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
|
||||||
JCUses Uses(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.
|
/** A generic visitor class for trees.
|
||||||
@ -3070,6 +3145,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
public void visitLabelled(JCLabeledStatement that) { visitTree(that); }
|
public void visitLabelled(JCLabeledStatement that) { visitTree(that); }
|
||||||
public void visitSwitch(JCSwitch that) { visitTree(that); }
|
public void visitSwitch(JCSwitch that) { visitTree(that); }
|
||||||
public void visitCase(JCCase 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 visitSynchronized(JCSynchronized that) { visitTree(that); }
|
||||||
public void visitTry(JCTry that) { visitTree(that); }
|
public void visitTry(JCTry that) { visitTree(that); }
|
||||||
public void visitCatch(JCCatch that) { visitTree(that); }
|
public void visitCatch(JCCatch that) { visitTree(that); }
|
||||||
|
@ -27,6 +27,7 @@ package com.sun.tools.javac.tree;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
|
||||||
import com.sun.source.tree.ModuleTree.ModuleKind;
|
import com.sun.source.tree.ModuleTree.ModuleKind;
|
||||||
import com.sun.tools.javac.code.*;
|
import com.sun.tools.javac.code.*;
|
||||||
@ -835,18 +836,43 @@ public class Pretty extends JCTree.Visitor {
|
|||||||
|
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
try {
|
try {
|
||||||
if (tree.pat == null) {
|
if (tree.pats.isEmpty()) {
|
||||||
print("default");
|
print("default");
|
||||||
} else {
|
} else {
|
||||||
print("case ");
|
print("case ");
|
||||||
printExpr(tree.pat);
|
printExprs(tree.pats);
|
||||||
}
|
}
|
||||||
|
if (tree.caseKind == JCCase.STATEMENT) {
|
||||||
print(":");
|
print(":");
|
||||||
println();
|
println();
|
||||||
indent();
|
indent();
|
||||||
printStats(tree.stats);
|
printStats(tree.stats);
|
||||||
undent();
|
undent();
|
||||||
align();
|
align();
|
||||||
|
} else {
|
||||||
|
print(" -> ");
|
||||||
|
printStat(tree.stats.head);
|
||||||
|
}
|
||||||
|
} 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();
|
||||||
|
printStats(tree.cases);
|
||||||
|
align();
|
||||||
|
print("}");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
@ -956,7 +982,7 @@ public class Pretty extends JCTree.Visitor {
|
|||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
try {
|
try {
|
||||||
print("break");
|
print("break");
|
||||||
if (tree.label != null) print(" " + tree.label);
|
if (tree.value != null) print(" " + tree.value);
|
||||||
print(";");
|
print(";");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
|
@ -140,15 +140,17 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
|
|||||||
@DefinedBy(Api.COMPILER_TREE)
|
@DefinedBy(Api.COMPILER_TREE)
|
||||||
public JCTree visitBreak(BreakTree node, P p) {
|
public JCTree visitBreak(BreakTree node, P p) {
|
||||||
JCBreak t = (JCBreak) node;
|
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)
|
@DefinedBy(Api.COMPILER_TREE)
|
||||||
public JCTree visitCase(CaseTree node, P p) {
|
public JCTree visitCase(CaseTree node, P p) {
|
||||||
JCCase t = (JCCase) node;
|
JCCase t = (JCCase) node;
|
||||||
JCExpression pat = copy(t.pat, p);
|
List<JCExpression> pats = copy(t.pats, p);
|
||||||
List<JCStatement> stats = copy(t.stats, 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)
|
@DefinedBy(Api.COMPILER_TREE)
|
||||||
@ -370,6 +372,15 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
|
|||||||
return M.at(t.pos).Switch(selector, cases);
|
return M.at(t.pos).Switch(selector, cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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)
|
@DefinedBy(Api.COMPILER_TREE)
|
||||||
public JCTree visitSynchronized(SynchronizedTree node, P p) {
|
public JCTree visitSynchronized(SynchronizedTree node, P p) {
|
||||||
JCSynchronized t = (JCSynchronized) node;
|
JCSynchronized t = (JCSynchronized) node;
|
||||||
@ -559,7 +570,7 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
|
|||||||
switch (tree.getTag()) {
|
switch (tree.getTag()) {
|
||||||
case LETEXPR: {
|
case LETEXPR: {
|
||||||
LetExpr t = (LetExpr) node;
|
LetExpr t = (LetExpr) node;
|
||||||
List<JCVariableDecl> defs = copy(t.defs, p);
|
List<JCStatement> defs = copy(t.defs, p);
|
||||||
JCExpression expr = copy(t.expr, p);
|
JCExpression expr = copy(t.expr, p);
|
||||||
return M.at(t.pos).LetExpr(defs, expr);
|
return M.at(t.pos).LetExpr(defs, expr);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ package com.sun.tools.javac.tree;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree.CaseKind;
|
||||||
import com.sun.source.tree.ModuleTree.ModuleKind;
|
import com.sun.source.tree.ModuleTree.ModuleKind;
|
||||||
import com.sun.source.tree.Tree.Kind;
|
import com.sun.source.tree.Tree.Kind;
|
||||||
import com.sun.tools.javac.code.*;
|
import com.sun.tools.javac.code.*;
|
||||||
@ -273,8 +274,15 @@ public class TreeMaker implements JCTree.Factory {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JCCase Case(JCExpression pat, List<JCStatement> stats) {
|
public JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
|
||||||
JCCase tree = new JCCase(pat, stats);
|
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;
|
tree.pos = pos;
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
@ -325,7 +333,7 @@ public class TreeMaker implements JCTree.Factory {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JCBreak Break(Name label) {
|
public JCBreak Break(JCExpression label) {
|
||||||
JCBreak tree = new JCBreak(label, null);
|
JCBreak tree = new JCBreak(label, null);
|
||||||
tree.pos = pos;
|
tree.pos = pos;
|
||||||
return tree;
|
return tree;
|
||||||
@ -599,7 +607,7 @@ public class TreeMaker implements JCTree.Factory {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
|
public LetExpr LetExpr(List<JCStatement> defs, JCExpression expr) {
|
||||||
LetExpr tree = new LetExpr(defs, expr);
|
LetExpr tree = new LetExpr(defs, expr);
|
||||||
tree.pos = pos;
|
tree.pos = pos;
|
||||||
return tree;
|
return tree;
|
||||||
|
@ -176,10 +176,15 @@ public class TreeScanner extends Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
scan(tree.pat);
|
scan(tree.pats);
|
||||||
scan(tree.stats);
|
scan(tree.stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitSwitchExpression(JCSwitchExpression tree) {
|
||||||
|
scan(tree.selector);
|
||||||
|
scan(tree.cases);
|
||||||
|
}
|
||||||
|
|
||||||
public void visitSynchronized(JCSynchronized tree) {
|
public void visitSynchronized(JCSynchronized tree) {
|
||||||
scan(tree.lock);
|
scan(tree.lock);
|
||||||
scan(tree.body);
|
scan(tree.body);
|
||||||
@ -214,6 +219,7 @@ public class TreeScanner extends Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
|
scan(tree.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitContinue(JCContinue tree) {
|
public void visitContinue(JCContinue tree) {
|
||||||
|
@ -207,11 +207,17 @@ public class TreeTranslator extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
tree.pat = translate(tree.pat);
|
tree.pats = translate(tree.pats);
|
||||||
tree.stats = translate(tree.stats);
|
tree.stats = translate(tree.stats);
|
||||||
result = tree;
|
result = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitSwitchExpression(JCSwitchExpression tree) {
|
||||||
|
tree.selector = translate(tree.selector);
|
||||||
|
tree.cases = translateCases(tree.cases);
|
||||||
|
result = tree;
|
||||||
|
}
|
||||||
|
|
||||||
public void visitSynchronized(JCSynchronized tree) {
|
public void visitSynchronized(JCSynchronized tree) {
|
||||||
tree.lock = translate(tree.lock);
|
tree.lock = translate(tree.lock);
|
||||||
tree.body = translate(tree.body);
|
tree.body = translate(tree.body);
|
||||||
@ -252,6 +258,8 @@ public class TreeTranslator extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
tree.value = translate(tree.value);
|
||||||
result = tree;
|
result = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +427,7 @@ public class TreeTranslator extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitLetExpr(LetExpr tree) {
|
public void visitLetExpr(LetExpr tree) {
|
||||||
tree.defs = translateVarDefs(tree.defs);
|
tree.defs = translate(tree.defs);
|
||||||
tree.expr = translate(tree.expr);
|
tree.expr = translate(tree.expr);
|
||||||
result = tree;
|
result = tree;
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,10 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
|
|||||||
else if (arg instanceof Source) {
|
else if (arg instanceof Source) {
|
||||||
return ((Source)arg).name;
|
return ((Source)arg).name;
|
||||||
}
|
}
|
||||||
|
else if (arg instanceof Tag) {
|
||||||
|
return messages.getLocalizedString(l, "compiler.misc.tree.tag." +
|
||||||
|
StringUtils.toLowerCase(((Tag) arg).name()));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return String.valueOf(arg);
|
return String.valueOf(arg);
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,8 @@ public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter {
|
|||||||
s = "@" + rawDiagnosticPosHelper.getPosition((JCExpression)arg);
|
s = "@" + rawDiagnosticPosHelper.getPosition((JCExpression)arg);
|
||||||
} else if (arg instanceof PathFileObject) {
|
} else if (arg instanceof PathFileObject) {
|
||||||
s = ((PathFileObject) arg).getShortName();
|
s = ((PathFileObject) arg).getShortName();
|
||||||
|
} else if (arg instanceof Tag) {
|
||||||
|
s = "compiler.misc.tree.tag." + StringUtils.toLowerCase(((Tag) arg).name());
|
||||||
} else {
|
} else {
|
||||||
s = super.formatArgument(diag, arg, null);
|
s = super.formatArgument(diag, arg, null);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ class CompletenessAnalyzer {
|
|||||||
FOR(TokenKind.FOR, XSTMT1|XSTART), // for
|
FOR(TokenKind.FOR, XSTMT1|XSTART), // for
|
||||||
IF(TokenKind.IF, XSTMT1|XSTART), // if
|
IF(TokenKind.IF, XSTMT1|XSTART), // if
|
||||||
RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART), // return
|
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
|
SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL), // synchronized
|
||||||
THROW(TokenKind.THROW, XSTMT1|XSTART), // throw
|
THROW(TokenKind.THROW, XSTMT1|XSTART), // throw
|
||||||
TRY(TokenKind.TRY, XSTMT1|XSTART), // try
|
TRY(TokenKind.TRY, XSTMT1|XSTART), // try
|
||||||
|
@ -185,7 +185,12 @@ public class CompletenessTest extends KullaTesting {
|
|||||||
"int n,",
|
"int n,",
|
||||||
"int[] m = {1, 2},",
|
"int[] m = {1, 2},",
|
||||||
"int[] m = {1, 2}, n = {3, 4},",
|
"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[] {
|
static final String[] unknown = new String[] {
|
||||||
|
@ -65,6 +65,13 @@ public class Diagnostics implements javax.tools.DiagnosticListener<JavaFileObjec
|
|||||||
.anyMatch(d -> d.getCode().equals(key));
|
.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 */
|
/** Get the error keys */
|
||||||
public List<String> errorKeys() {
|
public List<String> errorKeys() {
|
||||||
return diags.stream()
|
return diags.stream()
|
||||||
|
@ -178,6 +178,14 @@ public abstract class JavacTemplateTestBase {
|
|||||||
fail("Expected successful compilation");
|
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,
|
* If the provided boolean is true, assert all previous compiles succeeded,
|
||||||
* otherwise assert that a compile failed.
|
* otherwise assert that a compile failed.
|
||||||
@ -196,9 +204,22 @@ public abstract class JavacTemplateTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Assert that a previous call to compile() failed with a specific error key */
|
/** 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())
|
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 */
|
/** Assert that a previous call to compile() failed with all of the specified error keys */
|
||||||
|
@ -4,13 +4,17 @@
|
|||||||
* @summary The compiler was allowing void types in its parsing of conditional expressions.
|
* @summary The compiler was allowing void types in its parsing of conditional expressions.
|
||||||
* @author tball
|
* @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 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.
|
// Should fail to compile since Object.wait() has a void return type. Poly case.
|
||||||
System.out.println(o instanceof String ? o.hashCode() : o.wait());
|
System.out.println(o instanceof String ? o.hashCode() : o.wait());
|
||||||
// Should fail to compile since Object.wait() has a void return type. Standalone case.
|
// Should fail to compile since Object.wait() has a void return type. Standalone case.
|
||||||
(o instanceof String ? o.hashCode() : o.wait()).toString();
|
(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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
ConditionalWithVoid.java:12:71: compiler.err.void.not.allowed.here
|
ConditionalWithVoid.java:12:71: compiler.err.void.not.allowed.here
|
||||||
ConditionalWithVoid.java:14:30: compiler.err.neither.conditional.subtype: java.lang.Integer, void
|
ConditionalWithVoid.java:14:53: compiler.err.void.not.allowed.here
|
||||||
2 errors
|
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
|
||||||
|
@ -61,6 +61,7 @@ import com.sun.tools.javac.tree.JCTree.JCExpression;
|
|||||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCModifiers;
|
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.JCVariableDecl;
|
||||||
import com.sun.tools.javac.tree.JCTree.LetExpr;
|
import com.sun.tools.javac.tree.JCTree.LetExpr;
|
||||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||||
@ -327,8 +328,8 @@ public class BoxingAndSuper {
|
|||||||
if (tree.hasTag(Tag.LETEXPR)) {
|
if (tree.hasTag(Tag.LETEXPR)) {
|
||||||
LetExpr le = (LetExpr) tree;
|
LetExpr le = (LetExpr) tree;
|
||||||
|
|
||||||
for (JCVariableDecl var : le.defs) {
|
for (JCStatement var : le.defs) {
|
||||||
letExprRemap.put(var.name.toString(), "$le" + i++);
|
letExprRemap.put(((JCVariableDecl) var).name.toString(), "$le" + i++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visitOther(node, p);
|
return super.visitOther(node, p);
|
||||||
|
@ -302,6 +302,7 @@ public class CheckResourceKeys {
|
|||||||
// prefix/embedded strings
|
// prefix/embedded strings
|
||||||
"compiler.",
|
"compiler.",
|
||||||
"compiler.misc.",
|
"compiler.misc.",
|
||||||
|
"compiler.misc.tree.tag.",
|
||||||
"opt.Xlint.desc.",
|
"opt.Xlint.desc.",
|
||||||
"count.",
|
"count.",
|
||||||
"illegal.",
|
"illegal.",
|
||||||
|
@ -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) { }
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; };
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
test/langtools/tools/javac/diags/examples/NotExhaustive.java
Normal file
35
test/langtools/tools/javac/diags/examples/NotExhaustive.java
Normal file
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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 {}
|
||||||
|
}
|
@ -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; };
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,14 +21,14 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.err.neither.conditional.subtype
|
// key: compiler.err.switch.null.not.allowed
|
||||||
|
|
||||||
class NeitherConditionalSubtype {
|
class SwitchNullNotAllowed {
|
||||||
public int test(boolean cond, Object o) {
|
|
||||||
// Should fail to compile since Object.wait() has a void return type.
|
void test(Integer i) {
|
||||||
(o instanceof String ? o.hashCode() : o.wait()).toString();
|
switch (i) {
|
||||||
return 0;
|
case null: break;
|
||||||
|
case 0: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
test/langtools/tools/javac/diags/examples/SwitchRules.java
Normal file
34
test/langtools/tools/javac/diags/examples/SwitchRules.java
Normal file
@ -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; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
250
test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java
Normal file
250
test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
6
test/langtools/tools/javac/expswitch/TEST.properties
Normal file
6
test/langtools/tools/javac/expswitch/TEST.properties
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
TestNG.dirs = .
|
||||||
|
|
||||||
|
lib.dirs = /lib/combo
|
||||||
|
|
||||||
|
modules = \
|
||||||
|
jdk.compiler/com.sun.tools.javac.util
|
@ -95,6 +95,7 @@ import com.sun.tools.javac.code.Symbol;
|
|||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.tree.EndPosTable;
|
import com.sun.tools.javac.tree.EndPosTable;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
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.JCCompilationUnit;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCImport;
|
import com.sun.tools.javac.tree.JCTree.JCImport;
|
||||||
import com.sun.tools.javac.tree.TreeInfo;
|
import com.sun.tools.javac.tree.TreeInfo;
|
||||||
@ -446,6 +447,12 @@ public class CheckAttributedTree {
|
|||||||
scan(tree.defs);
|
scan(tree.defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBreak(JCBreak tree) {
|
||||||
|
if (tree.isValueBreak())
|
||||||
|
super.visitBreak(tree);
|
||||||
|
}
|
||||||
|
|
||||||
JavaFileObject sourcefile;
|
JavaFileObject sourcefile;
|
||||||
EndPosTable endPosTable;
|
EndPosTable endPosTable;
|
||||||
Info encl;
|
Info encl;
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -737,7 +737,7 @@ public class DPrinter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCase(JCCase tree) {
|
public void visitCase(JCCase tree) {
|
||||||
printTree("pat", tree.pat);
|
printList("pat", tree.pats);
|
||||||
printList("stats", tree.stats);
|
printList("stats", tree.stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,7 +782,7 @@ public class DPrinter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBreak(JCBreak tree) {
|
public void visitBreak(JCBreak tree) {
|
||||||
printName("label", tree.label);
|
printTree("value", tree.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,6 +82,9 @@ import javax.tools.JavaFileObject;
|
|||||||
import javax.tools.SimpleJavaFileObject;
|
import javax.tools.SimpleJavaFileObject;
|
||||||
import javax.tools.ToolProvider;
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
import com.sun.source.tree.CaseTree;
|
||||||
|
import com.sun.source.util.TreePathScanner;
|
||||||
|
|
||||||
public class JavacParserTest extends TestCase {
|
public class JavacParserTest extends TestCase {
|
||||||
static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
||||||
static final JavaFileManager fm = tool.getStandardFileManager(null, null, null);
|
static final JavaFileManager fm = tool.getStandardFileManager(null, null, null);
|
||||||
@ -1038,6 +1041,135 @@ public class JavacParserTest extends TestCase {
|
|||||||
assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
|
assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
void testTypeParamsWithoutMethod() throws IOException {
|
void testTypeParamsWithoutMethod() throws IOException {
|
||||||
assert tool != null;
|
assert tool != null;
|
||||||
|
52
test/langtools/tools/javac/switchexpr/BlockExpression.java
Normal file
52
test/langtools/tools/javac/switchexpr/BlockExpression.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
101
test/langtools/tools/javac/switchexpr/BreakTest.java
Normal file
101
test/langtools/tools/javac/switchexpr/BreakTest.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
test/langtools/tools/javac/switchexpr/EmptySwitch.java
Normal file
39
test/langtools/tools/javac/switchexpr/EmptySwitch.java
Normal file
@ -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 {
|
||||||
|
}
|
||||||
|
}
|
4
test/langtools/tools/javac/switchexpr/EmptySwitch.out
Normal file
4
test/langtools/tools/javac/switchexpr/EmptySwitch.out
Normal file
@ -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
|
@ -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;
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
@ -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
|
115
test/langtools/tools/javac/switchexpr/ExpressionSwitch.java
Normal file
115
test/langtools/tools/javac/switchexpr/ExpressionSwitch.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
185
test/langtools/tools/javac/switchexpr/ExpressionSwitchDA.java
Normal file
185
test/langtools/tools/javac/switchexpr/ExpressionSwitchDA.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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
|
99
test/langtools/tools/javac/switchexpr/ParseIncomplete.java
Normal file
99
test/langtools/tools/javac/switchexpr/ParseIncomplete.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
test/langtools/tools/javac/switchexpr/ParserRecovery.java
Normal file
15
test/langtools/tools/javac/switchexpr/ParserRecovery.java
Normal file
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
5
test/langtools/tools/javac/switchexpr/ParserRecovery.out
Normal file
5
test/langtools/tools/javac/switchexpr/ParserRecovery.out
Normal file
@ -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
|
@ -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; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
test/langtools/tools/javac/switchextra/CaseTest.java
Normal file
157
test/langtools/tools/javac/switchextra/CaseTest.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user