Details
-
Bug
-
Resolution: Fixed
-
P4
-
None
Description
The treatment of enum constants in JLS has been inconsistent. In the past there were references to the scope of an enum constant that included switch labels, but these didn't really align with the idea of an implicit enum class field which is what is really being referenced.
Some details were fixed/clarified in 16:
- Much like record components, each enum constant *corresponds to* an implicit field of the same name. The enum constant and the field are distinct entities. (See 8.9.3.)
- An enum constant is thus not a *member* of an enum class—the member is the implicit field. (See changes to 6.1.) (This is important, because a lot of language rules apply to fields and say nothing about enum constants—like the treatment of duplicate names or the interpretation of static imports.)
- There is, in general, no special treatment of scope and name resolution for enum constants. The implicit field has a scope, and it works just like any other field. (See changes to 6.3, and the existing text of 6.5.6.)
However, some further changes are needed to clarify how an enum constant is handled in a switch label, where the implicit field is not in scope.
I think a good model for switch label name resolution is to think of it like a field access: the selector expression provides the context to search, and then the name is looked up in that context. That doesn't mean that the scope of a field magically extends to the syntax following a '.' for every expression of the declaring class's type. Scope is just not relevant in these contexts. (I mean, we could define scope in that way, but it would be unintuitive.)
Syntactically, a CaseConstant is a ConditionalExpression, which (many layers down) may be an ExpressionName (15.14). So we just need to make sure that ExpressionName is interpreted correctly. Concretely, 6.5.6.1:
---
If an expression name consists of a single *Identifier*, then:
- **If the expression name appears as *CaseConstant* in a switch label ([14.11.1]), and the type of the selector expression of the enclosing `switch` statement or `switch` expression is an enum class type ([8.9]), and the enum class declares an enum constant with name *Identifier*, then the expression name refers to the corresponding implicit field of the enum class.**
- **Otherwise, if** there ~~must be~~ **is** exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scope at the point at which the identifier occurs**, then the expression name refers to the in-scope variable**.
- Otherwise, a compile-time error occurs.
---
And in 8.9.1:
---
The rules concerning annotation modifiers for an enum constant declaration are specified in §9.7.4 and §9.7.5.
The Identifier in a EnumConstant ~~may be used in a name~~ **provides the name of an implicit field of the enum class ([8.9.3]) that can be used** to refer to the enum constant.
~~The scope and shadowing of an enum constant is specified in §6.3 and §6.4.1.~~
---
The sequencing of name resolution is intentional, giving priority to enum constant names over in-scope names. This allows these rules to seamlessly support the behavior of JEP 441, which is to attempt to match an enum constant name, and in case of a mismatch fall back to scope-based name resolution.
It is intentional that the rules for switch labels *do not* attempt to match any other fields of an enum class (such as an explicitly-declared static field).
Some details were fixed/clarified in 16:
- Much like record components, each enum constant *corresponds to* an implicit field of the same name. The enum constant and the field are distinct entities. (See 8.9.3.)
- An enum constant is thus not a *member* of an enum class—the member is the implicit field. (See changes to 6.1.) (This is important, because a lot of language rules apply to fields and say nothing about enum constants—like the treatment of duplicate names or the interpretation of static imports.)
- There is, in general, no special treatment of scope and name resolution for enum constants. The implicit field has a scope, and it works just like any other field. (See changes to 6.3, and the existing text of 6.5.6.)
However, some further changes are needed to clarify how an enum constant is handled in a switch label, where the implicit field is not in scope.
I think a good model for switch label name resolution is to think of it like a field access: the selector expression provides the context to search, and then the name is looked up in that context. That doesn't mean that the scope of a field magically extends to the syntax following a '.' for every expression of the declaring class's type. Scope is just not relevant in these contexts. (I mean, we could define scope in that way, but it would be unintuitive.)
Syntactically, a CaseConstant is a ConditionalExpression, which (many layers down) may be an ExpressionName (15.14). So we just need to make sure that ExpressionName is interpreted correctly. Concretely, 6.5.6.1:
---
If an expression name consists of a single *Identifier*, then:
- **If the expression name appears as *CaseConstant* in a switch label ([14.11.1]), and the type of the selector expression of the enclosing `switch` statement or `switch` expression is an enum class type ([8.9]), and the enum class declares an enum constant with name *Identifier*, then the expression name refers to the corresponding implicit field of the enum class.**
- **Otherwise, if** there ~~must be~~ **is** exactly one declaration denoting either a local variable, formal parameter, exception parameter, or field in scope at the point at which the identifier occurs**, then the expression name refers to the in-scope variable**.
- Otherwise, a compile-time error occurs.
---
And in 8.9.1:
---
The rules concerning annotation modifiers for an enum constant declaration are specified in §9.7.4 and §9.7.5.
The Identifier in a EnumConstant ~~may be used in a name~~ **provides the name of an implicit field of the enum class ([8.9.3]) that can be used** to refer to the enum constant.
~~The scope and shadowing of an enum constant is specified in §6.3 and §6.4.1.~~
---
The sequencing of name resolution is intentional, giving priority to enum constant names over in-scope names. This allows these rules to seamlessly support the behavior of JEP 441, which is to attempt to match an enum constant name, and in case of a mismatch fall back to scope-based name resolution.
It is intentional that the rules for switch labels *do not* attempt to match any other fields of an enum class (such as an explicitly-declared static field).
Attachments
Issue Links
- relates to
-
JDK-8309336 Incorrect switch in enum not reported properly
-
- Resolved
-
-
JDK-8300542 JEP 441: Pattern Matching for switch
-
- Closed
-