From 4f7b2fa3214287d18b5567d211511ae33a8ae963 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 16 Jan 2023 14:21:44 +0100 Subject: [PATCH 1/2] 8300195: Fall-through issue occurs when using record pattern in switch statements --- .../sun/tools/javac/comp/TransPatterns.java | 21 ++-- .../javac/patterns/PatternDesugaring.java | 110 +++++++++++++++++- 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 450f1d067f1..57cd9671ca9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -590,14 +590,10 @@ private void handleSwitch(JCTree tree, } } 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 void visitCase(JCCase c) { }.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 args) { MethodSymbol method = rs.resolveInternalMethod( currentClassTree.pos(), env, @@ -740,6 +744,7 @@ public void resolve(VarSymbol commonBinding, } else { newLabel = List.of(make.PatternCaseLabel(binding, newGuard)); } + appendBreakIfNeeded(currentSwitch, accummulated); nestedCases.add(make.Case(CaseKind.STATEMENT, newLabel, accummulated.stats, null)); } if (!hasUnconditional) { diff --git a/test/langtools/tools/javac/patterns/PatternDesugaring.java b/test/langtools/tools/javac/patterns/PatternDesugaring.java index 67c19b2441b..09cb42d4a01 100644 --- a/test/langtools/tools/javac/patterns/PatternDesugaring.java +++ b/test/langtools/tools/javac/patterns/PatternDesugaring.java @@ -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,101 @@ private void doTest(Path base, String[] libraryCode, String testCode, Consumer 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 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); + } + validate.accept(new String(data.toByteArray(), StandardCharsets.UTF_8)); + } + } From 5ecb6eda272ce9d2e314b408e23ea351ebd585ab Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 18 Jan 2023 10:18:21 +0100 Subject: [PATCH 2/2] Fixing test on Windows. --- test/langtools/tools/javac/patterns/PatternDesugaring.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/langtools/tools/javac/patterns/PatternDesugaring.java b/test/langtools/tools/javac/patterns/PatternDesugaring.java index 09cb42d4a01..998fe5471cf 100644 --- a/test/langtools/tools/javac/patterns/PatternDesugaring.java +++ b/test/langtools/tools/javac/patterns/PatternDesugaring.java @@ -299,7 +299,9 @@ private void doTestRun(Path base, String[] libraryCode, String testCode, Consume } finally { System.setOut(prevOut); } - validate.accept(new String(data.toByteArray(), StandardCharsets.UTF_8)); + String output = new String(data.toByteArray(), StandardCharsets.UTF_8); + output = output.replaceAll("\\R", "\n"); + validate.accept(output); } }