8300195: Fall-through issue occurs when using record pattern in switch statements

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2023-01-18 10:43:53 +00:00
parent 0f925fefdf
commit c1b4212a53
2 changed files with 122 additions and 11 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/comp
test/langtools/tools/javac/patterns

@ -590,14 +590,10 @@ public class TransPatterns extends TreeTranslator {
}
}
c.labels = translatedLabels.toList();
if (c.caseKind == CaseTree.CaseKind.STATEMENT) {
previousCompletesNormally = c.completesNormally;
} else {
previousCompletesNormally = false;
JCBreak brk = make.at(TreeInfo.endPos(c.stats.last())).Break(null);
brk.target = tree;
c.stats = c.stats.append(brk);
}
previousCompletesNormally =
c.caseKind == CaseTree.CaseKind.STATEMENT &&
c.completesNormally;
appendBreakIfNeeded(tree, c);
}
if (tree.hasTag(Tag.SWITCH)) {
@ -642,6 +638,14 @@ public class TransPatterns extends TreeTranslator {
}.scan(c.stats);
}
private void appendBreakIfNeeded(JCTree switchTree, JCCase c) {
if (c.caseKind == CaseTree.CaseKind.RULE) {
JCBreak brk = make.at(TreeInfo.endPos(c.stats.last())).Break(null);
brk.target = switchTree;
c.stats = c.stats.append(brk);
}
}
JCMethodInvocation makeApply(JCExpression selector, Name name, List<JCExpression> args) {
MethodSymbol method = rs.resolveInternalMethod(
currentClassTree.pos(), env,
@ -740,6 +744,7 @@ public class TransPatterns extends TreeTranslator {
} else {
newLabel = List.of(make.PatternCaseLabel(binding, newGuard));
}
appendBreakIfNeeded(currentSwitch, accummulated);
nestedCases.add(make.Case(CaseKind.STATEMENT, newLabel, accummulated.stats, null));
}
if (!hasUnconditional) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, 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
@ -23,8 +23,9 @@
/**
* @test
* @bug 8291769
* @bug 8291769 8300195
* @summary Verify the compiled code does not have unwanted constructs.
* @enablePreview
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@ -34,11 +35,17 @@
* @run main PatternDesugaring
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import toolbox.TestRunner;
@ -198,4 +205,103 @@ public class PatternDesugaring extends TestRunner {
validate.accept(decompiled);
}
@Test
public void testRuleCases(Path base) throws Exception {
doTestRun(base,
new String[0],
"""
package test;
public class Test {
public static void main(String... args) {
System.out.println(test(new R("a")));
System.out.println(test(new R(3)));
System.out.println(test(new R(new R("a"))));
System.out.println(test(new R(new R(3))));
}
public static int test(Object obj) {
int res;
switch (obj) {
case R(String s) -> res = s.length();
case R(Integer i) -> res = i;
case R(R(String s)) -> res = 10 + s.length();
case R(R(Integer i)) -> res = 10 + i;
default -> res = -1;
}
return res;
}
record R(Object o) {}
}
""",
output -> {
String expectedOutput = """
1
3
11
13
""";
if (!Objects.equals(output, expectedOutput)) {
throw new AssertionError("Unexpected output," +
" expected: " + expectedOutput +
" actual: " + output);
}
});
}
private void doTestRun(Path base, String[] libraryCode, String testCode, Consumer<String> validate) throws Exception {
Path current = base.resolve(".");
Path libClasses = current.resolve("libClasses");
Files.createDirectories(libClasses);
if (libraryCode.length != 0) {
Path libSrc = current.resolve("lib-src");
for (String code : libraryCode) {
tb.writeJavaFiles(libSrc, code);
}
new JavacTask(tb)
.options("--enable-preview",
"-source", JAVA_VERSION)
.outdir(libClasses)
.files(tb.findJavaFiles(libSrc))
.run();
}
Path src = current.resolve("src");
tb.writeJavaFiles(src, testCode);
Path classes = current.resolve("libClasses");
Files.createDirectories(libClasses);
var log =
new JavacTask(tb)
.options("--enable-preview",
"-source", JAVA_VERSION,
"-XDrawDiagnostics",
"-Xlint:-preview",
"--class-path", libClasses.toString(),
"-XDshould-stop.at=FLOW")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.SUCCESS)
.writeAll();
ClassLoader cl = new URLClassLoader(new URL[] {classes.toUri().toURL()});
Class<?> testClass = cl.loadClass("test.Test");
Method main = testClass.getMethod("main", String[].class);
PrintStream prevOut = System.out;
var data = new ByteArrayOutputStream();
try (var outStream = new PrintStream(data, true, StandardCharsets.UTF_8)) {
System.setOut(outStream);
main.invoke(null, (Object) new String[0]);
} finally {
System.setOut(prevOut);
}
String output = new String(data.toByteArray(), StandardCharsets.UTF_8);
output = output.replaceAll("\\R", "\n");
validate.accept(output);
}
}