From 0d3969597c7fd068fe16f513ed2483834c2250a9 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 1 Apr 2021 22:58:58 -0700 Subject: [PATCH] FIR: more accurate nullability of intersection of flexible types --- .../jetbrains/kotlin/fir/types/ConeTypeIntersector.kt | 6 +----- .../tests/smartCasts/varnotnull/toFlexibleType.fir.kt | 9 +++++++++ .../tests/smartCasts/varnotnull/toFlexibleType.kt | 11 ++++++++++- .../tests/smartCasts/varnotnull/toFlexibleType.txt | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt index 3648d2ce65d..654bcc140bb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt @@ -145,11 +145,7 @@ object ConeTypeIntersector { protected fun ConeKotlinType.resultNullability(context: ConeTypeContext): ResultNullability = when { isMarkedNullable -> ACCEPT_NULL - // Technically, upper bound's nullability is more accurate, e.g., a type from Java with @NotNull. - // However, it requires one more recursive call here. In contrast, UNKNOWN here is a safe approximation: for even such - // flexible type case, as long as the upper bound is still used in the intersection computation (and it indeed is), - // we will still get the same nullability from the resulting intersected type. - this is ConeFlexibleType -> UNKNOWN + this is ConeFlexibleType -> upperBound.resultNullability(context) ConeNullabilityChecker.isSubtypeOfAny(context, this) -> NOT_NULL else -> UNKNOWN } diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.fir.kt index bf5f20bb8b2..38791473438 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.fir.kt @@ -1,7 +1,12 @@ // FILE: J.java +import org.jetbrains.annotations.*; +import java.util.List; class J { static String foo() { return "abc"; } + + @NotNull + static List bar() { return new List(); } } // FILE: test.kt @@ -11,6 +16,10 @@ fun bar() { v = J.foo() v.length gav(v) + + var l: List? + l = J.bar() + l.isEmpty() } fun gav(v: String) = v diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.kt index 90c91e1a31b..bb1f9397c68 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.kt @@ -1,7 +1,12 @@ // FILE: J.java +import org.jetbrains.annotations.*; +import java.util.List; class J { static String foo() { return "abc"; } + + @NotNull + static List bar() { return new List(); } } // FILE: test.kt @@ -11,6 +16,10 @@ fun bar() { v = J.foo() v.length gav(v) + + var l: List? + l = J.bar() + l.isEmpty() } -fun gav(v: String) = v \ No newline at end of file +fun gav(v: String) = v diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.txt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.txt index fa1c7984dea..37981f9964f 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.txt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/toFlexibleType.txt @@ -10,5 +10,6 @@ public/*package*/ open class J { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members + @org.jetbrains.annotations.NotNull public/*package*/ open fun bar(): kotlin.collections.(Mutable)List public/*package*/ open fun foo(): kotlin.String! }