8282274: Compiler implementation for Pattern Matching for switch (Third Preview)
Co-authored-by: Brian Goetz <briangoetz@openjdk.org> Co-authored-by: Jan Lahoda <jlahoda@openjdk.org> Reviewed-by: mcimadamore, vromero, abimpoudis
This commit is contained in:
parent
2d34acfec9
commit
0155e4b76b
66
src/java.base/share/classes/java/lang/MatchException.java
Normal file
66
src/java.base/share/classes/java/lang/MatchException.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 java.lang;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* Thrown to indicate an unexpected failure in pattern matching.
|
||||
*
|
||||
* {@code MatchException} may be thrown when an exhaustive pattern matching language construct
|
||||
* (such as a switch expression) encounters a value that does not match any of the provided
|
||||
* patterns at runtime. This can currently arise for separate compilation anomalies,
|
||||
* where a sealed interface has a different set of permitted subtypes at runtime than
|
||||
* it had at compilation time, an enum has a different set of constants at runtime than
|
||||
* it had at compilation time, or the type hierarchy has changed in incompatible ways between
|
||||
* compile time and run time.
|
||||
*
|
||||
* @jls 14.11.3 Execution of a switch Statement
|
||||
* @jls 14.30.2 Pattern Matching
|
||||
* @jls 15.28.2 Run-Time Evaluation of switch Expressions
|
||||
*
|
||||
* @since 19
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING)
|
||||
public final class MatchException extends RuntimeException {
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* Constructs an {@code MatchException} with the specified detail message and
|
||||
* cause.
|
||||
*
|
||||
* @param message the detail message (which is saved for later retrieval
|
||||
* by the {@link #getMessage()} method).
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link #getCause()} method). (A {@code null} value is
|
||||
* permitted, and indicates that the cause is nonexistent or
|
||||
* unknown.)
|
||||
*/
|
||||
public MatchException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
@ -25,10 +25,23 @@
|
||||
|
||||
package com.sun.source.tree;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A tree node used as the base class for the different kinds of
|
||||
* patterns.
|
||||
*
|
||||
* @since 16
|
||||
*/
|
||||
public interface PatternTree extends Tree, CaseLabelTree {}
|
||||
public interface PatternTree extends Tree, CaseLabelTree {
|
||||
|
||||
/**
|
||||
* The guard for the case.
|
||||
*
|
||||
* @return the guard
|
||||
* @since 19
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
ExpressionTree getGuard();
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, 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
|
||||
@ -228,14 +228,6 @@ public interface Tree {
|
||||
*/
|
||||
BINDING_PATTERN(BindingPatternTree.class),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link GuardedPatternTree}.
|
||||
*
|
||||
* @since 17
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
GUARDED_PATTERN(GuardedPatternTree.class),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link ParenthesizedPatternTree}.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, 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
|
||||
@ -302,16 +302,6 @@ public interface TreeVisitor<R,P> {
|
||||
*/
|
||||
R visitNewArray(NewArrayTree node, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code GuardPatternTree} node.
|
||||
* @param node the node being visited
|
||||
* @param p a parameter value
|
||||
* @return a result value
|
||||
* @since 17
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
R visitGuardedPattern(GuardedPatternTree node, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code ParenthesizedPatternTree} node.
|
||||
* @param node the node being visited
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, 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
|
||||
@ -703,22 +703,6 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation calls {@code defaultAction}.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of {@code defaultAction}
|
||||
* @since 17
|
||||
*/
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
public R visitGuardedPattern(GuardedPatternTree node, P p) {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, 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
|
||||
@ -771,7 +771,9 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
||||
*/
|
||||
@Override
|
||||
public R visitBindingPattern(BindingPatternTree node, P p) {
|
||||
return scan(node.getVariable(), p);
|
||||
R r = scan(node.getVariable(), p);
|
||||
r = scanAndReduce(node.getGuard(), p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -833,24 +835,9 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
public R visitParenthesizedPattern(ParenthesizedPatternTree node, P p) {
|
||||
return scan(node.getPattern(), p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation scans the children in left to right order.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of scanning
|
||||
* @since 17
|
||||
*/
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
public R visitGuardedPattern(GuardedPatternTree node, P p) {
|
||||
R r = scan(node.getPattern(), p);
|
||||
return scanAndReduce(node.getExpression(), p, r);
|
||||
r = scanAndReduce(node.getGuard(), p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, 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
|
||||
@ -186,6 +186,7 @@ public class Preview {
|
||||
return switch (feature) {
|
||||
case CASE_NULL -> true;
|
||||
case PATTERN_SWITCH -> true;
|
||||
case UNCONDITIONAL_PATTERN_IN_INSTANCEOF -> 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'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2022, 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
|
||||
@ -239,6 +239,7 @@ public enum Source {
|
||||
CASE_NULL(JDK17, Fragments.FeatureCaseNull, DiagKind.NORMAL),
|
||||
PATTERN_SWITCH(JDK17, Fragments.FeaturePatternSwitch, DiagKind.PLURAL),
|
||||
REDUNDANT_STRICTFP(JDK17),
|
||||
UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK19, Fragments.FeatureUnconditionalPatternsInInstanceof, DiagKind.PLURAL),
|
||||
;
|
||||
|
||||
enum DiagKind {
|
||||
|
@ -189,6 +189,7 @@ public class Symtab {
|
||||
public final Type assertionErrorType;
|
||||
public final Type incompatibleClassChangeErrorType;
|
||||
public final Type cloneNotSupportedExceptionType;
|
||||
public final Type matchExceptionType;
|
||||
public final Type annotationType;
|
||||
public final TypeSymbol enumSym;
|
||||
public final Type listType;
|
||||
@ -553,6 +554,7 @@ public class Symtab {
|
||||
assertionErrorType = enterClass("java.lang.AssertionError");
|
||||
incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError");
|
||||
cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
|
||||
matchExceptionType = enterClass("java.lang.MatchException");
|
||||
annotationType = enterClass("java.lang.annotation.Annotation");
|
||||
classLoaderType = enterClass("java.lang.ClassLoader");
|
||||
enumSym = enterClass(java_base, names.java_lang_Enum);
|
||||
|
@ -174,6 +174,8 @@ public class Attr extends JCTree.Visitor {
|
||||
allowRecords = Feature.RECORDS.allowedInSource(source);
|
||||
allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
|
||||
Feature.PATTERN_SWITCH.allowedInSource(source);
|
||||
allowUnconditionalPatternsInstanceOf = (preview.isEnabled() || !preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) &&
|
||||
Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF.allowedInSource(source);
|
||||
sourceName = source.name;
|
||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||
|
||||
@ -218,6 +220,10 @@ public class Attr extends JCTree.Visitor {
|
||||
*/
|
||||
private final boolean allowPatternSwitch;
|
||||
|
||||
/** Are unconditional patterns in instanceof allowed
|
||||
*/
|
||||
private final boolean allowUnconditionalPatternsInstanceOf;
|
||||
|
||||
/**
|
||||
* Switch: warn about use of variable before declaration?
|
||||
* RFE: 6425594
|
||||
@ -1691,7 +1697,8 @@ public class Attr extends JCTree.Visitor {
|
||||
List<Type> coveredTypesForPatterns = List.nil();
|
||||
List<Type> coveredTypesForConstants = List.nil();
|
||||
boolean hasDefault = false; // Is there a default label?
|
||||
boolean hasTotalPattern = false; // Is there a total pattern?
|
||||
boolean hasUnconditionalPattern = false; // Is there a unconditional pattern?
|
||||
boolean lastPatternErroneous = false; // Has the last pattern erroneous type?
|
||||
boolean hasNullPattern = false; // Is there a null pattern?
|
||||
CaseTree.CaseKind caseKind = null;
|
||||
boolean wasError = false;
|
||||
@ -1706,7 +1713,7 @@ public class Attr extends JCTree.Visitor {
|
||||
wasError = true;
|
||||
}
|
||||
MatchBindings currentBindings = prevBindings;
|
||||
boolean wasTotalPattern = hasTotalPattern;
|
||||
boolean wasUnconditionalPattern = hasUnconditionalPattern;
|
||||
for (JCCaseLabel pat : c.labels) {
|
||||
if (pat.isExpression()) {
|
||||
JCExpression expr = (JCExpression) pat;
|
||||
@ -1714,7 +1721,7 @@ public class Attr extends JCTree.Visitor {
|
||||
preview.checkSourceLevel(expr.pos(), Feature.CASE_NULL);
|
||||
if (hasNullPattern) {
|
||||
log.error(pat.pos(), Errors.DuplicateCaseLabel);
|
||||
} else if (wasTotalPattern) {
|
||||
} else if (wasUnconditionalPattern) {
|
||||
log.error(pat.pos(), Errors.PatternDominated);
|
||||
}
|
||||
hasNullPattern = true;
|
||||
@ -1767,42 +1774,57 @@ public class Attr extends JCTree.Visitor {
|
||||
} else if (pat.hasTag(DEFAULTCASELABEL)) {
|
||||
if (hasDefault) {
|
||||
log.error(pat.pos(), Errors.DuplicateDefaultLabel);
|
||||
} else if (hasTotalPattern) {
|
||||
log.error(pat.pos(), Errors.TotalPatternAndDefault);
|
||||
} else if (hasUnconditionalPattern) {
|
||||
log.error(pat.pos(), Errors.UnconditionalPatternAndDefault);
|
||||
}
|
||||
hasDefault = true;
|
||||
matchBindings = MatchBindingsComputer.EMPTY;
|
||||
} else {
|
||||
//binding pattern
|
||||
attribExpr(pat, switchEnv);
|
||||
var primary = TreeInfo.primaryPatternType((JCPattern) pat);
|
||||
Type primaryType = primary.type();
|
||||
Type primaryType = TreeInfo.primaryPatternType(pat);
|
||||
if (!primaryType.hasTag(TYPEVAR)) {
|
||||
primaryType = chk.checkClassOrArrayType(pat.pos(), primaryType);
|
||||
}
|
||||
checkCastablePattern(pat.pos(), seltype, primaryType);
|
||||
Type patternType = types.erasure(primaryType);
|
||||
boolean isTotal = primary.unconditional() &&
|
||||
!patternType.isErroneous() &&
|
||||
types.isSubtype(types.erasure(seltype), patternType);
|
||||
if (isTotal) {
|
||||
if (hasTotalPattern) {
|
||||
log.error(pat.pos(), Errors.DuplicateTotalPattern);
|
||||
} else if (hasDefault) {
|
||||
log.error(pat.pos(), Errors.TotalPatternAndDefault);
|
||||
JCExpression guard = ((JCPattern) pat).guard;
|
||||
if (guard != null) {
|
||||
MatchBindings afterPattern = matchBindings;
|
||||
Env<AttrContext> bodyEnv = bindingEnv(env, matchBindings.bindingsWhenTrue);
|
||||
try {
|
||||
attribExpr(guard, bodyEnv, syms.booleanType);
|
||||
} finally {
|
||||
bodyEnv.info.scope.leave();
|
||||
}
|
||||
hasTotalPattern = true;
|
||||
matchBindings = matchBindingsComputer.caseGuard(c, afterPattern, matchBindings);
|
||||
}
|
||||
boolean unguarded = TreeInfo.unguardedCaseLabel(pat);
|
||||
boolean unconditional =
|
||||
unguarded &&
|
||||
!patternType.isErroneous() &&
|
||||
types.isSubtype(types.boxedTypeOrType(types.erasure(seltype)),
|
||||
patternType);
|
||||
if (unconditional) {
|
||||
if (hasUnconditionalPattern) {
|
||||
log.error(pat.pos(), Errors.DuplicateUnconditionalPattern);
|
||||
} else if (hasDefault) {
|
||||
log.error(pat.pos(), Errors.UnconditionalPatternAndDefault);
|
||||
}
|
||||
hasUnconditionalPattern = true;
|
||||
}
|
||||
lastPatternErroneous = patternType.isErroneous();
|
||||
checkCaseLabelDominated(pat.pos(), coveredTypesForPatterns, patternType);
|
||||
if (!patternType.isErroneous()) {
|
||||
coveredTypesForConstants = coveredTypesForConstants.prepend(patternType);
|
||||
if (primary.unconditional()) {
|
||||
if (unguarded) {
|
||||
coveredTypesForPatterns = coveredTypesForPatterns.prepend(patternType);
|
||||
}
|
||||
}
|
||||
}
|
||||
currentBindings = matchBindingsComputer.switchCase(pat, currentBindings, matchBindings);
|
||||
}
|
||||
|
||||
Env<AttrContext> caseEnv =
|
||||
bindingEnv(switchEnv, c, currentBindings.bindingsWhenTrue);
|
||||
try {
|
||||
@ -1822,10 +1844,12 @@ public class Attr extends JCTree.Visitor {
|
||||
chk.checkSwitchCaseStructure(cases);
|
||||
}
|
||||
if (switchTree.hasTag(SWITCH)) {
|
||||
((JCSwitch) switchTree).hasTotalPattern = hasDefault || hasTotalPattern;
|
||||
((JCSwitch) switchTree).hasUnconditionalPattern =
|
||||
hasDefault || hasUnconditionalPattern || lastPatternErroneous;
|
||||
((JCSwitch) switchTree).patternSwitch = patternSwitch;
|
||||
} else if (switchTree.hasTag(SWITCH_EXPRESSION)) {
|
||||
((JCSwitchExpression) switchTree).hasTotalPattern = hasDefault || hasTotalPattern;
|
||||
((JCSwitchExpression) switchTree).hasUnconditionalPattern =
|
||||
hasDefault || hasUnconditionalPattern || lastPatternErroneous;
|
||||
((JCSwitchExpression) switchTree).patternSwitch = patternSwitch;
|
||||
} else {
|
||||
Assert.error(switchTree.getTag().name());
|
||||
@ -4095,7 +4119,11 @@ public class Attr extends JCTree.Visitor {
|
||||
clazztype = tree.pattern.type;
|
||||
if (types.isSubtype(exprtype, clazztype) &&
|
||||
!exprtype.isErroneous() && !clazztype.isErroneous()) {
|
||||
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(exprtype, clazztype));
|
||||
if (!allowUnconditionalPatternsInstanceOf) {
|
||||
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(exprtype, clazztype));
|
||||
} else if (preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) {
|
||||
preview.warnPreview(tree.pattern.pos(), Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF);
|
||||
}
|
||||
}
|
||||
typeTree = TreeInfo.primaryPatternTree((JCPattern) tree.pattern).var.vartype;
|
||||
} else {
|
||||
@ -4131,6 +4159,10 @@ public class Attr extends JCTree.Visitor {
|
||||
chk.basicHandler.report(pos,
|
||||
diags.fragment(Fragments.InconvertibleTypes(exprType, pattType)));
|
||||
return false;
|
||||
} else if (exprType.isPrimitive() ^ pattType.isPrimitive()) {
|
||||
chk.basicHandler.report(pos,
|
||||
diags.fragment(Fragments.NotApplicableTypes(exprType, pattType)));
|
||||
return false;
|
||||
} else if (warner.hasLint(LintCategory.UNCHECKED)) {
|
||||
log.error(pos,
|
||||
Errors.InstanceofReifiableNotSafe(exprType, pattType));
|
||||
@ -4163,20 +4195,6 @@ public class Attr extends JCTree.Visitor {
|
||||
result = tree.type = tree.pattern.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern tree) {
|
||||
attribExpr(tree.patt, env);
|
||||
MatchBindings afterPattern = matchBindings;
|
||||
Env<AttrContext> bodyEnv = bindingEnv(env, matchBindings.bindingsWhenTrue);
|
||||
try {
|
||||
attribExpr(tree.expr, bodyEnv, syms.booleanType);
|
||||
} finally {
|
||||
bodyEnv.info.scope.leave();
|
||||
}
|
||||
result = tree.type = tree.patt.type;
|
||||
matchBindings = matchBindingsComputer.guardedPattern(tree, afterPattern, matchBindings);
|
||||
}
|
||||
|
||||
public void visitIndexed(JCArrayAccess tree) {
|
||||
Type owntype = types.createErrorType(tree.type);
|
||||
Type atype = attribExpr(tree.indexed, env);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -39,7 +39,6 @@ import com.sun.tools.javac.code.Source.Feature;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
|
||||
import com.sun.tools.javac.tree.*;
|
||||
import com.sun.tools.javac.tree.TreeInfo.PatternPrimaryType;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.Error;
|
||||
@ -671,7 +670,9 @@ public class Flow {
|
||||
JCCase c = l.head;
|
||||
for (JCCaseLabel pat : c.labels) {
|
||||
scan(pat);
|
||||
handleConstantCaseLabel(constants, pat);
|
||||
if (TreeInfo.unguardedCaseLabel(pat)) {
|
||||
handleConstantCaseLabel(constants, pat);
|
||||
}
|
||||
}
|
||||
scanStats(c.stats);
|
||||
if (alive != Liveness.DEAD && c.caseKind == JCCase.RULE) {
|
||||
@ -686,7 +687,7 @@ public class Flow {
|
||||
l.tail.head.pos(),
|
||||
Warnings.PossibleFallThroughIntoCase);
|
||||
}
|
||||
tree.isExhaustive = tree.hasTotalPattern ||
|
||||
tree.isExhaustive = tree.hasUnconditionalPattern ||
|
||||
TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases);
|
||||
if (exhaustiveSwitch) {
|
||||
tree.isExhaustive |= isExhaustive(tree.selector.pos(), tree.selector.type, constants);
|
||||
@ -694,7 +695,7 @@ public class Flow {
|
||||
log.error(tree, Errors.NotExhaustiveStatement);
|
||||
}
|
||||
}
|
||||
if (!tree.hasTotalPattern) {
|
||||
if (!tree.hasUnconditionalPattern) {
|
||||
alive = Liveness.ALIVE;
|
||||
}
|
||||
alive = alive.or(resolveBreaks(tree, prevPendingExits));
|
||||
@ -712,7 +713,9 @@ public class Flow {
|
||||
JCCase c = l.head;
|
||||
for (JCCaseLabel pat : c.labels) {
|
||||
scan(pat);
|
||||
handleConstantCaseLabel(constants, pat);
|
||||
if (TreeInfo.unguardedCaseLabel(pat)) {
|
||||
handleConstantCaseLabel(constants, pat);
|
||||
}
|
||||
}
|
||||
scanStats(c.stats);
|
||||
if (alive == Liveness.ALIVE) {
|
||||
@ -725,7 +728,7 @@ public class Flow {
|
||||
}
|
||||
}
|
||||
}
|
||||
tree.isExhaustive = tree.hasTotalPattern ||
|
||||
tree.isExhaustive = tree.hasUnconditionalPattern ||
|
||||
TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) ||
|
||||
isExhaustive(tree.selector.pos(), tree.selector.type, constants);
|
||||
if (!tree.isExhaustive) {
|
||||
@ -742,11 +745,9 @@ public class Flow {
|
||||
if (expr.hasTag(IDENT) && ((JCIdent) expr).sym.isEnum())
|
||||
constants.add(((JCIdent) expr).sym);
|
||||
} else if (pat.isPattern()) {
|
||||
PatternPrimaryType patternType = TreeInfo.primaryPatternType((JCPattern) pat);
|
||||
Type primaryType = TreeInfo.primaryPatternType(pat);
|
||||
|
||||
if (patternType.unconditional()) {
|
||||
constants.add(patternType.type().tsym);
|
||||
}
|
||||
constants.add(primaryType.tsym);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2014,6 +2015,14 @@ public class Flow {
|
||||
scanExpr(l.head);
|
||||
}
|
||||
|
||||
void scanPattern(JCTree tree) {
|
||||
scan(tree);
|
||||
if (inits.isReset()) {
|
||||
inits.assign(initsWhenTrue);
|
||||
uninits.assign(uninitsWhenTrue);
|
||||
}
|
||||
}
|
||||
|
||||
/** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
|
||||
* rather than (un)inits on exit.
|
||||
*/
|
||||
@ -2454,11 +2463,7 @@ public class Flow {
|
||||
uninits.assign(uninits.andSet(uninitsSwitch));
|
||||
JCCase c = l.head;
|
||||
for (JCCaseLabel pat : c.labels) {
|
||||
scan(pat);
|
||||
if (inits.isReset()) {
|
||||
inits.assign(initsWhenTrue);
|
||||
uninits.assign(uninitsWhenTrue);
|
||||
}
|
||||
scanPattern(pat);
|
||||
}
|
||||
if (l.head.stats.isEmpty() &&
|
||||
l.tail.nonEmpty() &&
|
||||
@ -2847,8 +2852,9 @@ public class Flow {
|
||||
|
||||
@Override
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
super.visitBindingPattern(tree);
|
||||
scan(tree.var);
|
||||
initParam(tree.var);
|
||||
scan(tree.guard);
|
||||
}
|
||||
|
||||
void referenced(Symbol sym) {
|
||||
@ -2940,7 +2946,7 @@ public class Flow {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUARDPATTERN:
|
||||
case BINDINGPATTERN, PARENTHESIZEDPATTERN:
|
||||
case LAMBDA:
|
||||
if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
|
||||
reportEffectivelyFinalError(pos, sym);
|
||||
@ -2964,7 +2970,7 @@ public class Flow {
|
||||
reportInnerClsNeedsFinalError(tree, sym);
|
||||
break;
|
||||
}
|
||||
case GUARDPATTERN:
|
||||
case CASE:
|
||||
case LAMBDA:
|
||||
reportEffectivelyFinalError(tree, sym);
|
||||
}
|
||||
@ -2975,7 +2981,7 @@ public class Flow {
|
||||
void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
|
||||
Fragment subKey = switch (currentTree.getTag()) {
|
||||
case LAMBDA -> Fragments.Lambda;
|
||||
case GUARDPATTERN -> Fragments.Guard;
|
||||
case BINDINGPATTERN, PARENTHESIZEDPATTERN -> Fragments.Guard;
|
||||
case CLASSDEF -> Fragments.InnerCls;
|
||||
default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag());
|
||||
};
|
||||
@ -3015,12 +3021,24 @@ public class Flow {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern tree) {
|
||||
scan(tree.patt);
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
scan(tree.var);
|
||||
JCTree prevTree = currentTree;
|
||||
try {
|
||||
currentTree = tree;
|
||||
scan(tree.expr);
|
||||
scan(tree.guard);
|
||||
} finally {
|
||||
currentTree = prevTree;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
|
||||
scan(tree.pattern);
|
||||
JCTree prevTree = currentTree;
|
||||
try {
|
||||
currentTree = tree;
|
||||
scan(tree.guard);
|
||||
} finally {
|
||||
currentTree = prevTree;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -3615,20 +3615,26 @@ public class Lower extends TreeTranslator {
|
||||
}
|
||||
|
||||
public void visitSwitch(JCSwitch tree) {
|
||||
List<JCCase> cases = tree.patternSwitch ? addDefaultIfNeeded(tree.cases) : tree.cases;
|
||||
boolean matchException = tree.patternSwitch && !tree.wasEnumSelector;
|
||||
List<JCCase> cases = tree.patternSwitch ? addDefaultIfNeeded(matchException, tree.cases)
|
||||
: tree.cases;
|
||||
handleSwitch(tree, tree.selector, cases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitchExpression(JCSwitchExpression tree) {
|
||||
List<JCCase> cases = addDefaultIfNeeded(tree.cases);
|
||||
boolean matchException = tree.patternSwitch && !tree.wasEnumSelector;
|
||||
List<JCCase> cases = addDefaultIfNeeded(matchException, tree.cases);
|
||||
handleSwitch(tree, tree.selector, cases);
|
||||
}
|
||||
|
||||
private List<JCCase> addDefaultIfNeeded(List<JCCase> cases) {
|
||||
private List<JCCase> addDefaultIfNeeded(boolean matchException, List<JCCase> cases) {
|
||||
if (cases.stream().flatMap(c -> c.labels.stream()).noneMatch(p -> p.hasTag(Tag.DEFAULTCASELABEL))) {
|
||||
JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
|
||||
List.nil()));
|
||||
Type exception = matchException ? syms.matchExceptionType
|
||||
: syms.incompatibleClassChangeErrorType;
|
||||
List<JCExpression> params = matchException ? List.of(makeNull(), makeNull())
|
||||
: List.nil();
|
||||
JCThrow thr = make.Throw(makeNewClass(exception, params));
|
||||
JCCase c = make.Case(JCCase.STATEMENT, List.of(make.DefaultCaseLabel()), List.of(thr), null);
|
||||
cases = cases.prepend(c);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
@ -29,7 +29,7 @@ import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.BindingSymbol;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCGuardPattern;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCase;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
@ -112,7 +112,7 @@ public class MatchBindingsComputer extends TreeScanner {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
public MatchBindings guardedPattern(JCGuardPattern tree, MatchBindings patternBindings, MatchBindings guardBindings) {
|
||||
public MatchBindings caseGuard(JCCase tree, MatchBindings patternBindings, MatchBindings guardBindings) {
|
||||
return andOperation(tree.pos(), patternBindings, guardBindings);
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ public class MatchBindingsComputer extends TreeScanner {
|
||||
public MatchBindings finishBindings(JCTree tree, MatchBindings matchBindings) {
|
||||
switch (tree.getTag()) {
|
||||
case NOT: case AND: case OR: case BINDINGPATTERN:
|
||||
case PARENTHESIZEDPATTERN: case GUARDPATTERN:
|
||||
case PARENTHESIZEDPATTERN:
|
||||
case PARENS: case TYPETEST:
|
||||
case CONDEXPR: //error recovery:
|
||||
return matchBindings;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
@ -85,7 +85,6 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCContinue;
|
||||
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCGuardPattern;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLambda;
|
||||
import com.sun.tools.javac.tree.JCTree.JCParenthesizedPattern;
|
||||
import com.sun.tools.javac.tree.JCTree.JCPattern;
|
||||
@ -255,27 +254,22 @@ public class TransPatterns extends TreeTranslator {
|
||||
result = translate(tree.pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern tree) {
|
||||
JCExpression pattern = (JCExpression) this.<JCTree>translate(tree.patt);
|
||||
JCExpression guard = translate(tree.expr);
|
||||
result = makeBinary(Tag.AND, pattern, guard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitch(JCSwitch tree) {
|
||||
handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern, tree.patternSwitch);
|
||||
handleSwitch(tree, tree.selector, tree.cases,
|
||||
tree.hasUnconditionalPattern, tree.patternSwitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitchExpression(JCSwitchExpression tree) {
|
||||
handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern, tree.patternSwitch);
|
||||
handleSwitch(tree, tree.selector, tree.cases,
|
||||
tree.hasUnconditionalPattern, tree.patternSwitch);
|
||||
}
|
||||
|
||||
private void handleSwitch(JCTree tree,
|
||||
JCExpression selector,
|
||||
List<JCCase> cases,
|
||||
boolean hasTotalPattern,
|
||||
boolean hasUnconditionalPattern,
|
||||
boolean patternSwitch) {
|
||||
if (patternSwitch) {
|
||||
Type seltype = selector.type.hasTag(BOT)
|
||||
@ -340,12 +334,6 @@ public class TransPatterns extends TreeTranslator {
|
||||
|
||||
JCCase lastCase = cases.last();
|
||||
|
||||
if (hasTotalPattern && !hasNullCase) {
|
||||
if (cases.stream().flatMap(c -> c.labels.stream()).noneMatch(l -> l.hasTag(Tag.DEFAULTCASELABEL))) {
|
||||
lastCase.labels = lastCase.labels.prepend(makeLit(syms.botType, null));
|
||||
hasNullCase = true;
|
||||
}
|
||||
}
|
||||
selector = translate(selector);
|
||||
boolean needsNullCheck = !hasNullCase && !seltype.isPrimitive();
|
||||
statements.append(make.at(tree.pos).VarDef(temp, needsNullCheck ? attr.makeNullCheck(selector)
|
||||
@ -415,6 +403,9 @@ public class TransPatterns extends TreeTranslator {
|
||||
try {
|
||||
currentValue = temp;
|
||||
JCExpression test = (JCExpression) this.<JCTree>translate(p);
|
||||
if (((JCPattern) p).guard != null) {
|
||||
test = makeBinary(Tag.AND, test, translate(((JCPattern) p).guard));
|
||||
}
|
||||
c.stats = translate(c.stats);
|
||||
JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null);
|
||||
continueSwitch.target = tree;
|
||||
@ -437,10 +428,11 @@ public class TransPatterns extends TreeTranslator {
|
||||
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
|
||||
translatedLabels.add(p);
|
||||
hasDefault = true;
|
||||
} else if (hasTotalPattern && !hasDefault &&
|
||||
} else if (hasUnconditionalPattern && !hasDefault &&
|
||||
c == lastCase && p.isPattern()) {
|
||||
//If the switch has total pattern, the last case will contain it.
|
||||
//Convert the total pattern to default:
|
||||
//If the switch has unconditional pattern,
|
||||
//the last case will contain it.
|
||||
//Convert the unconditional pattern to default:
|
||||
translatedLabels.add(make.DefaultCaseLabel());
|
||||
} else {
|
||||
int value;
|
||||
@ -466,11 +458,13 @@ public class TransPatterns extends TreeTranslator {
|
||||
if (tree.hasTag(Tag.SWITCH)) {
|
||||
((JCSwitch) tree).selector = selector;
|
||||
((JCSwitch) tree).cases = cases;
|
||||
((JCSwitch) tree).wasEnumSelector = enumSelector;
|
||||
statements.append((JCSwitch) tree);
|
||||
result = make.Block(0, statements.toList());
|
||||
} else {
|
||||
((JCSwitchExpression) tree).selector = selector;
|
||||
((JCSwitchExpression) tree).cases = cases;
|
||||
((JCSwitchExpression) tree).wasEnumSelector = enumSelector;
|
||||
LetExpr r = (LetExpr) make.LetExpr(statements.toList(), (JCSwitchExpression) tree)
|
||||
.setType(tree.type);
|
||||
|
||||
@ -486,13 +480,13 @@ public class TransPatterns extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
private Type principalType(JCPattern p) {
|
||||
return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p).type()));
|
||||
private Type principalType(JCTree p) {
|
||||
return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p)));
|
||||
}
|
||||
|
||||
private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) {
|
||||
if (l.isPattern()) {
|
||||
Type principalType = principalType((JCPattern) l);
|
||||
Type principalType = principalType(l);
|
||||
if (types.isSubtype(selector, principalType)) {
|
||||
return (LoadableConstant) selector;
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -565,6 +565,7 @@ public class TransTypes extends TreeTranslator {
|
||||
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
tree.var = translate(tree.var, null);
|
||||
tree.guard = translate(tree.guard, syms.booleanType);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@ -582,13 +583,7 @@ public class TransTypes extends TreeTranslator {
|
||||
@Override
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
|
||||
tree.pattern = translate(tree.pattern, null);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern tree) {
|
||||
tree.patt = translate(tree.patt, null);
|
||||
tree.expr = translate(tree.expr, syms.booleanType);
|
||||
tree.guard = translate(tree.guard, syms.booleanType);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -763,12 +763,12 @@ public class JavacParser implements Parser {
|
||||
/** parses patterns.
|
||||
*/
|
||||
|
||||
public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType, boolean inInstanceOf) {
|
||||
public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType) {
|
||||
JCPattern pattern;
|
||||
if (token.kind == LPAREN && parsedType == null) {
|
||||
int startPos = token.pos;
|
||||
accept(LPAREN);
|
||||
JCPattern p = parsePattern(token.pos, null, null, false);
|
||||
JCPattern p = parsePattern(token.pos, null, null);
|
||||
accept(RPAREN);
|
||||
pattern = toP(F.at(startPos).ParenthesizedPattern(p));
|
||||
} else {
|
||||
@ -777,12 +777,6 @@ public class JavacParser implements Parser {
|
||||
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
|
||||
pattern = toP(F.at(pos).BindingPattern(var));
|
||||
}
|
||||
if (!inInstanceOf && token.kind == AMPAMP) {
|
||||
checkSourceLevel(Feature.PATTERN_SWITCH);
|
||||
nextToken();
|
||||
JCExpression guard = term(EXPR | NOLAMBDA);
|
||||
pattern = F.at(pos).GuardPattern(pattern, guard);
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@ -967,7 +961,7 @@ public class JavacParser implements Parser {
|
||||
JCTree pattern;
|
||||
if (token.kind == LPAREN) {
|
||||
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
|
||||
pattern = parsePattern(token.pos, null, null, true);
|
||||
pattern = parsePattern(token.pos, null, null);
|
||||
} else {
|
||||
int patternPos = token.pos;
|
||||
JCModifiers mods = optFinal(0);
|
||||
@ -975,7 +969,7 @@ public class JavacParser implements Parser {
|
||||
JCExpression type = unannotatedType(false);
|
||||
if (token.kind == IDENTIFIER) {
|
||||
checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
|
||||
pattern = parsePattern(patternPos, mods, type, true);
|
||||
pattern = parsePattern(patternPos, mods, type);
|
||||
} else {
|
||||
checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED);
|
||||
if (mods.annotations.nonEmpty()) {
|
||||
@ -3076,7 +3070,12 @@ public class JavacParser implements Parser {
|
||||
analyzePattern(lookahead) == PatternResult.PATTERN;
|
||||
if (pattern) {
|
||||
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
|
||||
return parsePattern(patternPos, mods, null, false);
|
||||
JCPattern p = parsePattern(patternPos, mods, null);
|
||||
if (token.kind == IDENTIFIER && token.name() == names.when) {
|
||||
nextToken();
|
||||
p.guard = term(EXPR | NOLAMBDA);
|
||||
}
|
||||
return p;
|
||||
} else {
|
||||
return term(EXPR | NOLAMBDA);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 1999, 2022, 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
|
||||
@ -506,11 +506,11 @@ compiler.err.pattern.dominated=\
|
||||
compiler.err.duplicate.default.label=\
|
||||
duplicate default label
|
||||
|
||||
compiler.err.duplicate.total.pattern=\
|
||||
duplicate total pattern
|
||||
compiler.err.duplicate.unconditional.pattern=\
|
||||
duplicate unconditional pattern
|
||||
|
||||
compiler.err.total.pattern.and.default=\
|
||||
switch has both a total pattern and a default label
|
||||
compiler.err.unconditional.pattern.and.default=\
|
||||
switch has both an unconditional pattern and a default label
|
||||
|
||||
# 0: type, 1: type
|
||||
compiler.err.constant.label.not.compatible=\
|
||||
@ -2518,6 +2518,10 @@ compiler.warn.prob.found.req=\
|
||||
compiler.misc.inconvertible.types=\
|
||||
{0} cannot be converted to {1}
|
||||
|
||||
# 0: type, 1: type
|
||||
compiler.misc.not.applicable.types=\
|
||||
pattern of type {1} is not applicable at {0}
|
||||
|
||||
# 0: type, 1: type
|
||||
compiler.misc.possible.loss.of.precision=\
|
||||
possible lossy conversion from {0} to {1}
|
||||
@ -3082,6 +3086,9 @@ compiler.misc.feature.case.null=\
|
||||
compiler.misc.feature.pattern.switch=\
|
||||
patterns in switch statements
|
||||
|
||||
compiler.misc.feature.unconditional.patterns.in.instanceof=\
|
||||
unconditional patterns in instanceof
|
||||
|
||||
compiler.warn.underscore.as.identifier=\
|
||||
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -241,7 +241,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
*/
|
||||
BINDINGPATTERN,
|
||||
DEFAULTCASELABEL,
|
||||
GUARDPATTERN,
|
||||
PARENTHESIZEDPATTERN,
|
||||
|
||||
/** Indexed array expressions, of type Indexed.
|
||||
@ -1284,9 +1283,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public List<JCCase> cases;
|
||||
/** Position of closing brace, optional. */
|
||||
public int endpos = Position.NOPOS;
|
||||
public boolean hasTotalPattern;
|
||||
public boolean hasUnconditionalPattern;
|
||||
public boolean isExhaustive;
|
||||
public boolean patternSwitch;
|
||||
public boolean wasEnumSelector;
|
||||
protected JCSwitch(JCExpression selector, List<JCCase> cases) {
|
||||
this.selector = selector;
|
||||
this.cases = cases;
|
||||
@ -1371,9 +1371,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public List<JCCase> cases;
|
||||
/** Position of closing brace, optional. */
|
||||
public int endpos = Position.NOPOS;
|
||||
public boolean hasTotalPattern;
|
||||
public boolean hasUnconditionalPattern;
|
||||
public boolean isExhaustive;
|
||||
public boolean patternSwitch;
|
||||
public boolean wasEnumSelector;
|
||||
protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
|
||||
this.selector = selector;
|
||||
this.cases = cases;
|
||||
@ -2243,6 +2244,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public abstract static class JCPattern extends JCCaseLabel
|
||||
implements PatternTree {
|
||||
|
||||
public JCExpression guard;
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public JCExpression getGuard() { return guard; }
|
||||
|
||||
@Override
|
||||
public boolean isExpression() {
|
||||
return false;
|
||||
@ -2362,48 +2368,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
}
|
||||
}
|
||||
|
||||
public static class JCGuardPattern extends JCPattern
|
||||
implements GuardedPatternTree {
|
||||
public JCPattern patt;
|
||||
public JCExpression expr;
|
||||
|
||||
public JCGuardPattern(JCPattern patt, JCExpression expr) {
|
||||
this.patt = patt;
|
||||
this.expr = expr;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public PatternTree getPattern() {
|
||||
return patt;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public ExpressionTree getExpression() {
|
||||
return expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) {
|
||||
v.visitGuardPattern(this);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public Kind getKind() {
|
||||
return Kind.GUARDED_PATTERN;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public <R, D> R accept(TreeVisitor<R, D> v, D d) {
|
||||
return v.visitGuardedPattern(this, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getTag() {
|
||||
return Tag.GUARDPATTERN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array selection
|
||||
*/
|
||||
@ -3446,7 +3410,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
|
||||
public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); }
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern that) { visitTree(that); }
|
||||
public void visitGuardPattern(JCGuardPattern that) { visitTree(that); }
|
||||
public void visitIndexed(JCArrayAccess that) { visitTree(that); }
|
||||
public void visitSelect(JCFieldAccess that) { visitTree(that); }
|
||||
public void visitReference(JCMemberReference that) { visitTree(that); }
|
||||
|
@ -900,6 +900,10 @@ public class Pretty extends JCTree.Visitor {
|
||||
public void visitBindingPattern(JCBindingPattern patt) {
|
||||
try {
|
||||
printExpr(patt.var);
|
||||
if (patt.guard != null) {
|
||||
print(" when ");
|
||||
printExpr(patt.guard);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
@ -911,17 +915,10 @@ public class Pretty extends JCTree.Visitor {
|
||||
print("(");
|
||||
printExpr(patt.pattern);
|
||||
print(")");
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern patt) {
|
||||
try {
|
||||
printExpr(patt.patt);
|
||||
print(" && ");
|
||||
printExpr(patt.expr);
|
||||
if (patt.guard != null) {
|
||||
print(" when ");
|
||||
printExpr(patt.guard);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2022, 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
|
||||
@ -494,22 +494,20 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
|
||||
public JCTree visitBindingPattern(BindingPatternTree node, P p) {
|
||||
JCBindingPattern t = (JCBindingPattern) node;
|
||||
JCVariableDecl var = copy(t.var, p);
|
||||
return M.at(t.pos).BindingPattern(var);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCTree visitGuardedPattern(GuardedPatternTree node, P p) {
|
||||
JCGuardPattern t = (JCGuardPattern) node;
|
||||
JCPattern patt = copy(t.patt, p);
|
||||
JCExpression expr = copy(t.expr, p);
|
||||
return M.at(t.pos).GuardPattern(patt, expr);
|
||||
JCExpression guard = copy(t.guard, p);
|
||||
JCPattern pat = M.at(t.pos).BindingPattern(var);
|
||||
pat.guard = guard;
|
||||
return pat;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCTree visitParenthesizedPattern(ParenthesizedPatternTree node, P p) {
|
||||
JCParenthesizedPattern t = (JCParenthesizedPattern) node;
|
||||
JCPattern pattern = copy(t.pattern, p);
|
||||
return M.at(t.pos).ParenthesizedPattern(pattern);
|
||||
JCExpression guard = copy(t.guard, p);
|
||||
JCPattern pat = M.at(t.pos).ParenthesizedPattern(pattern);
|
||||
pat.guard = guard;
|
||||
return pat;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -542,10 +542,6 @@ public class TreeInfo {
|
||||
JCBindingPattern node = (JCBindingPattern)tree;
|
||||
return getStartPos(node.var);
|
||||
}
|
||||
case GUARDPATTERN: {
|
||||
JCGuardPattern node = (JCGuardPattern) tree;
|
||||
return getStartPos(node.patt);
|
||||
}
|
||||
case ERRONEOUS: {
|
||||
JCErroneous node = (JCErroneous)tree;
|
||||
if (node.errs != null && node.errs.nonEmpty()) {
|
||||
@ -644,10 +640,6 @@ public class TreeInfo {
|
||||
JCParenthesizedPattern node = (JCParenthesizedPattern) tree;
|
||||
return getEndPos(node.pattern, endPosTable);
|
||||
}
|
||||
case GUARDPATTERN: {
|
||||
JCGuardPattern node = (JCGuardPattern) tree;
|
||||
return getEndPos(node.expr, endPosTable);
|
||||
}
|
||||
case ERRONEOUS: {
|
||||
JCErroneous node = (JCErroneous)tree;
|
||||
if (node.errs != null && node.errs.nonEmpty())
|
||||
@ -1314,42 +1306,40 @@ public class TreeInfo {
|
||||
.allMatch(p -> p.hasTag(IDENT));
|
||||
}
|
||||
|
||||
public static PatternPrimaryType primaryPatternType(JCPattern pat) {
|
||||
public static Type primaryPatternType(JCTree pat) {
|
||||
return switch (pat.getTag()) {
|
||||
case BINDINGPATTERN -> new PatternPrimaryType(((JCBindingPattern) pat).type, true);
|
||||
case GUARDPATTERN -> {
|
||||
JCGuardPattern guarded = (JCGuardPattern) pat;
|
||||
PatternPrimaryType nested = primaryPatternType(guarded.patt);
|
||||
boolean unconditional = nested.unconditional();
|
||||
if (guarded.expr.type.hasTag(BOOLEAN) && unconditional) {
|
||||
unconditional = false;
|
||||
var constValue = guarded.expr.type.constValue();
|
||||
if (constValue != null && ((int) constValue) == 1) {
|
||||
unconditional = true;
|
||||
}
|
||||
}
|
||||
yield new PatternPrimaryType(nested.type(), unconditional);
|
||||
}
|
||||
case BINDINGPATTERN -> pat.type;
|
||||
case PARENTHESIZEDPATTERN -> primaryPatternType(((JCParenthesizedPattern) pat).pattern);
|
||||
default -> throw new AssertionError();
|
||||
};
|
||||
}
|
||||
|
||||
public static JCBindingPattern primaryPatternTree(JCPattern pat) {
|
||||
public static JCBindingPattern primaryPatternTree(JCTree pat) {
|
||||
return switch (pat.getTag()) {
|
||||
case BINDINGPATTERN -> (JCBindingPattern) pat;
|
||||
case GUARDPATTERN -> primaryPatternTree(((JCGuardPattern) pat).patt);
|
||||
case PARENTHESIZEDPATTERN -> primaryPatternTree(((JCParenthesizedPattern) pat).pattern);
|
||||
default -> throw new AssertionError();
|
||||
};
|
||||
}
|
||||
|
||||
public record PatternPrimaryType(Type type, boolean unconditional) {}
|
||||
|
||||
public static boolean expectedExhaustive(JCSwitch tree) {
|
||||
return tree.patternSwitch ||
|
||||
tree.cases.stream()
|
||||
.flatMap(c -> c.labels.stream())
|
||||
.anyMatch(l -> TreeInfo.isNull(l));
|
||||
}
|
||||
|
||||
public static boolean unguardedCaseLabel(JCCaseLabel cse) {
|
||||
if (!cse.isPattern()) {
|
||||
return true;
|
||||
}
|
||||
JCExpression guard = ((JCPattern) cse).guard;
|
||||
if (guard == null) {
|
||||
return true;
|
||||
}
|
||||
var constValue = guard.type.constValue();
|
||||
return constValue != null &&
|
||||
guard.type.hasTag(BOOLEAN) &&
|
||||
((int) constValue) == 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -500,12 +500,6 @@ public class TreeMaker implements JCTree.Factory {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public JCGuardPattern GuardPattern(JCPattern guardedPattern, JCExpression expr) {
|
||||
JCGuardPattern tree = new JCGuardPattern(guardedPattern, expr);
|
||||
tree.pos = pos;
|
||||
return tree;
|
||||
}
|
||||
|
||||
public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) {
|
||||
JCArrayAccess tree = new JCArrayAccess(indexed, index);
|
||||
tree.pos = pos;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2022, 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
|
||||
@ -305,6 +305,7 @@ public class TreeScanner extends Visitor {
|
||||
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
scan(tree.var);
|
||||
scan(tree.guard);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -312,14 +313,9 @@ public class TreeScanner extends Visitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern that) {
|
||||
scan(that.pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern that) {
|
||||
scan(that.patt);
|
||||
scan(that.expr);
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
|
||||
scan(tree.pattern);
|
||||
scan(tree.guard);
|
||||
}
|
||||
|
||||
public void visitIndexed(JCArrayAccess tree) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -360,6 +360,7 @@ public class TreeTranslator extends JCTree.Visitor {
|
||||
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
tree.var = translate(tree.var);
|
||||
tree.guard = translate(tree.guard);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@ -371,13 +372,7 @@ public class TreeTranslator extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
|
||||
tree.pattern = translate(tree.pattern);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGuardPattern(JCGuardPattern tree) {
|
||||
tree.patt = translate(tree.patt);
|
||||
tree.expr = translate(tree.expr);
|
||||
tree.guard = translate(tree.guard);
|
||||
result = tree;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -69,6 +69,7 @@ public class Names {
|
||||
public final Name transitive;
|
||||
public final Name uses;
|
||||
public final Name open;
|
||||
public final Name when;
|
||||
public final Name with;
|
||||
public final Name yield;
|
||||
|
||||
@ -248,6 +249,7 @@ public class Names {
|
||||
transitive = fromString("transitive");
|
||||
uses = fromString("uses");
|
||||
open = fromString("open");
|
||||
when = fromString("when");
|
||||
with = fromString("with");
|
||||
yield = fromString("yield");
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class RuleSwitchBreaks extends LineNumberTestBase {
|
||||
public class TestGuards { // 1
|
||||
private void test(Object o) { // 2
|
||||
switch (o) { // 3
|
||||
case String s && s.isEmpty() -> // 4
|
||||
case String s when s.isEmpty() -> // 4
|
||||
System.out.println("a"); // 5
|
||||
case String s -> // 6
|
||||
System.out.println("a"); // 7
|
||||
|
@ -48,7 +48,7 @@ class CantRefNonEffectivelyFinalVar {
|
||||
|
||||
void test3(Object o, int i) {
|
||||
switch (o) {
|
||||
case String s && s.length() == i++: break;
|
||||
case String s when s.length() == i++: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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,12 +21,12 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.duplicate.total.pattern
|
||||
// key: compiler.err.duplicate.unconditional.pattern
|
||||
// key: compiler.misc.feature.pattern.switch
|
||||
// key: compiler.warn.preview.feature.use.plural
|
||||
// options: --enable-preview -source ${jdk.version} -Xlint:preview
|
||||
|
||||
class DuplicateTotalPattern {
|
||||
class DuplicateUnconditionalPattern {
|
||||
private void doSwitch(Object o) {
|
||||
switch (o) {
|
||||
case Object obj: break;
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2022, 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.unconditional.patterns.in.instanceof
|
||||
// key: compiler.warn.preview.feature.use.plural
|
||||
// options: --enable-preview -source ${jdk.version} -Xlint:-options,preview
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class FeatureUnconditionalTypesInstanceof {
|
||||
String s;
|
||||
boolean b = (s instanceof String str);
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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.
|
||||
* 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
|
||||
@ -23,28 +21,16 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.source.tree;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A guard pattern tree.
|
||||
*
|
||||
* @since 17
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
|
||||
public interface GuardedPatternTree extends PatternTree {
|
||||
|
||||
/**
|
||||
* The guarded pattern expression.
|
||||
* @return the guarded pattern
|
||||
*/
|
||||
public PatternTree getPattern();
|
||||
|
||||
/**
|
||||
* The guard expression.
|
||||
* @return the guard expression
|
||||
*/
|
||||
public ExpressionTree getExpression();
|
||||
// key: compiler.misc.not.applicable.types
|
||||
// key: compiler.err.prob.found.req
|
||||
// key: compiler.note.preview.filename
|
||||
// key: compiler.note.preview.recompile
|
||||
// options: --enable-preview --source ${jdk.version}
|
||||
|
||||
class NotApplicableTypes {
|
||||
void t(int i) {
|
||||
switch (i) {
|
||||
case Integer j -> {}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 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,12 +21,12 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.total.pattern.and.default
|
||||
// key: compiler.err.unconditional.pattern.and.default
|
||||
// key: compiler.misc.feature.pattern.switch
|
||||
// key: compiler.warn.preview.feature.use.plural
|
||||
// options: --enable-preview -source ${jdk.version} -Xlint:preview
|
||||
|
||||
class TotalPatternAndDefault {
|
||||
class UnconditionalPatternAndDefault {
|
||||
private void doSwitch(Object o) {
|
||||
switch (o) {
|
||||
case Object obj: break;
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -94,7 +94,7 @@ public class CaseStructureTest extends ComboInstance<CaseStructureTest> {
|
||||
|
||||
task.generate(result -> {
|
||||
boolean shouldPass = true;
|
||||
long patternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN || l == CaseLabel.GUARDED_PATTERN || l == CaseLabel.PARENTHESIZED_PATTERN).count();
|
||||
long patternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN || l == CaseLabel.PARENTHESIZED_PATTERN).count();
|
||||
long typePatternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN).count();
|
||||
long constantCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.CONSTANT).count();
|
||||
long nullCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.NULL).count();
|
||||
@ -126,7 +126,7 @@ public class CaseStructureTest extends ComboInstance<CaseStructureTest> {
|
||||
for (CaseLabel label : caseLabels) {
|
||||
switch (label) {
|
||||
case NULL: if (seenPattern) shouldPass = false; break;
|
||||
case GUARDED_PATTERN, PARENTHESIZED_PATTERN, TYPE_PATTERN: seenPattern = true; break;
|
||||
case PARENTHESIZED_PATTERN, TYPE_PATTERN: seenPattern = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,7 +140,6 @@ public class CaseStructureTest extends ComboInstance<CaseStructureTest> {
|
||||
NONE(""),
|
||||
TYPE_PATTERN("Integer i"),
|
||||
PARENTHESIZED_PATTERN("(Integer i)"),
|
||||
GUARDED_PATTERN("Integer i && i > 0"),
|
||||
CONSTANT("1"),
|
||||
NULL("null"),
|
||||
DEFAULT("default");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -53,7 +53,7 @@ public class DisambiguatePatterns {
|
||||
DisambiguatePatterns test = new DisambiguatePatterns();
|
||||
test.disambiguationTest("String s",
|
||||
ExpressionType.PATTERN);
|
||||
test.disambiguationTest("String s && s.isEmpty()",
|
||||
test.disambiguationTest("String s when s.isEmpty()",
|
||||
ExpressionType.PATTERN);
|
||||
test.disambiguationTest("(String s)",
|
||||
ExpressionType.PATTERN);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -40,22 +40,22 @@ public class Domination {
|
||||
int testDominatesError2(Object o) {
|
||||
switch (o) {
|
||||
case CharSequence cs: return 0;
|
||||
case String s && s.isEmpty(): return 1;
|
||||
case String s when s.isEmpty(): return 1;
|
||||
case Object x: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int testDominatesError3(Object o) {
|
||||
switch (o) {
|
||||
case CharSequence cs && true: return 0;
|
||||
case String s && s.isEmpty(): return 1;
|
||||
case CharSequence cs when true: return 0;
|
||||
case String s when s.isEmpty(): return 1;
|
||||
case Object x: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int testNotDominates1(Object o) {
|
||||
switch (o) {
|
||||
case CharSequence cs && cs.length() == 0: return 0;
|
||||
case CharSequence cs when cs.length() == 0: return 0;
|
||||
case String s: return 1;
|
||||
case Object x: return -1;
|
||||
}
|
||||
@ -70,14 +70,14 @@ public class Domination {
|
||||
|
||||
int testDominatesStringConstant2(String str) {
|
||||
switch (str) {
|
||||
case (String s && s.isEmpty()): return 1;
|
||||
case String s when s.isEmpty(): return 1;
|
||||
case "": return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int testDominatesStringConstant3(String str) {
|
||||
switch (str) {
|
||||
case (String s && !s.isEmpty()): return 1;
|
||||
case String s when !s.isEmpty(): return 1;
|
||||
case "": return -1;
|
||||
}
|
||||
}
|
||||
@ -91,14 +91,14 @@ public class Domination {
|
||||
|
||||
int testDominatesIntegerConstant2(Integer i) {
|
||||
switch (i) {
|
||||
case (Integer j && j == 0): return 1;
|
||||
case Integer j when j == 0: return 1;
|
||||
case 0: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int testDominatesIntegerConstant3(Integer i) {
|
||||
switch (i) {
|
||||
case (Integer j && j == 1): return 1;
|
||||
case Integer j when j == 1: return 1;
|
||||
case 0: return -1;
|
||||
}
|
||||
}
|
||||
@ -120,7 +120,7 @@ public class Domination {
|
||||
}
|
||||
E e = E.A;
|
||||
switch (e) {
|
||||
case (E d && d == E.A): return 1;
|
||||
case E d when d == E.A: return 1;
|
||||
case A: return -1;
|
||||
}
|
||||
}
|
||||
@ -131,7 +131,7 @@ public class Domination {
|
||||
}
|
||||
E e = E.A;
|
||||
switch (e) {
|
||||
case (E d && d == E.B): return 1;
|
||||
case E d when d == E.B: return 1;
|
||||
case A: return -1;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -42,6 +42,8 @@ public class EnumTypeChanges {
|
||||
void run() throws Exception {
|
||||
doRun(this::statementEnum);
|
||||
doRun(this::expressionEnum);
|
||||
doRunExhaustive(this::expressionEnumExhaustive);
|
||||
doRunExhaustive(this::statementEnumExhaustive);
|
||||
}
|
||||
|
||||
void doRun(Function<EnumTypeChangesEnum, String> c) throws Exception {
|
||||
@ -49,11 +51,20 @@ public class EnumTypeChanges {
|
||||
assertEquals("D", c.apply(EnumTypeChangesEnum.valueOf("C")));
|
||||
}
|
||||
|
||||
void doRunExhaustive(Function<EnumTypeChangesEnum, String> c) throws Exception {
|
||||
try {
|
||||
c.apply(EnumTypeChangesEnum.valueOf("C"));
|
||||
throw new AssertionError();
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
String statementEnum(EnumTypeChangesEnum e) {
|
||||
switch (e) {
|
||||
case A -> { return "A"; }
|
||||
case B -> { return "B"; }
|
||||
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
|
||||
case EnumTypeChangesEnum e1 when false -> throw new AssertionError();
|
||||
default -> { return "D"; }
|
||||
}
|
||||
}
|
||||
@ -62,11 +73,28 @@ public class EnumTypeChanges {
|
||||
return switch (e) {
|
||||
case A -> "A";
|
||||
case B -> "B";
|
||||
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
|
||||
case EnumTypeChangesEnum e1 when false -> throw new AssertionError();
|
||||
default -> "D";
|
||||
};
|
||||
}
|
||||
|
||||
String statementEnumExhaustive(EnumTypeChangesEnum e) {
|
||||
switch (e) {
|
||||
case A -> { return "A"; }
|
||||
case B -> { return "B"; }
|
||||
case EnumTypeChangesEnum x when e == EnumTypeChangesEnum.A -> throw new AssertionError();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
String expressionEnumExhaustive(EnumTypeChangesEnum e) {
|
||||
return switch (e) {
|
||||
case A -> "A";
|
||||
case B -> "B";
|
||||
case EnumTypeChangesEnum x when e == EnumTypeChangesEnum.A -> throw new AssertionError();
|
||||
};
|
||||
}
|
||||
|
||||
private static void assertEquals(Object o1, Object o2) {
|
||||
if (!Objects.equals(o1, o2)) {
|
||||
throw new AssertionError();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, 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
|
||||
@ -207,7 +207,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
public class Test {
|
||||
private int test(S obj) {
|
||||
return switch (obj) {
|
||||
case A a && a.toString().isEmpty() -> 0;
|
||||
case A a when a.toString().isEmpty() -> 0;
|
||||
case B b -> 1;
|
||||
};
|
||||
}
|
||||
@ -241,7 +241,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
private static final boolean TEST = true;
|
||||
private int test(S obj) {
|
||||
return switch (obj) {
|
||||
case A a && !(!(TEST)) -> 0;
|
||||
case A a when !(!(TEST)) -> 0;
|
||||
case B b -> 1;
|
||||
};
|
||||
}
|
||||
@ -270,7 +270,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
public class Test {
|
||||
private int test(S obj) {
|
||||
return switch (obj) {
|
||||
case A a && false -> 0;
|
||||
case A a when false -> 0;
|
||||
case B b -> 1;
|
||||
};
|
||||
}
|
||||
@ -531,7 +531,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
private int test(S obj, boolean b) {
|
||||
return switch (obj) {
|
||||
case A a -> 0;
|
||||
case C c && b -> 0;
|
||||
case C c when b -> 0;
|
||||
case C c -> 0;
|
||||
case D d -> 0;
|
||||
};
|
||||
@ -571,7 +571,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
return switch (obj) {
|
||||
case A a -> 0;
|
||||
case C c -> 0;
|
||||
case D d && b -> 0;
|
||||
case D d when b -> 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -620,7 +620,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
private <T extends Base & S & Marker> int test(T obj, boolean b) {
|
||||
return switch (obj) {
|
||||
case A a -> 0;
|
||||
case C c && b -> 0;
|
||||
case C c when b -> 0;
|
||||
case C c -> 0;
|
||||
case D d -> 0;
|
||||
};
|
||||
@ -668,7 +668,7 @@ public class Exhaustiveness extends TestRunner {
|
||||
return switch (obj) {
|
||||
case A a -> 0;
|
||||
case C c -> 0;
|
||||
case D d && b -> 0;
|
||||
case D d when b -> 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -867,6 +867,53 @@ public class Exhaustiveness extends TestRunner {
|
||||
"4 errors");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonPrimitiveBooleanGuard(Path base) throws Exception {
|
||||
doTest(base,
|
||||
new String[0],
|
||||
"""
|
||||
package test;
|
||||
public class Test {
|
||||
sealed interface A {}
|
||||
final class B1 implements A {}
|
||||
final class B2 implements A {}
|
||||
|
||||
void test(A arg, Boolean g) {
|
||||
int i = switch (arg) {
|
||||
case B1 b1 when g -> 1;
|
||||
case B2 b2 -> 2;
|
||||
};
|
||||
}
|
||||
}
|
||||
""",
|
||||
"Test.java:8:17: compiler.err.not.exhaustive",
|
||||
"- compiler.note.preview.filename: Test.java, DEFAULT",
|
||||
"- compiler.note.preview.recompile",
|
||||
"1 error");
|
||||
doTest(base,
|
||||
new String[0],
|
||||
"""
|
||||
package test;
|
||||
public class Test {
|
||||
sealed interface A {}
|
||||
final class B1 implements A {}
|
||||
final class B2 implements A {}
|
||||
|
||||
void test(A arg) {
|
||||
int i = switch (arg) {
|
||||
case B1 b1 when undefined() -> 1;
|
||||
case B2 b2 -> 2;
|
||||
};
|
||||
}
|
||||
}
|
||||
""",
|
||||
"Test.java:9:29: compiler.err.cant.resolve.location.args: kindname.method, undefined, , , (compiler.misc.location: kindname.class, test.Test, null)",
|
||||
"Test.java:8:17: compiler.err.not.exhaustive",
|
||||
"- compiler.note.preview.filename: Test.java, DEFAULT",
|
||||
"- compiler.note.preview.recompile",
|
||||
"2 errors");
|
||||
}
|
||||
|
||||
private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
|
||||
Path current = base.resolve(".");
|
||||
Path libClasses = current.resolve("libClasses");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
@ -49,6 +49,7 @@ public class Guards {
|
||||
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchStatement);
|
||||
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchExpression);
|
||||
runIfTrue(this::typeGuardAfterParenthesizedTrueIfStatement);
|
||||
testGuardNPE();
|
||||
}
|
||||
|
||||
void run(Function<Object, String> convert) {
|
||||
@ -66,8 +67,8 @@ public class Guards {
|
||||
|
||||
String typeTestPatternSwitchTest(Object o) {
|
||||
switch (o) {
|
||||
case Integer i && i == 0: return "zero";
|
||||
case Integer i && i == 1: return "one";
|
||||
case Integer i when i == 0: return "zero";
|
||||
case Integer i when i == 1: return "one";
|
||||
case Integer i: return "other";
|
||||
case Object x: return "any";
|
||||
}
|
||||
@ -75,8 +76,8 @@ public class Guards {
|
||||
|
||||
String typeTestPatternSwitchExpressionTest(Object o) {
|
||||
return switch (o) {
|
||||
case Integer i && i == 0 -> "zero";
|
||||
case Integer i && i == 1 -> { yield "one"; }
|
||||
case Integer i when i == 0 -> "zero";
|
||||
case Integer i when i == 1 -> { yield "one"; }
|
||||
case Integer i -> "other";
|
||||
case Object x -> "any";
|
||||
};
|
||||
@ -85,8 +86,8 @@ public class Guards {
|
||||
String testBooleanSwitchExpression(Object o) {
|
||||
String x;
|
||||
if (switch (o) {
|
||||
case Integer i && i == 0 -> (x = "zero") != null;
|
||||
case Integer i && i == 1 -> { x = "one"; yield true; }
|
||||
case Integer i when i == 0 -> (x = "zero") != null;
|
||||
case Integer i when i == 1 -> { x = "one"; yield true; }
|
||||
case Integer i -> { x = "other"; yield true; }
|
||||
case Object other -> (x = "any") != null;
|
||||
}) {
|
||||
@ -99,8 +100,8 @@ public class Guards {
|
||||
String typeGuardIfTrueSwitchStatement(Object o) {
|
||||
Object o2 = "";
|
||||
switch (o) {
|
||||
case Integer i && i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); return "true";
|
||||
case Integer i && i == 0 || i > 1: o = String.valueOf(i); return "second";
|
||||
case Integer i when i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); return "true";
|
||||
case Integer i when i == 0 || i > 1: o = String.valueOf(i); return "second";
|
||||
case Object x: return "any";
|
||||
}
|
||||
}
|
||||
@ -108,17 +109,17 @@ public class Guards {
|
||||
String typeGuardIfTrueSwitchExpression(Object o) {
|
||||
Object o2 = "";
|
||||
return switch (o) {
|
||||
case Integer i && i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); yield "true";
|
||||
case Integer i && i == 0 || i > 1: o = String.valueOf(i); yield "second";
|
||||
case Integer i when i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); yield "true";
|
||||
case Integer i when i == 0 || i > 1: o = String.valueOf(i); yield "second";
|
||||
case Object x: yield "any";
|
||||
};
|
||||
}
|
||||
|
||||
String typeGuardIfTrueIfStatement(Object o) {
|
||||
Object o2 = "";
|
||||
if (o != null && o instanceof (Integer i && i == 0 && i < 1) && (o = i) != null && o2 instanceof String s) {
|
||||
if (o != null && o instanceof Integer i && i == 0 && i < 1 && (o = i) != null && o2 instanceof String s) {
|
||||
return s != null ? "true" : null;
|
||||
} else if (o != null && o instanceof (Integer i && i == 0 || i > 1) && (o = i) != null) {
|
||||
} else if (o != null && o instanceof Integer i && (i == 0 || i > 1) && (o = i) != null) {
|
||||
return "second";
|
||||
} else {
|
||||
return "any";
|
||||
@ -127,24 +128,24 @@ public class Guards {
|
||||
|
||||
String typeGuardAfterParenthesizedTrueSwitchStatement(Object o) {
|
||||
switch (o) {
|
||||
case (Integer i) && i == 0: o = String.valueOf(i); return "true";
|
||||
case ((Integer i) && i == 2): o = String.valueOf(i); return "second";
|
||||
case (Integer i) when i == 0: o = String.valueOf(i); return "true";
|
||||
case (Integer i) when i == 2: o = String.valueOf(i); return "second";
|
||||
case Object x: return "any";
|
||||
}
|
||||
}
|
||||
|
||||
String typeGuardAfterParenthesizedTrueSwitchExpression(Object o) {
|
||||
return switch (o) {
|
||||
case (Integer i) && i == 0: o = String.valueOf(i); yield "true";
|
||||
case ((Integer i) && i == 2): o = String.valueOf(i); yield "second";
|
||||
case (Integer i) when i == 0: o = String.valueOf(i); yield "true";
|
||||
case (Integer i) when i == 2: o = String.valueOf(i); yield "second";
|
||||
case Object x: yield "any";
|
||||
};
|
||||
}
|
||||
|
||||
String typeGuardAfterParenthesizedTrueIfStatement(Object o) {
|
||||
if (o != null && o instanceof ((Integer i) && i == 0)) {
|
||||
if (o != null && o instanceof (Integer i) && i == 0) {
|
||||
return "true";
|
||||
} else if (o != null && o instanceof (((Integer i) && i == 2)) && (o = i) != null) {
|
||||
} else if (o != null && o instanceof (Integer i) && i == 2 && (o = i) != null) {
|
||||
return "second";
|
||||
} else {
|
||||
return "any";
|
||||
@ -152,12 +153,32 @@ public class Guards {
|
||||
}
|
||||
|
||||
String testPatternInGuard(Object o) {
|
||||
if (o instanceof (CharSequence cs && cs instanceof String s)) {
|
||||
if (o instanceof CharSequence cs && cs instanceof String s) {
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void testGuardNPE() {
|
||||
assertEquals("empty", guardNPE(""));
|
||||
assertEquals("A", guardNPE("A"));
|
||||
assertEquals("other", guardNPE(1));
|
||||
try {
|
||||
guardNPE(null);
|
||||
throw new AssertionError("Expected exception missing.");
|
||||
} catch (NullPointerException ex) {
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
String guardNPE(Object o) {
|
||||
return switch (o) {
|
||||
case null, String s when s.isEmpty() -> "empty";
|
||||
case String s -> s;
|
||||
case Object x -> "other";
|
||||
};
|
||||
}
|
||||
|
||||
void assertEquals(String expected, String actual) {
|
||||
if (!Objects.equals(expected, actual)) {
|
||||
throw new AssertionError("Expected: " + expected + ", but got: " + actual);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -28,11 +28,13 @@
|
||||
* @compile/fail/ref=GuardsErrors.out -XDrawDiagnostics --enable-preview -source ${jdk.version} GuardsErrors.java
|
||||
*/
|
||||
|
||||
//TODO: tests and error recovery for misplaced guards
|
||||
|
||||
public class GuardsErrors {
|
||||
|
||||
void typeTestPatternSwitchTest(Object o, int check) {
|
||||
switch (o) {
|
||||
case Integer i && i == check -> System.err.println(); //error: check is not effectivelly final
|
||||
case Integer i when i == check -> System.err.println(); //error: check is not effectivelly final
|
||||
default -> {}
|
||||
}
|
||||
check = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
GuardsErrors.java:35:36: compiler.err.cant.ref.non.effectively.final.var: check, (compiler.misc.guard)
|
||||
GuardsErrors.java:37:38: compiler.err.cant.ref.non.effectively.final.var: check, (compiler.misc.guard)
|
||||
- compiler.note.preview.filename: GuardsErrors.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
1 error
|
||||
|
@ -0,0 +1,2 @@
|
||||
InstanceofTotalPattern.java:18:37: compiler.err.feature.not.supported.in.source: (compiler.misc.feature.pattern.matching.instanceof), 15, 16
|
||||
1 error
|
@ -0,0 +1,3 @@
|
||||
InstanceofTotalPattern.java:18:19: compiler.err.instanceof.pattern.no.subtype: java.lang.String, java.lang.String
|
||||
InstanceofTotalPattern.java:22:17: compiler.err.instanceof.pattern.no.subtype: java.lang.String, java.lang.String
|
||||
2 errors
|
@ -0,0 +1,3 @@
|
||||
InstanceofTotalPattern.java:18:30: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.unconditional.patterns.in.instanceof)
|
||||
InstanceofTotalPattern.java:22:28: compiler.warn.preview.feature.use.plural: (compiler.misc.feature.unconditional.patterns.in.instanceof)
|
||||
2 warnings
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @summary Verify behavior of total patterns in instanceof
|
||||
* @compile/fail/ref=InstanceofTotalPattern-15.out -source 15 -Xlint:-options -XDrawDiagnostics InstanceofTotalPattern.java
|
||||
* @compile/fail/ref=InstanceofTotalPattern-16.out -source 16 -Xlint:-options -XDrawDiagnostics InstanceofTotalPattern.java
|
||||
* @compile/ref=InstanceofTotalPattern-preview.out --enable-preview -source ${jdk.version} -Xlint:-options,preview -XDrawDiagnostics InstanceofTotalPattern.java
|
||||
* @run main/othervm --enable-preview InstanceofTotalPattern
|
||||
*/
|
||||
|
||||
public class InstanceofTotalPattern {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new InstanceofTotalPattern().totalTest();
|
||||
}
|
||||
|
||||
void totalTest() {
|
||||
String str = "";
|
||||
if (!(str instanceof String s1)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
str = null;
|
||||
if (str instanceof String s2) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -71,7 +71,7 @@ public class NestedPatternVariablesBytecode extends TestRunner {
|
||||
String code = """
|
||||
class NestedPatterVariablesTest {
|
||||
String test(Object o) {
|
||||
if (o instanceof (CharSequence cs && cs instanceof String s)) {
|
||||
if (o instanceof CharSequence cs && cs instanceof String s) {
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
|
@ -45,12 +45,18 @@ public class NullSwitch {
|
||||
assertEquals(0, matchingSwitch8(""));
|
||||
assertEquals(1, matchingSwitch8(null));
|
||||
assertEquals(1, matchingSwitch8(0.0));
|
||||
assertEquals(0, matchingSwitch9(""));
|
||||
assertEquals(1, matchingSwitch9(null));
|
||||
assertEquals(1, matchingSwitch9(0.0));
|
||||
assertEquals(0, matchingSwitch10(""));
|
||||
assertEquals(1, matchingSwitch10(null));
|
||||
assertEquals(1, matchingSwitch10(0.0));
|
||||
assertEquals(0, matchingSwitch9a(""));
|
||||
assertEquals(1, matchingSwitch9a(null));
|
||||
assertEquals(1, matchingSwitch9a(0.0));
|
||||
assertEquals(0, matchingSwitch10a(""));
|
||||
assertEquals(1, matchingSwitch10a(null));
|
||||
assertEquals(1, matchingSwitch10a(0.0));
|
||||
assertEquals(0, matchingSwitch9b(""));
|
||||
assertEquals(2, matchingSwitch9b(null));
|
||||
assertEquals(1, matchingSwitch9b(0.0));
|
||||
assertEquals(0, matchingSwitch10b(""));
|
||||
assertEquals(2, matchingSwitch10b(null));
|
||||
assertEquals(1, matchingSwitch10b(0.0));
|
||||
assertEquals(0, matchingSwitch11(""));
|
||||
assertEquals(2, matchingSwitch11(null));
|
||||
assertEquals(1, matchingSwitch11(0.0));
|
||||
@ -126,17 +132,39 @@ public class NullSwitch {
|
||||
};
|
||||
}
|
||||
|
||||
private int matchingSwitch9(Object obj) {
|
||||
private int matchingSwitch9a(Object obj) {
|
||||
return switch (obj) {
|
||||
case String s: yield 0;
|
||||
case Object o: yield 1;
|
||||
case null, Object o: yield 1;
|
||||
};
|
||||
}
|
||||
|
||||
private int matchingSwitch10(Object obj) {
|
||||
private int matchingSwitch10a(Object obj) {
|
||||
switch (obj) {
|
||||
case String s: return 0;
|
||||
case Object o: return 1;
|
||||
case null, Object o: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private int matchingSwitch9b(Object obj) {
|
||||
try {
|
||||
return switch (obj) {
|
||||
case String s: yield 0;
|
||||
case Object o: yield 1;
|
||||
};
|
||||
} catch (NullPointerException ex) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
private int matchingSwitch10b(Object obj) {
|
||||
try {
|
||||
switch (obj) {
|
||||
case String s: return 0;
|
||||
case Object o: return 1;
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -36,17 +36,17 @@ public class Parenthesized {
|
||||
void run() {
|
||||
Object o = "";
|
||||
switch (o) {
|
||||
case (String s && s.isEmpty()) -> System.err.println("OK: " + s);
|
||||
case (String s) when s.isEmpty() -> System.err.println("OK: " + s);
|
||||
default -> throw new AssertionError();
|
||||
}
|
||||
System.err.println(switch (o) {
|
||||
case (String s && s.isEmpty()) -> "OK: " + s;
|
||||
case (String s) when s.isEmpty() -> "OK: " + s;
|
||||
default -> throw new AssertionError();
|
||||
});
|
||||
if (o instanceof (String s && s.isEmpty())) {
|
||||
if (o instanceof (String s) && s.isEmpty()) {
|
||||
System.err.println("OK: " + s);
|
||||
}
|
||||
boolean b1 = o instanceof (String s && s.isEmpty());
|
||||
boolean b1 = o instanceof (String s) && s.isEmpty();
|
||||
boolean b2 = o instanceof String s && s.isEmpty();
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ public class RawTypeBindingWarning<T> {
|
||||
default -> {}
|
||||
}
|
||||
switch (o) {
|
||||
case (RawTypeBindingWarning w && false) -> {}
|
||||
case RawTypeBindingWarning w when false -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
RawTypeBindingWarning.java:9:29: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
|
||||
RawTypeBindingWarning.java:13:18: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
|
||||
RawTypeBindingWarning.java:17:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
|
||||
RawTypeBindingWarning.java:21:19: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
|
||||
RawTypeBindingWarning.java:21:18: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
|
||||
- compiler.note.preview.filename: RawTypeBindingWarning.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
4 warnings
|
||||
4 warnings
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -39,11 +39,11 @@ public class SealedTypeChanges {
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
doRun(this::expressionIntf, this::validateIncompatibleClassChangeError);
|
||||
doRun(this::statementIntf, this::validateIncompatibleClassChangeError);
|
||||
doRun(this::expressionCls, this::validateIncompatibleClassChangeError);
|
||||
doRun(this::statementCls, this::validateIncompatibleClassChangeError);
|
||||
doRun(this::statementFallThrough, this::validateIncompatibleClassChangeError);
|
||||
doRun(this::expressionIntf, this::validateMatchException);
|
||||
doRun(this::statementIntf, this::validateMatchException);
|
||||
doRun(this::expressionCls, this::validateMatchException);
|
||||
doRun(this::statementCls, this::validateMatchException);
|
||||
doRun(this::statementFallThrough, this::validateMatchException);
|
||||
doRun(this::expressionCoveredIntf, this::validateTestException);
|
||||
doRun(this::statementCoveredIntf, this::validateTestException);
|
||||
doRun(this::expressionCoveredCls, this::validateTestException);
|
||||
@ -60,8 +60,8 @@ public class SealedTypeChanges {
|
||||
}
|
||||
}
|
||||
|
||||
void validateIncompatibleClassChangeError(Throwable t) {
|
||||
if (!(t instanceof IncompatibleClassChangeError)) {
|
||||
void validateMatchException(Throwable t) {
|
||||
if (!(t instanceof MatchException)) {
|
||||
throw new AssertionError("Unexpected exception", t);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
* @compile --enable-preview -source ${jdk.version} -doe SimpleAndGuardPattern.java
|
||||
* @run main/othervm --enable-preview SimpleAndGuardPattern
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SimpleAndGuardPattern {
|
||||
@ -23,7 +45,7 @@ public class SimpleAndGuardPattern {
|
||||
|
||||
private static int simple(Object o) throws Throwable {
|
||||
return switch (o) {
|
||||
case String s && s.equalsIgnoreCase("test") -> s.length();
|
||||
case String s when s.equalsIgnoreCase("test") -> s.length();
|
||||
default -> -1;
|
||||
};
|
||||
}
|
||||
|
@ -175,20 +175,20 @@ public class SwitchErrors {
|
||||
}
|
||||
Object guardWithMatchingStatement(Object o1, Object o2) {
|
||||
switch (o1) {
|
||||
case String s && s.isEmpty() || o2 instanceof Number n: return n;
|
||||
case String s when s.isEmpty() || o2 instanceof Number n: return n;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
Object guardWithMatchingExpression(Object o1, Object o2) {
|
||||
return switch (o1) {
|
||||
case String s && s.isEmpty() || o2 instanceof Number n -> n;
|
||||
case String s when s.isEmpty() || o2 instanceof Number n -> n;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
void test8269146a1(Integer i) {
|
||||
switch (i) {
|
||||
//error - illegal combination of pattern and constant:
|
||||
case 1, Integer o && o != null:
|
||||
case 1, Integer o when o != null:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -197,7 +197,7 @@ public class SwitchErrors {
|
||||
void test8269146a2(Integer i) {
|
||||
switch (i) {
|
||||
//error - illegal combination of pattern and constant:
|
||||
case Integer o && o != null, 1:
|
||||
case Integer o when o != null, 1:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -206,7 +206,7 @@ public class SwitchErrors {
|
||||
void test8269146b(Integer i) {
|
||||
switch (i) {
|
||||
//error - illegal combination of null and pattern other than type pattern:
|
||||
case null, Integer o && o != null:
|
||||
case null, Integer o when o != null:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -222,14 +222,14 @@ public class SwitchErrors {
|
||||
void test8269301a(Integer i) {
|
||||
switch (i) {
|
||||
//error - illegal combination of pattern, constant and default
|
||||
case 1, Integer o && o != null, default:
|
||||
case 1, Integer o when o != null, default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void test8269301b(Integer i) {
|
||||
switch (i) {
|
||||
//error - illegal combination of pattern, constant and default
|
||||
case Integer o && o != null, 1, default:
|
||||
case Integer o when o != null, 1, default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -244,4 +244,14 @@ public class SwitchErrors {
|
||||
case CharSequence cs: break;
|
||||
}
|
||||
}
|
||||
void primitiveToReference(int i) {
|
||||
switch (i) {
|
||||
case Integer j: break;
|
||||
}
|
||||
}
|
||||
void referenceToPrimitive(Integer i) {
|
||||
switch (i) {
|
||||
case int j: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ SwitchErrors.java:23:18: compiler.err.prob.found.req: (compiler.misc.inconvertib
|
||||
SwitchErrors.java:28:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, int)
|
||||
SwitchErrors.java:29:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
SwitchErrors.java:30:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.CharSequence)
|
||||
SwitchErrors.java:36:13: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:36:13: compiler.err.unconditional.pattern.and.default
|
||||
SwitchErrors.java:42:18: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:42:24: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:48:18: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:54:18: compiler.err.duplicate.total.pattern
|
||||
SwitchErrors.java:42:24: compiler.err.unconditional.pattern.and.default
|
||||
SwitchErrors.java:48:18: compiler.err.unconditional.pattern.and.default
|
||||
SwitchErrors.java:54:18: compiler.err.duplicate.unconditional.pattern
|
||||
SwitchErrors.java:60:13: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:66:13: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:71:27: compiler.err.duplicate.default.label
|
||||
@ -29,17 +29,18 @@ SwitchErrors.java:148:27: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:154:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:160:18: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:172:18: compiler.err.pattern.expected
|
||||
SwitchErrors.java:178:76: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:184:71: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:178:78: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:184:73: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:191:21: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:200:42: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:209:24: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:218:29: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:200:44: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:218:29: compiler.err.unconditional.pattern.and.default
|
||||
SwitchErrors.java:225:21: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:225:45: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:232:42: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:232:45: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:244:18: compiler.err.duplicate.total.pattern
|
||||
SwitchErrors.java:225:47: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:232:44: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:232:47: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:244:18: compiler.err.duplicate.unconditional.pattern
|
||||
SwitchErrors.java:249:18: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, java.lang.Integer)
|
||||
SwitchErrors.java:254:18: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
|
||||
SwitchErrors.java:9:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:21:9: compiler.err.not.exhaustive.statement
|
||||
@ -54,4 +55,4 @@ SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:237:9: compiler.err.not.exhaustive.statement
|
||||
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
54 errors
|
||||
55 errors
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2022, 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
|
||||
@ -82,7 +82,7 @@ public class Switches {
|
||||
switchNestingTest(this::switchNestingExpressionStatement);
|
||||
switchNestingTest(this::switchNestingExpressionExpression);
|
||||
switchNestingTest(this::switchNestingIfSwitch);
|
||||
assertEquals(2, switchOverNull1());
|
||||
npeTest(x -> switchOverNull1());
|
||||
assertEquals(2, switchOverNull2());
|
||||
assertEquals(2, switchOverNull3());
|
||||
assertEquals(5, switchOverPrimitiveInt(0));
|
||||
@ -269,7 +269,7 @@ public class Switches {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case C: return String.valueOf(e);
|
||||
case E x && "A".equals(x.name()): return "broken";
|
||||
case E x when "A".equals(x.name()): return "broken";
|
||||
case null, E x: return String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -279,7 +279,7 @@ public class Switches {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case C -> String.valueOf(e);
|
||||
case E x && "A".equals(x.name()) -> "broken";
|
||||
case E x when "A".equals(x.name()) -> "broken";
|
||||
case null, E x -> String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -288,7 +288,7 @@ public class Switches {
|
||||
switch (e) {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case E x && "C".equals(x.name()): return "C";
|
||||
case E x when "C".equals(x.name()): return "C";
|
||||
case null, E x: return e == E.C ? "broken" : String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -297,7 +297,7 @@ public class Switches {
|
||||
return switch (e) {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case E x && "C".equals(x.name()) -> "C";
|
||||
case E x when "C".equals(x.name()) -> "C";
|
||||
case null, E x -> e == E.C ? "broken" : String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -306,7 +306,7 @@ public class Switches {
|
||||
switch (e) {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case Object x && "C".equals(x.toString()): return "C";
|
||||
case Object x when "C".equals(x.toString()): return "C";
|
||||
case null, E x: return e == E.C ? "broken" : String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -315,7 +315,7 @@ public class Switches {
|
||||
return switch (e) {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case Object x && "C".equals(x.toString()) -> "C";
|
||||
case Object x when "C".equals(x.toString()) -> "C";
|
||||
case null, E x -> e == E.C ? "broken" : String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -324,7 +324,7 @@ public class Switches {
|
||||
switch (e) {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case Runnable x && "C".equals(x.toString()): return "C";
|
||||
case Runnable x when "C".equals(x.toString()): return "C";
|
||||
case null, E x: return e == E.C ? "broken" : String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -333,7 +333,7 @@ public class Switches {
|
||||
return switch (e) {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case Runnable x && "C".equals(x.toString()) -> "C";
|
||||
case Runnable x when "C".equals(x.toString()) -> "C";
|
||||
case null, E x -> e == E.C ? "broken" : String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -342,7 +342,7 @@ public class Switches {
|
||||
switch (e != null ? e.name() : null) {
|
||||
case "A": return "a";
|
||||
case Switches.ConstantClassClash: return "b";
|
||||
case String x && "C".equals(x): return "C";
|
||||
case String x when "C".equals(x): return "C";
|
||||
case null, String x: return "C".equals(x) ? "broken" : String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -351,7 +351,7 @@ public class Switches {
|
||||
return switch (e != null ? e.name() : null) {
|
||||
case "A" -> "a";
|
||||
case ConstantClassClash -> "b";
|
||||
case String x && "C".equals(x) -> "C";
|
||||
case String x when "C".equals(x) -> "C";
|
||||
case null, String x -> e == E.C ? "broken" : String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -360,7 +360,7 @@ public class Switches {
|
||||
switch (e != null ? e.ordinal() : null) {
|
||||
case 0: return "a";
|
||||
case 1: return "b";
|
||||
case Integer x && x.equals(2): return "C";
|
||||
case Integer x when x.equals(2): return "C";
|
||||
case null, Integer x: return Objects.equals(x, 2) ? "broken" : String.valueOf(x);
|
||||
}
|
||||
}
|
||||
@ -369,7 +369,7 @@ public class Switches {
|
||||
return switch (e != null ? e.ordinal() : null) {
|
||||
case 0 -> "a";
|
||||
case 1 -> "b";
|
||||
case Integer x && x.equals(2) -> "C";
|
||||
case Integer x when x.equals(2) -> "C";
|
||||
case null, Integer x -> Objects.equals(x, 2) ? "broken" : String.valueOf(x);
|
||||
};
|
||||
}
|
||||
@ -378,7 +378,7 @@ public class Switches {
|
||||
int r = 0;
|
||||
|
||||
switch (i) {
|
||||
case Integer o && o != null:
|
||||
case Integer o when o != null:
|
||||
r = 1;
|
||||
default:
|
||||
r = 2;
|
||||
@ -389,7 +389,7 @@ public class Switches {
|
||||
|
||||
Integer testFallThroughExpression(Integer i) {
|
||||
int r = switch (i) {
|
||||
case Integer o && o != null:
|
||||
case Integer o when o != null:
|
||||
r = 1;
|
||||
default:
|
||||
r = 2;
|
||||
@ -403,7 +403,7 @@ public class Switches {
|
||||
int r = 0;
|
||||
|
||||
switch (i) {
|
||||
case Integer o && o != null:
|
||||
case Integer o when o != null:
|
||||
r = 1;
|
||||
case null, default:
|
||||
r = 2;
|
||||
@ -414,7 +414,7 @@ public class Switches {
|
||||
|
||||
Integer testFallThrough2Expression(Integer i) {
|
||||
int r = switch (i) {
|
||||
case Integer o && o != null:
|
||||
case Integer o when o != null:
|
||||
r = 1;
|
||||
case null, default:
|
||||
r = 2;
|
||||
@ -439,8 +439,17 @@ public class Switches {
|
||||
}
|
||||
|
||||
void exhaustiveStatementSane(Object o) {
|
||||
switch (o) {
|
||||
case Object obj:; //no break intentionally - should not fall through to any possible default
|
||||
try {
|
||||
switch (o) {
|
||||
case Object obj:; //no break intentionally - should not fall through to any possible default
|
||||
}
|
||||
if (o == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
if (o != null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
switch (o) {
|
||||
case null, Object obj:; //no break intentionally - should not fall through to any possible default
|
||||
@ -597,7 +606,7 @@ public class Switches {
|
||||
private int switchOverPrimitiveInt(Integer i) {
|
||||
return switch (i) {
|
||||
case 0 -> 5 + 0;
|
||||
case Integer j && j == 1 -> 6 + j;
|
||||
case Integer j when j == 1 -> 6 + j;
|
||||
case Integer j -> 7 + j;
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user