You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Inference failure raised from dataflow is reported against an unrelated file, and can be the only diagnostic #1733
An inference failure raised while dataflow is running is attributed to an unrelated compilation unit. This is the defect in #1725, but with two additions that change what it costs a user:
It can be the only diagnostic in the build. In WarnOnGenericInferenceFailure redundantly reporting in wrong file #1725 the misplaced report sits next to a correct one, so it reads as redundant noise. When the failure is raised only from dataflow (calledFromDataflow=true), nothing else is emitted, and the build fails with a single error naming a file that has nothing to do with the cause.
The stale path is not the cause. Instrumenting the failure branch shows the TreePath, the VisitorState path, and javac's current source file all pointing at the right file, while the diagnostic still lands in another one. The JSpecify mode: NPE in CFGTranslationPhaseOne.getReceiver for a lambda nested inside a lambda passed to a generic method #1680 fix in AccessPathNullnessPropagation.genericReturnIsNullable updates the path, but the DescriptionListener the VisitorState carries still belongs to the compilation unit where it was created, and that is what decides the file a diagnostic is attributed to.
Because the tree's character offset is then interpreted against the wrong file, the position lands past its end. The reported line is that file's last line plus one, and Error Prone prints a blank line where the source snippet would be.
/Unrelated.java:3: warning: [NullAway] inference failure: type variable T constrained to be both @NonNull and @Nullable
(see http://t.uber.com/nullaway )
/Caller.java:6: warning: [NullAway] inference failure: type variable T constrained to be both @NonNull and @Nullable
call(() -> { return null; });
^
Unrelated.java is one line long and the report is on line 3, with no source snippet. This is #1725's reproducer; it is included because it is the smallest case, and because the real-world one below could not be reduced to it.
The case where it is the only diagnostic
Apache Calcite at apache/calcite#5213, commit dd0c99af0e, ./gradlew -Pwerror=false -PenableErrorprone :core:compileJava:
core/src/main/java/org/apache/calcite/interpreter/MatchNode.java:41: error: [NullAway] inference failure: type variable R constrained to be both @NonNull and @Nullable
1 error
MatchNode.java is 40 lines long, and that is the whole NullAway output for the module.
Adding @SuppressWarnings("NullAway") to MatchNode moves the report to AbstractSingleNode.java:41 (a 40-line file), then to Node.java:28 (a 27-line file). The position is always some file's last line plus one.
I patched the failure branch in GenericsChecks to print what it was working with, published that build, and ran the same compile:
One failure in the entire compilation, raised from dataflow, for a call in AggChecker.java — reported against MatchNode.java. All three of the path, the state's path and javac's current source file are correct at that moment, which is what rules out the stale path.
The finding itself is real. AggChecker extends SqlBasicVisitor<@Nullable Void> but declares its override as public Void visit(SqlIdentifier id), narrowed to non-null, so return call.accept(this); returns @Nullable Void into a non-null return type. A user has no way to learn that from the message they get.
I also ruled out the generated-code options as the reason the correct report is missing: rebuilding with TreatGeneratedAsUnannotated=false and disableWarningsInGeneratedCode(false) still yields exactly one error, in the same place.
Expected
The diagnostic is attributed to the file that contains the call.
Workaround
None that finds the cause. WarnOnGenericInferenceFailure=false silences it, at the price of losing every real inference failure.
Where we hit it
Replacing the Checker Framework with NullAway in Apache Calcite (apache/calcite#5213).
Version
NullAway 0.14.0, and current
master(21f02dd). Error Prone 2.50.0, JDK 21.Flags:
-XepOpt:NullAway:JSpecifyMode=true -XepOpt:NullAway:WarnOnGenericInferenceFailure=true -XDaddTypeAnnotationsToSymbol=true.Summary
An inference failure raised while dataflow is running is attributed to an unrelated compilation unit. This is the defect in #1725, but with two additions that change what it costs a user:
calledFromDataflow=true), nothing else is emitted, and the build fails with a single error naming a file that has nothing to do with the cause.TreePath, theVisitorStatepath, and javac's current source file all pointing at the right file, while the diagnostic still lands in another one. The JSpecify mode: NPE in CFGTranslationPhaseOne.getReceiver for a lambda nested inside a lambda passed to a generic method #1680 fix inAccessPathNullnessPropagation.genericReturnIsNullableupdates the path, but theDescriptionListenertheVisitorStatecarries still belongs to the compilation unit where it was created, and that is what decides the file a diagnostic is attributed to.Because the tree's character offset is then interpreted against the wrong file, the position lands past its end. The reported line is that file's last line plus one, and Error Prone prints a blank line where the source snippet would be.
Reproducer
Unrelated.javais one line long and the report is on line 3, with no source snippet. This is #1725's reproducer; it is included because it is the smallest case, and because the real-world one below could not be reduced to it.The case where it is the only diagnostic
Apache Calcite at apache/calcite#5213, commit
dd0c99af0e,./gradlew -Pwerror=false -PenableErrorprone :core:compileJava:MatchNode.javais 40 lines long, and that is the whole NullAway output for the module.Adding
@SuppressWarnings("NullAway")toMatchNodemoves the report toAbstractSingleNode.java:41(a 40-line file), then toNode.java:28(a 27-line file). The position is always some file's last line plus one.I patched the failure branch in
GenericsChecksto print what it was working with, published that build, and ran the same compile:One failure in the entire compilation, raised from dataflow, for a call in
AggChecker.java— reported againstMatchNode.java. All three of the path, the state's path and javac's current source file are correct at that moment, which is what rules out the stale path.The finding itself is real.
AggChecker extends SqlBasicVisitor<@Nullable Void>but declares its override aspublic Void visit(SqlIdentifier id), narrowed to non-null, soreturn call.accept(this);returns@Nullable Voidinto a non-null return type. A user has no way to learn that from the message they get.I also ruled out the generated-code options as the reason the correct report is missing: rebuilding with
TreatGeneratedAsUnannotated=falseanddisableWarningsInGeneratedCode(false)still yields exactly one error, in the same place.Expected
The diagnostic is attributed to the file that contains the call.
Workaround
None that finds the cause.
WarnOnGenericInferenceFailure=falsesilences it, at the price of losing every real inference failure.Where we hit it
Replacing the Checker Framework with NullAway in Apache Calcite (apache/calcite#5213).