8287236: Reorganize AST related to pattern matching for switch

Reviewed-by: mcimadamore
This commit is contained in:
Jan Lahoda 2022-06-07 10:31:09 +00:00
parent 2d8c649054
commit bde7a7ae03
27 changed files with 551 additions and 229 deletions

@ -0,0 +1,44 @@
/*
* 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 com.sun.source.tree;
import jdk.internal.javac.PreviewFeature;
/**
* A case label element that refers to a constant expression
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public interface ConstantCaseLabelTree extends CaseLabelTree {
/**
* The constant expression for the case.
*
* @return the constant expression
*/
public ExpressionTree getConstantExpression();
}

@ -25,8 +25,6 @@
package com.sun.source.tree;
import jdk.internal.javac.NoPreview;
/**
* A tree node used as the base class for the different types of
* expressions.
@ -37,5 +35,4 @@ import jdk.internal.javac.NoPreview;
* @author Jonathan Gibbons
* @since 1.6
*/
@NoPreview
public interface ExpressionTree extends Tree, CaseLabelTree {}
public interface ExpressionTree extends Tree {}

@ -0,0 +1,51 @@
/*
* 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 com.sun.source.tree;
import jdk.internal.javac.PreviewFeature;
/**
* A case label element that refers to an expression
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public interface PatternCaseLabelTree extends CaseLabelTree {
/**
* The pattern for the case.
*
* @return the pattern
*/
public PatternTree getPattern();
/**
* The guard for the case.
*
* @return the guard
*/
ExpressionTree getGuard();
}

