Summary
-------
After the record's spec was released as several internal and external contributors have reported several bugs or clarification issues that should be fixed in the spec
Problem
-------
The reported issues include:
- names of formal parameters in canonical constructors must match the name of the corresponding record component
- local records should not be allowed to capture any non-static state from any enclosing type
- the 'final' modifier shouldn't be allowed to be redundantly applied to record components
- clarify the interaction between records and @SafeVarargs annotation
Solution
--------
Fix the mentioned issues in the spec
Specification
-------------
@@ -2230,14 +2230,14 @@
#### **8.10.1 Record Components** {#jls-8.10.1}
The _record components_ of a record type, if any, are specified by a list of
-comma-separated parameter specifiers in the header of a record declaration.
-Each record component consists of a type (optionally preceded by the `final`
-modifier and/or one or more annotations) and an identifier (optionally
-followed by brackets) that specifies the name of the record component. If a
-record type has no record components, then the record header consists of an
-empty pair of parentheses.
+comma-separated parameter specifiers in the header of a record declaration. Each
+record component consists of a type (optionally preceded by one or more
+annotations) and an identifier (optionally followed by brackets) that specifies
+the name of the record component. If a record type has no record components,
+then the record header consists of an empty pair of parentheses.
@@ -2250,14 +2250,15 @@
*RecordComponent*:
-: { *VariableModifier* } *UnannType* *VariableDeclaratorId*
+: { *Annotation* } *UnannType* *VariableDeclaratorId*
: *VariableArityRecordComponent*
*VariableArityRecordComponent*:
-: { *VariableModifier* } *UnannType* { *Annotation* } `...` *Identifier*
+: { *Annotation* } *UnannType* { *Annotation* } `...` *Identifier*
> It can be seen that the production for *RecordComponent* is identical in
-> content to the production for *FormalParameter* ([8.4.1]).
+> content to the production for *FormalParameter* ([8.4.1]), except a record
+> component can not have a `final` modifier.
@@ -2279,10 +2280,6 @@
-It is permitted for a record component to redundantly specify the `final`
-modifier. It is a compile-time error if `final` appears more than once as a
-modifier for a record component.
-
A record component may be a variable arity record component, indicated by an
ellipsis following the type. At most one variable arity record component is
permitted for a record type. It is a compile-time error if a variable arity
@@ -2316,9 +2313,9 @@
If the declared type of a variable arity record component has a non-reifiable
element type ([4.7]), then a compile-time unchecked warning occurs for the
-declaration of the variable arity record component, unless the record type is
-annotated with `@SafeVarargs` ([9.6.4.7]) or the warning is suppressed by
-`@SuppressWarnings` ([9.6.4.5]).
+declaration of the variable arity record component, unless the canonical
+constructor ([8.10.4]) is annotated with `@SafeVarargs` ([9.6.4.7]) or the
+warning is suppressed by `@SuppressWarnings` ([9.6.4.5]).
:::
@@ -2480,8 +2477,8 @@
If a canonical constructor is explicitly declared, then it must additionally
satisfy the following conditions; otherwise a compile-time error occurs:
-- The types of the formal parameters in the formal parameter list of the
-canonical constructor must be identical to the declared type of the
+- The names and types of the formal parameters in the formal parameter list of the
+canonical constructor must be identical to the names and declared type of the
corresponding record component.
- A canonical constructor must not be generic ([8.8.4]).
@@ -2567,12 +2564,16 @@
-In a record type _R_, the signature of a compact constructor declaration is
-the derived constructor signature of _R_ ([8.10.4]).
-
-> Unlike constructors in records, and indeed in classes in general, no explicit
-> formal parameter list is given for a compact constructor, but is derived from
-> the record component list.
+In a record type _R_, the formal parameter list for a compact constructor
+declaration is implicitly declared and taken from the derived constructor
+signature of _R_ ([8.10.4]).
+
+More precisely, in a record type _R_, the signature of a compact constructor
+declaration is the derived constructor signature of _R_ ([8.10.4]).
+
+> This means that given a record type with a record component named *c*, in the
+> body of compact constructor an occurrence of an unqualified name *c* denotes
+> the implicit formal parameter *c*.
It is a compile-time error to declare more than one compact constructor
declaration for a record type.
@@ -2587,7 +2588,8 @@
- The compact constructor must be declared `public`.
-- The body of a compact constructor must not contain a `return` statement ([14.17]).
+- The body of a compact constructor must not contain a `return` statement
+ ([14.17]).
- The body of a compact constructor must not contain an explicit constructor
invocation statement ([8.8.7.1]).
@@ -2904,7 +2906,8 @@
applicable to local variable declarations or type contexts.
- **a record component but *T* is not applicable to record component
-declarations, field declarations, method declarations, or type contexts.**
+ declarations, field declarations, method declarations, formal and exception
+ parameter declarations, or type contexts.**
@@ -3595,8 +3598,41 @@
All local classes are inner classes ([8.1.3]).
-**A *local record* is a record type declaration ([8.10]) that is not a member of
-a class. A local record is implicitly `static`.**
+:::inserted
+
+A *local record* is a record type declaration ([8.10]) that is not a member of
+a class. A local record is implicitly `static`.
+
+It is a compile-time error if a local record contains a usage of a variable
+declared in the enclosing block.
+
+> Local records are constrained with regards to with variables they can access.
+> The fact that a local record is implicitly `static` means that it is a
+> compile-time error if a local record uses a non-`static` member of an
+> enclosing class. It is permitted to use a `static` member of an enclosing
+> class. Here is an example to illustrate the constraints.
+>
+> ```java
+> class LocalRecordTest {
+> static int si;
+> int nsi;
+>
+> void m() {
+> int li;
+>
+> record R(int r) {
+> void print() {
+> System.out.println(si); // ok, static member of enclosing class
+> System.out.println(nsi); // error, non-static member
+> System.out.println(li); // error, local variable
+> }
+> }
+> }
+> }
+> ```
+
+:::
+
Every local class declaration statement is immediately contained by a block
([14.2]).