1 /*
   2  * Copyright (c) 2019, 2022, 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  * RecordCompilationTests
  26  *
  27  * @test
  28  * @bug 8250629 8252307 8247352 8241151 8246774 8259025 8288130 8282714 8289647 8294020
  29  * @summary Negative compilation tests, and positive compilation (smoke) tests for records
  30  * @library /lib/combo /tools/lib /tools/javac/lib
  31  * @modules
  32  *      jdk.compiler/com.sun.tools.javac.api
  33  *      jdk.compiler/com.sun.tools.javac.code
  34  *      jdk.compiler/com.sun.tools.javac.util
  35  *      jdk.jdeps/com.sun.tools.classfile
  36  * @build JavacTestingAbstractProcessor
  37  * @run testng/othervm -DuseAP=false RecordCompilationTests
  38  * @run testng/othervm -DuseAP=true RecordCompilationTests
  39  */
  40 
  41 import java.io.File;
  42 
  43 import java.lang.annotation.ElementType;
  44 import java.util.Arrays;
  45 import java.util.EnumMap;
  46 import java.util.EnumSet;
  47 import java.util.HashSet;
  48 import java.util.List;
  49 import java.util.Map;
  50 import java.util.Set;
  51 import java.util.stream.Collectors;
  52 import java.util.stream.Stream;
  53 
  54 
  55 import com.sun.tools.javac.util.Assert;
  56 
  57 import javax.annotation.processing.AbstractProcessor;
  58 import javax.annotation.processing.RoundEnvironment;
  59 import javax.annotation.processing.SupportedAnnotationTypes;
  60 
  61 import javax.lang.model.element.AnnotationMirror;
  62 import javax.lang.model.element.AnnotationValue;
  63 import javax.lang.model.element.Element;
  64 import javax.lang.model.element.ElementKind;
  65 import javax.lang.model.element.ExecutableElement;
  66 import javax.lang.model.element.RecordComponentElement;
  67 import javax.lang.model.element.TypeElement;
  68 import javax.lang.model.element.VariableElement;
  69 
  70 import javax.lang.model.type.ArrayType;
  71 import javax.lang.model.type.TypeMirror;
  72 
  73 import com.sun.tools.classfile.AccessFlags;
  74 import com.sun.tools.classfile.Annotation;
  75 import com.sun.tools.classfile.Attribute;
  76 import com.sun.tools.classfile.Attributes;
  77 import com.sun.tools.classfile.ClassFile;
  78 import com.sun.tools.classfile.Code_attribute;
  79 import com.sun.tools.classfile.ConstantPool;
  80 import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
  81 import com.sun.tools.classfile.ConstantPool.CPInfo;
  82 import com.sun.tools.classfile.Field;
  83 import com.sun.tools.classfile.Instruction;
  84 import com.sun.tools.classfile.Method;
  85 import com.sun.tools.classfile.Record_attribute;
  86 import com.sun.tools.classfile.Record_attribute.ComponentInfo;
  87 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
  88 import com.sun.tools.classfile.RuntimeTypeAnnotations_attribute;
  89 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
  90 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
  91 import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
  92 import com.sun.tools.classfile.TypeAnnotation;
  93 
  94 import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
  95 import com.sun.tools.javac.code.Attribute.TypeCompound;
  96 import com.sun.tools.javac.code.Symbol;
  97 import com.sun.tools.javac.code.Symbol.VarSymbol;
  98 import com.sun.tools.javac.util.JCDiagnostic;
  99 
 100 import org.testng.annotations.Test;
 101 import tools.javac.combo.CompilationTestCase;
 102 
 103 import static java.lang.annotation.ElementType.*;
 104 import static org.testng.Assert.assertEquals;
 105 
 106 /** Records are the first feature which sports automatic injection of (declarative and type) annotations : from a
 107  *  given record component to one or more record members, if applicable.
 108  *  This implies that the record's implementation can be stressed with the presence of annotation processors. Which is
 109  *  something the implementator could easily skip. For this reason this test is executed twice, once without the
 110  *  presence of any annotation processor and one with a simple annotation processor (which does not annotation processing
 111  *  at all) just to force at least a round of annotation processing.
 112  *
 113  *  Tests needing special compilation options need to store current options, set its customs options by invoking method
 114  *  `setCompileOptions` and then reset the previous compilation options for other tests. To see an example of this check
 115  *  method: testAnnos()
 116  */
 117 
 118 @Test
 119 public class RecordCompilationTests extends CompilationTestCase {
 120     private static String[] OPTIONS_WITH_AP = {"-processor", SimplestAP.class.getName()};
 121 
 122     private static final List<String> BAD_COMPONENT_NAMES = List.of(
 123             "clone", "finalize", "getClass", "hashCode",
 124             "notify", "notifyAll", "toString", "wait");
 125 
 126     /* simplest annotation processor just to force a round of annotation processing for all tests
 127      */
 128     @SupportedAnnotationTypes("*")
 129     public static class SimplestAP extends AbstractProcessor {
 130         @Override
 131         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 132             return true;
 133         }
 134     }
 135 
 136     boolean useAP;
 137 
 138     public RecordCompilationTests() {
 139         useAP = System.getProperty("useAP", "false").equals("true");
 140         setDefaultFilename("R.java");
 141         if (useAP) {
 142             setCompileOptions(OPTIONS_WITH_AP);
 143         }
 144         System.out.println(useAP ? "running all tests using an annotation processor" : "running all tests without annotation processor");
 145     }
 146 
 147     public void testMalformedDeclarations() {
 148         assertFail("compiler.err.premature.eof", "record R()");
 149         assertFail("compiler.err.expected", "record R();");
 150         assertFail("compiler.err.illegal.start.of.type", "record R(,) { }");
 151         assertFail("compiler.err.illegal.start.of.type", "record R((int x)) { }");
 152         assertFail("compiler.err.expected", "record R { }");
 153         assertFail("compiler.err.expected", "record R(foo) { }");
 154         assertFail("compiler.err.expected", "record R(int int) { }");
 155         assertFail("compiler.err.mod.not.allowed.here", "abstract record R(String foo) { }");
 156         //assertFail("compiler.err.illegal.combination.of.modifiers", "non-sealed record R(String foo) { }");
 157         assertFail("compiler.err.repeated.modifier", "public public record R(String foo) { }");
 158         assertFail("compiler.err.repeated.modifier", "private private record R(String foo) { }");
 159         assertFail("compiler.err.already.defined", "record R(int x, int x) {}");
 160         for (String s : List.of("var", "record"))
 161             assertFail("compiler.err.restricted.type.not.allowed.here", "record R(# x) { }", s);
 162         for (String s : List.of("public", "protected", "private", "static", "final", "transient", "volatile",
 163                 "abstract", "synchronized", "native", "strictfp")) // missing: sealed and non-sealed
 164             assertFail("compiler.err.record.cant.declare.field.modifiers", "record R(# String foo) { }", s);
 165         assertFail("compiler.err.varargs.must.be.last", "record R(int... x, int... y) {}");
 166         assertFail("compiler.err.instance.initializer.not.allowed.in.records", "record R(int i) { {} }");
 167     }
 168 
 169     public void testGoodDeclarations() {
 170         assertOK("public record R() { }");
 171         assertOK("record R() { }");
 172         assertOK("record R() implements java.io.Serializable, Runnable { public void run() { } }");
 173         assertOK("record R(int x) { }");
 174         assertOK("record R(int x, int y) { }");
 175         assertOK("record R(int... xs) { }");
 176         assertOK("record R(String... ss) { }");
 177         assertOK("@Deprecated record R(int x, int y) { }");
 178         assertOK("record R(@Deprecated int x, int y) { }");
 179         assertOK("record R<T>(T x, T y) { }");
 180         assertOK(
 181                 """
 182                 record R<T>(T x) {
 183                     public T x() {
 184                         return this.x;
 185                     }
 186                 }
 187                 """);
 188         assertOK(
 189                 """
 190                 import java.util.List;
 191                 record R<T>(List<T> x) {
 192                     public List<T> x() {
 193                         return this.x;
 194                     }
 195                 }
 196                 """);
 197     }
 198 
 199     public void testGoodMemberDeclarations() {
 200         String template = "public record R(int x) {\n"
 201                 + "    public R(int x) { this.x = x; }\n"
 202                 + "    public int x() { return x; }\n"
 203                 + "    public boolean equals(Object o) { return true; }\n"
 204                 + "    public int hashCode() { return 0; }\n"
 205                 + "    public String toString() { return null; }\n"
 206                 + "}";
 207         assertOK(template);
 208     }
 209 
 210     public void testBadComponentNames() {
 211         for (String s : BAD_COMPONENT_NAMES)
 212             assertFail("compiler.err.illegal.record.component.name", "record R(int #) { } ", s);
 213     }
 214 
 215     public void testRestrictedIdentifiers() {
 216         for (String s : List.of("interface record { void m(); }",
 217                 "@interface record { }",
 218                 "class record { }",
 219                 "record record(int x) { }",
 220                 "enum record { A, B }",
 221                 "class R<record> { }")) {
 222             assertFail(
 223                     "compiler.err.restricted.type.not.allowed",
 224                     diagWrapper -> {
 225                         JCDiagnostic diagnostic = ((DiagnosticSourceUnwrapper)diagWrapper).d;
 226                         Object[] args = diagnostic.getArgs();
 227                         Assert.check(args.length == 2);
 228                         Assert.check(args[1].toString().equals("JDK14"));
 229                     },
 230                     s);
 231         }
 232     }
 233 
 234     public void testValidMembers() {
 235         for (String s : List.of("record X(int j) { }",
 236                 "interface I { }",
 237                 "static { }",
 238                 "enum E { A, B }",
 239                 "class C { }"
 240         )) {
 241             assertOK("record R(int i) { # }", s);
 242         }
 243     }
 244 
 245     public void testCyclic() {
 246         // Cyclic records are OK, but cyclic inline records would not be
 247         assertOK("record R(R r) { }");
 248     }
 249 
 250     public void testBadExtends() {
 251         assertFail("compiler.err.expected", "record R(int x) extends Object { }");
 252         assertFail("compiler.err.expected", "record R(int x) {}\n"
 253                 + "record R2(int x) extends R { }");
 254         assertFail("compiler.err.cant.inherit.from.final", "record R(int x) {}\n"
 255                 + "class C extends R { }");
 256     }
 257 
 258     public void testNoExtendRecord() {
 259         assertFail("compiler.err.invalid.supertype.record",
 260                    """
 261                    class R extends Record {
 262                        public String toString() { return null; }
 263                        public int hashCode() { return 0; }
 264                        public boolean equals(Object o) { return false; }
 265                    }
 266                    """
 267         );
 268     }
 269 
 270     public void testFieldDeclarations() {
 271         // static fields are OK
 272         assertOK("public record R(int x) {\n" +
 273                 "    static int I = 1;\n" +
 274                 "    static final String S = \"Hello World!\";\n" +
 275                 "    static private Object O = null;\n" +
 276                 "    static protected Object O2 = null;\n" +
 277                 "}");
 278 
 279         // instance fields are not
 280         assertFail("compiler.err.record.cannot.declare.instance.fields",
 281                 "public record R(int x) {\n" +
 282                         "    private final int y = 0;" +
 283                         "}");
 284 
 285         // mutable instance fields definitely not
 286         assertFail("compiler.err.record.cannot.declare.instance.fields",
 287                 "public record R(int x) {\n" +
 288                         "    private int y = 0;" +
 289                         "}");
 290 
 291         // redeclaring components also not
 292         assertFail("compiler.err.record.cannot.declare.instance.fields",
 293                 "public record R(int x) {\n" +
 294                         "    private final int x;" +
 295                         "}");
 296     }
 297 
 298     public void testAccessorRedeclaration() {
 299         assertOK("public record R(int x) {\n" +
 300                 "    public int x() { return x; };" +
 301                 "}");
 302 
 303         assertOK("public record R(int... x) {\n" +
 304                 "    public int[] x() { return x; };" +
 305                 "}");
 306 
 307         assertOK("public record R(int x) {\n" +
 308                 "    public final int x() { return 0; };" +
 309                 "}");
 310 
 311         assertOK("public record R(int x) {\n" +
 312                 "    public final int x() { return 0; };" +
 313                 "}");
 314 
 315         assertFail("compiler.err.invalid.accessor.method.in.record",
 316                 "public record R(int x) {\n" +
 317                         "    final int x() { return 0; };" +
 318                         "}");
 319 
 320         assertFail("compiler.err.invalid.accessor.method.in.record",
 321                 "public record R(int x) {\n" +
 322                         "    int x() { return 0; };" +
 323                         "}");
 324 
 325         assertFail("compiler.err.invalid.accessor.method.in.record",
 326                 "public record R(int x) {\n" +
 327                         "    private int x() { return 0; };" +
 328                         "}");
 329 
 330         assertFail("compiler.err.invalid.accessor.method.in.record",
 331                    "public record R(int x) {\n" +
 332                    "    public int x() throws Exception { return 0; };" +
 333                    "}");
 334 
 335         for (String s : List.of("List", "List<?>", "Object", "ArrayList<String>", "int"))
 336             assertFail("compiler.err.invalid.accessor.method.in.record",
 337                     "import java.util.*;\n" +
 338                             "public record R(List<String> x) {\n" +
 339                             "    public # x() { return null; };" +
 340                             "}", s);
 341 
 342         assertFail("compiler.err.invalid.accessor.method.in.record",
 343                 "public record R(int x) {\n" +
 344                         "    public <T> int x() { return x; };" +
 345                         "}");
 346 
 347         assertFail("compiler.err.invalid.accessor.method.in.record",
 348                 "public record R(int x) {\n" +
 349                         "    static private final j = 0;" +
 350                         "    static public int x() { return j; };" +
 351                         "}");
 352     }
 353 
 354     public void testConstructorRedeclaration() {
 355         for (String goodCtor : List.of(
 356                 "public R(int x) { this(x, 0); }",
 357                 "public R(int x, int y) { this.x = x; this.y = y; }",
 358                 "public R { }"))
 359             assertOK("record R(int x, int y) { # }", goodCtor);
 360 
 361         assertOK("import java.util.*; record R(String x, String y) {  public R { Objects.requireNonNull(x); Objects.requireNonNull(y); } }");
 362 
 363         // The lambda expressions in the constructor should be compiled successfully.
 364         assertOK("""
 365                 import static java.util.Objects.*;
 366                 record R(String v) {
 367                     R {
 368                         requireNonNull(v, () -> "v must be provided");
 369                         requireNonNullElseGet(v, () -> "w");
 370                     }
 371                 }""");
 372 
 373         // Not OK to redeclare canonical without DA
 374         assertFail("compiler.err.var.might.not.have.been.initialized", "record R(int x, int y) { # }",
 375                    "public R(int x, int y) { this.x = x; }");
 376 
 377         // Not OK to rearrange or change names
 378         for (String s : List.of("public R(int y, int x) { this.x = x; this.y = y; }",
 379                                 "public R(int _x, int _y) { this.x = _x; this.y = _y; }"))
 380             assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x, int y) { # }", s);
 381 
 382         // ctor args must match types
 383         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 384                 "import java.util.*;\n" +
 385                         "record R(List<String> list) { # }",
 386                 "R(List list) { this.list = list; }");
 387 
 388         // canonical ctor should not throw checked exceptions
 389         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 390                    "record R() { # }",
 391                    "public R() throws Exception { }");
 392 
 393         // same for compact
 394         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 395                 "record R() { # }",
 396                 "public R throws Exception { }");
 397 
 398         // not even unchecked exceptions
 399         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 400                 "record R() { # }",
 401                  "public R() throws IllegalArgumentException { }");
 402 
 403         // ditto
 404         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 405                 "record R() { # }",
 406                 "public R throws IllegalArgumentException { }");
 407 
 408         // If types match, names must match
 409         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 410                    "record R(int x, int y) { public R(int y, int x) { this.x = this.y = 0; }}");
 411 
 412         // first invocation should be one to the canonical
 413         assertFail("compiler.err.first.statement.must.be.call.to.another.constructor",
 414                 "record R(int x, int y) { public R(int y, int x, int z) { this.x = this.y = 0; } }");
 415 
 416         assertFail("compiler.err.first.statement.must.be.call.to.another.constructor",
 417                 "record R(int x, int y) { public R(int y, int x, int z) { super(); this.x = this.y = 0; } }");
 418 
 419         assertOK("record R(int x, int y) { " +
 420                  "    public R(int x, int y, int z) { this(x, y); } " +
 421                  "}");
 422 
 423         assertOK("record R(int x) { " +
 424                 "    public R(int x, int y) { this(x, y, 0); } " +
 425                 "    public R(int x, int y, int z) { this(x); } " +
 426                 "}");
 427 
 428         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 429                 "record R<T>(T a) { # }",
 430                 "public <T> R {}");
 431 
 432         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 433                 "record R(int i) { # }",
 434                 "public <T> R(int i) { this.i = i; }");
 435 
 436         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 437                 "record R<T>(T a) { # }",
 438                 "public <T> R(T a) { this.a = a; }");
 439 
 440         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 441                 "record R(int a) { # }",
 442                 "public R(int a) { super(); this.a = a; }");
 443     }
 444 
 445     public void testAnnotationCriteria() {
 446         String imports = "import java.lang.annotation.*;\n";
 447         String template = "@Target({ # }) @interface A {}\n";
 448         EnumMap<ElementType, String> annotations = new EnumMap<>(ElementType.class);
 449         for (ElementType e : values())
 450             annotations.put(e, template.replace("#", "ElementType." + e.name()));
 451         EnumSet<ElementType> goodSet = EnumSet.of(RECORD_COMPONENT, FIELD, METHOD, PARAMETER, TYPE_USE);
 452         EnumSet<ElementType> badSet = EnumSet.of(CONSTRUCTOR, PACKAGE, TYPE, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER, MODULE);
 453 
 454         assertEquals(goodSet.size() + badSet.size(), values().length);
 455         String A_GOOD = template.replace("#",
 456                                          goodSet.stream().map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 457         String A_BAD = template.replace("#",
 458                                         badSet.stream().map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 459         String A_ALL = template.replace("#",
 460                                         Stream.of(ElementType.values()).map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 461         String A_NONE = "@interface A {}";
 462 
 463         for (ElementType e : goodSet)
 464             assertOK(imports + annotations.get(e) + "record R(@A int x) { }");
 465         assertOK(imports + A_GOOD + "record R(@A int x) { }");
 466         assertOK(imports + A_ALL + "record R(@A int x) { }");
 467         assertOK(imports + A_NONE);
 468 
 469         for (ElementType e : badSet) {
 470             assertFail("compiler.err.annotation.type.not.applicable", imports + annotations.get(e) + "record R(@A int x) { }");
 471         }
 472 
 473         assertFail("compiler.err.annotation.type.not.applicable", imports + A_BAD + "record R(@A int x) { }");
 474 
 475         // TODO: OK to redeclare with or without same annos
 476     }
 477 
 478     public void testNestedRecords() {
 479         String template = "class R { \n" +
 480                           "    # record RR(int a) { }\n" +
 481                           "}";
 482 
 483         for (String s : List.of("", "static", "final",
 484                                 "private", "public", "protected",
 485                                 "private static", "public static", "private static final"))
 486             assertOK(template, s);
 487 
 488         for (String s : List.of("class C { }",
 489                                 "static class C { }",
 490                                 "enum X { A; }",
 491                                 "interface I { }",
 492                                 "record RR(int y) { }"))
 493             assertOK("record R(int x) { # }", s);
 494     }
 495 
 496     public void testDuplicatedMember() {
 497         String template
 498                 = "    record R(int i) {\n" +
 499                   "        public int i() { return i; }\n" +
 500                   "        public int i() { return i; }\n" +
 501                   "    }";
 502         assertFail("compiler.err.already.defined", template);
 503     }
 504 
 505     public void testStaticLocals() {
 506         // static locals can't capture local variables, instance fields or type variables
 507         for (String s : List.of(
 508                 "record RR(int x) { public int x() { return y; }};",
 509                 "record RR(int x) { public int x() { return z; }};",
 510                 "record RR(int x) { public int x() { return instance; }};",
 511                 "record RR(T t) {};",
 512                 "record RR(U u) {};",
 513 
 514                 "interface I { default int x() { return y; }};",
 515                 "interface I { default int x() { return z; }};",
 516                 "interface I { default int x() { return instance; }};",
 517                 "interface I { default int x(T t) { return 0; }};",
 518                 "interface I { default int x(U u) { return 0; }};",
 519 
 520                 "enum E { A; int x() { return y; }};",
 521                 "enum E { A; int x() { return z; }};",
 522                 "enum E { A; int x() { return instance; }};",
 523                 "enum E { A; int x(T t) { return 0; }};",
 524                 "enum E { A; int x(U u) { return 0; }};"
 525         )) {
 526             assertFail("compiler.err.non-static.cant.be.ref",
 527                 """
 528                 class R<T> {
 529                     int instance = 0;
 530                     <U> U m(int y) {
 531                         int z;
 532                         #S
 533                         return null;
 534                     }
 535                 }
 536                 """.replaceFirst("#S", s));
 537         }
 538 
 539         // a similar example but a bit more complex
 540         for (String s : List.of(
 541                 "record R() { void test1() { class X { void test2() { System.err.println(localVar); } } } }",
 542                 "record R() { void test1() { class X { void test2() { System.err.println(param); } } } }",
 543                 "record R() {void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
 544                 "record R() { void test1() { class X { T t; } } }",
 545                 "record R() { void test1() { class X { U u; } } }",
 546 
 547                 "interface I { default void test1() { class X { void test2() { System.err.println(localVar); } } } }",
 548                 "interface I() { default void test1() { class X { void test2() {System.err.println(param);} } } }",
 549                 "interface I { default void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
 550                 "interface I { default void test1() { class X { T t; } } }",
 551                 "interface I() { default void test1() { class X {U u;} } }",
 552 
 553                 "enum E { A; void test1() { class X { void test2() { System.err.println(localVar); } } } }",
 554                 "enum E { A; void test1() { class X { void test2() {System.err.println(param);} } } }",
 555                 "enum E { A; void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
 556                 "enum E { A; void test1() { class X { T t; } } }",
 557                 "enum E { A; void test1() { class X {U u;} } }"
 558         )) {
 559             assertFail("compiler.err.non-static.cant.be.ref",
 560                     """
 561                     class C<T> {
 562                         String instanceField = "instance";
 563                         static <U> U m(String param) {
 564                             String localVar = "local";
 565                             #S
 566                             return null;
 567                     }
 568                 }
 569                 """.replaceFirst("#S", s));
 570         }
 571 
 572         // can't self-shadow
 573         for (String s : List.of("record R() {}", "interface R {}", "enum R { A }")) {
 574             assertFail("compiler.err.already.defined", "class R { void m() { #S } }".replaceFirst("#S", s));
 575         }
 576 
 577         // can't be explicitly static
 578         for (String s : List.of("static record RR() { }", "static interface I {}", "static enum E { A }")) {
 579             assertFail("compiler.err.illegal.start.of.expr", "class R { void m() { #S } }".replaceFirst("#S", s));
 580         }
 581 
 582         // but static fields can be accessed
 583         for (String s : List.of(
 584                 "record RR() { public int x() { return z; } };",
 585                 "interface I { default int x() { return z; } }",
 586                 "enum E { A; int x() { return z; } }"
 587         )) {
 588             assertOK("class R { static int z = 0; void m() { #S } }".replaceFirst("#S", s));
 589         }
 590 
 591         // local records can also be final
 592         assertOK("class R { void m() { final record RR(int x) { }; } }");
 593     }
 594 
 595     public void testStaticDefinitionsInInnerClasses() {
 596         // static defs in inner classes can't capture instance fields or type variables
 597         for (String s : List.of(
 598                 """
 599                 record R() {
 600                     void test() { System.err.println(field); }
 601                 }
 602                 """,
 603                 """
 604                 record R() {
 605                     void test(T t) {}
 606                 }
 607                 """,
 608                 """
 609                 record R() {
 610                     void test1() {
 611                         class X {
 612                             void test2() { System.err.println(field); }
 613                         }
 614                     }
 615                 }
 616                 """,
 617                 """
 618                 record R() {
 619                     void test1() {
 620                         class X { void test2(T t) {} }
 621                     }
 622                 }
 623                 """,
 624 
 625                 """
 626                 interface I {
 627                     default void test() { System.err.println(field); }
 628                 }
 629                 """,
 630                 """
 631                 interface I {
 632                     default void test(T t) {}
 633                 }
 634                 """,
 635                 """
 636                 interface I {
 637                     default void test1() {
 638                         class X {
 639                             void test2() { System.err.println(field); }
 640                         }
 641                     }
 642                 }
 643                 """,
 644                 """
 645                 interface I {
 646                     default void test1() {
 647                         class X { void test2(T t) {} }
 648                     }
 649                 }
 650                 """,
 651 
 652                 """
 653                 enum E {
 654                     A;
 655                     void test() { System.err.println(field); }
 656                 }
 657                 """,
 658                 """
 659                 enum E {
 660                     A;
 661                     void test(T t) {}
 662                 }
 663                 """,
 664                 """
 665                 enum E {
 666                     A;
 667                     void test1() {
 668                         class X {
 669                             void test2() { System.err.println(field); }
 670                         }
 671                     }
 672                 }
 673                 """,
 674                 """
 675                 enum E {
 676                     A;
 677                     void test1() {
 678                         class X { void test2(T t) {} }
 679                     }
 680                 }
 681                 """,
 682 
 683                 """
 684                 static class SC {
 685                     void test() { System.err.println(field); }
 686                 }
 687                 """,
 688                 """
 689                 static class SC {
 690                     void test(T t) {}
 691                 }
 692                 """,
 693                 """
 694                 static class SC {
 695                     void test1() {
 696                         class X {
 697                             void test2() { System.err.println(field); }
 698                         }
 699                     }
 700                 }
 701                 """,
 702                 """
 703                 static class SC {
 704                     void test1() {
 705                         class X { void test2(T t) {} }
 706                     }
 707                 }
 708                 """
 709         )) {
 710             assertFail("compiler.err.non-static.cant.be.ref",
 711                     """
 712                     class C<T> {
 713                         String field = "field";
 714                         class Inner {
 715                             #S
 716                         }
 717                     }
 718                     """.replaceFirst("#S", s));
 719         }
 720 
 721         // another, more complex, example
 722         // static defs in inner classes can't capture instance locals, fields or type variables
 723         for (String s : List.of(
 724                 """
 725                 record R() {
 726                     void test() { System.err.println(field); }
 727                 }
 728                 """,
 729                 """
 730                 record R() {
 731                     void test1() {
 732                         class X { void test2() { System.err.println(field); } }
 733                     }
 734                 }
 735                 """,
 736                 """
 737                 record R() {
 738                     void test() { System.err.println(param); }
 739                 }
 740                 """,
 741                 """
 742                 record R() {
 743                     void test1() {
 744                         class X { void test2() { System.err.println(param); } }
 745                     }
 746                 }
 747                 """,
 748                 """
 749                 record R() {
 750                     void test() { System.err.println(local); }
 751                 }
 752                 """,
 753                 """
 754                 record R() {
 755                     void test1() {
 756                         class X { void test2() { System.err.println(local); } }
 757                     }
 758                 }
 759                 """,
 760                 """
 761                 record R() {
 762                     void test(T t) {}
 763                 }
 764                 """,
 765                 """
 766                 record R() {
 767                     void test(U u) {}
 768                 }
 769                 """,
 770                 """
 771                 record R() {
 772                     void test1() {
 773                         class X { void test2(T t) {} }
 774                     }
 775                 }
 776                 """,
 777                 """
 778                 record R() {
 779                     void test1() {
 780                         class X { void test2(U u) {} }
 781                     }
 782                 }
 783                 """,
 784 
 785                 """
 786                 interface I {
 787                     default void test() { System.err.println(field); }
 788                 }
 789                 """,
 790                 """
 791                 interface I {
 792                     default void test1() {
 793                         class X {
 794                             void test2() { System.err.println(field); }
 795                         }
 796                     }
 797                 }
 798                 """,
 799                 """
 800                 interface I {
 801                     default void test() { System.err.println(param); }
 802                 }
 803                 """,
 804                 """
 805                 interface I {
 806                     default void test1() {
 807                         class X {
 808                             void test2() { System.err.println(param); }
 809                         }
 810                     }
 811                 }
 812                 """,
 813                 """
 814                 interface I {
 815                     default void test() { System.err.println(local); }
 816                 }
 817                 """,
 818                 """
 819                 interface I {
 820                     default void test1() {
 821                         class X {
 822                             void test2() { System.err.println(local); }
 823                         }
 824                     }
 825                 }
 826                 """,
 827                 """
 828                 interface I {
 829                     default void test(T t) {}
 830                 }
 831                 """,
 832                 """
 833                 interface I {
 834                     default void test(U u) {}
 835                 }
 836                 """,
 837                 """
 838                 interface I {
 839                     default void test1() {
 840                         class X { void test2(T t) {} }
 841                     }
 842                 }
 843                 """,
 844                 """
 845                 interface I {
 846                     default void test1() {
 847                         class X { void test2(U u) {} }
 848                     }
 849                 }
 850                 """,
 851 
 852                 """
 853                 enum E {
 854                     A;
 855                     void test() { System.err.println(field); }
 856                 }
 857                 """,
 858                 """
 859                 enum E {
 860                     A;
 861                     void test1() {
 862                         class X {
 863                             void test2() { System.err.println(field); }
 864                         }
 865                     }
 866                 }
 867                 """,
 868                 """
 869                 enum E {
 870                     A;
 871                     void test() { System.err.println(param); }
 872                 }
 873                 """,
 874                 """
 875                 enum E {
 876                     A;
 877                     void test1() {
 878                         class X {
 879                             void test2() { System.err.println(param); }
 880                         }
 881                     }
 882                 }
 883                 """,
 884                 """
 885                 enum E {
 886                     A;
 887                     void test() { System.err.println(local); }
 888                 }
 889                 """,
 890                 """
 891                 enum E {
 892                     A;
 893                     void test1() {
 894                         class X {
 895                             void test2() { System.err.println(local); }
 896                         }
 897                     }
 898                 }
 899                 """,
 900                 """
 901                 enum E {
 902                     A;
 903                     void test(T t) {}
 904                 }
 905                 """,
 906                 """
 907                 enum E {
 908                     A;
 909                     void test(U u) {}
 910                 }
 911                 """,
 912                 """
 913                 enum E {
 914                     A;
 915                     void test1() {
 916                         class X { void test2(T t) {} }
 917                     }
 918                 }
 919                 """,
 920                 """
 921                 enum E {
 922                     A;
 923                     void test1() {
 924                         class X { void test2(U u) {} }
 925                     }
 926                 }
 927                 """,
 928 
 929                 """
 930                 static class SC {
 931                     void test() { System.err.println(field); }
 932                 }
 933                 """,
 934                 """
 935                 static class SC {
 936                     void test1() {
 937                         class X {
 938                             void test2() { System.err.println(field); }
 939                         }
 940                     }
 941                 }
 942                 """,
 943                 """
 944                 static class SC {
 945                     void test() { System.err.println(param); }
 946                 }
 947                 """,
 948                 """
 949                 static class SC {
 950                     void test1() {
 951                         class X {
 952                             void test2() { System.err.println(param); }
 953                         }
 954                     }
 955                 }
 956                 """,
 957                 """
 958                 static class SC {
 959                     void test() { System.err.println(local); }
 960                 }
 961                 """,
 962                 """
 963                 static class SC {
 964                     void test1() {
 965                         class X {
 966                             void test2() { System.err.println(local); }
 967                         }
 968                     }
 969                 }
 970                 """,
 971                 """
 972                 static class SC {
 973                     void test(T t) {}
 974                 }
 975                 """,
 976                 """
 977                 static class SC {
 978                     void test(U u) {}
 979                 }
 980                 """,
 981                 """
 982                 static class SC {
 983                     void test1() {
 984                         class X { void test2(T t) {} }
 985                     }
 986                 }
 987                 """,
 988                 """
 989                 static class SC {
 990                     void test1() {
 991                         class X { void test2(U u) {} }
 992                     }
 993                 }
 994                 """
 995         )) {
 996             assertFail("compiler.err.non-static.cant.be.ref",
 997                     """
 998                     class C<T> {
 999                         String field = "field";
1000                         <U> U m(String param) {
1001                             String local = "local";
1002                             class Local {
1003                                 class Inner { #S }
1004                             }
1005                             return null;
1006                         }
1007                     }
1008                     """.replaceFirst("#S", s));
1009         }
1010 
1011         // inner classes can contain static methods too
1012         assertOK(
1013                 """
1014                 class C {
1015                     class Inner {
1016                         // static method inside inner class
1017                         static void m() {}
1018                     }
1019                 }
1020                 """
1021         );
1022 
1023         assertOK(
1024                 """
1025                 class C {
1026                      void m() {
1027                          new Object() {
1028                             // static method inside inner class
1029                             static void m() {}
1030                          };
1031                      }
1032                 }
1033                 """
1034         );
1035 
1036         // but still non-static declarations can't be accessed from a static method inside a local class
1037         for (String s : List.of(
1038                 "System.out.println(localVar)",
1039                 "System.out.println(param)",
1040                 "System.out.println(field)",
1041                 "T t",
1042                 "U u"
1043         )) {
1044             assertFail("compiler.err.non-static.cant.be.ref",
1045                     """
1046                     class C<T> {
1047                         int field = 0;
1048                         <U> void foo(int param) {
1049                             int localVar = 1;
1050                             class Local {
1051                                 static void m() {
1052                                     #S;
1053                                 }
1054                             }
1055                         }
1056                     }
1057                     """.replaceFirst("#S", s));
1058         }
1059     }
1060 
1061     public void testReturnInCanonical_Compact() {
1062         assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x) { # }",
1063                 "public R { return; }");
1064         assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x) { # }",
1065                 "public R { if (i < 0) { return; }}");
1066         assertOK("record R(int x) { public R(int x) { this.x = x; return; } }");
1067         assertOK("record R(int x) { public R { Runnable r = () -> { return; };} }");
1068     }
1069 
1070     public void testArgumentsAreNotFinalInCompact() {
1071         assertOK(
1072                 """
1073                 record R(int x) {
1074                     public R {
1075                         x++;
1076                     }
1077                 }
1078                 """);
1079     }
1080 
1081     public void testNoNativeMethods() {
1082         assertFail("compiler.err.mod.not.allowed.here", "record R(int x) { # }",
1083                 "public native R {}");
1084         assertFail("compiler.err.mod.not.allowed.here", "record R(int x) { # }",
1085                 "public native void m();");
1086     }
1087 
1088     public void testRecordsInsideInner() {
1089         assertOK(
1090                 """
1091                 class Outer {
1092                     class Inner {
1093                         record R(int a) {}
1094                     }
1095                 }
1096                 """
1097         );
1098         assertOK(
1099                 """
1100                 class Outer {
1101                     public void test() {
1102                         class Inner extends Outer {
1103                             record R(int i) {}
1104                         }
1105                     }
1106                 }
1107                 """);
1108         assertOK(
1109                 """
1110                 class Outer {
1111                     Runnable run = new Runnable() {
1112                         record TestRecord(int i) {}
1113                         public void run() {}
1114                     };
1115                 }
1116                 """);
1117         assertOK(
1118                 """
1119                 class Outer {
1120                     void m() {
1121                         record A() {
1122                             record B() { }
1123                         }
1124                     }
1125                 }
1126                 """);
1127     }
1128 
1129     public void testAnnoInsideLocalOrAnonymous() {
1130         assertFail("compiler.err.annotation.decl.not.allowed.here",
1131                 """
1132                 class Outer {
1133                     public void test() {
1134                         class Local {
1135                             @interface A {}
1136                         }
1137                     }
1138                 }
1139                 """);
1140         assertFail("compiler.err.annotation.decl.not.allowed.here",
1141                 """
1142                 class Outer {
1143                     public void test() {
1144                         interface I {
1145                             @interface A {}
1146                         }
1147                     }
1148                 }
1149                 """);
1150         assertFail("compiler.err.annotation.decl.not.allowed.here",
1151                 """
1152                 class Outer {
1153                     public void test() {
1154                         record R() {
1155                             @interface A {}
1156                         }
1157                     }
1158                 }
1159                 """);
1160         assertFail("compiler.err.annotation.decl.not.allowed.here",
1161                 """
1162                 class Outer {
1163                     public void test() {
1164                         enum E {
1165                             E1;
1166                             @interface A {}
1167                         }
1168                     }
1169                 }
1170                 """);
1171 
1172         assertFail("compiler.err.annotation.decl.not.allowed.here",
1173                 """
1174                 class Outer {
1175                     public void test() {
1176                         class Local1 {
1177                             class Local2 {
1178                                 @interface A {}
1179                             }
1180                         }
1181                     }
1182                 }
1183                 """);
1184         assertFail("compiler.err.annotation.decl.not.allowed.here",
1185                 """
1186                 class Outer {
1187                     public void test() {
1188                         class Local {
1189                             interface I {
1190                                 @interface A {}
1191                             }
1192                         }
1193                     }
1194                 }
1195                 """);
1196         assertFail("compiler.err.annotation.decl.not.allowed.here",
1197                 """
1198                 class Outer {
1199                     public void test() {
1200                         class Local {
1201                             record R() {
1202                                 @interface A {}
1203                             }
1204                         }
1205                     }
1206                 }
1207                 """);
1208         assertFail("compiler.err.annotation.decl.not.allowed.here",
1209                 """
1210                 class Outer {
1211                     public void test() {
1212                         class Local {
1213                             enum E {
1214                                 E1;
1215                                 @interface A {}
1216                             }
1217                         }
1218                     }
1219                 }
1220                 """);
1221 
1222         assertFail("compiler.err.annotation.decl.not.allowed.here",
1223                 """
1224                 class Outer {
1225                     Runnable run = new Runnable() {
1226                         @interface A {}
1227                         public void run() {}
1228                     };
1229                 }
1230                 """);
1231     }
1232 
1233     public void testReceiverParameter() {
1234         assertFail("compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class",
1235                 """
1236                 record R(int i) {
1237                     public R(R this, int i) {
1238                         this.i = i;
1239                     }
1240                 }
1241                 """);
1242         assertFail("compiler.err.non-static.cant.be.ref",
1243                 """
1244                 class Outer {
1245                     record R(int i) {
1246                         public R(Outer Outer.this, int i) {
1247                             this.i = i;
1248                         }
1249                     }
1250                 }
1251                 """);
1252         assertOK(
1253                 """
1254                 record R(int i) {
1255                     void m(R this) {}
1256                     public int i(R this) { return i; }
1257                 }
1258                 """);
1259     }
1260 
1261     public void testOnlyOneFieldRef() throws Exception {
1262         for (String source : List.of(
1263                 "record R(int recordComponent) {}",
1264                 """
1265                 class Test {
1266                     class Inner {
1267                         Inner() {
1268                             record R(int recordComponent) {}
1269                         }
1270                     }
1271                 }
1272                 """,
1273                 """
1274                 class Test {
1275                     class Inner {
1276                         void m() {
1277                             record R(int recordComponent) {}
1278                         }
1279                     }
1280                 }
1281                 """,
1282                 """
1283                 class Test {
1284                     void m() {
1285                         record R(int recordComponent) {}
1286                     }
1287                 }
1288                 """
1289         )) {
1290             File dir = assertOK(true, source);
1291             int numberOfFieldRefs = 0;
1292             for (final File fileEntry : dir.listFiles()) {
1293                 if (fileEntry.getName().endsWith("R.class")) {
1294                     ClassFile classFile = ClassFile.read(fileEntry);
1295                     for (CPInfo cpInfo : classFile.constant_pool.entries()) {
1296                         if (cpInfo instanceof ConstantPool.CONSTANT_Fieldref_info) {
1297                             numberOfFieldRefs++;
1298                             ConstantPool.CONSTANT_NameAndType_info nameAndType =
1299                                     (ConstantPool.CONSTANT_NameAndType_info)classFile.constant_pool
1300                                             .get(((ConstantPool.CONSTANT_Fieldref_info)cpInfo).name_and_type_index);
1301                             Assert.check(nameAndType.getName().equals("recordComponent"));
1302                         }
1303                     }
1304                     Assert.check(numberOfFieldRefs == 1);
1305                 }
1306             }
1307         }
1308     }
1309 
1310     //  check that fields are initialized in a canonical constructor in the same declaration order as the corresponding
1311     //  record component
1312     public void testCheckInitializationOrderInCompactConstructor() throws Exception {
1313         int putField1 = -1;
1314         int putField2 = -1;
1315         File dir = assertOK(true, "record R(int i, String s) { R {} }");
1316         for (final File fileEntry : dir.listFiles()) {
1317             if (fileEntry.getName().equals("R.class")) {
1318                 ClassFile classFile = ClassFile.read(fileEntry);
1319                 for (Method method : classFile.methods) {
1320                     if (method.getName(classFile.constant_pool).equals("<init>")) {
1321                         Code_attribute code_attribute = (Code_attribute) method.attributes.get("Code");
1322                         for (Instruction instruction : code_attribute.getInstructions()) {
1323                             if (instruction.getMnemonic().equals("putfield")) {
1324                                 if (putField1 != -1 && putField2 != -1) {
1325                                     throw new AssertionError("was expecting only two putfield instructions in this method");
1326                                 }
1327                                 if (putField1 == -1) {
1328                                     putField1 = instruction.getShort(1);
1329                                 } else if (putField2 == -1) {
1330                                     putField2 = instruction.getShort(1);
1331                                 }
1332                             }
1333                         }
1334                         // now we need to check that we are assigning to `i` first and to `s` afterwards
1335                         CONSTANT_Fieldref_info fieldref_info1 = (CONSTANT_Fieldref_info)classFile.constant_pool.get(putField1);
1336                         if (!fieldref_info1.getNameAndTypeInfo().getName().equals("i")) {
1337                             throw new AssertionError("was expecting variable name 'i'");
1338                         }
1339 
1340                         CONSTANT_Fieldref_info fieldref_info2 = (CONSTANT_Fieldref_info)classFile.constant_pool.get(putField2);
1341                         if (!fieldref_info2.getNameAndTypeInfo().getName().equals("s")) {
1342                             throw new AssertionError("was expecting variable name 's'");
1343                         }
1344                     }
1345                 }
1346             }
1347         }
1348     }
1349 
1350     public void testAcceptRecordId() {
1351         String[] previousOptions = getCompileOptions();
1352         try {
1353             String[] testOptions = {};
1354             setCompileOptions(testOptions);
1355             assertFail("compiler.err.illegal.start.of.type",
1356                     "class R {\n" +
1357                             "    record RR(int i) {\n" +
1358                             "        return null;\n" +
1359                             "    }\n" +
1360                             "    class record {}\n" +
1361                             "}");
1362         } finally {
1363             setCompileOptions(previousOptions);
1364         }
1365     }
1366 
1367     public void testMultipleAnnosInRecord() throws Exception {
1368         String[] previousOptions = getCompileOptions();
1369 
1370         try {
1371             String imports = """
1372                     import java.lang.annotation.ElementType;
1373                     import java.lang.annotation.Target;
1374                     """;
1375 
1376             String annotTemplate =
1377                     """
1378                     @Target(ElementType.#TARGET)
1379                     @interface anno#TARGET { }
1380                     """;
1381 
1382             String recordTemplate =
1383                     """
1384                     record R(#TARGETS String s) {}
1385                     """;
1386 
1387             String[] generalOptions = {
1388                     "-processor", Processor.class.getName(),
1389             };
1390 
1391             List<String> targets = List.of("FIELD", "RECORD_COMPONENT", "PARAMETER", "METHOD");
1392 
1393             var interfaces = targets.stream().map(t -> annotTemplate.replaceAll("#TARGET", t)).collect(Collectors.joining("\n"));
1394             var recordAnnotations = targets.stream().map(t -> "@anno" + t).collect(Collectors.joining(" "));
1395             String record = recordTemplate.replaceFirst("#TARGETS", recordAnnotations);
1396             String code = String.format("%s\n%s\n%s\n",imports,interfaces,record);
1397             String[] testOptions = generalOptions.clone();
1398             setCompileOptions(testOptions);
1399 
1400             assertOK(true, code);
1401 
1402         // let's reset the default compiler options for other tests
1403         } finally {
1404             setCompileOptions(previousOptions);
1405         }
1406     }
1407 
1408     public void testAnnos() throws Exception {
1409         String[] previousOptions = getCompileOptions();
1410         try {
1411             String srcTemplate =
1412                     """
1413                     import java.lang.annotation.*;
1414                     @Target({#TARGET})
1415                     @Retention(RetentionPolicy.RUNTIME)
1416                     @interface Anno { }
1417                     record R(@Anno String s) {}
1418                     """;
1419 
1420             // testing several combinations, adding even more combinations won't add too much value
1421             List<String> annoApplicableTargets = List.of(
1422                     "ElementType.FIELD",
1423                     "ElementType.METHOD",
1424                     "ElementType.PARAMETER",
1425                     "ElementType.RECORD_COMPONENT",
1426                     "ElementType.TYPE_USE",
1427                     "ElementType.TYPE_USE,ElementType.FIELD",
1428                     "ElementType.TYPE_USE,ElementType.METHOD",
1429                     "ElementType.TYPE_USE,ElementType.PARAMETER",
1430                     "ElementType.TYPE_USE,ElementType.RECORD_COMPONENT",
1431                     "ElementType.TYPE_USE,ElementType.FIELD,ElementType.METHOD",
1432                     "ElementType.TYPE_USE,ElementType.FIELD,ElementType.PARAMETER",
1433                     "ElementType.TYPE_USE,ElementType.FIELD,ElementType.RECORD_COMPONENT",
1434                     "ElementType.FIELD,ElementType.TYPE_USE",
1435                     "ElementType.FIELD,ElementType.CONSTRUCTOR",
1436                     "ElementType.FIELD,ElementType.LOCAL_VARIABLE",
1437                     "ElementType.FIELD,ElementType.ANNOTATION_TYPE",
1438                     "ElementType.FIELD,ElementType.PACKAGE",
1439                     "ElementType.FIELD,ElementType.TYPE_PARAMETER",
1440                     "ElementType.FIELD,ElementType.MODULE",
1441                     "ElementType.METHOD,ElementType.TYPE_USE",
1442                     "ElementType.PARAMETER,ElementType.TYPE_USE",
1443                     "ElementType.RECORD_COMPONENT,ElementType.TYPE_USE",
1444                     "ElementType.FIELD,ElementType.METHOD,ElementType.TYPE_USE",
1445                     "ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE_USE",
1446                     "ElementType.FIELD,ElementType.RECORD_COMPONENT,ElementType.TYPE_USE"
1447             );
1448 
1449             String[] generalOptions = {
1450                     "-processor", Processor.class.getName(),
1451                     "-Atargets="
1452             };
1453 
1454             for (String target : annoApplicableTargets) {
1455                 String code = srcTemplate.replaceFirst("#TARGET", target);
1456                 String[] testOptions = generalOptions.clone();
1457                 testOptions[testOptions.length - 1] = testOptions[testOptions.length - 1] + target;
1458                 setCompileOptions(testOptions);
1459 
1460                 File dir = assertOK(true, code);
1461 
1462                 ClassFile classFile = ClassFile.read(findClassFileOrFail(dir, "R.class"));
1463 
1464                 // field first
1465                 Assert.check(classFile.fields.length == 1);
1466                 Field field = classFile.fields[0];
1467                 // if FIELD is one of the targets then there must be a declaration annotation applied to the field, apart from
1468                 // the type annotation
1469                 if (target.contains("ElementType.FIELD")) {
1470                     checkAnno(classFile,
1471                             (RuntimeAnnotations_attribute) findAttributeOrFail(
1472                                     field.attributes,
1473                                     RuntimeVisibleAnnotations_attribute.class),
1474                             "Anno");
1475                 } else {
1476                     assertAttributeNotPresent(field.attributes, RuntimeVisibleAnnotations_attribute.class);
1477                 }
1478 
1479                 // lets check now for the type annotation
1480                 if (target.contains("ElementType.TYPE_USE")) {
1481                     checkTypeAnno(
1482                             classFile,
1483                             (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(field.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1484                             "FIELD",
1485                             "Anno");
1486                 } else {
1487                     assertAttributeNotPresent(field.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1488                 }
1489 
1490                 // checking for the annotation on the corresponding parameter of the canonical constructor
1491                 Method init = findMethodOrFail(classFile, "<init>");
1492                 // if PARAMETER is one of the targets then there must be a declaration annotation applied to the parameter, apart from
1493                 // the type annotation
1494                 if (target.contains("ElementType.PARAMETER")) {
1495                     checkParameterAnno(classFile,
1496                             (RuntimeVisibleParameterAnnotations_attribute) findAttributeOrFail(
1497                                     init.attributes,
1498                                     RuntimeVisibleParameterAnnotations_attribute.class),
1499                             "Anno");
1500                 } else {
1501                     assertAttributeNotPresent(init.attributes, RuntimeVisibleAnnotations_attribute.class);
1502                 }
1503                 // let's check now for the type annotation
1504                 if (target.contains("ElementType.TYPE_USE")) {
1505                     checkTypeAnno(
1506                             classFile,
1507                             (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(init.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1508                             "METHOD_FORMAL_PARAMETER", "Anno");
1509                 } else {
1510                     assertAttributeNotPresent(init.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1511                 }
1512 
1513                 // checking for the annotation in the accessor
1514                 Method accessor = findMethodOrFail(classFile, "s");
1515                 // if METHOD is one of the targets then there must be a declaration annotation applied to the accessor, apart from
1516                 // the type annotation
1517                 if (target.contains("ElementType.METHOD")) {
1518                     checkAnno(classFile,
1519                             (RuntimeAnnotations_attribute) findAttributeOrFail(
1520                                     accessor.attributes,
1521                                     RuntimeVisibleAnnotations_attribute.class),
1522                             "Anno");
1523                 } else {
1524                     assertAttributeNotPresent(accessor.attributes, RuntimeVisibleAnnotations_attribute.class);
1525                 }
1526                 // let's check now for the type annotation
1527                 if (target.contains("ElementType.TYPE_USE")) {
1528                     checkTypeAnno(
1529                             classFile,
1530                             (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(accessor.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1531                             "METHOD_RETURN", "Anno");
1532                 } else {
1533                     assertAttributeNotPresent(accessor.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1534                 }
1535 
1536                 // checking for the annotation in the Record attribute
1537                 Record_attribute record = (Record_attribute) findAttributeOrFail(classFile.attributes, Record_attribute.class);
1538                 Assert.check(record.component_count == 1);
1539                 // if RECORD_COMPONENT is one of the targets then there must be a declaration annotation applied to the
1540                 // field, apart from the type annotation
1541                 if (target.contains("ElementType.RECORD_COMPONENT")) {
1542                     checkAnno(classFile,
1543                             (RuntimeAnnotations_attribute) findAttributeOrFail(
1544                                     record.component_info_arr[0].attributes,
1545                                     RuntimeVisibleAnnotations_attribute.class),
1546                             "Anno");
1547                 } else {
1548                     assertAttributeNotPresent(record.component_info_arr[0].attributes, RuntimeVisibleAnnotations_attribute.class);
1549                 }
1550                 // lets check now for the type annotation
1551                 if (target.contains("ElementType.TYPE_USE")) {
1552                     checkTypeAnno(
1553                             classFile,
1554                             (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(
1555                                     record.component_info_arr[0].attributes,
1556                                     RuntimeVisibleTypeAnnotations_attribute.class),
1557                             "FIELD", "Anno");
1558                 } else {
1559                     assertAttributeNotPresent(record.component_info_arr[0].attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1560                 }
1561             }
1562 
1563             // let's reset the default compiler options for other tests
1564         } finally {
1565             setCompileOptions(previousOptions);
1566         }
1567     }
1568 
1569     // JDK-8292159: TYPE_USE annotations on generic type arguments
1570     //              of record components discarded
1571     public void testOnlyTypeAnnotationsOnComponentField() throws Exception {
1572         String code =
1573                 """
1574                 import java.lang.annotation.*;
1575                 import java.util.List;
1576                 @Target({ElementType.TYPE_USE})
1577                 @Retention(RetentionPolicy.RUNTIME)
1578                 @interface Anno { }
1579                 record R(List<@Anno String> s) {}
1580                 """;
1581 
1582         File dir = assertOK(true, code);
1583 
1584         ClassFile classFile = ClassFile.read(findClassFileOrFail(dir, "R.class"));
1585 
1586         // field first
1587         Assert.check(classFile.fields.length == 1);
1588         Field field = classFile.fields[0];
1589         checkTypeAnno(
1590                 classFile,
1591                 (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(field.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1592                 "FIELD",
1593                 "Anno");
1594 
1595         // checking for the annotation on the corresponding parameter of the canonical constructor
1596         Method init = findMethodOrFail(classFile, "<init>");
1597         checkTypeAnno(
1598                 classFile,
1599                 (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(init.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1600                 "METHOD_FORMAL_PARAMETER", "Anno");
1601 
1602         // checking for the annotation in the accessor
1603         Method accessor = findMethodOrFail(classFile, "s");
1604         checkTypeAnno(
1605                 classFile,
1606                 (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(accessor.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1607                 "METHOD_RETURN", "Anno");
1608 
1609         // checking for the annotation in the Record attribute
1610         Record_attribute record = (Record_attribute) findAttributeOrFail(classFile.attributes, Record_attribute.class);
1611         Assert.check(record.component_count == 1);
1612         checkTypeAnno(
1613                 classFile,
1614                 (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(
1615                             record.component_info_arr[0].attributes,
1616                                 RuntimeVisibleTypeAnnotations_attribute.class),
1617                         "FIELD", "Anno");
1618     }
1619 
1620     private void checkTypeAnno(ClassFile classFile,
1621                                RuntimeTypeAnnotations_attribute rtAnnos,
1622                                String positionType,
1623                                String annoName) throws Exception {
1624         // containing only one type annotation
1625         Assert.check(rtAnnos.annotations.length == 1);
1626         TypeAnnotation tAnno = (TypeAnnotation)rtAnnos.annotations[0];
1627         Assert.check(tAnno.position.type.toString().equals(positionType));
1628         String annotationName = classFile.constant_pool.getUTF8Value(tAnno.annotation.type_index).toString().substring(1);
1629         Assert.check(annotationName.startsWith(annoName));
1630     }
1631 
1632     private void checkAnno(ClassFile classFile,
1633                            RuntimeAnnotations_attribute rAnnos,
1634                            String annoName) throws Exception {
1635         // containing only one type annotation
1636         Assert.check(rAnnos.annotations.length == 1);
1637         Annotation anno = (Annotation)rAnnos.annotations[0];
1638         String annotationName = classFile.constant_pool.getUTF8Value(anno.type_index).toString().substring(1);
1639         Assert.check(annotationName.startsWith(annoName));
1640     }
1641 
1642     // special case for parameter annotations
1643     private void checkParameterAnno(ClassFile classFile,
1644                            RuntimeVisibleParameterAnnotations_attribute rAnnos,
1645                            String annoName) throws Exception {
1646         // containing only one type annotation
1647         Assert.check(rAnnos.parameter_annotations.length == 1);
1648         Assert.check(rAnnos.parameter_annotations[0].length == 1);
1649         Annotation anno = (Annotation)rAnnos.parameter_annotations[0][0];
1650         String annotationName = classFile.constant_pool.getUTF8Value(anno.type_index).toString().substring(1);
1651         Assert.check(annotationName.startsWith(annoName));
1652     }
1653 
1654     private File findClassFileOrFail(File dir, String name) {
1655         for (final File fileEntry : dir.listFiles()) {
1656             if (fileEntry.getName().equals("R.class")) {
1657                 return fileEntry;
1658             }
1659         }
1660         throw new AssertionError("file not found");
1661     }
1662 
1663     private Method findMethodOrFail(ClassFile classFile, String name) throws Exception {
1664         for (Method method : classFile.methods) {
1665             if (method.getName(classFile.constant_pool).equals(name)) {
1666                 return method;
1667             }
1668         }
1669         throw new AssertionError("method not found");
1670     }
1671 
1672     private Attribute findAttributeOrFail(Attributes attributes, Class<? extends Attribute> attrClass) {
1673         for (Attribute attribute : attributes) {
1674             if (attribute.getClass() == attrClass) {
1675                 return attribute;
1676             }
1677         }
1678         throw new AssertionError("attribute not found");
1679     }
1680 
1681     private void assertAttributeNotPresent(Attributes attributes, Class<? extends Attribute> attrClass) {
1682         for (Attribute attribute : attributes) {
1683             if (attribute.getClass() == attrClass) {
1684                 throw new AssertionError("attribute not expected");
1685             }
1686         }
1687     }
1688 
1689     @SupportedAnnotationTypes("*")
1690     public static final class Processor extends JavacTestingAbstractProcessor {
1691 
1692         String targets;
1693         int numberOfTypeAnnotations;
1694 
1695         @Override
1696         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
1697             targets = processingEnv.getOptions().get("targets");
1698             for (TypeElement te : annotations) {
1699                 if (te.toString().equals("Anno")) {
1700                     checkElements(te, roundEnv, targets);
1701                     if (targets.contains("TYPE_USE")) {
1702                         Element element = processingEnv.getElementUtils().getTypeElement("R");
1703                         numberOfTypeAnnotations = 0;
1704                         checkTypeAnnotations(element);
1705                         Assert.check(numberOfTypeAnnotations == 4);
1706                     }
1707                 }
1708             }
1709             return true;
1710         }
1711 
1712         void checkElements(TypeElement te, RoundEnvironment renv, String targets) {
1713             Set<? extends Element> annoElements = renv.getElementsAnnotatedWith(te);
1714             Set<String> targetSet = new HashSet<>(Arrays.asList(targets.split(",")));
1715             // we will check for type annotation in another method
1716             targetSet.remove("ElementType.TYPE_USE");
1717             for (Element e : annoElements) {
1718                 Symbol s = (Symbol) e;
1719                 switch (s.getKind()) {
1720                     case FIELD:
1721                         Assert.check(targetSet.contains("ElementType.FIELD"));
1722                         targetSet.remove("ElementType.FIELD");
1723                         break;
1724                     case METHOD:
1725                         Assert.check(targetSet.contains("ElementType.METHOD"));
1726                         targetSet.remove("ElementType.METHOD");
1727                         break;
1728                     case PARAMETER:
1729                         Assert.check(targetSet.contains("ElementType.PARAMETER"));
1730                         targetSet.remove("ElementType.PARAMETER");
1731                         break;
1732                     case RECORD_COMPONENT:
1733                         Assert.check(targetSet.contains("ElementType.RECORD_COMPONENT"));
1734                         targetSet.remove("ElementType.RECORD_COMPONENT");
1735                         break;
1736                     default:
1737                         throw new AssertionError("unexpected element kind");
1738                 }
1739             }
1740         }
1741 
1742         private void checkTypeAnnotations(Element rootElement) {
1743             new ElementScanner<Void, Void>() {
1744                 @Override public Void visitVariable(VariableElement e, Void p) {
1745                     Symbol s = (Symbol) e;
1746                     if (s.getKind() == ElementKind.FIELD ||
1747                             s.getKind() == ElementKind.PARAMETER &&
1748                             s.name.toString().equals("s")) {
1749                         int currentTAs = numberOfTypeAnnotations;
1750                         verifyTypeAnnotations(e.asType().getAnnotationMirrors());
1751                         Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1752                     }
1753                     return null;
1754                 }
1755                 @Override
1756                 public Void visitExecutable(ExecutableElement e, Void p) {
1757                     Symbol s = (Symbol) e;
1758                     if (s.getKind() == ElementKind.METHOD &&
1759                                     s.name.toString().equals("s")) {
1760                         int currentTAs = numberOfTypeAnnotations;
1761                         verifyTypeAnnotations(e.getReturnType().getAnnotationMirrors());
1762                         Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1763                     }
1764                     scan(e.getParameters(), p);
1765                     return null;
1766                 }
1767                 @Override public Void visitRecordComponent(RecordComponentElement e, Void p) {
1768                     int currentTAs = numberOfTypeAnnotations;
1769                     verifyTypeAnnotations(e.asType().getAnnotationMirrors());
1770                     Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1771                     return null;
1772                 }
1773             }.scan(rootElement, null);
1774         }
1775 
1776         private void verifyTypeAnnotations(Iterable<? extends AnnotationMirror> annotations) {
1777             for (AnnotationMirror mirror : annotations) {
1778                 Assert.check(mirror.toString().startsWith("@Anno"));
1779                 if (mirror instanceof TypeCompound) {
1780                     numberOfTypeAnnotations++;
1781                 }
1782             }
1783         }
1784     }
1785 
1786     public void testMethodsInheritedFromRecordArePublicAndFinal() throws Exception {
1787         int numberOfFieldRefs = 0;
1788         File dir = assertOK(true, "record R() {}");
1789         for (final File fileEntry : dir.listFiles()) {
1790             if (fileEntry.getName().equals("R.class")) {
1791                 ClassFile classFile = ClassFile.read(fileEntry);
1792                 for (Method method : classFile.methods)
1793                     switch (method.getName(classFile.constant_pool)) {
1794                         case "toString", "equals", "hashCode" ->
1795                             Assert.check(method.access_flags.is(AccessFlags.ACC_PUBLIC) && method.access_flags.is(AccessFlags.ACC_FINAL));
1796                         default -> {}
1797                     }
1798             }
1799         }
1800     }
1801 
1802     private static final List<String> ACCESSIBILITY = List.of(
1803             "public", "protected", "", "private");
1804 
1805     public void testCanonicalAccessibility() throws Exception {
1806         // accessibility of canonical can't be stronger than that of the record type
1807         for (String a1 : ACCESSIBILITY) {
1808             for (String a2 : ACCESSIBILITY) {
1809                 if (protection(a2) > protection(a1)) {
1810                     assertFail("compiler.err.invalid.canonical.constructor.in.record", "class R {# record RR() { # RR {} } }", a1, a2);
1811                 } else {
1812                     assertOK("class R {# record RR() { # RR {} } }", a1, a2);
1813                 }
1814             }
1815         }
1816 
1817         // now lets check that when compiler the compiler generates the canonical, it has the same accessibility
1818         // as the record type
1819         for (String a : ACCESSIBILITY) {
1820             File dir = assertOK(true, "class R {# record RR() {} }", a);
1821             for (final File fileEntry : dir.listFiles()) {
1822                 if (fileEntry.getName().equals("R$RR.class")) {
1823                     ClassFile classFile = ClassFile.read(fileEntry);
1824                     for (Method method : classFile.methods)
1825                         if (method.getName(classFile.constant_pool).equals("<init>")) {
1826                             Assert.check(method.access_flags.flags == accessFlag(a),
1827                                     "was expecting access flag " + accessFlag(a) + " but found " + method.access_flags.flags);
1828                         }
1829                 }
1830             }
1831         }
1832     }
1833 
1834     private int protection(String access) {
1835         switch (access) {
1836             case "private": return 3;
1837             case "protected": return 1;
1838             case "public": return 0;
1839             case "": return 2;
1840             default:
1841                 throw new AssertionError();
1842         }
1843     }
1844 
1845     private int accessFlag(String access) {
1846         switch (access) {
1847             case "private": return AccessFlags.ACC_PRIVATE;
1848             case "protected": return AccessFlags.ACC_PROTECTED;
1849             case "public": return AccessFlags.ACC_PUBLIC;
1850             case "": return 0;
1851             default:
1852                 throw new AssertionError();
1853         }
1854     }
1855 
1856     public void testSameArity() {
1857         for (String source : List.of(
1858                 """
1859                 record R(int... args) {
1860                     public R(int... args) {
1861                         this.args = args;
1862                     }
1863                 }
1864                 """,
1865                 """
1866                 record R(int[] args) {
1867                     public R(int[] args) {
1868                         this.args = args;
1869                     }
1870                 }
1871                 """,
1872                 """
1873                 record R(@A int... ints) {}
1874 
1875                 @java.lang.annotation.Target({
1876                         java.lang.annotation.ElementType.TYPE_USE,
1877                         java.lang.annotation.ElementType.RECORD_COMPONENT})
1878                 @interface A {}
1879                 """,
1880                 """
1881                 record R(@A int... ints) {
1882                     R(@A int... ints) {
1883                         this.ints = ints;
1884                     }
1885                 }
1886 
1887                 @java.lang.annotation.Target({
1888                         java.lang.annotation.ElementType.TYPE_USE,
1889                         java.lang.annotation.ElementType.RECORD_COMPONENT})
1890                 @interface A {}
1891                 """
1892         )) {
1893             assertOK(source);
1894         }
1895 
1896         for (String source : List.of(
1897                 """
1898                 record R(int... args) {
1899                     public R(int[] args) {
1900                         this.args = args;
1901                     }
1902                 }
1903                 """,
1904                 """
1905                 record R(int... args) {
1906                     public R(int[] args) {
1907                         this.args = args;
1908                     }
1909                 }
1910                 """,
1911                 """
1912                 record R(String... args) {
1913                     public R(String[] args) {
1914                         this.args = args;
1915                     }
1916                 }
1917                 """,
1918                 """
1919                 record R(String... args) {
1920                     public R(String[] args) {
1921                         this.args = args;
1922                     }
1923                 }
1924                 """
1925         )) {
1926             assertFail("compiler.err.invalid.canonical.constructor.in.record", source);
1927         }
1928     }
1929 
1930     public void testSafeVararsAnno() {
1931         assertFail("compiler.err.annotation.type.not.applicable",
1932                 """
1933                 @SafeVarargs
1934                 record R<T>(T... t) {}
1935                 """,
1936                 """
1937                 @SafeVarargs
1938                 record R<T>(T... t) {
1939                     R(T... t) {
1940                         this.t = t;
1941                     }
1942                 }
1943                 """
1944         );
1945 
1946         assertOK(
1947                 """
1948                 record R<T>(T... t) {
1949                     @SafeVarargs
1950                     R(T... t) {
1951                         this.t = t;
1952                     }
1953                 }
1954                 """
1955         );
1956 
1957         appendCompileOptions("-Xlint:unchecked");
1958         assertOKWithWarning("compiler.warn.unchecked.varargs.non.reifiable.type",
1959                 """
1960                 record R<T>(T... t) {
1961                     R(T... t) {
1962                         this.t = t;
1963                     }
1964                 }
1965                 """
1966         );
1967         removeLastCompileOptions(1);
1968 
1969         assertOK(
1970                 """
1971                 @SuppressWarnings("unchecked")
1972                 record R<T>(T... t) {
1973                     R(T... t) {
1974                         this.t = t;
1975                     }
1976                 }
1977                 """
1978         );
1979 
1980         assertOK(
1981                 """
1982                 record R<T>(T... t) {
1983                     @SuppressWarnings("unchecked")
1984                     R(T... t) {
1985                         this.t = t;
1986                     }
1987                 }
1988                 """
1989         );
1990     }
1991 
1992     public void testOverrideAtAccessor() {
1993         assertOK(
1994                 """
1995                 record R(int i) {
1996                     @Override
1997                     public int i() { return i; }
1998                 }
1999                 """,
2000                 """
2001                 record R(int i, int j) {
2002                     @Override
2003                     public int i() { return i; }
2004                     public int j() { return j; }
2005                 }
2006                 """,
2007                 """
2008                 interface I { int i(); }
2009                 record R(int i) implements I {
2010                     @Override
2011                     public int i() { return i; }
2012                 }
2013                 """,
2014                 """
2015                 interface I { int i(); }
2016                 record R(int i) implements I {
2017                     public int i() { return i; }
2018                 }
2019                 """,
2020                 """
2021                 interface I { default int i() { return 0; } }
2022                 record R(int i) implements I {
2023                     @Override
2024                     public int i() { return i; }
2025                 }
2026                 """
2027         );
2028     }
2029 
2030     public void testNoAssigmentInsideCompactRecord() {
2031         assertFail("compiler.err.cant.assign.val.to.final.var",
2032                 """
2033                 record R(int i) {
2034                     R {
2035                         this.i = i;
2036                     }
2037                 }
2038                 """
2039         );
2040         assertFail("compiler.err.cant.assign.val.to.final.var",
2041                 """
2042                 record R(int i) {
2043                     R {
2044                         (this).i = i;
2045                     }
2046                 }
2047                 """
2048         );
2049     }
2050 
2051     public void testNoNPEStaticAnnotatedFields() {
2052         assertOK(
2053                 """
2054                 import java.lang.annotation.Native;
2055                 record R() {
2056                     @Native public static final int i = 0;
2057                 }
2058                 """
2059         );
2060         assertOK(
2061                 """
2062                 import java.lang.annotation.Native;
2063                 class Outer {
2064                     record R() {
2065                         @Native public static final int i = 0;
2066                     }
2067                 }
2068                 """
2069         );
2070         assertOK(
2071                 """
2072                 import java.lang.annotation.Native;
2073                 class Outer {
2074                     void m() {
2075                         record R () {
2076                             @Native public static final int i = 0;
2077                         }
2078                     }
2079                 }
2080                 """
2081         );
2082     }
2083 
2084     public void testDoNotAllowCStyleArraySyntaxForRecComponents() {
2085         assertFail("compiler.err.record.component.and.old.array.syntax",
2086                 """
2087                 record R(int i[]) {}
2088                 """
2089         );
2090         assertFail("compiler.err.record.component.and.old.array.syntax",
2091                 """
2092                 record R(String s[]) {}
2093                 """
2094         );
2095         assertFail("compiler.err.record.component.and.old.array.syntax",
2096                 """
2097                 record R<T>(T t[]) {}
2098                 """
2099         );
2100     }
2101 
2102     public void testNoWarningForSerializableRecords() {
2103         if (!useAP) {
2104             // dont execute this test when the default annotation processor is on as it will fail due to
2105             // spurious warnings
2106             appendCompileOptions("-Werror", "-Xlint:serial");
2107             assertOK(
2108                     """
2109                     import java.io.*;
2110                     record R() implements java.io.Serializable {}
2111                     """
2112             );
2113             removeLastCompileOptions(2);
2114         }
2115     }
2116 
2117     public void testAnnotationsOnVarargsRecComp() {
2118         assertOK(
2119                 """
2120                 import java.lang.annotation.*;
2121 
2122                 @Target({ElementType.TYPE_USE})
2123                 @interface Simple {}
2124 
2125                 record R(@Simple int... val) {
2126                     static void test() {
2127                         R rec = new R(10, 20);
2128                     }
2129                 }
2130                 """
2131         );
2132         assertOK(
2133                 """
2134                 import java.lang.annotation.*;
2135 
2136                 @Target({ElementType.TYPE_USE})
2137                 @interface SimpleContainer{ Simple[] value(); }
2138 
2139                 @Repeatable(SimpleContainer.class)
2140                 @Target({ElementType.TYPE_USE})
2141                 @interface Simple {}
2142 
2143                 record R(@Simple int... val) {
2144                     static void test() {
2145                         R rec = new R(10, 20);
2146                     }
2147                 }
2148                 """
2149         );
2150     }
2151 
2152     public void testSaveVarargsAnno() {
2153         // the compiler would generate an erronous accessor
2154         assertFail("compiler.err.varargs.invalid.trustme.anno",
2155                 """
2156                 record R(@SafeVarargs String... s) {}
2157                 """
2158         );
2159         // but this is OK
2160         assertOK(
2161                 """
2162                 record R(@SafeVarargs String... s) {
2163                     public String[] s() { return s; }
2164                 }
2165                 """
2166         );
2167     }
2168 }
--- EOF ---