From 4378ad05083547d4121cde51767d12e9f24bae11 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 27 Nov 2024 13:16:56 +0100 Subject: [PATCH] Initial support for pattern in ct.sym. --- .../tools/symbolgenerator/CreateSymbols.java | 238 ++++++++++++--- .../com/sun/tools/javac/code/Symbol.java | 5 +- .../com/sun/tools/javac/jvm/ClassReader.java | 16 + .../javac/processing/PrintingProcessor.java | 19 +- .../com/sun/tools/classfile/ClassWriter.java | 2 +- .../createsymbols/CreateSymbolsTestImpl.java | 282 +++++++++++++++++- 6 files changed, 491 insertions(+), 71 deletions(-) diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index 114c82c52295b..ff3d0b0d85a07 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -135,6 +135,7 @@ import com.sun.tools.classfile.Module_attribute.RequiresEntry; import com.sun.tools.classfile.NestHost_attribute; import com.sun.tools.classfile.NestMembers_attribute; +import com.sun.tools.classfile.Pattern_attribute; import com.sun.tools.classfile.PermittedSubclasses_attribute; import com.sun.tools.classfile.Record_attribute; import com.sun.tools.classfile.Record_attribute.ComponentInfo; @@ -1134,6 +1135,28 @@ private void addAttributes(MethodDescription desc, List constantPool, Ma attributes.put(Attribute.AnnotationDefault, new AnnotationDefault_attribute(attributeString, attributeValue)); } + addParameterableAttributes(desc, constantPool, attributes); + if (desc.patternDescription != null) { + int attributeString = + addString(constantPool, Attribute.Pattern); + int signatureIndex = + addString(constantPool, desc.patternDescription.descriptor); + ConstantPool.CONSTANT_MethodType_info methodTypeInfo = new ConstantPool.CONSTANT_MethodType_info(null, signatureIndex); + addToCP(constantPool, methodTypeInfo); + Map patternAttribute = new HashMap<>(); + addParameterableAttributes(desc.patternDescription, constantPool, patternAttribute); + Pattern_attribute pattern = + new Pattern_attribute(attributeString, + desc.patternDescription.flags, + addString(constantPool, desc.patternDescription.name), + methodTypeInfo, + new Attributes(patternAttribute)); + attributes.put(Attribute.Pattern, + pattern); + } + } + + private void addParameterableAttributes(ParameterableDescription desc, List constantPool, Map attributes) { if (desc.classParameterAnnotations != null && !desc.classParameterAnnotations.isEmpty()) { int attributeString = addString(constantPool, Attribute.RuntimeInvisibleParameterAnnotations); @@ -2604,13 +2627,13 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut case "Synthetic": break; case "RuntimeVisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).runtimeParameterAnnotations = + assert feature instanceof ParameterableDescription; + ((ParameterableDescription) feature).runtimeParameterAnnotations = parameterAnnotations2Description(cf.constant_pool, attr); break; case "RuntimeInvisibleParameterAnnotations": - assert feature instanceof MethodDescription; - ((MethodDescription) feature).classParameterAnnotations = + assert feature instanceof ParameterableDescription; + ((ParameterableDescription) feature).classParameterAnnotations = parameterAnnotations2Description(cf.constant_pool, attr); break; case Attribute.Module: { @@ -2716,15 +2739,15 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut break; } case Attribute.MethodParameters: { - assert feature instanceof MethodDescription; + assert feature instanceof ParameterableDescription; MethodParameters_attribute params = (MethodParameters_attribute) attr; - MethodDescription method = (MethodDescription) feature; + ParameterableDescription method = (ParameterableDescription) feature; method.methodParameters = new ArrayList<>(); for (MethodParameters_attribute.Entry e : params.method_parameter_table) { String name = e.name_index == 0 ? null : cf.constant_pool.getUTF8Value(e.name_index); - MethodDescription.MethodParam param = - new MethodDescription.MethodParam(e.flags, name); + ParameterableDescription.MethodParam param = + new ParameterableDescription.MethodParam(e.flags, name); method.methodParameters.add(param); } break; @@ -2746,6 +2769,20 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut mhd.moduleMainClass = moduleMainClass.getMainClassName(cf.constant_pool); break; } + case Attribute.Pattern: { + assert feature instanceof MethodDescription; + MethodDescription method = (MethodDescription) feature; + Pattern_attribute pattern = (Pattern_attribute) attr; + PatternDescription pd = new PatternDescription(); + pd.flags = pattern.pattern_flags; + pd.name = cf.constant_pool.getUTF8Value(pattern.pattern_name_index); + pd.descriptor = pattern.pattern_methodtype.getType(); + for (Attribute patternAttr : pattern.attributes) { + readAttribute(cf, pd, patternAttr); + } + method.patternDescription = pd; + break; + } default: throw new IllegalStateException("Unhandled attribute: " + attrName); @@ -3900,15 +3937,13 @@ protected void readInnerClasses(LineBasedReader reader) throws IOException { } - static class MethodDescription extends FeatureDescription { + static class MethodDescription extends ParameterableDescription { static int METHODS_FLAGS_NORMALIZATION = ~0; String name; String descriptor; List thrownTypes; Object annotationDefaultValue; - List> classParameterAnnotations; - List> runtimeParameterAnnotations; - List methodParameters; + PatternDescription patternDescription; public MethodDescription() { flagsNormalization = METHODS_FLAGS_NORMALIZATION; @@ -3945,6 +3980,9 @@ public boolean equals(Object obj) { if (!Objects.equals(this.annotationDefaultValue, other.annotationDefaultValue)) { return false; } + if (!Objects.equals(this.patternDescription, other.patternDescription)) { + return false; + } return true; } @@ -3967,6 +4005,144 @@ public void write(Appendable output, String baselineVersion, String version) thr if (annotationDefaultValue != null) output.append(" annotationDefaultValue " + quote(AnnotationDescription.dumpAnnotationValue(annotationDefaultValue), false)); writeAttributes(output); + output.append("\n"); + + if (patternDescription != null) { + patternDescription.write(output, baselineVersion, version); + } + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"method".equals(reader.lineKey)) + return false; + + name = reader.attributes.get("name"); + descriptor = reader.attributes.get("descriptor"); + + String thrownTypesValue = reader.attributes.get("thrownTypes"); + + if (thrownTypesValue != null) { + thrownTypes = deserializeList(thrownTypesValue); + } + + String inAnnotationDefaultValue = reader.attributes.get("annotationDefaultValue"); + + if (inAnnotationDefaultValue != null) { + annotationDefaultValue = parseAnnotationValue(inAnnotationDefaultValue, new int[1]); + } + + readAttributes(reader); + + reader.moveNext(); + + if ("pattern-info".equals(reader.lineKey)) { + patternDescription = new PatternDescription(); + patternDescription.read(reader); + } + + return true; + } + + } + + static class PatternDescription extends ParameterableDescription { + String name; + String descriptor; + + public PatternDescription() { + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + hash = 59 * hash + Objects.hashCode(this.name); + hash = 59 * hash + Objects.hashCode(this.descriptor); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final MethodDescription other = (MethodDescription) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.descriptor, other.descriptor)) { + return false; + } + return true; + } + + @Override + public void write(Appendable output, String baselineVersion, String version) throws IOException { + output.append("pattern-info"); + output.append(" name " + quote(name, false)); + output.append(" descriptor " + quote(descriptor, false)); + writeAttributes(output); + output.append("\n"); + } + + @Override + public boolean read(LineBasedReader reader) throws IOException { + if (!"pattern-info".equals(reader.lineKey)) + return false; + + name = reader.attributes.get("name"); + descriptor = reader.attributes.get("descriptor"); + + readAttributes(reader); + + reader.moveNext(); + + return true; + } + + } + + static abstract class ParameterableDescription extends FeatureDescription { + List> classParameterAnnotations; + List> runtimeParameterAnnotations; + List methodParameters; + + public ParameterableDescription() { + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + final MethodDescription other = (MethodDescription) obj; + if (!Objects.equals(this.classParameterAnnotations, other.classParameterAnnotations)) { + return false; + } + if (!Objects.equals(this.runtimeParameterAnnotations, other.runtimeParameterAnnotations)) { + return false; + } + if (!Objects.equals(this.methodParameters, other.methodParameters)) { + return false; + } + return true; + } + + @Override + public void writeAttributes(Appendable output) throws IOException { + super.writeAttributes(output); if (classParameterAnnotations != null && !classParameterAnnotations.isEmpty()) { output.append(" classParameterAnnotations "); for (List pa : classParameterAnnotations) { @@ -3994,31 +4170,11 @@ public void write(Appendable output, String baselineVersion, String version) thr .collect(Collectors.toList()); output.append(" methodParameters " + serializeList(paramsAsStrings)); } - output.append("\n"); } @Override - public boolean read(LineBasedReader reader) throws IOException { - if (!"method".equals(reader.lineKey)) - return false; - - name = reader.attributes.get("name"); - descriptor = reader.attributes.get("descriptor"); - - String thrownTypesValue = reader.attributes.get("thrownTypes"); - - if (thrownTypesValue != null) { - thrownTypes = deserializeList(thrownTypesValue); - } - - String inAnnotationDefaultValue = reader.attributes.get("annotationDefaultValue"); - - if (inAnnotationDefaultValue != null) { - annotationDefaultValue = parseAnnotationValue(inAnnotationDefaultValue, new int[1]); - } - - readAttributes(reader); - + protected void readAttributes(LineBasedReader reader) { + super.readAttributes(reader); String inClassParamAnnotations = reader.attributes.get("classParameterAnnotations"); if (inClassParamAnnotations != null) { List> annos = new ArrayList<>(); @@ -4054,21 +4210,9 @@ public boolean read(LineBasedReader reader) throws IOException { .map(string2Param) .collect(Collectors.toList()); } - - reader.moveNext(); - - return true; } - public static class MethodParam { - public final int flags; - public final String name; - - public MethodParam(int flags, String name) { - this.flags = flags; - this.name = name; - } - } + public record MethodParam(int flags, String name) {} } static class FieldDescription extends FeatureDescription { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index ee50143c53243..e00c8adaec52c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -894,7 +894,8 @@ public List getEnclosedElements() { apiComplete(); for (Symbol sym : members().getSymbols(NON_RECURSIVE)) { sym.apiComplete(); - if ((sym.flags() & SYNTHETIC) == 0 && sym.owner == this && sym.kind != ERR) { + //TODO: patterns should be part of the output, but they are marked synthetic: + if (((sym.flags() & SYNTHETIC) == 0 || sym.isPattern()) && sym.owner == this && sym.kind != ERR) { list = list.prepend(sym); } } @@ -2015,6 +2016,8 @@ public static class MethodSymbol extends Symbol implements ExecutableElement { */ public Attribute defaultValue = null; + //TODO: would be good to avoid creating an EnumSet instance for *every* MethodSymbol, + //even though only a small fraction of them will be patterns: public final Set patternFlags = EnumSet.noneOf(PatternFlags.class); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index fa3c802a89408..531c968526beb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1388,6 +1388,22 @@ protected void read(Symbol sym, int attrLen) { msym.name = patternName; msym.flags_field |= PATTERN; + + //recover pattern flags: + for (PatternFlags flag : PatternFlags.values()) { + if ((patternFlags & flag.value) != 0) { + msym.patternFlags.add(flag); + } + } + + if (msym.patternFlags.contains(PatternFlags.DECONSTRUCTOR)) { + //TODO: should check the method is static, and has a reasonable first/only parameter? + //reconstitue the deconstructor back: + MethodType mtype = msym.type.asMethodType(); + mtype.argtypes = mtype.argtypes.tail; + msym.flags_field &= ~Flags.STATIC; + } + // todo: check if special handling is needed similar to generic methods for binding types msym.type.asMethodType().bindingtypes = patternType.getParameterTypes(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index d0eee6d6195c7..8eeb11a1a266d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -143,7 +143,7 @@ public NestingKind visitType(TypeElement e, Void p) { printFormalTypeParameters(e, true); switch(kind) { - case CONSTRUCTOR: + case CONSTRUCTOR, DECONSTRUCTOR: // Print out simple name of the class writer.print(e.getEnclosingElement().getSimpleName()); break; @@ -162,7 +162,11 @@ public NestingKind visitType(TypeElement e, Void p) { writer.print(" {} /* compact constructor */ "); } else { writer.print("("); - printParameters(e); + if (e.getKind() == DECONSTRUCTOR) { + printParameters(e.getBindings(), false); + } else { + printParameters(e); + } writer.print(")"); // Display any default values for an annotation @@ -469,7 +473,7 @@ private void printDocComment(Element e) { private void printModifiers(Element e) { ElementKind kind = e.getKind(); - if (kind == PARAMETER || kind == RECORD_COMPONENT) { + if (kind == PARAMETER || kind == RECORD_COMPONENT || kind == PATTERN_BINDING) { // Print annotation inline writer.print(annotationsToString(e)); } else { @@ -623,7 +627,10 @@ public Boolean visitArray(List vals, Void p) { // TODO: Refactor private void printParameters(ExecutableElement e) { - List parameters = e.getParameters(); + printParameters(e.getParameters(), e.isVarArgs()); + } + + private void printParameters(List parameters, boolean isVarArgs) { int size = parameters.size(); switch (size) { @@ -634,7 +641,7 @@ private void printParameters(ExecutableElement e) { for(VariableElement parameter: parameters) { printModifiers(parameter); - if (e.isVarArgs() ) { + if (isVarArgs) { TypeMirror tm = parameter.asType(); if (tm.getKind() != TypeKind.ARRAY) throw new AssertionError("Var-args parameter is not an array type: " + tm); @@ -658,7 +665,7 @@ private void printParameters(ExecutableElement e) { printModifiers(parameter); - if (i == size && e.isVarArgs() ) { + if (i == size && isVarArgs) { TypeMirror tm = parameter.asType(); if (tm.getKind() != TypeKind.ARRAY) throw new AssertionError("Var-args parameter is not an array type: " + tm); diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java index 8058510533e7f..9529905fa732b 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java @@ -528,8 +528,8 @@ protected void writeLocalVariableTypeTableEntry(LocalVariableTypeTable_attribute @Override public Void visitMatcher(Pattern_attribute attr, ClassOutputStream out) { - out.writeShort(attr.pattern_flags); out.writeShort(attr.pattern_name_index); + out.writeShort(attr.pattern_flags); out.writeShort(attr.pattern_methodtype.descriptor_index); int size = attr.attributes.size(); out.writeShort(size); diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java index c66cd08852a21..fb08d78172016 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java @@ -21,6 +21,20 @@ * questions. */ +/** + * @test + * @bug 8072480 8277106 8331027 + * @summary Unit test for CreateSymbols + * @enablePreview + * @modules java.compiler + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * jdk.jdeps/com.sun.tools.classfile + * @clean * + * @run main/othervm CreateSymbolsTest + */ import java.io.File; import java.io.InputStream; import java.io.Writer; @@ -72,16 +86,17 @@ public class CreateSymbolsTestImpl { static final String CREATE_SYMBOLS_NAME = "symbolgenerator.CreateSymbols"; + private List additionalCompilerOptions = List.of(); public static void main(String... args) throws Exception { - new CreateSymbolsTestImpl().doTest(); + doTest(); } - void doTest() throws Exception { + static void doTest() throws Exception { boolean testRun = false; for (Method m : CreateSymbolsTestImpl.class.getDeclaredMethods()) { - if (m.isAnnotationPresent(Test.class)) { - m.invoke(this); + if (m.isAnnotationPresent(Test.class) && "testPatterns".equals(m.getName())) { + m.invoke(new CreateSymbolsTestImpl()); testRun = true; } } @@ -486,20 +501,22 @@ void doPrintElementTest(String[] code7, String[] code8, String className7, Strin String out; out = new JavacTask(tb, Task.Mode.CMDLINE) - .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-Xprint", className7) + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-Xprint", className7)) .run(Expect.SUCCESS) + .writeAll() .getOutput(Task.OutputKind.STDOUT) .replaceAll("\\R", "\n"); if (!out.equals(printed7)) { throw new AssertionError("out=" + out + "; printed7=" + printed7); } out = new JavacTask(tb, Task.Mode.CMDLINE) - .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-Xprint", className8) + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-Xprint", className8)) .run(Expect.SUCCESS) + .writeAll() .getOutput(Task.OutputKind.STDOUT) .replaceAll("\\R", "\n"); if (!out.equals(printed8)) { - throw new AssertionError("out=" + out + "; printed8=" + printed8); + throw new AssertionError("out=" + out + "; printed8=" + printed8 + ", classpath: " + computeClassPath(classes, "8")); } } @@ -792,8 +809,8 @@ void doTestComplex(String printClass, { String out = new JavacTask(tb, Task.Mode.CMDLINE) - .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, - "--add-modules", "m", "-Xprint", "api.Api") + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m", "-Xprint", "api.Api")) .run(Expect.SUCCESS) .getOutput(Task.OutputKind.STDOUT) .replaceAll("\\R", "\n"); @@ -805,8 +822,8 @@ void doTestComplex(String printClass, { new JavacTask(tb) - .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, - "--add-modules", "m") + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m")) .sources(depSuccess) .run(Expect.SUCCESS) .writeAll(); @@ -814,16 +831,16 @@ void doTestComplex(String printClass, { String expectedFailure = new JavacTask(tb) - .options("-d", scratch.toAbsolutePath().toString(), "--module-path", output.resolve("temp").toString(), - "--add-modules", "m", "-XDrawDiagnostics") + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "--module-path", output.resolve("temp").toString(), + "--add-modules", "m", "-XDrawDiagnostics")) .sources(depFailure) .run(Expect.FAIL) .getOutput(Task.OutputKind.DIRECT) .replaceAll("\\R", "\n"); String out = new JavacTask(tb) - .options("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, - "--add-modules", "m", "-XDrawDiagnostics") + .options(augmentOptions("-d", scratch.toAbsolutePath().toString(), "--module-path", modulePath, + "--add-modules", "m", "-XDrawDiagnostics")) .sources(depFailure) .run(Expect.FAIL) .getOutput(Task.OutputKind.DIRECT) @@ -908,6 +925,225 @@ public static class OtherNested {} """); } + @Test + void testPatterns() throws Exception { + additionalCompilerOptions = List.of("--enable-preview", + "-source", System.getProperty("java.specification.version")); + doPrintElementTest(""" + package t; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + } + """, + """ + package t; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + public pattern T(int i, long l) { + match T(i, l); + } + } + """, + "t.T", + """ + package t; + + public class T { + + public T(int arg0, + long arg1); + } + """, + "t.T", + """ + package t; + + public class T { + + public T(int arg0, + long arg1); + + public pattern T(int arg0, + long arg1); + } + """); + doPrintElementTest(""" + package t; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + public pattern T(int i) { + match T(i); + } + } + """, + """ + package t; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + public pattern T(int i, long l) { + match T(i, l); + } + } + """, + "t.T", + """ + package t; + + public class T { + + public T(int arg0, + long arg1); + + public pattern T(int arg0); + } + """, + "t.T", + """ + package t; + + public class T { + + public T(int arg0, + long arg1); + + public pattern T(int arg0, + long arg1); + } + """); + doPrintElementTest(""" + package t; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + } + """, + """ + package t; + import java.lang.annotation.*; + public class T { + private final int i; + private final long l; + public T(int i, long l) { + this.i = i; + this.l = l; + } + public pattern T(@Visible @Invisible int i, + @Visible @Invisible long l) { + match T(i, l); + } + @Retention(RetentionPolicy.RUNTIME) + public @interface Visible {} + public @interface Invisible {} + } + """, + "t.T", + """ + package t; + + public class T { + + public T(int arg0, + long arg1); + } + """, + "t.T", + """ + package t; + + public class T { + + public static @interface Invisible { + } + + public static @interface Visible { + } + + public T(int arg0, + long arg1); + + public pattern T(@t.T.Invisible @t.T.Visible int arg0, + @t.T.Invisible @t.T.Visible long arg1); + } + """); + } + + @Test + void testPatternsCompile() throws Exception { + additionalCompilerOptions = List.of("--enable-preview", + "-source", System.getProperty("java.specification.version")); + doTestComplex("api.Api", + """ + package api; + + public class Api { + + public Api(int arg0, + long arg1); + + public pattern Api(int arg0, + long arg1); + } + """, + """ + import api.Api; + public class Test { + private void t(Object o) { + boolean b = o instanceof Api(var i, var l); + } + } + """, + """ + public class Test { + private void t() { + fail + } + } + """, + """ + module m { + exports api; + } + """, + """ + package api; + public class Api { + private final int i; + private final long l; + public Api(int i, long l) { + this.i = i; + this.l = l; + } + public pattern Api(int i, long l) { + match Api(this.i, this.l); + } + } + """); + } + void doTestData(String data, String... code) throws Exception { String testClasses = System.getProperty("test.classes"); @@ -1166,7 +1402,7 @@ void compileAndPack(Path output, Path outputFile, deleteRecursively(scratch); Files.createDirectories(scratch); System.err.println(Arrays.asList(code)); - new JavacTask(tb).sources(code).options("-d", scratch.toAbsolutePath().toString()).run(Expect.SUCCESS); + new JavacTask(tb).sources(code).options("-d", scratch.toAbsolutePath().toString(), "--enable-preview", "-source", System.getProperty("java.specification.version")).run(Expect.SUCCESS); List classFiles = collectClassFile(scratch); Path moduleInfo = scratch.resolve("module-info.class"); if (Files.exists(moduleInfo)) { @@ -1237,6 +1473,20 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th }); } + private List augmentOptions(String... options) { + if (additionalCompilerOptions.isEmpty()) { + return List.of(options); + } + + List result = + new ArrayList<>(options.length + additionalCompilerOptions.size()); + + result.addAll(List.of(options)); + result.addAll(additionalCompilerOptions); + + return result; + } + @Retention(RetentionPolicy.RUNTIME) @interface Test { }