[NI] Refine nullability for CST of types with undefined nullability

This commit is contained in:
Mikhail Zarechenskiy
2017-12-01 18:11:09 +03:00
parent b9d390449c
commit 1d736f59b6
10 changed files with 28 additions and 25 deletions
@@ -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<SimpleType>, 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<SimpleType>.uniquify(): List<SimpleType> {
@@ -1,7 +1,7 @@
package
public fun foobar(/*0*/ a: A, /*1*/ b: B): In<kotlin.Nothing>?
public fun </*0*/ T> select(/*0*/ x: T, /*1*/ y: T): T?
public fun foobar(/*0*/ a: A, /*1*/ b: B): In<kotlin.Nothing>
public fun </*0*/ T> select(/*0*/ x: T, /*1*/ y: T): T
public final class A : In<A> {
public constructor A()
+2 -2
View File
@@ -12,7 +12,7 @@ fun <T> test(v: T): T {
v
}
val t: T = <!NI;DEBUG_INFO_SMARTCAST!>a<!>
val t: T = a
return t
}
@@ -36,7 +36,7 @@ fun <T> test3(v: T): T {
v
}
val t: T = <!NI;DEBUG_INFO_SMARTCAST!>a<!>
val t: T = a
return t
}
@@ -1,5 +1,4 @@
// !DIAGNOSTICS: -NOTHING_TO_INLINE
// NI_EXPECTED_FILE
inline fun <T> foo(t1: T, t2: T) = t1 ?: t2
@@ -1,5 +0,0 @@
package
public inline fun </*0*/ T> bar(/*0*/ l: (T) -> kotlin.Unit): T
public inline fun </*0*/ T> foo(/*0*/ t1: T, /*1*/ t2: T): T?
public fun use(): kotlin.Unit
@@ -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 <T> foo(t1: T, t2: T) = t1 ?: t2
@@ -1,5 +0,0 @@
package
public inline fun </*0*/ T> bar(/*0*/ l: (T) -> kotlin.Unit): T
public inline fun </*0*/ T> foo(/*0*/ t1: T, /*1*/ t2: T): T?
public fun use(): kotlin.Unit
@@ -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
@@ -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
@@ -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) {