8231826: Implement javac changes for pattern matching for instanceof
Reviewed-by: mcimadamore
Contributed-by: brian.goetz@oracle.com, gavin.bierman@oracle.com, maurizio.cimadamore@oracle.com, srikanth.adayapalam@oracle.com, vicente.romero@oracle.com, jan.lahoda@oracle.com
/*
* Copyright (c) 2009, 2019, 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.
*
* 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.
*/
/*
* @test
* @summary Verify type annotation on binding patterns
* @library /tools/lib
* @modules java.compiler
* jdk.jdeps/com.sun.tools.javap
* @build toolbox.JavapTask
* @compile --enable-preview -source ${jdk.version} Patterns.java
* @run main/othervm --enable-preview Patterns
*/
import java.lang.annotation.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import toolbox.JavapTask;
import toolbox.Task;
import toolbox.ToolBox;
public class Patterns {
private ToolBox tb = new ToolBox();
public static void main(String[] args) throws Exception {
new Patterns().run();
}
public void run() throws Exception {
String out = new JavapTask(tb)
.options("-private",
"-verbose")
.classpath(System.getProperty("test.classes"))
.classes("Patterns$SimpleBindingPattern")
.run()
.getOutputLines(Task.OutputKind.DIRECT)
.stream()
.collect(Collectors.joining("\n"));
String constantPool = out.substring(0, out.indexOf('{'));
out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1");
out = out.substring(out.indexOf('{'));
out = out.substring(0, out.lastIndexOf('}') + 1);
String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;");
String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;");
String value = snipCPNumber(constantPool, "value");
String expected = """
{
private static final java.lang.Object o;
descriptor: Ljava/lang/Object;
flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
private static final boolean B1s;
descriptor: Z
flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
private static final boolean B1m;
descriptor: Z
flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
private final boolean B2s;
descriptor: Z
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
private final boolean B2m;
descriptor: Z
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
public Patterns$SimpleBindingPattern();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=257, length=18, index=2}
Patterns$SimpleBindingPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=297, length=19, index=3}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
2: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=1}
Patterns$SimpleBindingPattern$A
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=18, index=1}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=18, index=2}
Patterns$SimpleBindingPattern$A
5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=141, length=19, index=3}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
6: #_A_(): LOCAL_VARIABLE, {start_pc=179, length=18, index=2}
Patterns$SimpleBindingPattern$A
7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=219, length=19, index=3}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
void testPatterns();
descriptor: ()V
flags: (0x0000)
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=18, index=2}
Patterns$SimpleBindingPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=57, length=19, index=3}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
void testPatternsDesugared();
descriptor: ()V
flags: (0x0000)
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1}
Patterns$SimpleBindingPattern$A
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
RuntimeInvisibleTypeAnnotations:
0: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=0}
Patterns$SimpleBindingPattern$A
1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=61, length=18, index=0}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
2: #_A_(): LOCAL_VARIABLE, {start_pc=100, length=18, index=1}
Patterns$SimpleBindingPattern$A
3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=137, length=18, index=2}
Patterns$SimpleBindingPattern$CA(
value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
)
}""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value);
if (!expected.equals(out)) {
throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected);
}
}
private String snipCPNumber(String constantPool, String expectedConstant) {
Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant))
.matcher(constantPool);
if (!m.find()) {
throw new AssertionError("Cannot find constant pool item");
}
return m.group(1);
}
/*********************** Test class *************************/
static class SimpleBindingPattern {
@Target(ElementType.TYPE_USE)
@Repeatable(CA.class)
@interface A {}
@Target(ElementType.TYPE_USE)
@interface CA {
public A[] value();
}
private static final Object o = "";
private static final boolean B1s = o instanceof @A String s && s.isEmpty();
private static final boolean B1m = o instanceof @A @A String s && s.isEmpty();
private final boolean B2s = o instanceof @A String s && s.isEmpty();
private final boolean B2m = o instanceof @A @A String s && s.isEmpty();
static {
boolean B3s = o instanceof @A String s && s.isEmpty();
boolean B3m = o instanceof @A @A String s && s.isEmpty();
}
{
boolean B4s = o instanceof @A String s && s.isEmpty();
boolean B4m = o instanceof @A @A String s && s.isEmpty();
}
{
boolean B5s = o instanceof @A String s && s.isEmpty();
boolean B5m = o instanceof @A @A String s && s.isEmpty();
}
public SimpleBindingPattern() {
boolean B6s = o instanceof @A String s && s.isEmpty();
boolean B6m = o instanceof @A @A String s && s.isEmpty();
}
void testPatterns() {
boolean B7s = o instanceof @A String s && s.isEmpty();
boolean B7m = o instanceof @A @A String s && s.isEmpty();
}
void testPatternsDesugared() {
@A String s;
boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty();
boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty();
}
}
}