[ 
https://issues.apache.org/jira/browse/GROOVY-12691?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King updated GROOVY-12691:
-------------------------------
    Description: 
Under {{@TypeChecked}} or {{@CompileStatic}}, a type checking error is silently 
dropped when an earlier error was reported at certain other positions. Four 
undefined method calls that start in column 47 give only two errors.

{{Col47.groovy}} (each call is preceded by 46 spaces, so it starts in column 
47):

{code:groovy}
@groovy.transform.TypeChecked
void m() {
                                              missing1()
                                              missing2()
                                              missing3()
                                              missing4()
}
{code}

{code:sh}
groovyc Col47.groovy
{code}

Actual: exit 1 with two errors.

{noformat}
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Col47.groovy: 3: [Static type checking] - Cannot find matching method 
Col47#missing1(). Please check if the declared type is correct and if the 
method exists.
 @ line 3, column 47.
                                                 missing1()
                                                 ^

Col47.groovy: 4: [Static type checking] - Cannot find matching method 
Col47#missing2(). Please check if the declared type is correct and if the 
method exists.
 @ line 4, column 47.
                                                 missing2()
                                                 ^

2 errors
{noformat}

Expected: four errors, one for each call. When the same four calls start in 
column 5, all four are reported.

The number of errors that survive depends on the column. With 32 undefined 
calls, one per line, all starting in the same column:

||column||errors reported||
|5, 20, 32, 40|32 of 32|
|44|16 of 32|
|45|8 of 32|
|46|4 of 32|
|47|2 of 32|
|48, 60, 65|32 of 32|

Long lines are not needed. Each of these pairs of calls also gives only the 
first error:

* two calls on the same line 64 columns apart, for example columns 5 and 69 of 
line 3;
* a call at line 3, column 9 and a call at line 6, column 8 (in general, line L 
column c and line 2L column c - 1).
The warning "The field: ... is hidden by a dynamic property" (GROOVY-11360) is 
dropped in the same way: in a class with {{private static final value}}, a 
reference to {{value}} inside {{d.with \{ ... \}}} at line 7, column 47 gets no 
warning when an unrelated error was reported at line 5, column 47. It gets the 
warning when that error is at column 5.

Affected versions: 6.0.0, 6.0.0-beta-1, 5.0.8 and 5.0.0 give the counts above, 
and so does current master (7.0.0-SNAPSHOT at 5e9212ce1e). The same expression 
is in {{StaticTypeCheckingVisitor}} on {{GROOVY_2_5_X}}, {{GROOVY_3_0_X}} and 
{{GROOVY_4_0_X}}; those were not run.

Cause: {{StaticTypeCheckingVisitor.addError}} skips an error whose key is 
already in {{TypeCheckingContext.reportedErrors}}, and builds the key as 
{{((long) node.getLineNumber()) << 16 + node.getColumnNumber()}}. Because {{+}} 
binds tighter than {{<<}}, that is {{line << (16 + column)}}, and a shift of a 
{{long}} uses only the low six bits of the distance. So up to column 47 the key 
keeps only the low 48 - column bits of the line number, two columns 64 apart on 
one line give the same key, and line L at column c gives the same key as line 
2L at column c - 1. The check for the hidden-field warning in 
{{visitVariableExpression}} builds the key the same way.

Fix outline: build the key as {{(((long) line) << 32) + column}}, so that each 
line and column pair has its own key; {{(line << 16) + column}} would still let 
column c + 65536 of one line collide with column c of the next.

A pull request with regression tests follows.

Environment: Groovy 6.0.0 on BellSoft JDK 21.0.12, macOS 26.5 (arm64); 
reproduced on master at 5e9212ce1e with the same JDK.

  was:
Under {{@TypeChecked}} or {{@CompileStatic}}, a type checking error is silently 
dropped when an earlier error was reported at certain other positions. Four 
undefined method calls that start in column 47 give only two errors.

{{Col47.groovy}} (each call is preceded by 46 spaces, so it starts in column 
47):

{code:groovy}
@groovy.transform.TypeChecked
void m() {
                                              missing1()
                                              missing2()
                                              missing3()
                                              missing4()
}
{code}

{code:sh}
groovyc Col47.groovy
{code}

Actual: exit 1 with two errors.

{code:text}
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Col47.groovy: 3: [Static type checking] - Cannot find matching method 
Col47#missing1(). Please check if the declared type is correct and if the 
method exists.
 @ line 3, column 47.
                                                 missing1()
                                                 ^

Col47.groovy: 4: [Static type checking] - Cannot find matching method 
Col47#missing2(). Please check if the declared type is correct and if the 
method exists.
 @ line 4, column 47.
                                                 missing2()
                                                 ^

2 errors
{code}

Expected: four errors, one for each call. When the same four calls start in 
column 5, all four are reported.

The number of errors that survive depends on the column. With 32 undefined 
calls, one per line, all starting in the same column:

||column||errors reported||
|5, 20, 32, 40|32 of 32|
|44|16 of 32|
|45|8 of 32|
|46|4 of 32|
|47|2 of 32|
|48, 60, 65|32 of 32|

Long lines are not needed. Each of these pairs of calls also gives only the 
first error:

* two calls on the same line 64 columns apart, for example columns 5 and 69 of 
line 3;
* a call at line 3, column 9 and a call at line 6, column 8 (in general, line L 
column c and line 2L column c - 1).
The warning "The field: ... is hidden by a dynamic property" (GROOVY-11360) is 
dropped in the same way: in a class with {{private static final value}}, a 
reference to {{value}} inside {{d.with \{ ... \}}} at line 7, column 47 gets no 
warning when an unrelated error was reported at line 5, column 47. It gets the 
warning when that error is at column 5.

Affected versions: 6.0.0, 6.0.0-beta-1, 5.0.8 and 5.0.0 give the counts above, 
and so does current master (7.0.0-SNAPSHOT at 5e9212ce1e). The same expression 
is in {{StaticTypeCheckingVisitor}} on {{GROOVY_2_5_X}}, {{GROOVY_3_0_X}} and 
{{GROOVY_4_0_X}}; those were not run.

Cause: {{StaticTypeCheckingVisitor.addError}} skips an error whose key is 
already in {{TypeCheckingContext.reportedErrors}}, and builds the key as 
{{((long) node.getLineNumber()) << 16 + node.getColumnNumber()}}. Because {{+}} 
binds tighter than {{<<}}, that is {{line << (16 + column)}}, and a shift of a 
{{long}} uses only the low six bits of the distance. So up to column 47 the key 
keeps only the low 48 - column bits of the line number, two columns 64 apart on 
one line give the same key, and line L at column c gives the same key as line 
2L at column c - 1. The check for the hidden-field warning in 
{{visitVariableExpression}} builds the key the same way.

Fix outline: build the key as {{(((long) line) << 32) + column}}, so that each 
line and column pair has its own key; {{(line << 16) + column}} would still let 
column c + 65536 of one line collide with column c of the next.

A pull request with regression tests follows.

Environment: Groovy 6.0.0 on BellSoft JDK 21.0.12, macOS 26.5 (arm64); 
reproduced on master at 5e9212ce1e with the same JDK.


> Static type checking silently drops some errors that are at distinct source 
> positions
> -------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12691
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12691
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> Under {{@TypeChecked}} or {{@CompileStatic}}, a type checking error is 
> silently dropped when an earlier error was reported at certain other 
> positions. Four undefined method calls that start in column 47 give only two 
> errors.
> {{Col47.groovy}} (each call is preceded by 46 spaces, so it starts in column 
> 47):
> {code:groovy}
> @groovy.transform.TypeChecked
> void m() {
>                                               missing1()
>                                               missing2()
>                                               missing3()
>                                               missing4()
> }
> {code}
> {code:sh}
> groovyc Col47.groovy
> {code}
> Actual: exit 1 with two errors.
> {noformat}
> org.codehaus.groovy.control.MultipleCompilationErrorsException: startup 
> failed:
> Col47.groovy: 3: [Static type checking] - Cannot find matching method 
> Col47#missing1(). Please check if the declared type is correct and if the 
> method exists.
>  @ line 3, column 47.
>                                                  missing1()
>                                                  ^
> Col47.groovy: 4: [Static type checking] - Cannot find matching method 
> Col47#missing2(). Please check if the declared type is correct and if the 
> method exists.
>  @ line 4, column 47.
>                                                  missing2()
>                                                  ^
> 2 errors
> {noformat}
> Expected: four errors, one for each call. When the same four calls start in 
> column 5, all four are reported.
> The number of errors that survive depends on the column. With 32 undefined 
> calls, one per line, all starting in the same column:
> ||column||errors reported||
> |5, 20, 32, 40|32 of 32|
> |44|16 of 32|
> |45|8 of 32|
> |46|4 of 32|
> |47|2 of 32|
> |48, 60, 65|32 of 32|
> Long lines are not needed. Each of these pairs of calls also gives only the 
> first error:
> * two calls on the same line 64 columns apart, for example columns 5 and 69 
> of line 3;
> * a call at line 3, column 9 and a call at line 6, column 8 (in general, line 
> L column c and line 2L column c - 1).
> The warning "The field: ... is hidden by a dynamic property" (GROOVY-11360) 
> is dropped in the same way: in a class with {{private static final value}}, a 
> reference to {{value}} inside {{d.with \{ ... \}}} at line 7, column 47 gets 
> no warning when an unrelated error was reported at line 5, column 47. It gets 
> the warning when that error is at column 5.
> Affected versions: 6.0.0, 6.0.0-beta-1, 5.0.8 and 5.0.0 give the counts 
> above, and so does current master (7.0.0-SNAPSHOT at 5e9212ce1e). The same 
> expression is in {{StaticTypeCheckingVisitor}} on {{GROOVY_2_5_X}}, 
> {{GROOVY_3_0_X}} and {{GROOVY_4_0_X}}; those were not run.
> Cause: {{StaticTypeCheckingVisitor.addError}} skips an error whose key is 
> already in {{TypeCheckingContext.reportedErrors}}, and builds the key as 
> {{((long) node.getLineNumber()) << 16 + node.getColumnNumber()}}. Because 
> {{+}} binds tighter than {{<<}}, that is {{line << (16 + column)}}, and a 
> shift of a {{long}} uses only the low six bits of the distance. So up to 
> column 47 the key keeps only the low 48 - column bits of the line number, two 
> columns 64 apart on one line give the same key, and line L at column c gives 
> the same key as line 2L at column c - 1. The check for the hidden-field 
> warning in {{visitVariableExpression}} builds the key the same way.
> Fix outline: build the key as {{(((long) line) << 32) + column}}, so that 
> each line and column pair has its own key; {{(line << 16) + column}} would 
> still let column c + 65536 of one line collide with column c of the next.
> A pull request with regression tests follows.
> Environment: Groovy 6.0.0 on BellSoft JDK 21.0.12, macOS 26.5 (arm64); 
> reproduced on master at 5e9212ce1e with the same JDK.



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

Reply via email to