8287236: Reorganize AST related to pattern matching for switch
Reviewed-by: mcimadamore
This commit is contained in:
parent
2d8c649054
commit
bde7a7ae03
src/jdk.compiler/share/classes/com/sun
source
tree
ConstantCaseLabelTree.javaExpressionTree.javaPatternCaseLabelTree.javaPatternTree.javaTree.javaTreeVisitor.java
util
tools/javac
test/langtools/tools/javac
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user