Scott Murphy Heiberg created GROOVY-12695:
---------------------------------------------

             Summary: Primitive type keyword used as a variable name gets 
inconsistent and misleading diagnostics
                 Key: GROOVY-12695
                 URL: https://issues.apache.org/jira/browse/GROOVY-12695
             Project: Groovy
          Issue Type: Bug
          Components: parser
    Affects Versions: 6.0.0
            Reporter: Scott Murphy Heiberg


*Environment:* macOS 26.5, BellSoft Liberica JDK 21.0.12; reproduced with the 
{{groovy}} command of each distribution

h3. Problem

Declaring a local variable named after a primitive type keyword is rejected (as 
it should be), but the message depends on which declaration keyword was used, 
and neither message says what is wrong.

{code}
var long = 1
val long = 1
def long = 1
final long = 1
{code}

h3. Actual

{{var}} and {{val}} report a resolve-phase message that talks about assigning 
to a class, with the caret on the keyword:

{noformat}
var_long.groovy: 1: you tried to assign a value to the class 'long'
 @ line 1, column 5.
   var long = 1
       ^
{noformat}
{noformat}
val_long.groovy: 1: you tried to assign a value to the class 'long'
 @ line 1, column 5.
   val long = 1
       ^
{noformat}

{{def}} and {{final}} report a generic syntax error with the caret on the 
{{=}}, one token past the mistake:

{noformat}
def_long.groovy: 1: Unexpected input: 'def long =' @ line 1, column 10.
   def long = 1
            ^
{noformat}
{noformat}
final_long.groovy: 1: Unexpected input: 'final long =' @ line 1, column 12.
   final long = 1
              ^
{noformat}

Other primitive names and {{void}} behave the same way ({{var int = 1}} reports 
{{you tried to assign a value to the class 'int'}}, {{def int = 1}} reports 
{{Unexpected input: 'def int ='}}). Inside a method body {{def long = 1}} 
reports {{Unexpected input: '='}} on the {{=}}. The same two shapes also appear 
for a typed declaration ({{String long = "x"}} and {{int long = 1}} report the 
class message, a field {{class C { int long = 1 }}} reports {{Unexpected input: 
'int long'}}) and for a bare {{long = 1}}.

h3. Cause

{{var}} and {{val}} are soft keywords, so when {{var long = 1}} fails to parse 
as a declaration the parser accepts it as the command expression {{var(long = 
1)}}; {{AstBuilder}} builds an assignment whose left-hand side is the built-in 
type name, and {{ResolveVisitor}} later reports it as an assignment to a class. 
({{var long}} without an initializer actually runs, as a call to a method named 
{{var}}.) {{def}} and {{final}} are reserved, so the parser commits to a 
declaration, consumes {{long}} as the declared type and fails on the {{=}} with 
the generic {{Unexpected input}} sentence.

h3. Expected

One diagnostic for every form, naming the keyword, with the caret on the 
keyword:

{noformat}
'long' is a keyword and cannot be used as a variable name @ line 1, column 5.
   var long = 1
       ^
{noformat}

This is in line with the other developer-facing parser sentences added in 
GROOVY-12353 and GROOVY-12401.

A pull request with regression tests follows.

h3. Versions

Reproduced on 6.0.0, 6.0.1-SNAPSHOT (GROOVY_6_0_X at 7c0dcf17dd) and master 
(d86ea7eb85).



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to