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:
Jan Lahoda 2022-05-16 07:49:26 +00:00
parent 2d34acfec9
commit 0155e4b76b
53 changed files with 685 additions and 456 deletions

View 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);
}
}

View File

@ -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();
}

View File

@ -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}.
*

View File

@ -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

View File

@ -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}
*

View File

@ -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;
}
/**

View File

@ -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'

View File

@ -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 {

View File

@ -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);

View File

@ -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() &&
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();
}
matchBindings = matchBindingsComputer.caseGuard(c, afterPattern, matchBindings);
}
boolean unguarded = TreeInfo.unguardedCaseLabel(pat);
boolean unconditional =
unguarded &&
!patternType.isErroneous() &&
types.isSubtype(types.erasure(seltype), patternType);
if (isTotal) {
if (hasTotalPattern) {
log.error(pat.pos(), Errors.DuplicateTotalPattern);
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.TotalPatternAndDefault);
log.error(pat.pos(), Errors.UnconditionalPatternAndDefault);
}
hasTotalPattern = true;
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()) {
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);

View File

@ -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,8 +670,10 @@ public class Flow {
JCCase c = l.head;
for (JCCaseLabel pat : c.labels) {
scan(pat);
if (TreeInfo.unguardedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
}
scanStats(c.stats);
if (alive != Liveness.DEAD && c.caseKind == JCCase.RULE) {
scanSyntheticBreak(make, tree);
@ -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,8 +713,10 @@ public class Flow {
JCCase c = l.head;
for (JCCaseLabel pat : c.labels) {
scan(pat);
if (TreeInfo.unguardedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
}
scanStats(c.stats);
if (alive == Liveness.ALIVE) {
if (c.caseKind == JCCase.RULE) {
@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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); }

View File

@ -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);
if (patt.guard != null) {
print(" when ");
printExpr(patt.guard);
}
}
@Override
public void visitGuardPattern(JCGuardPattern patt) {
try {
printExpr(patt.patt);
print(" && ");
printExpr(patt.expr);
} catch (IOException e) {
throw new UncheckedIOException(e);
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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");

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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 -> {}
}
}
}

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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,18 +132,40 @@ public class NullSwitch {
};
}
private int matchingSwitch9(Object obj) {
private int matchingSwitch9a(Object obj) {
return switch (obj) {
case String s: yield 0;
case null, Object o: yield 1;
};
}
private int matchingSwitch10a(Object obj) {
switch (obj) {
case String s: return 0;
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 matchingSwitch10(Object obj) {
private int matchingSwitch10b(Object obj) {
try {
switch (obj) {
case String s: return 0;
case Object o: return 1;
}
} catch (NullPointerException ex) {
return 2;
}
}
private int matchingSwitch11(Object obj) {

View File

@ -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();
}

View File

@ -18,7 +18,7 @@ public class RawTypeBindingWarning<T> {
default -> {}
}
switch (o) {
case (RawTypeBindingWarning w && false) -> {}
case RawTypeBindingWarning w when false -> {}
default -> {}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
};
}

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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,9 +439,18 @@ public class Switches {
}
void exhaustiveStatementSane(Object o) {
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;
};
}