[
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)