Skip to content

Commit 7ab1285

Browse files
committed
8267610: NPE at at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop
8268748: Javac generates uncorrect bytecodes when using nested pattern variables Reviewed-by: jlahoda, vromero
1 parent cfa6a99 commit 7ab1285

3 files changed

Lines changed: 189 additions & 2 deletions

File tree

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,14 @@ public void visitTypeTest(JCInstanceOf tree) {
186186
//=>
187187
//(let T' N$temp = E; N$temp instanceof typeof($pattern) && <desugared $pattern>)
188188
//note the pattern desugaring performs binding variable assignments
189-
Symbol exprSym = TreeInfo.symbol(tree.expr);
190189
Type tempType = tree.expr.type.hasTag(BOT) ?
191190
syms.objectType
192191
: tree.expr.type;
193192
VarSymbol prevCurrentValue = currentValue;
194193
try {
194+
JCExpression translatedExpr = translate(tree.expr);
195+
Symbol exprSym = TreeInfo.symbol(translatedExpr);
196+
195197
if (exprSym != null &&
196198
exprSym.kind == Kind.VAR &&
197199
exprSym.owner.kind.matches(Kinds.KindSelector.VAL_MTH)) {
@@ -203,7 +205,6 @@ public void visitTypeTest(JCInstanceOf tree) {
203205
currentMethodSym);
204206
}
205207

206-
JCExpression translatedExpr = translate(tree.expr);
207208
Type principalType = principalType((JCPattern) tree.pattern);
208209
result = makeBinary(Tag.AND,
209210
makeTypeTest(make.Ident(currentValue), make.Type(principalType)),
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8267610
27+
* @summary LambdaToMethod cannot capture pattern variables. So the TransPatterns should
28+
* transform the pattern variables and symbols to normal variables and symbols.
29+
* @compile --enable-preview -source ${jdk.version} LambdaCannotCapturePatternVariables.java
30+
* @run main/othervm --enable-preview LambdaCannotCapturePatternVariables
31+
*/
32+
33+
import java.util.function.Supplier;
34+
35+
public class LambdaCannotCapturePatternVariables {
36+
37+
public static void main(String[] args) {
38+
var testVar = new LambdaCannotCapturePatternVariables();
39+
testVar.testInstanceOfPatternVariable(Integer.valueOf(1));
40+
testVar.testSwitchPatternVariable(Integer.valueOf(1));
41+
testVar.test(Integer.valueOf(1));
42+
}
43+
44+
public Integer testInstanceOfPatternVariable(Object x) {
45+
if(x instanceof Number y) {
46+
return ((Supplier<Integer>) (() -> {
47+
return ((y instanceof Integer z) ? z : 1);
48+
})).get();
49+
}
50+
return null;
51+
}
52+
53+
public Integer testSwitchPatternVariable(Object x) {
54+
switch (x) {
55+
case Number n: {
56+
return ((Supplier<Integer>) (() -> {
57+
return ((n instanceof Integer i) ? i : 1);
58+
})).get();
59+
}
60+
default: return null;
61+
}
62+
}
63+
64+
// Provided by the user
65+
public Integer test(Object x) {
66+
Integer bar = 1;
67+
return ((x instanceof Number y) ?
68+
((Supplier<Integer>) (() -> {
69+
return ((y instanceof Integer z) ? z : bar);
70+
})).get() : bar);
71+
}
72+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8268748
27+
* @summary Javac generates error opcodes when using nest pattern variables
28+
* @library /tools/lib
29+
* @modules jdk.compiler/com.sun.tools.javac.api
30+
* jdk.compiler/com.sun.tools.javac.main
31+
* jdk.jdeps/com.sun.tools.classfile
32+
* @build toolbox.ToolBox toolbox.JavacTask
33+
* @run main NestedPatternVariablesBytecode
34+
*/
35+
36+
import java.nio.file.Path;
37+
import java.util.Arrays;
38+
import java.util.List;
39+
import java.util.stream.StreamSupport;
40+
41+
import com.sun.tools.classfile.ClassFile;
42+
import com.sun.tools.classfile.ConstantPoolException;
43+
import com.sun.tools.classfile.Method;
44+
import com.sun.tools.classfile.Attribute;
45+
import com.sun.tools.classfile.Code_attribute;
46+
import com.sun.tools.classfile.Instruction;
47+
48+
import toolbox.JavacTask;
49+
import toolbox.TestRunner;
50+
import toolbox.ToolBox;
51+
52+
public class NestedPatternVariablesBytecode extends TestRunner {
53+
private static final String JAVA_VERSION = System.getProperty("java.specification.version");
54+
private static final String TEST_METHOD = "test";
55+
56+
ToolBox tb;
57+
ClassFile cf;
58+
59+
public NestedPatternVariablesBytecode() {
60+
super(System.err);
61+
tb = new ToolBox();
62+
}
63+
64+
public static void main(String[] args) throws Exception {
65+
NestedPatternVariablesBytecode t = new NestedPatternVariablesBytecode();
66+
t.runTests();
67+
}
68+
69+
@Test
70+
public void testNestedPatternVariablesBytecode() throws Exception {
71+
String code = """
72+
class NestedPatterVariablesTest {
73+
String test(Object o) {
74+
if (o instanceof (CharSequence cs && cs instanceof String s)) {
75+
return s;
76+
}
77+
return null;
78+
}
79+
}""";
80+
Path curPath = Path.of(".");
81+
new JavacTask(tb)
82+
.options("--enable-preview", "-source", JAVA_VERSION)
83+
.sources(code)
84+
.outdir(curPath)
85+
.run();
86+
87+
cf = ClassFile.read(curPath.resolve("NestedPatterVariablesTest.class"));
88+
Method testMethod = Arrays.stream(cf.methods)
89+
.filter(m -> isTestMethod(m))
90+
.findAny()
91+
.get();
92+
Code_attribute code_attribute = (Code_attribute) testMethod.attributes.get(Attribute.Code);
93+
94+
List<String> actualCode = getCodeInstructions(code_attribute);
95+
List<String> expectedCode = Arrays.asList(
96+
"aload_1", "instanceof", "ifeq", "aload_1", "checkcast", "astore_2", "aload_2", "instanceof",
97+
"ifeq", "aload_2", "checkcast", "astore_3", "aload_3", "areturn", "aconst_null", "areturn");
98+
tb.checkEqual(expectedCode, actualCode);
99+
}
100+
101+
boolean isTestMethod(Method m) {
102+
try {
103+
return TEST_METHOD.equals(m.getName(cf.constant_pool));
104+
} catch (ConstantPoolException e) {
105+
throw new IllegalStateException(e);
106+
}
107+
}
108+
109+
List<String> getCodeInstructions(Code_attribute code) {
110+
return StreamSupport.stream(code.getInstructions().spliterator(), false)
111+
.map(Instruction::getMnemonic)
112+
.toList();
113+
}
114+
}

0 commit comments

Comments
 (0)