[ 
https://issues.apache.org/jira/browse/CALCITE-7736?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18109325#comment-18109325
 ] 

Julian Hyde commented on CALCITE-7736:
--------------------------------------

I think you should do it, as a single PR. Ping me on the ML when it's ready and 
I will approve.

It's a little difficult to read your PR (it's based off of 67e5bfcdc0, which is 
ten months behind origin/main). But I get the following stats:
{code:java}
% git diff 5d7f75d5d8 vlsi/CALCITE-7736 --stat
1509 files changed, 5822 insertions(+), 5832 deletions(-) {code}
The changes look modest, and in one or two places we were able to remove 
{{{}Nullable{}}}:
{code:java}
       // The windows of each key are kept sorted by start time; the merge
       // below only compares a window with the one that precedes it.
-      Map<@Nullable Object, NavigableMap<Pair<Long, Long>, List<@Nullable 
Object[]>>>
+      Map<Object, NavigableMap<Pair<Long, Long>, List<Object[]>>>
           sessionKeyMap = new HashMap<>(); {code}
Replacing {{PolyNull}} with {{Contract}} is an improvement:
{code:java}
-  <T> @PolyNull T fun(Class<T> operatorTableClass,
-      @PolyNull T defaultOperatorTable);
+  @Contract("_, !null -> !null")
+  <T> @Nullable T fun(Class<T> operatorTableClass,
+      @Nullable T defaultOperatorTable); {code}
This is the only regression I noticed:
{code:java}
-  private static List<Object> keyOf(Object[] rowValues) {
-    return Arrays.asList(Arrays.copyOf(rowValues, rowValues.length));
+  private static List<@Nullable Object> keyOf(Object[] rowValues) {
+    return Arrays.<@Nullable Object>asList(
+        Arrays.copyOf(rowValues, rowValues.length)); {code}
Adding {{firstNonNull}} is a smart move:
{code:java}
   public static final Version AVATICA_VERSION =
-      Version.of(first(System.getProperty("calcite.avatica.version"), "0"));
+      Version.of(
+          firstNonNull(System.getProperty("calcite.avatica.version"), "0")); 
{code}
 

> Replace the Checker Framework with NullAway and JSpecify
> --------------------------------------------------------
>
>                 Key: CALCITE-7736
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7736
>             Project: Calcite
>          Issue Type: Improvement
>          Components: core, linq4j
>            Reporter: Vladimir Sitnikov
>            Assignee: Vladimir Sitnikov
>            Priority: Major
>              Labels: pull-request-available
>
> Calcite verifies nullness with the Checker Framework. That setup carries a 
> Gradle plugin of its own, 48 {{.astub}} files that patch the nullness of the 
> JDK and of third-party libraries, and two dedicated CI jobs.
> NullAway runs as an Error Prone check, so it needs no separate plugin and no 
> stub files: it ships nullness models for the JDK and for popular libraries. 
> The annotations come from JSpecify, a specification that several checkers 
> read, rather than from one checker's own package.
> h3. Plan
> * replace {{org.checkerframework:checker-qual}} with {{org.jspecify:jspecify}}
> * delete the 48 stub files and the two CheckerFramework CI jobs, and fold 
> nullness verification into the existing {{errorprone}} job
> * configure NullAway in JSpecify mode, with the experimental generics options 
> ({{JSpecifyExperimental}}, {{HandleWildcardGenerics}}, {{JSpecifyJDKModels}}, 
> {{WarnOnGenericInferenceFailure}}) and {{CheckContracts}}
> * declare {{@NullMarked}} on the main packages of {{calcite-linq4j}} and 
> {{calcite-core}}, the two modules NullAway verifies, and add a lint test that 
> fails when a package there has no {{package-info.java}}
> h3. Annotations that JSpecify does not define
> JSpecify defines {{@Nullable}}, {{@NonNull}} and {{@NullMarked}}. Calcite 
> also uses {{@PolyNull}}, {{@MonotonicNonNull}}, {{@RequiresNonNull}}, 
> {{@EnsuresNonNull}}, {{@EnsuresNonNullIf}}, {{@Pure}}, {{@KeyFor}} and the 
> initialization annotations.
> {{@PolyNull}} becomes {{@Contract("!null, _ -> !null")}}, which NullAway 
> verifies against the method body. {{@MonotonicNonNull}} and the annotations 
> for field preconditions and postconditions move to a new 
> {{org.apache.calcite.linq4j.annotations}} package: NullAway matches these by 
> the last component of their name rather than by their package, so Calcite 
> declares its own and takes no dependency on the checker. The rest have no 
> equivalent and go away.
> h3. Type parameter bounds
> The two tools default an unwritten type parameter bound in opposite 
> directions. The Checker Framework's CLIMB-to-top rule gives implicit bounds 
> the top qualifier, so {{<T>}} there means {{<T extends @Nullable Object>}}. 
> JSpecify fills in {{Object}}, which under {{@NullMarked}} is non-null.
> Every unbounded type parameter therefore changes meaning, and Calcite relied 
> on the Checker Framework reading. For example {{SqlShuttle extends 
> SqlBasicVisitor<@Nullable SqlNode>}} was passed to 
> {{SqlNode.accept(SqlVisitor<R>)}} with no suppression, which typechecks only 
> if {{R}} admits a nullable argument. Writing the bound out at 61 declarations 
> accounts for most of what NullAway reports.
> h3. Why NullAway rather than another checker
> The Checker Framework is thorough but slow, which is why Calcite runs it in 
> two CI jobs of its own rather than as part of an ordinary build. NullAway is 
> a single Error Prone check and costs a fraction of that, so nullness 
> verification can move into a normal compile and eventually run by default 
> rather than in a job that only a maintainer looks at. A nullness mistake then 
> surfaces in the build that introduced it.
> NullAway also reports the whole set of problems in one pass — the run below 
> produces 576 in calcite-core — which is what makes a migration of this size 
> tractable: you fix a class of errors across the codebase and re-run, instead 
> of discovering them one at a time.
> h3. Status
> A first pass leaves 576 errors in {{calcite-core}} and 126 in 
> {{calcite-linq4j}}, so the nullness CI job is red. The pull request is a 
> preview: it shows the migration and the shape of what remains, rather than a 
> finished conversion.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to