From 1d736f59b6640f63056efaedb4393b5512900d1d Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Fri, 1 Dec 2017 18:11:09 +0300 Subject: [PATCH] [NI] Refine nullability for CST of types with undefined nullability --- .../resolve/calls/NewCommonSuperTypeCalculator.kt | 14 ++++++++++++-- .../generics/commonSupertypeContravariant2.ni.txt | 4 ++-- .../diagnostics/tests/regressions/kt7804.kt | 4 ++-- .../tests/smartCasts/lambdaAndArgument.kt | 1 - .../tests/smartCasts/lambdaAndArgument.ni.txt | 5 ----- .../tests/smartCasts/lambdaAndArgumentFun.kt | 1 - .../tests/smartCasts/lambdaAndArgumentFun.ni.txt | 5 ----- .../src/org/jetbrains/kotlin/types/SpecialTypes.kt | 9 ++------- .../src/org/jetbrains/kotlin/types/TypeUtils.kt | 7 +++++++ .../kotlin/types/checker/NewKotlinTypeChecker.kt | 3 +++ 10 files changed, 28 insertions(+), 25 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.ni.txt delete mode 100644 compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.ni.txt diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index 8107fd2e28b..999c2af7cdd 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.canHaveUndefinedNullability object NewCommonSuperTypeCalculator { @@ -61,9 +62,18 @@ object NewCommonSuperTypeCalculator { val notAllNotNull = types.any { !NullabilityChecker.isSubtypeOfAny(it) } val notNullTypes = if (notAllNotNull) types.map { it.makeNullableAsSpecified(false) } else types - val commonSuperTypes = commonSuperTypeForNotNullTypes(notNullTypes, depth) + val commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth) + return if (notAllNotNull) + refineNullabilityForUndefinedNullability(types, commonSuperType) ?: commonSuperType.makeNullableAsSpecified(true) + else + commonSuperType + } - return if (notAllNotNull) commonSuperTypes.makeNullableAsSpecified(true) else commonSuperTypes + private fun refineNullabilityForUndefinedNullability(types: List, commonSuperType: SimpleType): SimpleType? { + if (!commonSuperType.unwrap().canHaveUndefinedNullability()) return null + + val actuallyNotNull = types.all { NullabilityChecker.hasPathByNotMarkedNullableNodes(it, commonSuperType.constructor) } + return if (actuallyNotNull) commonSuperType else null } private fun List.uniquify(): List { diff --git a/compiler/testData/diagnostics/tests/generics/commonSupertypeContravariant2.ni.txt b/compiler/testData/diagnostics/tests/generics/commonSupertypeContravariant2.ni.txt index c17bb395715..96ff3132dce 100644 --- a/compiler/testData/diagnostics/tests/generics/commonSupertypeContravariant2.ni.txt +++ b/compiler/testData/diagnostics/tests/generics/commonSupertypeContravariant2.ni.txt @@ -1,7 +1,7 @@ package -public fun foobar(/*0*/ a: A, /*1*/ b: B): In? -public fun select(/*0*/ x: T, /*1*/ y: T): T? +public fun foobar(/*0*/ a: A, /*1*/ b: B): In +public fun select(/*0*/ x: T, /*1*/ y: T): T public final class A : In { public constructor A() diff --git a/compiler/testData/diagnostics/tests/regressions/kt7804.kt b/compiler/testData/diagnostics/tests/regressions/kt7804.kt index fcb08117fb7..272a5ff8555 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt7804.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt7804.kt @@ -12,7 +12,7 @@ fun test(v: T): T { v } - val t: T = a + val t: T = a return t } @@ -36,7 +36,7 @@ fun test3(v: T): T { v } - val t: T = a + val t: T = a return t } diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.kt b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.kt index e4efe818d83..5792a3f89a0 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.kt @@ -1,5 +1,4 @@ // !DIAGNOSTICS: -NOTHING_TO_INLINE -// NI_EXPECTED_FILE inline fun foo(t1: T, t2: T) = t1 ?: t2 diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.ni.txt b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.ni.txt deleted file mode 100644 index ac27408f189..00000000000 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgument.ni.txt +++ /dev/null @@ -1,5 +0,0 @@ -package - -public inline fun bar(/*0*/ l: (T) -> kotlin.Unit): T -public inline fun foo(/*0*/ t1: T, /*1*/ t2: T): T? -public fun use(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.kt b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.kt index fd177fa4bf1..0cbe4c4629b 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.kt @@ -1,5 +1,4 @@ // !DIAGNOSTICS: -NOTHING_TO_INLINE -// NI_EXPECTED_FILE // See KT-9143: smart cast on a variable nulled inside a lambda argument inline fun foo(t1: T, t2: T) = t1 ?: t2 diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.ni.txt b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.ni.txt deleted file mode 100644 index ac27408f189..00000000000 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.ni.txt +++ /dev/null @@ -1,5 +0,0 @@ -package - -public inline fun bar(/*0*/ l: (T) -> kotlin.Unit): T -public inline fun foo(/*0*/ t1: T, /*1*/ t2: T): T? -public fun use(): kotlin.Unit diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt index f101d274f44..9b622ac8080 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt @@ -20,9 +20,9 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.types.checker.NewCapturedType import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.checker.NullabilityChecker +import org.jetbrains.kotlin.types.typeUtil.canHaveUndefinedNullability abstract class DelegatingSimpleType : SimpleType() { protected abstract val delegate: SimpleType @@ -82,12 +82,7 @@ class DefinitelyNotNullType private constructor(val original: SimpleType) : Dele } fun makesSenseToBeDefinitelyNotNull(type: UnwrappedType): Boolean = - canHaveUndefinedNullability(type) && !NullabilityChecker.isSubtypeOfAny(type) - - private fun canHaveUndefinedNullability(type: UnwrappedType): Boolean = - type.constructor is NewTypeVariableConstructor || - type.constructor.declarationDescriptor is TypeParameterDescriptor || - type is NewCapturedType + type.canHaveUndefinedNullability() && !NullabilityChecker.isSubtypeOfAny(type) } override val delegate: SimpleType diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 5c1e6025826..21bb294f90d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.inference.isCaptured import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.NewCapturedType +import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import java.util.* enum class TypeNullability { @@ -201,3 +203,8 @@ fun KotlinType.containsTypeProjectionsInTopLevelArguments(): Boolean { val possiblyInnerType = buildPossiblyInnerType() ?: return false return possiblyInnerType.arguments.any { it.isStarProjection || it.projectionKind != Variance.INVARIANT } } + +fun UnwrappedType.canHaveUndefinedNullability(): Boolean = + constructor is NewTypeVariableConstructor || + constructor.declarationDescriptor is TypeParameterDescriptor || + this is NewCapturedType diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 3691d5070e5..60859d5d4d9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -398,6 +398,9 @@ object NullabilityChecker { fun isSubtypeOfAny(type: UnwrappedType): Boolean = TypeCheckerContext(false).hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible) + fun hasPathByNotMarkedNullableNodes(start: SimpleType, end: TypeConstructor) = + TypeCheckerContext(false).hasPathByNotMarkedNullableNodes(start, end) + private fun TypeCheckerContext.runIsPossibleSubtype(subType: SimpleType, superType: SimpleType): Boolean { // it makes for case String? & Any <: String assert(subType.isIntersectionType || subType.isSingleClassifierType || subType.isAllowedTypeVariable) {