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