@ -25,23 +25,11 @@
package com.sun.source.tree;
import jdk.internal.javac.PreviewFeature;
/**
* A tree node used as the base class for the different kinds of
* patterns.
*
* @since 16
*/
public interface PatternTree extends Tree, CaseLabelTree {
/**
* The guard for the case.
*
* @return the guard
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
ExpressionTree getGuard();
public interface PatternTree extends Tree {
}

@ -244,6 +244,22 @@ public interface Tree {
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
DEFAULT_CASE_LABEL(DefaultCaseLabelTree.class),
/**
* Used for instances of {@link ConstantCaseLabelTree}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
CONSTANT_CASE_LABEL(ConstantCaseLabelTree.class),
/**
* Used for instances of {@link PatternCaseLabelTree}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
PATTERN_CASE_LABEL(PatternCaseLabelTree.class),
/**
* Used for instances of {@link DeconstructionPatternTree}.
*

@ -278,6 +278,26 @@ public interface TreeVisitor<R,P> {
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
R visitDefaultCaseLabel(DefaultCaseLabelTree node, P p);
/**
* Visits a {@code ConstantCaseLabelTree} node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
R visitConstantCaseLabel(ConstantCaseLabelTree node, P p);
/**
* Visits a {@code PatternCaseLabelTree} node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
R visitPatternCaseLabel(PatternCaseLabelTree node, P p);
/**
* Visits a {@code DeconstructionPatternTree} node.
* @param node the node being visited

@ -659,6 +659,22 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
return defaultAction(node, p);
}
/**
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
* @since 19
*/
@Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitConstantCaseLabel(ConstantCaseLabelTree node, P p) {
return defaultAction(node, p);
}
/**
* {@inheritDoc}
*
@ -676,7 +692,25 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
}
/**
* {@inheritDoc} This implementation calls {@code defaultAction}.
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
* @since 19
*/
@Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitPatternCaseLabel(PatternCaseLabelTree node, P p) {
return defaultAction(node, p);
}
/**
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}

@ -396,7 +396,7 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
*/
@Override
public R visitCase(CaseTree node, P p) {
R r = scan(node.getExpressions(), p);
R r = scan(node.getLabels(), p);
if (node.getCaseKind() == CaseTree.CaseKind.RULE)
r = scanAndReduce(node.getBody(), p, r);
else
@ -771,9 +771,7 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
*/
@Override
public R visitBindingPattern(BindingPatternTree node, P p) {
R r = scan(node.getVariable(), p);
r = scanAndReduce(node.getGuard(), p, r);
return r;
return scan(node.getVariable(), p);
}
/**
@ -792,6 +790,40 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
return null;
}
/**
* {@inheritDoc}
*
* @implSpec This implementation returns {@code null}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
* @since 19
*/
@Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitConstantCaseLabel(ConstantCaseLabelTree node, P p) {
return scan(node.getConstantExpression(), p);
}
/**
* {@inheritDoc}
*
* @implSpec This implementation returns {@code null}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
* @since 19
*/
@Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitPatternCaseLabel(PatternCaseLabelTree node, P p) {
R r = scan(node.getPattern(), p);
r = scanAndReduce(node.getGuard(), p, r);
return r;
}
/**
* {@inheritDoc}
*
@ -808,7 +840,6 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
R r = scan(node.getDeconstructor(), p);
r = scanAndReduce(node.getNestedPatterns(), p, r);
r = scanAndReduce(node.getVariable(), p, r);
r = scanAndReduce(node.getGuard(), p, r);
return r;
}
@ -853,9 +884,7 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
@Override
@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING, reflective=true)
public R visitParenthesizedPattern(ParenthesizedPatternTree node, P p) {
R r = scan(node.getPattern(), p);
r = scanAndReduce(node.getGuard(), p, r);
return r;
return scan(node.getPattern(), p);
}
/**

@ -1689,7 +1689,7 @@ public class Attr extends JCTree.Visitor {
} else {
patternSwitch = cases.stream()
.flatMap(c -> c.labels.stream())
.anyMatch(l -> l.isPattern());
.anyMatch(l -> l.hasTag(PATTERNCASELABEL));
}
// Attribute all cases and
@ -1715,15 +1715,15 @@ public class Attr extends JCTree.Visitor {
}
MatchBindings currentBindings = prevBindings;
boolean wasUnconditionalPattern = hasUnconditionalPattern;
for (JCCaseLabel pat : c.labels) {
if (pat.isExpression()) {
JCExpression expr = (JCExpression) pat;
for (JCCaseLabel label : c.labels) {
if (label instanceof JCConstantCaseLabel constLabel) {
JCExpression expr = constLabel.expr;
if (TreeInfo.isNull(expr)) {
preview.checkSourceLevel(expr.pos(), Feature.CASE_NULL);
if (hasNullPattern) {
log.error(pat.pos(), Errors.DuplicateCaseLabel);
log.error(label.pos(), Errors.DuplicateCaseLabel);
} else if (wasUnconditionalPattern) {
log.error(pat.pos(), Errors.PatternDominated);
log.error(label.pos(), Errors.PatternDominated);
}
hasNullPattern = true;
attribExpr(expr, switchEnv, seltype);
@ -1733,9 +1733,9 @@ public class Attr extends JCTree.Visitor {
if (sym == null) {
log.error(expr.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
} else if (!labels.add(sym)) {
log.error(pat.pos(), Errors.DuplicateCaseLabel);
log.error(label.pos(), Errors.DuplicateCaseLabel);
} else {
checkCaseLabelDominated(pat.pos(), coveredTypesForConstants, sym.type);
checkCaseLabelDominated(label.pos(), coveredTypesForConstants, sym.type);
}
} else if (errorEnumSwitch) {
//error recovery: the selector is erroneous, and all the case labels
@ -1744,7 +1744,7 @@ public class Attr extends JCTree.Visitor {
var prevResolveHelper = rs.basicLogResolveHelper;
try {
rs.basicLogResolveHelper = rs.silentLogResolveHelper;
attribExpr(pat, switchEnv, seltype);
attribExpr(expr, switchEnv, seltype);
} finally {
rs.basicLogResolveHelper = prevResolveHelper;
}
@ -1764,24 +1764,25 @@ public class Attr extends JCTree.Visitor {
(stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
}
} else if (!stringSwitch && !types.isAssignable(seltype, syms.intType)) {
log.error(pat.pos(), Errors.ConstantLabelNotCompatible(pattype, seltype));
log.error(label.pos(), Errors.ConstantLabelNotCompatible(pattype, seltype));
} else if (!labels.add(pattype.constValue())) {
log.error(c.pos(), Errors.DuplicateCaseLabel);
} else {
checkCaseLabelDominated(pat.pos(), coveredTypesForConstants, types.boxedTypeOrType(pattype));
checkCaseLabelDominated(label.pos(), coveredTypesForConstants, types.boxedTypeOrType(pattype));
}
}
}
} else if (pat.hasTag(DEFAULTCASELABEL)) {
} else if (label instanceof JCDefaultCaseLabel def) {
if (hasDefault) {
log.error(pat.pos(), Errors.DuplicateDefaultLabel);
log.error(label.pos(), Errors.DuplicateDefaultLabel);
} else if (hasUnconditionalPattern) {
log.error(pat.pos(), Errors.UnconditionalPatternAndDefault);
log.error(label.pos(), Errors.UnconditionalPatternAndDefault);
}
hasDefault = true;
matchBindings = MatchBindingsComputer.EMPTY;
} else {
//binding pattern
} else if (label instanceof JCPatternCaseLabel patternlabel) {
//pattern
JCPattern pat = patternlabel.pat;
attribExpr(pat, switchEnv);
Type primaryType = TreeInfo.primaryPatternType(pat);
if (!primaryType.hasTag(TYPEVAR)) {
@ -1789,7 +1790,7 @@ public class Attr extends JCTree.Visitor {
}
checkCastablePattern(pat.pos(), seltype, primaryType);
Type patternType = types.erasure(primaryType);
JCExpression guard = ((JCPattern) pat).guard;
JCExpression guard = patternlabel.guard;
if (guard != null) {
MatchBindings afterPattern = matchBindings;
Env<AttrContext> bodyEnv = bindingEnv(env, matchBindings.bindingsWhenTrue);
@ -1804,7 +1805,7 @@ public class Attr extends JCTree.Visitor {
log.error(guard.pos(), Errors.GuardHasConstantExpressionFalse);
}
}
boolean unguarded = TreeInfo.unguardedCaseLabel(pat) && !pat.hasTag(RECORDPATTERN);
boolean unguarded = TreeInfo.unguardedCaseLabel(label) && !pat.hasTag(RECORDPATTERN);
boolean unconditional =
unguarded &&
!patternType.isErroneous() &&
@ -1826,8 +1827,10 @@ public class Attr extends JCTree.Visitor {
coveredTypesForPatterns = coveredTypesForPatterns.prepend(patternType);
}
}
} else {
Assert.error();
}
currentBindings = matchBindingsComputer.switchCase(pat, currentBindings, matchBindings);
currentBindings = matchBindingsComputer.switchCase(label, currentBindings, matchBindings);
}
Env<AttrContext> caseEnv =

@ -4327,30 +4327,31 @@ public class Check {
boolean wasNonEmptyFallThrough = false;
for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
JCCase c = l.head;
for (JCCaseLabel pat : c.labels) {
if (pat.isExpression()) {
JCExpression expr = (JCExpression) pat;
for (JCCaseLabel label : c.labels) {
if (label.hasTag(CONSTANTCASELABEL)) {
JCExpression expr = ((JCConstantCaseLabel) label).expr;
if (TreeInfo.isNull(expr)) {
if (wasPattern && !wasTypePattern && !wasNonEmptyFallThrough) {
log.error(pat.pos(), Errors.FlowsThroughFromPattern);
log.error(label.pos(), Errors.FlowsThroughFromPattern);
}
wasNullPattern = true;
} else {
if (wasPattern && !wasNonEmptyFallThrough) {
log.error(pat.pos(), Errors.FlowsThroughFromPattern);
log.error(label.pos(), Errors.FlowsThroughFromPattern);
}
wasConstant = true;
}
} else if (pat.hasTag(DEFAULTCASELABEL)) {
} else if (label.hasTag(DEFAULTCASELABEL)) {
if (wasPattern && !wasNonEmptyFallThrough) {
log.error(pat.pos(), Errors.FlowsThroughFromPattern);
log.error(label.pos(), Errors.FlowsThroughFromPattern);
}
wasDefault = true;
} else {
JCPattern pat = ((JCPatternCaseLabel) label).pat;
boolean isTypePattern = pat.hasTag(BINDINGPATTERN);
if (wasPattern || wasConstant || wasDefault ||
(wasNullPattern && (!isTypePattern || wasNonEmptyFallThrough))) {
log.error(pat.pos(), Errors.FlowsThroughToPattern);
log.error(label.pos(), Errors.FlowsThroughToPattern);
}
wasPattern = true;
wasTypePattern = isTypePattern;

@ -738,28 +738,31 @@ public class Flow {
private Set<Symbol> coveredSymbolsForCases(DiagnosticPosition pos,
JCExpression selector, List<JCCase> cases) {
HashSet<JCCaseLabel> labels = cases.stream()
HashSet<JCTree> labelValues = cases.stream()
.flatMap(c -> c.labels.stream())
.filter(TreeInfo::unguardedCaseLabel)
.filter(l -> !l.hasTag(DEFAULTCASELABEL))
.map(l -> l.hasTag(CONSTANTCASELABEL) ? ((JCConstantCaseLabel) l).expr
: ((JCPatternCaseLabel) l).pat)
.collect(Collectors.toCollection(HashSet::new));
return coveredSymbols(pos, selector.type, labels);
return coveredSymbols(pos, selector.type, labelValues);
}
private Set<Symbol> coveredSymbols(DiagnosticPosition pos, Type targetType,
Iterable<? extends JCCaseLabel> labels) {
Iterable<? extends JCTree> labels) {
Set<Symbol> coveredSymbols = new HashSet<>();
Map<Symbol, List<JCRecordPattern>> deconstructionPatternsBySymbol = new HashMap<>();
for (JCCaseLabel label : labels) {
switch (label.getTag()) {
for (JCTree labelValue : labels) {
switch (labelValue.getTag()) {
case BINDINGPATTERN, PARENTHESIZEDPATTERN -> {
Type primaryPatternType = TreeInfo.primaryPatternType((JCPattern) label);
Type primaryPatternType = TreeInfo.primaryPatternType((JCPattern) labelValue);
if (!primaryPatternType.hasTag(NONE)) {
coveredSymbols.add(primaryPatternType.tsym);
}
}
case RECORDPATTERN -> {
JCRecordPattern dpat = (JCRecordPattern) label;
JCRecordPattern dpat = (JCRecordPattern) labelValue;
Symbol type = dpat.record;
List<JCRecordPattern> augmentedPatterns =
deconstructionPatternsBySymbol.getOrDefault(type, List.nil())
@ -768,16 +771,11 @@ public class Flow {
deconstructionPatternsBySymbol.put(type, augmentedPatterns);
}
case DEFAULTCASELABEL -> {}
default -> {
if (label.isExpression()) {
JCExpression expr = (JCExpression) label;
if (expr.hasTag(IDENT) && ((JCIdent) expr).sym.isEnum())
coveredSymbols.add(((JCIdent) expr).sym);
} else {
throw new AssertionError(label.getTag());
}
Assert.check(labelValue instanceof JCExpression, labelValue.getTag().name());
JCExpression expr = (JCExpression) labelValue;
if (expr.hasTag(IDENT) && ((JCIdent) expr).sym.isEnum())
coveredSymbols.add(((JCIdent) expr).sym);
}
}
}
@ -2585,8 +2583,7 @@ public class Flow {
if (l.head.stats.isEmpty() &&
l.tail.nonEmpty() &&
l.tail.head.labels.size() == 1 &&
l.tail.head.labels.head.isExpression() &&
TreeInfo.isNull(l.tail.head.labels.head)) {
TreeInfo.isNullCaseLabel(l.tail.head.labels.head)) {
//handling:
//case Integer i:
//case null:
@ -2977,6 +2974,11 @@ public class Flow {
public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.var);
initParam(tree.var);
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
scan(tree.pat);
scan(tree.guard);
}
@ -3077,7 +3079,7 @@ public class Flow {
}
break;
}
case BINDINGPATTERN, PARENTHESIZEDPATTERN:
case PATTERNCASELABEL:
case LAMBDA:
if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
reportEffectivelyFinalError(pos, sym);
@ -3112,7 +3114,7 @@ public class Flow {
void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
Fragment subKey = switch (currentTree.getTag()) {
case LAMBDA -> Fragments.Lambda;
case BINDINGPATTERN, PARENTHESIZEDPATTERN -> Fragments.Guard;
case PATTERNCASELABEL -> Fragments.Guard;
case CLASSDEF -> Fragments.InnerCls;
default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag());
};
@ -3154,18 +3156,16 @@ public class Flow {
@Override
public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.var);
JCTree prevTree = currentTree;
try {
currentTree = tree;
scan(tree.guard);
} finally {
currentTree = prevTree;
}
}
@Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
scan(tree.pattern);
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
scan(tree.pat);
JCTree prevTree = currentTree;
try {
currentTree = tree;
@ -3179,13 +3179,7 @@ public class Flow {
public void visitRecordPattern(JCRecordPattern tree) {
scan(tree.deconstructor);
scan(tree.nested);
JCTree prevTree = currentTree;
try {
currentTree = tree;
scan(tree.guard);
} finally {
currentTree = prevTree;
}
scan(tree.var);
}
@Override

@ -703,7 +703,7 @@ public class LambdaToMethod extends TreeTranslator {
JCBreak br = make.Break(null);
breaks.add(br);
List<JCStatement> stmts = entry.getValue().append(br).toList();
cases.add(make.Case(JCCase.STATEMENT, List.of(make.Literal(entry.getKey())), stmts, null));
cases.add(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(make.Literal(entry.getKey()))), stmts, null));
}
JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
for (JCBreak br : breaks) {

@ -3728,7 +3728,7 @@ public class Lower extends TreeTranslator {
List.nil());
JCExpression newSelector;
if (cases.stream().anyMatch(c -> TreeInfo.isNull(c.labels.head))) {
if (cases.stream().anyMatch(c -> TreeInfo.isNullCaseLabel(c.labels.head))) {
//for enum switches with case null, do:
//switch ($selector != null ? $mapVar[$selector.ordinal()] : -1) {...}
//replacing case null with case -1:
@ -3754,15 +3754,15 @@ public class Lower extends TreeTranslator {
}
ListBuffer<JCCase> newCases = new ListBuffer<>();
for (JCCase c : cases) {
if (c.labels.head.isExpression()) {
if (c.labels.head.hasTag(CONSTANTCASELABEL)) {
JCExpression pat;
if (TreeInfo.isNull(c.labels.head)) {
if (TreeInfo.isNullCaseLabel(c.labels.head)) {
pat = makeLit(syms.intType, -1);
} else {
VarSymbol label = (VarSymbol)TreeInfo.symbol((JCExpression) c.labels.head);
VarSymbol label = (VarSymbol)TreeInfo.symbol(((JCConstantCaseLabel) c.labels.head).expr);
pat = map.forConstant(label);
}
newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
newCases.append(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(pat)), c.stats, null));
} else {
newCases.append(c);
}
@ -3842,12 +3842,12 @@ public class Lower extends TreeTranslator {
int nullCaseLabel = -1;
for(JCCase oneCase : caseList) {
if (oneCase.labels.head.isExpression()) {
if (TreeInfo.isNull(oneCase.labels.head)) {
if (oneCase.labels.head.hasTag(CONSTANTCASELABEL)) {
if (TreeInfo.isNullCaseLabel(oneCase.labels.head)) {
nullCase = oneCase;
nullCaseLabel = casePosition;
} else {
JCExpression expression = (JCExpression) oneCase.labels.head;
JCExpression expression = ((JCConstantCaseLabel) oneCase.labels.head).expr;
String labelExpr = (String) expression.type.constValue();
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
Assert.checkNull(mapping);
@ -3932,7 +3932,10 @@ public class Lower extends TreeTranslator {
breakStmt.target = switch1;
lb.append(elsepart).append(breakStmt);
caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
caseBuffer.append(make.Case(JCCase.STATEMENT,
List.of(make.ConstantCaseLabel(make.Literal(hashCode))),
lb.toList(),
null));
}
switch1.cases = caseBuffer.toList();
@ -3951,18 +3954,21 @@ public class Lower extends TreeTranslator {
ListBuffer<JCCase> lb = new ListBuffer<>();
for(JCCase oneCase : caseList ) {
boolean isDefault = !oneCase.labels.head.isExpression();
JCCaseLabel caseExpr;
boolean isDefault = !oneCase.labels.head.hasTag(CONSTANTCASELABEL);
JCExpression caseExpr;
if (isDefault)
caseExpr = null;
else if (oneCase == nullCase) {
caseExpr = make.Literal(nullCaseLabel);
} else {
caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens((JCExpression) oneCase.labels.head).
type.constValue()));
JCExpression expression = ((JCConstantCaseLabel) oneCase.labels.head).expr;
String name = (String) TreeInfo.skipParens(expression)
.type.constValue();
caseExpr = make.Literal(caseLabelToPosition.get(name));
}
lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.of(make.DefaultCaseLabel()) : List.of(caseExpr),
lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.of(make.DefaultCaseLabel())
: List.of(make.ConstantCaseLabel(caseExpr)),
oneCase.stats, null));
}
@ -3999,7 +4005,7 @@ public class Lower extends TreeTranslator {
private JCTree visitBoxedPrimitiveSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
JCExpression newSelector;
if (cases.stream().anyMatch(c -> TreeInfo.isNull(c.labels.head))) {
if (cases.stream().anyMatch(c -> TreeInfo.isNullCaseLabel(c.labels.head))) {
//a switch over a boxed primitive, with a null case. Pick two constants that are
//not used by any branch in the case (c1 and c2), close to other constants that are
//used in the switch. Then do:
@ -4009,10 +4015,10 @@ public class Lower extends TreeTranslator {
JCCase nullCase = null;
for (JCCase c : cases) {
if (TreeInfo.isNull(c.labels.head)) {
if (TreeInfo.isNullCaseLabel(c.labels.head)) {
nullCase = c;
} else if (!c.labels.head.hasTag(DEFAULTCASELABEL)) {
constants.add((int) c.labels.head.type.constValue());
constants.add((int) ((JCConstantCaseLabel) c.labels.head).expr.type.constValue());
}
}
@ -4023,7 +4029,7 @@ public class Lower extends TreeTranslator {
while (constants.contains(nullValue)) nullValue++;
constants.add(nullValue);
nullCase.labels.head = makeLit(syms.intType, nullValue);
nullCase.labels.head = make.ConstantCaseLabel(makeLit(syms.intType, nullValue));
int replacementValue = nullValue;

@ -83,12 +83,14 @@ import com.sun.tools.javac.tree.JCTree.JCCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCConstantCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCLambda;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParenthesizedPattern;
import com.sun.tools.javac.tree.JCTree.JCPattern;
import com.sun.tools.javac.tree.JCTree.JCPatternCaseLabel;
import com.sun.tools.javac.tree.JCTree.JCRecordPattern;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
@ -458,8 +460,7 @@ public class TransPatterns extends TreeTranslator {
currentMethodSym);
boolean hasNullCase = cases.stream()
.flatMap(c -> c.labels.stream())
.anyMatch(p -> p.isExpression() &&
TreeInfo.isNull((JCExpression) p));
.anyMatch(p -> TreeInfo.isNullCaseLabel(p));
JCCase lastCase = cases.last();
@ -519,21 +520,21 @@ public class TransPatterns extends TreeTranslator {
for (var c : cases) {
List<JCCaseLabel> clearedPatterns = c.labels;
boolean hasJoinedNull =
c.labels.size() > 1 && c.labels.stream().anyMatch(l -> l.isNullPattern());
c.labels.size() > 1 && c.labels.stream().anyMatch(l -> TreeInfo.isNullCaseLabel(l));
if (hasJoinedNull) {
clearedPatterns = c.labels.stream()
.filter(l -> !l.isNullPattern())
.filter(l -> !TreeInfo.isNullCaseLabel(l))
.collect(List.collector());
}
if (clearedPatterns.size() == 1 && clearedPatterns.head.isPattern() && !previousCompletesNormally) {
JCCaseLabel p = clearedPatterns.head;
if (clearedPatterns.size() == 1 && clearedPatterns.head.hasTag(Tag.PATTERNCASELABEL) && !previousCompletesNormally) {
JCPatternCaseLabel label = (JCPatternCaseLabel) clearedPatterns.head;
bindingContext = new BasicBindingContext();
VarSymbol prevCurrentValue = currentValue;
try {
currentValue = temp;
JCExpression test = (JCExpression) this.<JCTree>translate(p);
if (((JCPattern) p).guard != null) {
test = makeBinary(Tag.AND, test, translate(((JCPattern) p).guard));
JCExpression test = (JCExpression) this.<JCTree>translate(label.pat);
if (label.guard != null) {
test = makeBinary(Tag.AND, test, translate(label.guard));
}
c.stats = translate(c.stats);
JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null);
@ -558,19 +559,19 @@ public class TransPatterns extends TreeTranslator {
translatedLabels.add(p);
hasDefault = true;
} else if (hasUnconditionalPattern && !hasDefault &&
c == lastCase && p.isPattern()) {
c == lastCase && p.hasTag(Tag.PATTERNCASELABEL)) {
//If the switch has unconditional pattern,
//the last case will contain it.
//Convert the unconditional pattern to default:
translatedLabels.add(make.DefaultCaseLabel());
} else {
int value;
if (p.isNullPattern()) {
if (TreeInfo.isNullCaseLabel(p)) {
value = -1;
} else {
value = i++;
}
translatedLabels.add(make.Literal(value));
translatedLabels.add(make.ConstantCaseLabel(make.Literal(value)));
}
}
c.labels = translatedLabels.toList();
@ -633,23 +634,24 @@ public class TransPatterns extends TreeTranslator {
}
private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) {
if (l.isPattern()) {
Type principalType = principalType(l);
if (l.hasTag(Tag.PATTERNCASELABEL)) {
Type principalType = principalType(((JCPatternCaseLabel) l).pat);
if (types.isSubtype(selector, principalType)) {
return (LoadableConstant) selector;
} else {
return (LoadableConstant) principalType;
}
} else if (l.isExpression() && !TreeInfo.isNull((JCExpression) l)) {
if ((l.type.tsym.flags_field & Flags.ENUM) != 0) {
return LoadableConstant.String(((JCIdent) l).name.toString());
} else if (l.hasTag(Tag.CONSTANTCASELABEL)&& !TreeInfo.isNullCaseLabel(l)) {
JCExpression expr = ((JCConstantCaseLabel) l).expr;
if ((expr.type.tsym.flags_field & Flags.ENUM) != 0) {
return LoadableConstant.String(((JCIdent) expr).name.toString());
} else {
Assert.checkNonNull(l.type.constValue());
Assert.checkNonNull(expr.type.constValue());
return switch (l.type.getTag()) {
return switch (expr.type.getTag()) {
case BYTE, CHAR,
SHORT, INT -> LoadableConstant.Int((Integer) l.type.constValue());
case CLASS -> LoadableConstant.String((String) l.type.constValue());
SHORT, INT -> LoadableConstant.Int((Integer) expr.type.constValue());
case CLASS -> LoadableConstant.String((String) expr.type.constValue());
default -> throw new AssertionError();
};
}

@ -565,6 +565,18 @@ public class TransTypes extends TreeTranslator {
public void visitBindingPattern(JCBindingPattern tree) {
tree.var = translate(tree.var, null);
result = tree;
}
@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
tree.expr = translate(tree.expr, null);
result = tree;
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
tree.pat = translate(tree.pat, null);
tree.guard = translate(tree.guard, syms.booleanType);
result = tree;
}
@ -583,7 +595,6 @@ public class TransTypes extends TreeTranslator {
@Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
tree.pattern = translate(tree.pattern, null);
tree.guard = translate(tree.guard, syms.booleanType);
result = tree;
}

@ -332,6 +332,21 @@ implements CRTFlags {
result = null;
}
@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.expr));
result = sr;
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.pat));
sr.mergeWith(csp(tree.guard));
result = sr;
}
public void visitSynchronized(JCSynchronized tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.lock));

@ -1303,9 +1303,9 @@ public class Gen extends JCTree.Visitor {
List<JCCase> l = cases;
for (int i = 0; i < labels.length; i++) {
if (l.head.labels.head.isExpression()) {
if (l.head.labels.head instanceof JCConstantCaseLabel constLabel) {
Assert.check(l.head.labels.size() == 1);
int val = ((Number)((JCExpression) l.head.labels.head).type.constValue()).intValue();
int val = ((Number) constLabel.expr.type.constValue()).intValue();
labels[i] = val;
if (val < lo) lo = val;
if (hi < val) hi = val;

@ -3117,13 +3117,15 @@ public class JavacParser implements Parser {
if (pattern) {
checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
JCPattern p = parsePattern(patternPos, mods, null, false, true);
JCExpression guard = null;
if (token.kind == IDENTIFIER && token.name() == names.when) {
nextToken();
p.guard = term(EXPR | NOLAMBDA);
guard = term(EXPR | NOLAMBDA);
}
return p;
return toP(F.at(patternPos).PatternCaseLabel(p, guard));
} else {
return term(EXPR | NOLAMBDA);
JCExpression expr = term(EXPR | NOLAMBDA);
return toP(F.at(patternPos).ConstantCaseLabel(expr));
}
}

@ -240,11 +240,15 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/** Patterns.
*/
BINDINGPATTERN,
DEFAULTCASELABEL,
PARENTHESIZEDPATTERN,
RECORDPATTERN,
/* Case labels.
*/
DEFAULTCASELABEL,
CONSTANTCASELABEL,
PATTERNCASELABEL,
/** Indexed array expressions, of type Indexed.
*/
INDEXED,
@ -704,14 +708,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
public abstract static class JCCaseLabel extends JCTree implements CaseLabelTree {
public abstract boolean isExpression();
public boolean isNullPattern() {
return isExpression() && TreeInfo.isNull((JCExpression) this);
}
public abstract boolean isPattern();
}
public abstract static class JCExpression extends JCCaseLabel implements ExpressionTree {
public abstract static class JCExpression extends JCTree implements ExpressionTree {
@Override
public JCExpression setType(Type type) {
super.setType(type);
@ -726,15 +725,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public boolean isPoly() { return false; }
public boolean isStandalone() { return true; }
@Override
public boolean isExpression() {
return true;
}
@Override
public boolean isPattern() {
return false;
}
}
/**
@ -1341,8 +1331,15 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public Kind getKind() { return Kind.CASE; }
@Override @Deprecated @DefinedBy(Api.COMPILER_TREE)
public JCExpression getExpression() { return getExpressions().head; }
@Override @DefinedBy(Api.COMPILER_TREE)
public List<JCExpression> getExpressions() { return labels.stream().filter(p -> p instanceof JCExpression).map(p -> (JCExpression) p).collect(List.collector()); }
public List<JCExpression> getExpressions() {
return labels.stream()
.filter(p -> p.hasTag(CONSTANTCASELABEL))
.map(p -> ((JCConstantCaseLabel) p).expr)
.collect(List.collector());
}
@Override @DefinedBy(Api.COMPILER_TREE)
public List<JCCaseLabel> getLabels() { return labels; }
@Override @DefinedBy(Api.COMPILER_TREE)
@ -2243,23 +2240,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* Pattern matching forms.
*/
public abstract static class JCPattern extends JCCaseLabel
public abstract static class JCPattern extends JCTree
implements PatternTree {
public JCExpression guard;
@Override @DefinedBy(Api.COMPILER_TREE)
public JCExpression getGuard() { return guard; }
@Override
public boolean isExpression() {
return false;
}
@Override
public boolean isPattern() {
return true;
}
}
public static class JCBindingPattern extends JCPattern
@ -2324,15 +2306,87 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
return DEFAULTCASELABEL;
}
@Override
public boolean isExpression() {
return false;
}
public static class JCConstantCaseLabel extends JCCaseLabel
implements ConstantCaseLabelTree {
public JCExpression expr;
protected JCConstantCaseLabel(JCExpression expr) {
this.expr = expr;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public JCExpression getConstantExpression() {
return expr;
}
@Override
public boolean isPattern() {
return false;
public void accept(Visitor v) {
v.visitConstantCaseLabel(this);
}
@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() {
return Kind.CONSTANT_CASE_LABEL;
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public <R, D> R accept(TreeVisitor<R, D> v, D d) {
return v.visitConstantCaseLabel(this, d);
}
@Override
public Tag getTag() {
return CONSTANTCASELABEL;
}
}
public static class JCPatternCaseLabel extends JCCaseLabel
implements PatternCaseLabelTree {
public JCPattern pat;
public JCExpression guard;
protected JCPatternCaseLabel(JCPattern pat, JCExpression guard) {
this.pat = pat;
this.guard = guard;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public JCPattern getPattern() {
return pat;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public JCExpression getGuard() {
return guard;
}
@Override
public void accept(Visitor v) {
v.visitPatternCaseLabel(this);
}
@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() {
return Kind.PATTERN_CASE_LABEL;
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public <R, D> R accept(TreeVisitor<R, D> v, D d) {
return v.visitPatternCaseLabel(this, d);
}
@Override
public Tag getTag() {
return PATTERNCASELABEL;
}
}
public static class JCParenthesizedPattern extends JCPattern
@ -3469,6 +3523,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public void visitTypeTest(JCInstanceOf that) { visitTree(that); }
public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); }
public void visitConstantCaseLabel(JCConstantCaseLabel that) { visitTree(that); }
public void visitPatternCaseLabel(JCPatternCaseLabel that) { visitTree(that); }
public void visitParenthesizedPattern(JCParenthesizedPattern that) { visitTree(that); }
public void visitRecordPattern(JCRecordPattern that) { visitTree(that); }
public void visitIndexed(JCArrayAccess that) { visitTree(that); }

@ -877,6 +877,28 @@ public class Pretty extends JCTree.Visitor {
}
}
@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
try {
print(tree.expr);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
try {
print(tree.pat);
if (tree.guard != null) {
print(" when ");
print(tree.guard);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSwitchExpression(JCSwitchExpression tree) {
try {
print("switch ");
@ -900,10 +922,6 @@ public class Pretty extends JCTree.Visitor {
public void visitBindingPattern(JCBindingPattern patt) {
try {
printExpr(patt.var);
if (patt.guard != null) {
print(" when ");
printExpr(patt.guard);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@ -915,10 +933,6 @@ public class Pretty extends JCTree.Visitor {
print("(");
printExpr(patt.pattern);
print(")");
if (patt.guard != null) {
print(" when ");
printExpr(patt.guard);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@ -935,10 +949,6 @@ public class Pretty extends JCTree.Visitor {
print(" ");
print(tree.var.name);
}
if (tree.guard != null) {
print(" when ");
printExpr(tree.guard);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}

@ -494,20 +494,14 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
public JCTree visitBindingPattern(BindingPatternTree node, P p) {
JCBindingPattern t = (JCBindingPattern) node;
JCVariableDecl var = copy(t.var, p);
JCExpression guard = copy(t.guard, p);
JCPattern pat = M.at(t.pos).BindingPattern(var);
pat.guard = guard;
return pat;
return M.at(t.pos).BindingPattern(var);
}
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitParenthesizedPattern(ParenthesizedPatternTree node, P p) {
JCParenthesizedPattern t = (JCParenthesizedPattern) node;
JCPattern pattern = copy(t.pattern, p);
JCExpression guard = copy(t.guard, p);
JCPattern pat = M.at(t.pos).ParenthesizedPattern(pattern);
pat.guard = guard;
return pat;
return M.at(t.pos).ParenthesizedPattern(pattern);
}
@DefinedBy(Api.COMPILER_TREE)
@ -516,6 +510,21 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
return M.at(t.pos).DefaultCaseLabel();
}
@Override @DefinedBy(Api.COMPILER_TREE)
public JCTree visitConstantCaseLabel(ConstantCaseLabelTree node, P p) {
JCConstantCaseLabel t = (JCConstantCaseLabel) node;
JCExpression expr = copy(t.expr, p);
return M.at(t.pos).ConstantCaseLabel(expr);
}
@Override
public JCTree visitPatternCaseLabel(PatternCaseLabelTree node, P p) {
JCPatternCaseLabel t = (JCPatternCaseLabel) node;
JCPattern pat = copy(t.pat, p);
JCExpression guard = copy(t.guard, p);
return M.at(t.pos).PatternCaseLabel(pat, guard);
}
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
JCRecordPattern t = (JCRecordPattern) node;

@ -1303,6 +1303,8 @@ public class TreeInfo {
public static boolean isErrorEnumSwitch(JCExpression selector, List<JCCase> cases) {
return selector.type.tsym.kind == Kinds.Kind.ERR &&
cases.stream().flatMap(c -> c.labels.stream())
.filter(l -> l.hasTag(CONSTANTCASELABEL))
.map(l -> ((JCConstantCaseLabel) l).expr)
.allMatch(p -> p.hasTag(IDENT));
}
@ -1328,14 +1330,14 @@ public class TreeInfo {
return tree.patternSwitch ||
tree.cases.stream()
.flatMap(c -> c.labels.stream())
.anyMatch(l -> TreeInfo.isNull(l));
.anyMatch(l -> TreeInfo.isNullCaseLabel(l));
}
public static boolean unguardedCaseLabel(JCCaseLabel cse) {
if (!cse.isPattern()) {
if (!cse.hasTag(PATTERNCASELABEL)) {
return true;
}
JCExpression guard = ((JCPattern) cse).guard;
JCExpression guard = ((JCPatternCaseLabel) cse).guard;
if (guard == null) {
return true;
}
@ -1348,4 +1350,9 @@ public class TreeInfo {
guard.type.hasTag(BOOLEAN) &&
((int) constValue) == value;
}
public static boolean isNullCaseLabel(JCCaseLabel label) {
return label.hasTag(CONSTANTCASELABEL) &&
TreeInfo.isNull(((JCConstantCaseLabel) label).expr);
}
}

@ -494,6 +494,18 @@ public class TreeMaker implements JCTree.Factory {
return tree;
}
public JCConstantCaseLabel ConstantCaseLabel(JCExpression expr) {
JCConstantCaseLabel tree = new JCConstantCaseLabel(expr);
tree.pos = pos;
return tree;
}
public JCPatternCaseLabel PatternCaseLabel(JCPattern pat, JCExpression guard) {
JCPatternCaseLabel tree = new JCPatternCaseLabel(pat, guard);
tree.pos = pos;
return tree;
}
public JCParenthesizedPattern ParenthesizedPattern(JCPattern pattern) {
JCParenthesizedPattern tree = new JCParenthesizedPattern(pattern);
tree.pos = pos;

@ -305,17 +305,26 @@ public class TreeScanner extends Visitor {
public void visitBindingPattern(JCBindingPattern tree) {
scan(tree.var);
scan(tree.guard);
}
@Override
public void visitDefaultCaseLabel(JCDefaultCaseLabel tree) {
}
@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
scan(tree.expr);
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
scan(tree.pat);
scan(tree.guard);
}
@Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
scan(tree.pattern);
scan(tree.guard);
}
@Override
@ -325,7 +334,6 @@ public class TreeScanner extends Visitor {
if (that.var != null) {
scan(that.var);
}
scan(that.guard);
}
public void visitIndexed(JCArrayAccess tree) {

@ -360,7 +360,6 @@ public class TreeTranslator extends JCTree.Visitor {
public void visitBindingPattern(JCBindingPattern tree) {
tree.var = translate(tree.var);
tree.guard = translate(tree.guard);
result = tree;
}
@ -369,10 +368,22 @@ public class TreeTranslator extends JCTree.Visitor {
result = tree;
}
@Override
public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
tree.expr = translate(tree.expr);
result = tree;
}
@Override
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
tree.pat = translate(tree.pat);
tree.guard = translate(tree.guard);
result = tree;
}
@Override
public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
tree.pattern = translate(tree.pattern);
tree.guard = translate(tree.guard);
result = tree;
}

@ -35,9 +35,9 @@
import com.sun.source.tree.CaseLabelTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ConstantCaseLabelTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.PatternTree;
import com.sun.source.tree.PatternCaseLabelTree;
import com.sun.source.tree.SwitchTree;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.JavacParser;
@ -139,8 +139,8 @@ public class DisambiguatePatterns {
SwitchTree st = (SwitchTree) method.getBody().getStatements().get(0);
CaseLabelTree label = st.getCases().get(0).getLabels().get(0);
ExpressionType actualType = switch (label) {
case ExpressionTree et -> ExpressionType.EXPRESSION;
case PatternTree pt -> ExpressionType.PATTERN;
case ConstantCaseLabelTree et -> ExpressionType.EXPRESSION;
case PatternCaseLabelTree pt -> ExpressionType.PATTERN;
default -> throw new AssertionError("Unexpected result: " + result);
};
if (expectedType != actualType) {

@ -95,8 +95,6 @@ public class SourceTreeScannerTest extends AbstractTreeScannerTest {
private class ScanTester extends TreeScanner<Void,Void> {
/** Main entry method for the class. */
int test(JCCompilationUnit tree) {
if (!tree.sourcefile.toString().contains("EmptyBreak.java"))
return 0;
sourcefile = tree.sourcefile;
found = new HashSet<Tree>();
scan(tree, null);
@ -145,30 +143,28 @@ public class SourceTreeScannerTest extends AbstractTreeScannerTest {
if (o instanceof JCTree) {
JCTree tree = (JCTree) o;
//System.err.println("EXPECT: " + tree.getKind() + " " + trim(tree, 64));
if (!tree.hasTag(JCTree.Tag.DEFAULTCASELABEL)) {
expect.add(tree);
for (Field f: getFields(tree)) {
if (TypeBoundKind.class.isAssignableFrom(f.getType())) {
// not part of public API
continue;
}
try {
//System.err.println("FIELD: " + f.getName());
if (tree instanceof JCModuleDecl && f.getName().equals("mods")) {
// The modifiers will not found by TreeScanner,
// but the embedded annotations will be.
reflectiveScan(((JCModuleDecl) tree).mods.annotations);
} else if (tree instanceof JCCase &&
((JCCase) tree).getCaseKind() == CaseKind.RULE &&
f.getName().equals("stats")) {
//value case, visit value:
reflectiveScan(((JCCase) tree).getBody());
} else {
reflectiveScan(f.get(tree));
}
} catch (IllegalAccessException e) {
error(e.toString());
expect.add(tree);
for (Field f: getFields(tree)) {
if (TypeBoundKind.class.isAssignableFrom(f.getType())) {
// not part of public API
continue;
}
try {
//System.err.println("FIELD: " + f.getName());
if (tree instanceof JCModuleDecl && f.getName().equals("mods")) {
// The modifiers will not found by TreeScanner,
// but the embedded annotations will be.
reflectiveScan(((JCModuleDecl) tree).mods.annotations);
} else if (tree instanceof JCCase &&
((JCCase) tree).getCaseKind() == CaseKind.RULE &&
f.getName().equals("stats")) {
//value case, visit value:
reflectiveScan(((JCCase) tree).getBody());
} else {
reflectiveScan(f.get(tree));
}
} catch (IllegalAccessException e) {
error(e.toString());
}
}
} else if (o instanceof List) {