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

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,10 +25,23 @@
package com.sun.source.tree; package com.sun.source.tree;
import jdk.internal.javac.PreviewFeature;
/** /**
* A tree node used as the base class for the different kinds of * A tree node used as the base class for the different kinds of
* patterns. * patterns.
* *
* @since 16 * @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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -228,14 +228,6 @@ public interface Tree {
*/ */
BINDING_PATTERN(BindingPatternTree.class), 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}. * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -302,16 +302,6 @@ public interface TreeVisitor<R,P> {
*/ */
R visitNewArray(NewArrayTree node, P 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. * Visits a {@code ParenthesizedPatternTree} node.
* @param node the node being visited * @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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -703,22 +703,6 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
return defaultAction(node, 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} * {@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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -771,7 +771,9 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
*/ */
@Override @Override
public R visitBindingPattern(BindingPatternTree node, P p) { 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 @Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true) @PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitParenthesizedPattern(ParenthesizedPatternTree node, P p) { 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); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -186,6 +186,7 @@ public class Preview {
return switch (feature) { return switch (feature) {
case CASE_NULL -> true; case CASE_NULL -> true;
case PATTERN_SWITCH -> 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). //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true' //When real preview features will be added, this method can be implemented to return 'true'

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -239,6 +239,7 @@ public enum Source {
CASE_NULL(JDK17, Fragments.FeatureCaseNull, DiagKind.NORMAL), CASE_NULL(JDK17, Fragments.FeatureCaseNull, DiagKind.NORMAL),
PATTERN_SWITCH(JDK17, Fragments.FeaturePatternSwitch, DiagKind.PLURAL), PATTERN_SWITCH(JDK17, Fragments.FeaturePatternSwitch, DiagKind.PLURAL),
REDUNDANT_STRICTFP(JDK17), REDUNDANT_STRICTFP(JDK17),
UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK19, Fragments.FeatureUnconditionalPatternsInInstanceof, DiagKind.PLURAL),
; ;
enum DiagKind { enum DiagKind {

@ -189,6 +189,7 @@ public class Symtab {
public final Type assertionErrorType; public final Type assertionErrorType;
public final Type incompatibleClassChangeErrorType; public final Type incompatibleClassChangeErrorType;
public final Type cloneNotSupportedExceptionType; public final Type cloneNotSupportedExceptionType;
public final Type matchExceptionType;
public final Type annotationType; public final Type annotationType;
public final TypeSymbol enumSym; public final TypeSymbol enumSym;
public final Type listType; public final Type listType;
@ -553,6 +554,7 @@ public class Symtab {
assertionErrorType = enterClass("java.lang.AssertionError"); assertionErrorType = enterClass("java.lang.AssertionError");
incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError"); incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError");
cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException"); cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
matchExceptionType = enterClass("java.lang.MatchException");
annotationType = enterClass("java.lang.annotation.Annotation"); annotationType = enterClass("java.lang.annotation.Annotation");
classLoaderType = enterClass("java.lang.ClassLoader"); classLoaderType = enterClass("java.lang.ClassLoader");
enumSym = enterClass(java_base, names.java_lang_Enum); enumSym = enterClass(java_base, names.java_lang_Enum);

@ -174,6 +174,8 @@ public class Attr extends JCTree.Visitor {
allowRecords = Feature.RECORDS.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source);
allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) && allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
Feature.PATTERN_SWITCH.allowedInSource(source); 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; sourceName = source.name;
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning"); useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
@ -218,6 +220,10 @@ public class Attr extends JCTree.Visitor {
*/ */
private final boolean allowPatternSwitch; private final boolean allowPatternSwitch;
/** Are unconditional patterns in instanceof allowed
*/
private final boolean allowUnconditionalPatternsInstanceOf;
/** /**
* Switch: warn about use of variable before declaration? * Switch: warn about use of variable before declaration?
* RFE: 6425594 * RFE: 6425594
@ -1691,7 +1697,8 @@ public class Attr extends JCTree.Visitor {
List<Type> coveredTypesForPatterns = List.nil(); List<Type> coveredTypesForPatterns = List.nil();
List<Type> coveredTypesForConstants = List.nil(); List<Type> coveredTypesForConstants = List.nil();
boolean hasDefault = false; // Is there a default label? 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? boolean hasNullPattern = false; // Is there a null pattern?
CaseTree.CaseKind caseKind = null; CaseTree.CaseKind caseKind = null;
boolean wasError = false; boolean wasError = false;
@ -1706,7 +1713,7 @@ public class Attr extends JCTree.Visitor {
wasError = true; wasError = true;
} }
MatchBindings currentBindings = prevBindings; MatchBindings currentBindings = prevBindings;
boolean wasTotalPattern = hasTotalPattern; boolean wasUnconditionalPattern = hasUnconditionalPattern;
for (JCCaseLabel pat : c.labels) { for (JCCaseLabel pat : c.labels) {
if (pat.isExpression()) { if (pat.isExpression()) {
JCExpression expr = (JCExpression) pat; JCExpression expr = (JCExpression) pat;
@ -1714,7 +1721,7 @@ public class Attr extends JCTree.Visitor {
preview.checkSourceLevel(expr.pos(), Feature.CASE_NULL); preview.checkSourceLevel(expr.pos(), Feature.CASE_NULL);
if (hasNullPattern) { if (hasNullPattern) {
log.error(pat.pos(), Errors.DuplicateCaseLabel); log.error(pat.pos(), Errors.DuplicateCaseLabel);
} else if (wasTotalPattern) { } else if (wasUnconditionalPattern) {
log.error(pat.pos(), Errors.PatternDominated); log.error(pat.pos(), Errors.PatternDominated);
} }
hasNullPattern = true; hasNullPattern = true;
@ -1767,42 +1774,57 @@ public class Attr extends JCTree.Visitor {
} else if (pat.hasTag(DEFAULTCASELABEL)) { } else if (pat.hasTag(DEFAULTCASELABEL)) {
if (hasDefault) { if (hasDefault) {
log.error(pat.pos(), Errors.DuplicateDefaultLabel); log.error(pat.pos(), Errors.DuplicateDefaultLabel);
} else if (hasTotalPattern) { } else if (hasUnconditionalPattern) {
log.error(pat.pos(), Errors.TotalPatternAndDefault); log.error(pat.pos(), Errors.UnconditionalPatternAndDefault);
} }
hasDefault = true; hasDefault = true;
matchBindings = MatchBindingsComputer.EMPTY; matchBindings = MatchBindingsComputer.EMPTY;
} else { } else {
//binding pattern //binding pattern
attribExpr(pat, switchEnv); attribExpr(pat, switchEnv);
var primary = TreeInfo.primaryPatternType((JCPattern) pat); Type primaryType = TreeInfo.primaryPatternType(pat);
Type primaryType = primary.type();
if (!primaryType.hasTag(TYPEVAR)) { if (!primaryType.hasTag(TYPEVAR)) {
primaryType = chk.checkClassOrArrayType(pat.pos(), primaryType); primaryType = chk.checkClassOrArrayType(pat.pos(), primaryType);
} }
checkCastablePattern(pat.pos(), seltype, primaryType); checkCastablePattern(pat.pos(), seltype, primaryType);
Type patternType = types.erasure(primaryType); Type patternType = types.erasure(primaryType);
boolean isTotal = primary.unconditional() && JCExpression guard = ((JCPattern) pat).guard;
!patternType.isErroneous() && if (guard != null) {
types.isSubtype(types.erasure(seltype), patternType); MatchBindings afterPattern = matchBindings;
if (isTotal) { Env<AttrContext> bodyEnv = bindingEnv(env, matchBindings.bindingsWhenTrue);
if (hasTotalPattern) { try {
log.error(pat.pos(), Errors.DuplicateTotalPattern); attribExpr(guard, bodyEnv, syms.booleanType);
} else if (hasDefault) { } finally {
log.error(pat.pos(), Errors.TotalPatternAndDefault); 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); checkCaseLabelDominated(pat.pos(), coveredTypesForPatterns, patternType);
if (!patternType.isErroneous()) { if (!patternType.isErroneous()) {
coveredTypesForConstants = coveredTypesForConstants.prepend(patternType); coveredTypesForConstants = coveredTypesForConstants.prepend(patternType);
if (primary.unconditional()) { if (unguarded) {
coveredTypesForPatterns = coveredTypesForPatterns.prepend(patternType); coveredTypesForPatterns = coveredTypesForPatterns.prepend(patternType);
} }
} }
} }
currentBindings = matchBindingsComputer.switchCase(pat, currentBindings, matchBindings); currentBindings = matchBindingsComputer.switchCase(pat, currentBindings, matchBindings);
} }
Env<AttrContext> caseEnv = Env<AttrContext> caseEnv =
bindingEnv(switchEnv, c, currentBindings.bindingsWhenTrue); bindingEnv(switchEnv, c, currentBindings.bindingsWhenTrue);
try { try {
@ -1822,10 +1844,12 @@ public class Attr extends JCTree.Visitor {
chk.checkSwitchCaseStructure(cases); chk.checkSwitchCaseStructure(cases);
} }
if (switchTree.hasTag(SWITCH)) { if (switchTree.hasTag(SWITCH)) {
((JCSwitch) switchTree).hasTotalPattern = hasDefault || hasTotalPattern; ((JCSwitch) switchTree).hasUnconditionalPattern =
hasDefault || hasUnconditionalPattern || lastPatternErroneous;
((JCSwitch) switchTree).patternSwitch = patternSwitch; ((JCSwitch) switchTree).patternSwitch = patternSwitch;
} else if (switchTree.hasTag(SWITCH_EXPRESSION)) { } else if (switchTree.hasTag(SWITCH_EXPRESSION)) {
((JCSwitchExpression) switchTree).hasTotalPattern = hasDefault || hasTotalPattern; ((JCSwitchExpression) switchTree).hasUnconditionalPattern =
hasDefault || hasUnconditionalPattern || lastPatternErroneous;
((JCSwitchExpression) switchTree).patternSwitch = patternSwitch; ((JCSwitchExpression) switchTree).patternSwitch = patternSwitch;
} else { } else {
Assert.error(switchTree.getTag().name()); Assert.error(switchTree.getTag().name());
@ -4095,7 +4119,11 @@ public class Attr extends JCTree.Visitor {
clazztype = tree.pattern.type; clazztype = tree.pattern.type;
if (types.isSubtype(exprtype, clazztype) && if (types.isSubtype(exprtype, clazztype) &&
!exprtype.isErroneous() && !clazztype.isErroneous()) { !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; typeTree = TreeInfo.primaryPatternTree((JCPattern) tree.pattern).var.vartype;
} else { } else {
@ -4131,6 +4159,10 @@ public class Attr extends JCTree.Visitor {
chk.basicHandler.report(pos, chk.basicHandler.report(pos,
diags.fragment(Fragments.InconvertibleTypes(exprType, pattType))); diags.fragment(Fragments.InconvertibleTypes(exprType, pattType)));
return false; 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)) { } else if (warner.hasLint(LintCategory.UNCHECKED)) {
log.error(pos, log.error(pos,
Errors.InstanceofReifiableNotSafe(exprType, pattType)); Errors.InstanceofReifiableNotSafe(exprType, pattType));
@ -4163,20 +4195,6 @@ public class Attr extends JCTree.Visitor {
result = tree.type = tree.pattern.type; 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) { public void visitIndexed(JCArrayAccess tree) {
Type owntype = types.createErrorType(tree.type); Type owntype = types.createErrorType(tree.type);
Type atype = attribExpr(tree.indexed, env); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -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.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.tree.*; 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.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.Error; import com.sun.tools.javac.util.JCDiagnostic.Error;
@ -671,7 +670,9 @@ public class Flow {
JCCase c = l.head; JCCase c = l.head;
for (JCCaseLabel pat : c.labels) { for (JCCaseLabel pat : c.labels) {
scan(pat); scan(pat);
handleConstantCaseLabel(constants, pat); if (TreeInfo.unguardedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
} }
scanStats(c.stats); scanStats(c.stats);
if (alive != Liveness.DEAD && c.caseKind == JCCase.RULE) { if (alive != Liveness.DEAD && c.caseKind == JCCase.RULE) {
@ -686,7 +687,7 @@ public class Flow {
l.tail.head.pos(), l.tail.head.pos(),
Warnings.PossibleFallThroughIntoCase); Warnings.PossibleFallThroughIntoCase);
} }
tree.isExhaustive = tree.hasTotalPattern || tree.isExhaustive = tree.hasUnconditionalPattern ||
TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases);
if (exhaustiveSwitch) { if (exhaustiveSwitch) {
tree.isExhaustive |= isExhaustive(tree.selector.pos(), tree.selector.type, constants); tree.isExhaustive |= isExhaustive(tree.selector.pos(), tree.selector.type, constants);
@ -694,7 +695,7 @@ public class Flow {
log.error(tree, Errors.NotExhaustiveStatement); log.error(tree, Errors.NotExhaustiveStatement);
} }
} }
if (!tree.hasTotalPattern) { if (!tree.hasUnconditionalPattern) {
alive = Liveness.ALIVE; alive = Liveness.ALIVE;
} }
alive = alive.or(resolveBreaks(tree, prevPendingExits)); alive = alive.or(resolveBreaks(tree, prevPendingExits));
@ -712,7 +713,9 @@ public class Flow {
JCCase c = l.head; JCCase c = l.head;
for (JCCaseLabel pat : c.labels) { for (JCCaseLabel pat : c.labels) {
scan(pat); scan(pat);
handleConstantCaseLabel(constants, pat); if (TreeInfo.unguardedCaseLabel(pat)) {
handleConstantCaseLabel(constants, pat);
}
} }
scanStats(c.stats); scanStats(c.stats);
if (alive == Liveness.ALIVE) { 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) || TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) ||
isExhaustive(tree.selector.pos(), tree.selector.type, constants); isExhaustive(tree.selector.pos(), tree.selector.type, constants);
if (!tree.isExhaustive) { if (!tree.isExhaustive) {
@ -742,11 +745,9 @@ public class Flow {
if (expr.hasTag(IDENT) && ((JCIdent) expr).sym.isEnum()) if (expr.hasTag(IDENT) && ((JCIdent) expr).sym.isEnum())
constants.add(((JCIdent) expr).sym); constants.add(((JCIdent) expr).sym);
} else if (pat.isPattern()) { } else if (pat.isPattern()) {
PatternPrimaryType patternType = TreeInfo.primaryPatternType((JCPattern) pat); Type primaryType = TreeInfo.primaryPatternType(pat);
if (patternType.unconditional()) { constants.add(primaryType.tsym);
constants.add(patternType.type().tsym);
}
} }
} }
} }
@ -2014,6 +2015,14 @@ public class Flow {
scanExpr(l.head); 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) /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
* rather than (un)inits on exit. * rather than (un)inits on exit.
*/ */
@ -2454,11 +2463,7 @@ public class Flow {
uninits.assign(uninits.andSet(uninitsSwitch)); uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head; JCCase c = l.head;
for (JCCaseLabel pat : c.labels) { for (JCCaseLabel pat : c.labels) {
scan(pat); scanPattern(pat);
if (inits.isReset()) {
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
}
} }
if (l.head.stats.isEmpty() && if (l.head.stats.isEmpty() &&
l.tail.nonEmpty() && l.tail.nonEmpty() &&
@ -2847,8 +2852,9 @@ public class Flow {
@Override @Override
public void visitBindingPattern(JCBindingPattern tree) { public void visitBindingPattern(JCBindingPattern tree) {
super.visitBindingPattern(tree); scan(tree.var);
initParam(tree.var); initParam(tree.var);
scan(tree.guard);
} }
void referenced(Symbol sym) { void referenced(Symbol sym) {
@ -2940,7 +2946,7 @@ public class Flow {
} }
break; break;
} }
case GUARDPATTERN: case BINDINGPATTERN, PARENTHESIZEDPATTERN:
case LAMBDA: case LAMBDA:
if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) { if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
reportEffectivelyFinalError(pos, sym); reportEffectivelyFinalError(pos, sym);
@ -2964,7 +2970,7 @@ public class Flow {
reportInnerClsNeedsFinalError(tree, sym); reportInnerClsNeedsFinalError(tree, sym);
break; break;
} }
case GUARDPATTERN: case CASE:
case LAMBDA: case LAMBDA:
reportEffectivelyFinalError(tree, sym); reportEffectivelyFinalError(tree, sym);
} }
@ -2975,7 +2981,7 @@ public class Flow {
void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
Fragment subKey = switch (currentTree.getTag()) { Fragment subKey = switch (currentTree.getTag()) {
case LAMBDA -> Fragments.Lambda; case LAMBDA -> Fragments.Lambda;
case GUARDPATTERN -> Fragments.Guard; case BINDINGPATTERN, PARENTHESIZEDPATTERN -> Fragments.Guard;
case CLASSDEF -> Fragments.InnerCls; case CLASSDEF -> Fragments.InnerCls;
default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag()); default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag());
}; };
@ -3015,12 +3021,24 @@ public class Flow {
} }
@Override @Override
public void visitGuardPattern(JCGuardPattern tree) { public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.patt); scan(tree.var);
JCTree prevTree = currentTree; JCTree prevTree = currentTree;
try { try {
currentTree = tree; 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 { } finally {
currentTree = prevTree; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -3615,20 +3615,26 @@ public class Lower extends TreeTranslator {
} }
public void visitSwitch(JCSwitch tree) { 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); handleSwitch(tree, tree.selector, cases);
} }
@Override @Override
public void visitSwitchExpression(JCSwitchExpression tree) { 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); 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))) { if (cases.stream().flatMap(c -> c.labels.stream()).noneMatch(p -> p.hasTag(Tag.DEFAULTCASELABEL))) {
JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType, Type exception = matchException ? syms.matchExceptionType
List.nil())); : 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); JCCase c = make.Case(JCCase.STATEMENT, List.of(make.DefaultCaseLabel()), List.of(thr), null);
cases = cases.prepend(c); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -29,7 +29,7 @@ import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.BindingSymbol; import com.sun.tools.javac.code.Symbol.BindingSymbol;
import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.tree.JCTree; 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.JCTree.Tag;
import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context;
@ -112,7 +112,7 @@ public class MatchBindingsComputer extends TreeScanner {
return EMPTY; 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); return andOperation(tree.pos(), patternBindings, guardBindings);
} }
@ -142,7 +142,7 @@ public class MatchBindingsComputer extends TreeScanner {
public MatchBindings finishBindings(JCTree tree, MatchBindings matchBindings) { public MatchBindings finishBindings(JCTree tree, MatchBindings matchBindings) {
switch (tree.getTag()) { switch (tree.getTag()) {
case NOT: case AND: case OR: case BINDINGPATTERN: case NOT: case AND: case OR: case BINDINGPATTERN:
case PARENTHESIZEDPATTERN: case GUARDPATTERN: case PARENTHESIZEDPATTERN:
case PARENS: case TYPETEST: case PARENS: case TYPETEST:
case CONDEXPR: //error recovery: case CONDEXPR: //error recovery:
return matchBindings; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -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.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess; 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.JCLambda;
import com.sun.tools.javac.tree.JCTree.JCParenthesizedPattern; import com.sun.tools.javac.tree.JCTree.JCParenthesizedPattern;
import com.sun.tools.javac.tree.JCTree.JCPattern; import com.sun.tools.javac.tree.JCTree.JCPattern;
@ -255,27 +254,22 @@ public class TransPatterns extends TreeTranslator {
result = translate(tree.pattern); 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 @Override
public void visitSwitch(JCSwitch tree) { 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 @Override
public void visitSwitchExpression(JCSwitchExpression tree) { 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, private void handleSwitch(JCTree tree,
JCExpression selector, JCExpression selector,
List<JCCase> cases, List<JCCase> cases,
boolean hasTotalPattern, boolean hasUnconditionalPattern,
boolean patternSwitch) { boolean patternSwitch) {
if (patternSwitch) { if (patternSwitch) {
Type seltype = selector.type.hasTag(BOT) Type seltype = selector.type.hasTag(BOT)
@ -340,12 +334,6 @@ public class TransPatterns extends TreeTranslator {
JCCase lastCase = cases.last(); 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); selector = translate(selector);
boolean needsNullCheck = !hasNullCase && !seltype.isPrimitive(); boolean needsNullCheck = !hasNullCase && !seltype.isPrimitive();
statements.append(make.at(tree.pos).VarDef(temp, needsNullCheck ? attr.makeNullCheck(selector) statements.append(make.at(tree.pos).VarDef(temp, needsNullCheck ? attr.makeNullCheck(selector)
@ -415,6 +403,9 @@ public class TransPatterns extends TreeTranslator {
try { try {
currentValue = temp; currentValue = temp;
JCExpression test = (JCExpression) this.<JCTree>translate(p); 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); c.stats = translate(c.stats);
JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null); JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null);
continueSwitch.target = tree; continueSwitch.target = tree;
@ -437,10 +428,11 @@ public class TransPatterns extends TreeTranslator {
if (p.hasTag(Tag.DEFAULTCASELABEL)) { if (p.hasTag(Tag.DEFAULTCASELABEL)) {
translatedLabels.add(p); translatedLabels.add(p);
hasDefault = true; hasDefault = true;
} else if (hasTotalPattern && !hasDefault && } else if (hasUnconditionalPattern && !hasDefault &&
c == lastCase && p.isPattern()) { c == lastCase && p.isPattern()) {
//If the switch has total pattern, the last case will contain it. //If the switch has unconditional pattern,
//Convert the total pattern to default: //the last case will contain it.
//Convert the unconditional pattern to default:
translatedLabels.add(make.DefaultCaseLabel()); translatedLabels.add(make.DefaultCaseLabel());
} else { } else {
int value; int value;
@ -466,11 +458,13 @@ public class TransPatterns extends TreeTranslator {
if (tree.hasTag(Tag.SWITCH)) { if (tree.hasTag(Tag.SWITCH)) {
((JCSwitch) tree).selector = selector; ((JCSwitch) tree).selector = selector;
((JCSwitch) tree).cases = cases; ((JCSwitch) tree).cases = cases;
((JCSwitch) tree).wasEnumSelector = enumSelector;
statements.append((JCSwitch) tree); statements.append((JCSwitch) tree);
result = make.Block(0, statements.toList()); result = make.Block(0, statements.toList());
} else { } else {
((JCSwitchExpression) tree).selector = selector; ((JCSwitchExpression) tree).selector = selector;
((JCSwitchExpression) tree).cases = cases; ((JCSwitchExpression) tree).cases = cases;
((JCSwitchExpression) tree).wasEnumSelector = enumSelector;
LetExpr r = (LetExpr) make.LetExpr(statements.toList(), (JCSwitchExpression) tree) LetExpr r = (LetExpr) make.LetExpr(statements.toList(), (JCSwitchExpression) tree)
.setType(tree.type); .setType(tree.type);
@ -486,13 +480,13 @@ public class TransPatterns extends TreeTranslator {
} }
} }
private Type principalType(JCPattern p) { private Type principalType(JCTree p) {
return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p).type())); return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p)));
} }
private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) { private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) {
if (l.isPattern()) { if (l.isPattern()) {
Type principalType = principalType((JCPattern) l); Type principalType = principalType(l);
if (types.isSubtype(selector, principalType)) { if (types.isSubtype(selector, principalType)) {
return (LoadableConstant) selector; return (LoadableConstant) selector;
} else { } 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -565,6 +565,7 @@ public class TransTypes extends TreeTranslator {
public void visitBindingPattern(JCBindingPattern tree) { public void visitBindingPattern(JCBindingPattern tree) {
tree.var = translate(tree.var, null); tree.var = translate(tree.var, null);
tree.guard = translate(tree.guard, syms.booleanType);
result = tree; result = tree;
} }
@ -582,13 +583,7 @@ public class TransTypes extends TreeTranslator {
@Override @Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) { public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
tree.pattern = translate(tree.pattern, null); tree.pattern = translate(tree.pattern, null);
result = tree; tree.guard = translate(tree.guard, syms.booleanType);
}
@Override
public void visitGuardPattern(JCGuardPattern tree) {
tree.patt = translate(tree.patt, null);
tree.expr = translate(tree.expr, syms.booleanType);
result = tree; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -763,12 +763,12 @@ public class JavacParser implements Parser {
/** parses patterns. /** parses patterns.
*/ */
public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType, boolean inInstanceOf) { public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType) {
JCPattern pattern; JCPattern pattern;
if (token.kind == LPAREN && parsedType == null) { if (token.kind == LPAREN && parsedType == null) {
int startPos = token.pos; int startPos = token.pos;
accept(LPAREN); accept(LPAREN);
JCPattern p = parsePattern(token.pos, null, null, false); JCPattern p = parsePattern(token.pos, null, null);
accept(RPAREN); accept(RPAREN);
pattern = toP(F.at(startPos).ParenthesizedPattern(p)); pattern = toP(F.at(startPos).ParenthesizedPattern(p));
} else { } else {
@ -777,12 +777,6 @@ public class JavacParser implements Parser {
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null)); JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
pattern = toP(F.at(pos).BindingPattern(var)); 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; return pattern;
} }
@ -967,7 +961,7 @@ public class JavacParser implements Parser {
JCTree pattern; JCTree pattern;
if (token.kind == LPAREN) { if (token.kind == LPAREN) {
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH); checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
pattern = parsePattern(token.pos, null, null, true); pattern = parsePattern(token.pos, null, null);
} else { } else {
int patternPos = token.pos; int patternPos = token.pos;
JCModifiers mods = optFinal(0); JCModifiers mods = optFinal(0);
@ -975,7 +969,7 @@ public class JavacParser implements Parser {
JCExpression type = unannotatedType(false); JCExpression type = unannotatedType(false);
if (token.kind == IDENTIFIER) { if (token.kind == IDENTIFIER) {
checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF); checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
pattern = parsePattern(patternPos, mods, type, true); pattern = parsePattern(patternPos, mods, type);
} else { } else {
checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED); checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED);
if (mods.annotations.nonEmpty()) { if (mods.annotations.nonEmpty()) {
@ -3076,7 +3070,12 @@ public class JavacParser implements Parser {
analyzePattern(lookahead) == PatternResult.PATTERN; analyzePattern(lookahead) == PatternResult.PATTERN;
if (pattern) { if (pattern) {
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH); 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 { } else {
return term(EXPR | NOLAMBDA); 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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -506,11 +506,11 @@ compiler.err.pattern.dominated=\
compiler.err.duplicate.default.label=\ compiler.err.duplicate.default.label=\
duplicate default label duplicate default label
compiler.err.duplicate.total.pattern=\ compiler.err.duplicate.unconditional.pattern=\
duplicate total pattern duplicate unconditional pattern
compiler.err.total.pattern.and.default=\ compiler.err.unconditional.pattern.and.default=\
switch has both a total pattern and a default label switch has both an unconditional pattern and a default label
# 0: type, 1: type # 0: type, 1: type
compiler.err.constant.label.not.compatible=\ compiler.err.constant.label.not.compatible=\
@ -2518,6 +2518,10 @@ compiler.warn.prob.found.req=\
compiler.misc.inconvertible.types=\ compiler.misc.inconvertible.types=\
{0} cannot be converted to {1} {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 # 0: type, 1: type
compiler.misc.possible.loss.of.precision=\ compiler.misc.possible.loss.of.precision=\
possible lossy conversion from {0} to {1} possible lossy conversion from {0} to {1}
@ -3082,6 +3086,9 @@ compiler.misc.feature.case.null=\
compiler.misc.feature.pattern.switch=\ compiler.misc.feature.pattern.switch=\
patterns in switch statements patterns in switch statements
compiler.misc.feature.unconditional.patterns.in.instanceof=\
unconditional patterns in instanceof
compiler.warn.underscore.as.identifier=\ compiler.warn.underscore.as.identifier=\
as of release 9, ''_'' is a keyword, and may not be used as an identifier as of release 9, ''_'' is a keyword, and may not be used as an identifier

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -241,7 +241,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
*/ */
BINDINGPATTERN, BINDINGPATTERN,
DEFAULTCASELABEL, DEFAULTCASELABEL,
GUARDPATTERN,
PARENTHESIZEDPATTERN, PARENTHESIZEDPATTERN,
/** Indexed array expressions, of type Indexed. /** Indexed array expressions, of type Indexed.
@ -1284,9 +1283,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public List<JCCase> cases; public List<JCCase> cases;
/** Position of closing brace, optional. */ /** Position of closing brace, optional. */
public int endpos = Position.NOPOS; public int endpos = Position.NOPOS;
public boolean hasTotalPattern; public boolean hasUnconditionalPattern;
public boolean isExhaustive; public boolean isExhaustive;
public boolean patternSwitch; public boolean patternSwitch;
public boolean wasEnumSelector;
protected JCSwitch(JCExpression selector, List<JCCase> cases) { protected JCSwitch(JCExpression selector, List<JCCase> cases) {
this.selector = selector; this.selector = selector;
this.cases = cases; this.cases = cases;
@ -1371,9 +1371,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public List<JCCase> cases; public List<JCCase> cases;
/** Position of closing brace, optional. */ /** Position of closing brace, optional. */
public int endpos = Position.NOPOS; public int endpos = Position.NOPOS;
public boolean hasTotalPattern; public boolean hasUnconditionalPattern;
public boolean isExhaustive; public boolean isExhaustive;
public boolean patternSwitch; public boolean patternSwitch;
public boolean wasEnumSelector;
protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) { protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
this.selector = selector; this.selector = selector;
this.cases = cases; this.cases = cases;
@ -2243,6 +2244,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public abstract static class JCPattern extends JCCaseLabel public abstract static class JCPattern extends JCCaseLabel
implements PatternTree { implements PatternTree {
public JCExpression guard;
@Override @DefinedBy(Api.COMPILER_TREE)
public JCExpression getGuard() { return guard; }
@Override @Override
public boolean isExpression() { public boolean isExpression() {
return false; 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 * An array selection
*/ */
@ -3446,7 +3410,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public void visitBindingPattern(JCBindingPattern that) { visitTree(that); } public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); } public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); }
public void visitParenthesizedPattern(JCParenthesizedPattern 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 visitIndexed(JCArrayAccess that) { visitTree(that); }
public void visitSelect(JCFieldAccess that) { visitTree(that); } public void visitSelect(JCFieldAccess that) { visitTree(that); }
public void visitReference(JCMemberReference 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) { public void visitBindingPattern(JCBindingPattern patt) {
try { try {
printExpr(patt.var); printExpr(patt.var);
if (patt.guard != null) {
print(" when ");
printExpr(patt.guard);
}
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }
@ -911,17 +915,10 @@ public class Pretty extends JCTree.Visitor {
print("("); print("(");
printExpr(patt.pattern); printExpr(patt.pattern);
print(")"); print(")");
} catch (IOException e) { if (patt.guard != null) {
throw new UncheckedIOException(e); print(" when ");
} printExpr(patt.guard);
} }
@Override
public void visitGuardPattern(JCGuardPattern patt) {
try {
printExpr(patt.patt);
print(" && ");
printExpr(patt.expr);
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -494,22 +494,20 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
public JCTree visitBindingPattern(BindingPatternTree node, P p) { public JCTree visitBindingPattern(BindingPatternTree node, P p) {
JCBindingPattern t = (JCBindingPattern) node; JCBindingPattern t = (JCBindingPattern) node;
JCVariableDecl var = copy(t.var, p); JCVariableDecl var = copy(t.var, p);
return M.at(t.pos).BindingPattern(var); JCExpression guard = copy(t.guard, p);
} JCPattern pat = M.at(t.pos).BindingPattern(var);
pat.guard = guard;
@DefinedBy(Api.COMPILER_TREE) return pat;
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);
} }
@DefinedBy(Api.COMPILER_TREE) @DefinedBy(Api.COMPILER_TREE)
public JCTree visitParenthesizedPattern(ParenthesizedPatternTree node, P p) { public JCTree visitParenthesizedPattern(ParenthesizedPatternTree node, P p) {
JCParenthesizedPattern t = (JCParenthesizedPattern) node; JCParenthesizedPattern t = (JCParenthesizedPattern) node;
JCPattern pattern = copy(t.pattern, p); 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) @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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -542,10 +542,6 @@ public class TreeInfo {
JCBindingPattern node = (JCBindingPattern)tree; JCBindingPattern node = (JCBindingPattern)tree;
return getStartPos(node.var); return getStartPos(node.var);
} }
case GUARDPATTERN: {
JCGuardPattern node = (JCGuardPattern) tree;
return getStartPos(node.patt);
}
case ERRONEOUS: { case ERRONEOUS: {
JCErroneous node = (JCErroneous)tree; JCErroneous node = (JCErroneous)tree;
if (node.errs != null && node.errs.nonEmpty()) { if (node.errs != null && node.errs.nonEmpty()) {
@ -644,10 +640,6 @@ public class TreeInfo {
JCParenthesizedPattern node = (JCParenthesizedPattern) tree; JCParenthesizedPattern node = (JCParenthesizedPattern) tree;
return getEndPos(node.pattern, endPosTable); return getEndPos(node.pattern, endPosTable);
} }
case GUARDPATTERN: {
JCGuardPattern node = (JCGuardPattern) tree;
return getEndPos(node.expr, endPosTable);
}
case ERRONEOUS: { case ERRONEOUS: {
JCErroneous node = (JCErroneous)tree; JCErroneous node = (JCErroneous)tree;
if (node.errs != null && node.errs.nonEmpty()) if (node.errs != null && node.errs.nonEmpty())
@ -1314,42 +1306,40 @@ public class TreeInfo {
.allMatch(p -> p.hasTag(IDENT)); .allMatch(p -> p.hasTag(IDENT));
} }
public static PatternPrimaryType primaryPatternType(JCPattern pat) { public static Type primaryPatternType(JCTree pat) {
return switch (pat.getTag()) { return switch (pat.getTag()) {
case BINDINGPATTERN -> new PatternPrimaryType(((JCBindingPattern) pat).type, true); case BINDINGPATTERN -> pat.type;
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 PARENTHESIZEDPATTERN -> primaryPatternType(((JCParenthesizedPattern) pat).pattern); case PARENTHESIZEDPATTERN -> primaryPatternType(((JCParenthesizedPattern) pat).pattern);
default -> throw new AssertionError(); default -> throw new AssertionError();
}; };
} }
public static JCBindingPattern primaryPatternTree(JCPattern pat) { public static JCBindingPattern primaryPatternTree(JCTree pat) {
return switch (pat.getTag()) { return switch (pat.getTag()) {
case BINDINGPATTERN -> (JCBindingPattern) pat; case BINDINGPATTERN -> (JCBindingPattern) pat;
case GUARDPATTERN -> primaryPatternTree(((JCGuardPattern) pat).patt);
case PARENTHESIZEDPATTERN -> primaryPatternTree(((JCParenthesizedPattern) pat).pattern); case PARENTHESIZEDPATTERN -> primaryPatternTree(((JCParenthesizedPattern) pat).pattern);
default -> throw new AssertionError(); default -> throw new AssertionError();
}; };
} }
public record PatternPrimaryType(Type type, boolean unconditional) {}
public static boolean expectedExhaustive(JCSwitch tree) { public static boolean expectedExhaustive(JCSwitch tree) {
return tree.patternSwitch || return tree.patternSwitch ||
tree.cases.stream() tree.cases.stream()
.flatMap(c -> c.labels.stream()) .flatMap(c -> c.labels.stream())
.anyMatch(l -> TreeInfo.isNull(l)); .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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -500,12 +500,6 @@ public class TreeMaker implements JCTree.Factory {
return tree; 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) { public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) {
JCArrayAccess tree = new JCArrayAccess(indexed, index); JCArrayAccess tree = new JCArrayAccess(indexed, index);
tree.pos = pos; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -305,6 +305,7 @@ public class TreeScanner extends Visitor {
public void visitBindingPattern(JCBindingPattern tree) { public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.var); scan(tree.var);
scan(tree.guard);
} }
@Override @Override
@ -312,14 +313,9 @@ public class TreeScanner extends Visitor {
} }
@Override @Override
public void visitParenthesizedPattern(JCParenthesizedPattern that) { public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
scan(that.pattern); scan(tree.pattern);
} scan(tree.guard);
@Override
public void visitGuardPattern(JCGuardPattern that) {
scan(that.patt);
scan(that.expr);
} }
public void visitIndexed(JCArrayAccess tree) { 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -360,6 +360,7 @@ public class TreeTranslator extends JCTree.Visitor {
public void visitBindingPattern(JCBindingPattern tree) { public void visitBindingPattern(JCBindingPattern tree) {
tree.var = translate(tree.var); tree.var = translate(tree.var);
tree.guard = translate(tree.guard);
result = tree; result = tree;
} }
@ -371,13 +372,7 @@ public class TreeTranslator extends JCTree.Visitor {
@Override @Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) { public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
tree.pattern = translate(tree.pattern); tree.pattern = translate(tree.pattern);
result = tree; tree.guard = translate(tree.guard);
}
@Override
public void visitGuardPattern(JCGuardPattern tree) {
tree.patt = translate(tree.patt);
tree.expr = translate(tree.expr);
result = tree; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -69,6 +69,7 @@ public class Names {
public final Name transitive; public final Name transitive;
public final Name uses; public final Name uses;
public final Name open; public final Name open;
public final Name when;
public final Name with; public final Name with;
public final Name yield; public final Name yield;
@ -248,6 +249,7 @@ public class Names {
transitive = fromString("transitive"); transitive = fromString("transitive");
uses = fromString("uses"); uses = fromString("uses");
open = fromString("open"); open = fromString("open");
when = fromString("when");
with = fromString("with"); with = fromString("with");
yield = fromString("yield"); yield = fromString("yield");

@ -69,7 +69,7 @@ public class RuleSwitchBreaks extends LineNumberTestBase {
public class TestGuards { // 1 public class TestGuards { // 1
private void test(Object o) { // 2 private void test(Object o) { // 2
switch (o) { // 3 switch (o) { // 3
case String s && s.isEmpty() -> // 4 case String s when s.isEmpty() -> // 4
System.out.println("a"); // 5 System.out.println("a"); // 5
case String s -> // 6 case String s -> // 6
System.out.println("a"); // 7 System.out.println("a"); // 7

@ -48,7 +48,7 @@ class CantRefNonEffectivelyFinalVar {
void test3(Object o, int i) { void test3(Object o, int i) {
switch (o) { switch (o) {
case String s && s.length() == i++: break; case String s when s.length() == i++: break;
default: 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,12 +21,12 @@
* questions. * questions.
*/ */
// key: compiler.err.duplicate.total.pattern // key: compiler.err.duplicate.unconditional.pattern
// key: compiler.misc.feature.pattern.switch // key: compiler.misc.feature.pattern.switch
// key: compiler.warn.preview.feature.use.plural // key: compiler.warn.preview.feature.use.plural
// options: --enable-preview -source ${jdk.version} -Xlint:preview // options: --enable-preview -source ${jdk.version} -Xlint:preview
class DuplicateTotalPattern { class DuplicateUnconditionalPattern {
private void doSwitch(Object o) { private void doSwitch(Object o) {
switch (o) { switch (o) {
case Object obj: break; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as * under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this * published by the Free Software Foundation.
* 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 * This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
@ -23,28 +21,16 @@
* questions. * questions.
*/ */
package com.sun.source.tree; // key: compiler.misc.not.applicable.types
// key: compiler.err.prob.found.req
import jdk.internal.javac.PreviewFeature; // key: compiler.note.preview.filename
// key: compiler.note.preview.recompile
/** // options: --enable-preview --source ${jdk.version}
* 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();
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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,12 +21,12 @@
* questions. * questions.
*/ */
// key: compiler.err.total.pattern.and.default // key: compiler.err.unconditional.pattern.and.default
// key: compiler.misc.feature.pattern.switch // key: compiler.misc.feature.pattern.switch
// key: compiler.warn.preview.feature.use.plural // key: compiler.warn.preview.feature.use.plural
// options: --enable-preview -source ${jdk.version} -Xlint:preview // options: --enable-preview -source ${jdk.version} -Xlint:preview
class TotalPatternAndDefault { class UnconditionalPatternAndDefault {
private void doSwitch(Object o) { private void doSwitch(Object o) {
switch (o) { switch (o) {
case Object obj: break; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -94,7 +94,7 @@ public class CaseStructureTest extends ComboInstance<CaseStructureTest> {
task.generate(result -> { task.generate(result -> {
boolean shouldPass = true; 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 typePatternCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.TYPE_PATTERN).count();
long constantCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.CONSTANT).count(); long constantCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.CONSTANT).count();
long nullCases = Arrays.stream(caseLabels).filter(l -> l == CaseLabel.NULL).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) { for (CaseLabel label : caseLabels) {
switch (label) { switch (label) {
case NULL: if (seenPattern) shouldPass = false; break; 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(""), NONE(""),
TYPE_PATTERN("Integer i"), TYPE_PATTERN("Integer i"),
PARENTHESIZED_PATTERN("(Integer i)"), PARENTHESIZED_PATTERN("(Integer i)"),
GUARDED_PATTERN("Integer i && i > 0"),
CONSTANT("1"), CONSTANT("1"),
NULL("null"), NULL("null"),
DEFAULT("default"); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -53,7 +53,7 @@ public class DisambiguatePatterns {
DisambiguatePatterns test = new DisambiguatePatterns(); DisambiguatePatterns test = new DisambiguatePatterns();
test.disambiguationTest("String s", test.disambiguationTest("String s",
ExpressionType.PATTERN); ExpressionType.PATTERN);
test.disambiguationTest("String s && s.isEmpty()", test.disambiguationTest("String s when s.isEmpty()",
ExpressionType.PATTERN); ExpressionType.PATTERN);
test.disambiguationTest("(String s)", test.disambiguationTest("(String s)",
ExpressionType.PATTERN); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -40,22 +40,22 @@ public class Domination {
int testDominatesError2(Object o) { int testDominatesError2(Object o) {
switch (o) { switch (o) {
case CharSequence cs: return 0; 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; case Object x: return -1;
} }
} }
int testDominatesError3(Object o) { int testDominatesError3(Object o) {
switch (o) { switch (o) {
case CharSequence cs && true: return 0; case CharSequence cs when true: return 0;
case String s && s.isEmpty(): return 1; case String s when s.isEmpty(): return 1;
case Object x: return -1; case Object x: return -1;
} }
} }
int testNotDominates1(Object o) { int testNotDominates1(Object o) {
switch (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 String s: return 1;
case Object x: return -1; case Object x: return -1;
} }
@ -70,14 +70,14 @@ public class Domination {
int testDominatesStringConstant2(String str) { int testDominatesStringConstant2(String str) {
switch (str) { switch (str) {
case (String s && s.isEmpty()): return 1; case String s when s.isEmpty(): return 1;
case "": return -1; case "": return -1;
} }
} }
int testDominatesStringConstant3(String str) { int testDominatesStringConstant3(String str) {
switch (str) { switch (str) {
case (String s && !s.isEmpty()): return 1; case String s when !s.isEmpty(): return 1;
case "": return -1; case "": return -1;
} }
} }
@ -91,14 +91,14 @@ public class Domination {
int testDominatesIntegerConstant2(Integer i) { int testDominatesIntegerConstant2(Integer i) {
switch (i) { switch (i) {
case (Integer j && j == 0): return 1; case Integer j when j == 0: return 1;
case 0: return -1; case 0: return -1;
} }
} }
int testDominatesIntegerConstant3(Integer i) { int testDominatesIntegerConstant3(Integer i) {
switch (i) { switch (i) {
case (Integer j && j == 1): return 1; case Integer j when j == 1: return 1;
case 0: return -1; case 0: return -1;
} }
} }
@ -120,7 +120,7 @@ public class Domination {
} }
E e = E.A; E e = E.A;
switch (e) { switch (e) {
case (E d && d == E.A): return 1; case E d when d == E.A: return 1;
case A: return -1; case A: return -1;
} }
} }
@ -131,7 +131,7 @@ public class Domination {
} }
E e = E.A; E e = E.A;
switch (e) { switch (e) {
case (E d && d == E.B): return 1; case E d when d == E.B: return 1;
case A: 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -42,6 +42,8 @@ public class EnumTypeChanges {
void run() throws Exception { void run() throws Exception {
doRun(this::statementEnum); doRun(this::statementEnum);
doRun(this::expressionEnum); doRun(this::expressionEnum);
doRunExhaustive(this::expressionEnumExhaustive);
doRunExhaustive(this::statementEnumExhaustive);
} }
void doRun(Function<EnumTypeChangesEnum, String> c) throws Exception { void doRun(Function<EnumTypeChangesEnum, String> c) throws Exception {
@ -49,11 +51,20 @@ public class EnumTypeChanges {
assertEquals("D", c.apply(EnumTypeChangesEnum.valueOf("C"))); 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) { String statementEnum(EnumTypeChangesEnum e) {
switch (e) { switch (e) {
case A -> { return "A"; } case A -> { return "A"; }
case B -> { return "B"; } case B -> { return "B"; }
case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); case EnumTypeChangesEnum e1 when false -> throw new AssertionError();
default -> { return "D"; } default -> { return "D"; }
} }
} }
@ -62,11 +73,28 @@ public class EnumTypeChanges {
return switch (e) { return switch (e) {
case A -> "A"; case A -> "A";
case B -> "B"; case B -> "B";
case EnumTypeChangesEnum e1 && false -> throw new AssertionError(); case EnumTypeChangesEnum e1 when false -> throw new AssertionError();
default -> "D"; 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) { private static void assertEquals(Object o1, Object o2) {
if (!Objects.equals(o1, o2)) { if (!Objects.equals(o1, o2)) {
throw new AssertionError(); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -207,7 +207,7 @@ public class Exhaustiveness extends TestRunner {
public class Test { public class Test {
private int test(S obj) { private int test(S obj) {
return switch (obj) { return switch (obj) {
case A a && a.toString().isEmpty() -> 0; case A a when a.toString().isEmpty() -> 0;
case B b -> 1; case B b -> 1;
}; };
} }
@ -241,7 +241,7 @@ public class Exhaustiveness extends TestRunner {
private static final boolean TEST = true; private static final boolean TEST = true;
private int test(S obj) { private int test(S obj) {
return switch (obj) { return switch (obj) {
case A a && !(!(TEST)) -> 0; case A a when !(!(TEST)) -> 0;
case B b -> 1; case B b -> 1;
}; };
} }
@ -270,7 +270,7 @@ public class Exhaustiveness extends TestRunner {
public class Test { public class Test {
private int test(S obj) { private int test(S obj) {
return switch (obj) { return switch (obj) {
case A a && false -> 0; case A a when false -> 0;
case B b -> 1; case B b -> 1;
}; };
} }
@ -531,7 +531,7 @@ public class Exhaustiveness extends TestRunner {
private int test(S obj, boolean b) { private int test(S obj, boolean b) {
return switch (obj) { return switch (obj) {
case A a -> 0; case A a -> 0;
case C c && b -> 0; case C c when b -> 0;
case C c -> 0; case C c -> 0;
case D d -> 0; case D d -> 0;
}; };
@ -571,7 +571,7 @@ public class Exhaustiveness extends TestRunner {
return switch (obj) { return switch (obj) {
case A a -> 0; case A a -> 0;
case C c -> 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) { private <T extends Base & S & Marker> int test(T obj, boolean b) {
return switch (obj) { return switch (obj) {
case A a -> 0; case A a -> 0;
case C c && b -> 0; case C c when b -> 0;
case C c -> 0; case C c -> 0;
case D d -> 0; case D d -> 0;
}; };
@ -668,7 +668,7 @@ public class Exhaustiveness extends TestRunner {
return switch (obj) { return switch (obj) {
case A a -> 0; case A a -> 0;
case C c -> 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"); "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 { private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {
Path current = base.resolve("."); Path current = base.resolve(".");
Path libClasses = current.resolve("libClasses"); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -49,6 +49,7 @@ public class Guards {
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchStatement); runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchStatement);
runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchExpression); runIfTrue(this::typeGuardAfterParenthesizedTrueSwitchExpression);
runIfTrue(this::typeGuardAfterParenthesizedTrueIfStatement); runIfTrue(this::typeGuardAfterParenthesizedTrueIfStatement);
testGuardNPE();
} }
void run(Function<Object, String> convert) { void run(Function<Object, String> convert) {
@ -66,8 +67,8 @@ public class Guards {
String typeTestPatternSwitchTest(Object o) { String typeTestPatternSwitchTest(Object o) {
switch (o) { switch (o) {
case Integer i && i == 0: return "zero"; case Integer i when i == 0: return "zero";
case Integer i && i == 1: return "one"; case Integer i when i == 1: return "one";
case Integer i: return "other"; case Integer i: return "other";
case Object x: return "any"; case Object x: return "any";
} }
@ -75,8 +76,8 @@ public class Guards {
String typeTestPatternSwitchExpressionTest(Object o) { String typeTestPatternSwitchExpressionTest(Object o) {
return switch (o) { return switch (o) {
case Integer i && i == 0 -> "zero"; case Integer i when i == 0 -> "zero";
case Integer i && i == 1 -> { yield "one"; } case Integer i when i == 1 -> { yield "one"; }
case Integer i -> "other"; case Integer i -> "other";
case Object x -> "any"; case Object x -> "any";
}; };
@ -85,8 +86,8 @@ public class Guards {
String testBooleanSwitchExpression(Object o) { String testBooleanSwitchExpression(Object o) {
String x; String x;
if (switch (o) { if (switch (o) {
case Integer i && i == 0 -> (x = "zero") != null; case Integer i when i == 0 -> (x = "zero") != null;
case Integer i && i == 1 -> { x = "one"; yield true; } case Integer i when i == 1 -> { x = "one"; yield true; }
case Integer i -> { x = "other"; yield true; } case Integer i -> { x = "other"; yield true; }
case Object other -> (x = "any") != null; case Object other -> (x = "any") != null;
}) { }) {
@ -99,8 +100,8 @@ public class Guards {
String typeGuardIfTrueSwitchStatement(Object o) { String typeGuardIfTrueSwitchStatement(Object o) {
Object o2 = ""; Object o2 = "";
switch (o) { switch (o) {
case Integer i && i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); return "true"; case Integer i when 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: o = String.valueOf(i); return "second";
case Object x: return "any"; case Object x: return "any";
} }
} }
@ -108,17 +109,17 @@ public class Guards {
String typeGuardIfTrueSwitchExpression(Object o) { String typeGuardIfTrueSwitchExpression(Object o) {
Object o2 = ""; Object o2 = "";
return switch (o) { return switch (o) {
case Integer i && i == 0 && i < 1 && o2 instanceof String s: o = s + String.valueOf(i); yield "true"; case Integer i when 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: o = String.valueOf(i); yield "second";
case Object x: yield "any"; case Object x: yield "any";
}; };
} }
String typeGuardIfTrueIfStatement(Object o) { String typeGuardIfTrueIfStatement(Object o) {
Object o2 = ""; 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; 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"; return "second";
} else { } else {
return "any"; return "any";
@ -127,24 +128,24 @@ public class Guards {
String typeGuardAfterParenthesizedTrueSwitchStatement(Object o) { String typeGuardAfterParenthesizedTrueSwitchStatement(Object o) {
switch (o) { switch (o) {
case (Integer i) && i == 0: o = String.valueOf(i); return "true"; case (Integer i) when i == 0: o = String.valueOf(i); return "true";
case ((Integer i) && i == 2): o = String.valueOf(i); return "second"; case (Integer i) when i == 2: o = String.valueOf(i); return "second";
case Object x: return "any"; case Object x: return "any";
} }
} }
String typeGuardAfterParenthesizedTrueSwitchExpression(Object o) { String typeGuardAfterParenthesizedTrueSwitchExpression(Object o) {
return switch (o) { return switch (o) {
case (Integer i) && i == 0: o = String.valueOf(i); yield "true"; case (Integer i) when i == 0: o = String.valueOf(i); yield "true";
case ((Integer i) && i == 2): o = String.valueOf(i); yield "second"; case (Integer i) when i == 2: o = String.valueOf(i); yield "second";
case Object x: yield "any"; case Object x: yield "any";
}; };
} }
String typeGuardAfterParenthesizedTrueIfStatement(Object o) { String typeGuardAfterParenthesizedTrueIfStatement(Object o) {
if (o != null && o instanceof ((Integer i) && i == 0)) { if (o != null && o instanceof (Integer i) && i == 0) {
return "true"; 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"; return "second";
} else { } else {
return "any"; return "any";
@ -152,12 +153,32 @@ public class Guards {
} }
String testPatternInGuard(Object o) { 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 s;
} }
return null; 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) { void assertEquals(String expected, String actual) {
if (!Objects.equals(expected, actual)) { if (!Objects.equals(expected, actual)) {
throw new AssertionError("Expected: " + expected + ", but got: " + 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,11 +28,13 @@
* @compile/fail/ref=GuardsErrors.out -XDrawDiagnostics --enable-preview -source ${jdk.version} GuardsErrors.java * @compile/fail/ref=GuardsErrors.out -XDrawDiagnostics --enable-preview -source ${jdk.version} GuardsErrors.java
*/ */
//TODO: tests and error recovery for misplaced guards
public class GuardsErrors { public class GuardsErrors {
void typeTestPatternSwitchTest(Object o, int check) { void typeTestPatternSwitchTest(Object o, int check) {
switch (o) { 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 -> {} default -> {}
} }
check = 0; 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.filename: GuardsErrors.java, DEFAULT
- compiler.note.preview.recompile - compiler.note.preview.recompile
1 error 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -71,7 +71,7 @@ public class NestedPatternVariablesBytecode extends TestRunner {
String code = """ String code = """
class NestedPatterVariablesTest { class NestedPatterVariablesTest {
String test(Object o) { 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 s;
} }
return null; return null;

@ -45,12 +45,18 @@ public class NullSwitch {
assertEquals(0, matchingSwitch8("")); assertEquals(0, matchingSwitch8(""));
assertEquals(1, matchingSwitch8(null)); assertEquals(1, matchingSwitch8(null));
assertEquals(1, matchingSwitch8(0.0)); assertEquals(1, matchingSwitch8(0.0));
assertEquals(0, matchingSwitch9("")); assertEquals(0, matchingSwitch9a(""));
assertEquals(1, matchingSwitch9(null)); assertEquals(1, matchingSwitch9a(null));
assertEquals(1, matchingSwitch9(0.0)); assertEquals(1, matchingSwitch9a(0.0));
assertEquals(0, matchingSwitch10("")); assertEquals(0, matchingSwitch10a(""));
assertEquals(1, matchingSwitch10(null)); assertEquals(1, matchingSwitch10a(null));
assertEquals(1, matchingSwitch10(0.0)); 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(0, matchingSwitch11(""));
assertEquals(2, matchingSwitch11(null)); assertEquals(2, matchingSwitch11(null));
assertEquals(1, matchingSwitch11(0.0)); 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) { return switch (obj) {
case String s: yield 0; 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) { switch (obj) {
case String s: return 0; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -36,17 +36,17 @@ public class Parenthesized {
void run() { void run() {
Object o = ""; Object o = "";
switch (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(); default -> throw new AssertionError();
} }
System.err.println(switch (o) { System.err.println(switch (o) {
case (String s && s.isEmpty()) -> "OK: " + s; case (String s) when s.isEmpty() -> "OK: " + s;
default -> throw new AssertionError(); default -> throw new AssertionError();
}); });
if (o instanceof (String s && s.isEmpty())) { if (o instanceof (String s) && s.isEmpty()) {
System.err.println("OK: " + s); 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(); boolean b2 = o instanceof String s && s.isEmpty();
} }

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

@ -1,7 +1,7 @@
RawTypeBindingWarning.java:9:29: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T> 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:13:18: compiler.warn.raw.class.use: RawTypeBindingWarning, RawTypeBindingWarning<T>
RawTypeBindingWarning.java:17:19: 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.filename: RawTypeBindingWarning.java, DEFAULT
- compiler.note.preview.recompile - 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,11 +39,11 @@ public class SealedTypeChanges {
} }
void run() throws Exception { void run() throws Exception {
doRun(this::expressionIntf, this::validateIncompatibleClassChangeError); doRun(this::expressionIntf, this::validateMatchException);
doRun(this::statementIntf, this::validateIncompatibleClassChangeError); doRun(this::statementIntf, this::validateMatchException);
doRun(this::expressionCls, this::validateIncompatibleClassChangeError); doRun(this::expressionCls, this::validateMatchException);
doRun(this::statementCls, this::validateIncompatibleClassChangeError); doRun(this::statementCls, this::validateMatchException);
doRun(this::statementFallThrough, this::validateIncompatibleClassChangeError); doRun(this::statementFallThrough, this::validateMatchException);
doRun(this::expressionCoveredIntf, this::validateTestException); doRun(this::expressionCoveredIntf, this::validateTestException);
doRun(this::statementCoveredIntf, this::validateTestException); doRun(this::statementCoveredIntf, this::validateTestException);
doRun(this::expressionCoveredCls, this::validateTestException); doRun(this::expressionCoveredCls, this::validateTestException);
@ -60,8 +60,8 @@ public class SealedTypeChanges {
} }
} }
void validateIncompatibleClassChangeError(Throwable t) { void validateMatchException(Throwable t) {
if (!(t instanceof IncompatibleClassChangeError)) { if (!(t instanceof MatchException)) {
throw new AssertionError("Unexpected exception", t); 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 * @test
* @compile --enable-preview -source ${jdk.version} -doe SimpleAndGuardPattern.java * @compile --enable-preview -source ${jdk.version} -doe SimpleAndGuardPattern.java
* @run main/othervm --enable-preview SimpleAndGuardPattern * @run main/othervm --enable-preview SimpleAndGuardPattern
*/ */
import java.util.List;
import java.util.Objects; import java.util.Objects;
public class SimpleAndGuardPattern { public class SimpleAndGuardPattern {
@ -23,7 +45,7 @@ public class SimpleAndGuardPattern {
private static int simple(Object o) throws Throwable { private static int simple(Object o) throws Throwable {
return switch (o) { return switch (o) {
case String s && s.equalsIgnoreCase("test") -> s.length(); case String s when s.equalsIgnoreCase("test") -> s.length();
default -> -1; default -> -1;
}; };
} }

@ -175,20 +175,20 @@ public class SwitchErrors {
} }
Object guardWithMatchingStatement(Object o1, Object o2) { Object guardWithMatchingStatement(Object o1, Object o2) {
switch (o1) { 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; default: return null;
} }
} }
Object guardWithMatchingExpression(Object o1, Object o2) { Object guardWithMatchingExpression(Object o1, Object o2) {
return switch (o1) { 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; default -> null;
}; };
} }
void test8269146a1(Integer i) { void test8269146a1(Integer i) {
switch (i) { switch (i) {
//error - illegal combination of pattern and constant: //error - illegal combination of pattern and constant:
case 1, Integer o && o != null: case 1, Integer o when o != null:
break; break;
default: default:
break; break;
@ -197,7 +197,7 @@ public class SwitchErrors {
void test8269146a2(Integer i) { void test8269146a2(Integer i) {
switch (i) { switch (i) {
//error - illegal combination of pattern and constant: //error - illegal combination of pattern and constant:
case Integer o && o != null, 1: case Integer o when o != null, 1:
break; break;
default: default:
break; break;
@ -206,7 +206,7 @@ public class SwitchErrors {
void test8269146b(Integer i) { void test8269146b(Integer i) {
switch (i) { switch (i) {
//error - illegal combination of null and pattern other than type pattern: //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; break;
default: default:
break; break;
@ -222,14 +222,14 @@ public class SwitchErrors {
void test8269301a(Integer i) { void test8269301a(Integer i) {
switch (i) { switch (i) {
//error - illegal combination of pattern, constant and default //error - illegal combination of pattern, constant and default
case 1, Integer o && o != null, default: case 1, Integer o when o != null, default:
break; break;
} }
} }
void test8269301b(Integer i) { void test8269301b(Integer i) {
switch (i) { switch (i) {
//error - illegal combination of pattern, constant and default //error - illegal combination of pattern, constant and default
case Integer o && o != null, 1, default: case Integer o when o != null, 1, default:
break; break;
} }
} }
@ -244,4 +244,14 @@ public class SwitchErrors {
case CharSequence cs: break; 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: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: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: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:18: compiler.err.pattern.dominated
SwitchErrors.java:42:24: compiler.err.total.pattern.and.default SwitchErrors.java:42:24: compiler.err.unconditional.pattern.and.default
SwitchErrors.java:48:18: compiler.err.total.pattern.and.default SwitchErrors.java:48:18: compiler.err.unconditional.pattern.and.default
SwitchErrors.java:54:18: compiler.err.duplicate.total.pattern SwitchErrors.java:54:18: compiler.err.duplicate.unconditional.pattern
SwitchErrors.java:60:13: compiler.err.duplicate.default.label SwitchErrors.java:60:13: compiler.err.duplicate.default.label
SwitchErrors.java:66:13: compiler.err.duplicate.default.label SwitchErrors.java:66:13: compiler.err.duplicate.default.label
SwitchErrors.java:71:27: 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:154:18: compiler.err.flows.through.to.pattern
SwitchErrors.java:160:18: compiler.err.pattern.dominated SwitchErrors.java:160:18: compiler.err.pattern.dominated
SwitchErrors.java:172:18: compiler.err.pattern.expected 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:178:78: 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: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:191:21: compiler.err.flows.through.to.pattern
SwitchErrors.java:200:42: compiler.err.pattern.dominated SwitchErrors.java:200:44: compiler.err.pattern.dominated
SwitchErrors.java:209:24: compiler.err.flows.through.to.pattern SwitchErrors.java:218:29: compiler.err.unconditional.pattern.and.default
SwitchErrors.java:218:29: compiler.err.total.pattern.and.default
SwitchErrors.java:225:21: compiler.err.flows.through.to.pattern SwitchErrors.java:225:21: compiler.err.flows.through.to.pattern
SwitchErrors.java:225:45: compiler.err.flows.through.from.pattern SwitchErrors.java:225:47: compiler.err.flows.through.from.pattern
SwitchErrors.java:232:42: compiler.err.pattern.dominated SwitchErrors.java:232:44: compiler.err.pattern.dominated
SwitchErrors.java:232:45: compiler.err.flows.through.from.pattern SwitchErrors.java:232:47: compiler.err.flows.through.from.pattern
SwitchErrors.java:244:18: compiler.err.duplicate.total.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:9:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement
SwitchErrors.java:21: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 SwitchErrors.java:237:9: compiler.err.not.exhaustive.statement
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT - compiler.note.preview.filename: SwitchErrors.java, DEFAULT
- compiler.note.preview.recompile - 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -82,7 +82,7 @@ public class Switches {
switchNestingTest(this::switchNestingExpressionStatement); switchNestingTest(this::switchNestingExpressionStatement);
switchNestingTest(this::switchNestingExpressionExpression); switchNestingTest(this::switchNestingExpressionExpression);
switchNestingTest(this::switchNestingIfSwitch); switchNestingTest(this::switchNestingIfSwitch);
assertEquals(2, switchOverNull1()); npeTest(x -> switchOverNull1());
assertEquals(2, switchOverNull2()); assertEquals(2, switchOverNull2());
assertEquals(2, switchOverNull3()); assertEquals(2, switchOverNull3());
assertEquals(5, switchOverPrimitiveInt(0)); assertEquals(5, switchOverPrimitiveInt(0));
@ -269,7 +269,7 @@ public class Switches {
case A: return "a"; case A: return "a";
case B: return "b"; case B: return "b";
case C: return String.valueOf(e); 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); case null, E x: return String.valueOf(x);
} }
} }
@ -279,7 +279,7 @@ public class Switches {
case A -> "a"; case A -> "a";
case B -> "b"; case B -> "b";
case C -> String.valueOf(e); 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); case null, E x -> String.valueOf(x);
}; };
} }
@ -288,7 +288,7 @@ public class Switches {
switch (e) { switch (e) {
case A: return "a"; case A: return "a";
case B: return "b"; 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); case null, E x: return e == E.C ? "broken" : String.valueOf(x);
} }
} }
@ -297,7 +297,7 @@ public class Switches {
return switch (e) { return switch (e) {
case A -> "a"; case A -> "a";
case B -> "b"; 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); case null, E x -> e == E.C ? "broken" : String.valueOf(x);
}; };
} }
@ -306,7 +306,7 @@ public class Switches {
switch (e) { switch (e) {
case A: return "a"; case A: return "a";
case B: return "b"; 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); case null, E x: return e == E.C ? "broken" : String.valueOf(x);
} }
} }
@ -315,7 +315,7 @@ public class Switches {
return switch (e) { return switch (e) {
case A -> "a"; case A -> "a";
case B -> "b"; 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); case null, E x -> e == E.C ? "broken" : String.valueOf(x);
}; };
} }
@ -324,7 +324,7 @@ public class Switches {
switch (e) { switch (e) {
case A: return "a"; case A: return "a";
case B: return "b"; 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); case null, E x: return e == E.C ? "broken" : String.valueOf(x);
} }
} }
@ -333,7 +333,7 @@ public class Switches {
return switch (e) { return switch (e) {
case A -> "a"; case A -> "a";
case B -> "b"; 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); case null, E x -> e == E.C ? "broken" : String.valueOf(x);
}; };
} }
@ -342,7 +342,7 @@ public class Switches {
switch (e != null ? e.name() : null) { switch (e != null ? e.name() : null) {
case "A": return "a"; case "A": return "a";
case Switches.ConstantClassClash: return "b"; 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); 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) { return switch (e != null ? e.name() : null) {
case "A" -> "a"; case "A" -> "a";
case ConstantClassClash -> "b"; 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); case null, String x -> e == E.C ? "broken" : String.valueOf(x);
}; };
} }
@ -360,7 +360,7 @@ public class Switches {
switch (e != null ? e.ordinal() : null) { switch (e != null ? e.ordinal() : null) {
case 0: return "a"; case 0: return "a";
case 1: return "b"; 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); 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) { return switch (e != null ? e.ordinal() : null) {
case 0 -> "a"; case 0 -> "a";
case 1 -> "b"; 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); case null, Integer x -> Objects.equals(x, 2) ? "broken" : String.valueOf(x);
}; };
} }
@ -378,7 +378,7 @@ public class Switches {
int r = 0; int r = 0;
switch (i) { switch (i) {
case Integer o && o != null: case Integer o when o != null:
r = 1; r = 1;
default: default:
r = 2; r = 2;
@ -389,7 +389,7 @@ public class Switches {
Integer testFallThroughExpression(Integer i) { Integer testFallThroughExpression(Integer i) {
int r = switch (i) { int r = switch (i) {
case Integer o && o != null: case Integer o when o != null:
r = 1; r = 1;
default: default:
r = 2; r = 2;
@ -403,7 +403,7 @@ public class Switches {
int r = 0; int r = 0;
switch (i) { switch (i) {
case Integer o && o != null: case Integer o when o != null:
r = 1; r = 1;
case null, default: case null, default:
r = 2; r = 2;
@ -414,7 +414,7 @@ public class Switches {
Integer testFallThrough2Expression(Integer i) { Integer testFallThrough2Expression(Integer i) {
int r = switch (i) { int r = switch (i) {
case Integer o && o != null: case Integer o when o != null:
r = 1; r = 1;
case null, default: case null, default:
r = 2; r = 2;
@ -439,8 +439,17 @@ public class Switches {
} }
void exhaustiveStatementSane(Object o) { void exhaustiveStatementSane(Object o) {
switch (o) { try {
case Object obj:; //no break intentionally - should not fall through to any possible default 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) { switch (o) {
case null, Object obj:; //no break intentionally - should not fall through to any possible default 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) { private int switchOverPrimitiveInt(Integer i) {
return switch (i) { return switch (i) {
case 0 -> 5 + 0; case 0 -> 5 + 0;
case Integer j && j == 1 -> 6 + j; case Integer j when j == 1 -> 6 + j;
case Integer j -> 7 + j; case Integer j -> 7 + j;
}; };
} }