NullAway icon indicating copy to clipboard operation
NullAway copied to clipboard

Unexpected type: <nulltype> when both operands of a ternary expression are null

Open gavlyukovskiy opened this issue 1 year ago • 4 comments

Without any nullability annotations, compiling this code

public static String foo(String x) {
    return x.isEmpty() ? null : null;
}

gives an error

An exception has occurred in the compiler (22.0.2). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
com.google.common.util.concurrent.ExecutionError: java.lang.AssertionError: unexpected type: <nulltype>

The code compiles fine when either of the operands is not null - x.isEmpty() ? "null" : null or x.isEmpty() ? null : "null".

Similar error can be observed when the expression is inside a lambda function:

Function<String, String> f = x -> x.isEmpty() ? null : null;

Full stacktrace:

An exception has occurred in the compiler (22.0.2). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
com.google.common.util.concurrent.ExecutionError: java.lang.AssertionError: unexpected type: <nulltype>
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2084)
        at com.google.common.cache.LocalCache.get(LocalCache.java:4012)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4035)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5011)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:5018)
        at com.uber.nullaway.dataflow.DataFlow.dataflow(DataFlow.java:154)
        at com.uber.nullaway.dataflow.DataFlow.resultFor(DataFlow.java:283)
        at com.uber.nullaway.dataflow.DataFlow.resultForExpr(DataFlow.java:261)
        at com.uber.nullaway.dataflow.DataFlow.expressionDataflow(DataFlow.java:207)
        at com.uber.nullaway.dataflow.AccessPathNullnessAnalysis.getNullness(AccessPathNullnessAnalysis.java:130)
        at com.uber.nullaway.NullAway.nullnessFromDataflow(NullAway.java:2470)
        at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:2448)
        at com.uber.nullaway.NullAway.checkReturnExpression(NullAway.java:937)
        at com.uber.nullaway.NullAway.matchReturn(NullAway.java:379)
        at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449)
        at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:816)
        at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1736)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:272)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:520)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1104)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:96)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:224)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:740)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:948)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:96)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:203)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:548)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:855)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:152)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:560)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:623)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:66)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
        at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
        at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:227)
        at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:133)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1443)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1390)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:963)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
        at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:92)
        at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94)
        at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:76)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:46)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractIsolatedCompilerWorkerExecutor$CompilerWorkAction.execute(AbstractIsolatedCompilerWorkerExecutor.java:78)
        at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:54)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:48)
        at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
        at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:48)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:32)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:22)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:104)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:73)
        at org.gradle.process.internal.worker.request.WorkerAction$1.call(WorkerAction.java:146)
        at org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41)
        at org.gradle.process.internal.worker.request.WorkerAction.lambda$run$0(WorkerAction.java:143)
        at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:85)
        at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1570)
Caused by: java.lang.AssertionError: unexpected type: <nulltype>
        at jdk.compiler/com.sun.tools.javac.tree.TreeMaker.Type(TreeMaker.java:883)
        at jdk.compiler/com.sun.tools.javac.tree.TreeMaker.VarDef(TreeMaker.java:905)
        at org.checkerframework.nullaway.javacutil.trees.TreeBuilder.buildVariableDecl(TreeBuilder.java:330)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitConditionalExpression(CFGTranslationPhaseOne.java:2732)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitConditionalExpression(CFGTranslationPhaseOne.java:212)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCConditional.accept(JCTree.java:1548)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.scan(CFGTranslationPhaseOne.java:571)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitReturn(CFGTranslationPhaseOne.java:3511)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitReturn(CFGTranslationPhaseOne.java:212)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1736)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.scan(CFGTranslationPhaseOne.java:571)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitBlock(CFGTranslationPhaseOne.java:2349)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitBlock(CFGTranslationPhaseOne.java:212)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1104)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.scan(CFGTranslationPhaseOne.java:571)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.process(CFGTranslationPhaseOne.java:468)
        at com.uber.nullaway.dataflow.cfg.NullAwayCFGBuilder.build(NullAwayCFGBuilder.java:80)
        at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:137)
        at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:102)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3571)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2313)
        at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2190)
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2080)
        ... 96 more

Reproducer (branch nulltype): https://github.com/gavlyukovskiy/nullaway-reproducer/tree/nulltype (./gradlew build)

JDK: temurin 22.0.2, also reproducible on 21.0.3 and 17.0.11

Versions:

  • com.google.errorprone:error_prone_core:2.29.2
  • com.uber.nullaway:nullaway:0.11.1
  • net.ltgt.errorprone:4.0.1

gavlyukovskiy avatar Aug 04 '24 14:08 gavlyukovskiy

Nice find! I will take a look.

msridhar avatar Aug 04 '24 14:08 msridhar

This is an upstream issue in Checker Framework: https://github.com/typetools/checker-framework/issues/6743 We will need a fix there and then we can pull in the release with the fix.

I presume this is not hard for you to work around @gavlyukovskiy?

msridhar avatar Aug 07 '24 00:08 msridhar

Thank you for checking @msridhar. The code is pretty much nonsensical, and it is certainly very easy to workaround, just thought that it's worth it to report 🙂

gavlyukovskiy avatar Aug 07 '24 06:08 gavlyukovskiy

Fixed by https://github.com/typetools/checker-framework/pull/6752. We'll get the fix when it reaches a Checker Framework release and we update.

msridhar avatar Aug 19 '24 17:08 msridhar