[NI] Introduce DefinitelyNotNullType as type for T!! or {T & Any}
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
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
|
||||
|
||||
abstract class DelegatingSimpleType : SimpleType() {
|
||||
protected abstract val delegate: SimpleType
|
||||
@@ -55,3 +59,64 @@ class LazyWrappedType(storageManager: StorageManager, computation: () -> KotlinT
|
||||
|
||||
override fun isComputed(): Boolean = lazyValue.isComputed()
|
||||
}
|
||||
|
||||
class DefinitelyNotNullType private constructor(val original: SimpleType) : DelegatingSimpleType(), CustomTypeVariable {
|
||||
companion object {
|
||||
internal fun makeDefinitelyNotNull(type: UnwrappedType): DefinitelyNotNullType? {
|
||||
return when {
|
||||
type is DefinitelyNotNullType -> type
|
||||
|
||||
makesSenseToBeDefinitelyNotNull(type) -> {
|
||||
if (type is FlexibleType) {
|
||||
assert(type.lowerBound.constructor == type.upperBound.constructor) {
|
||||
"DefinitelyNotNullType for flexible type ($type) can be created only from type variable with the same constructor for bounds"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DefinitelyNotNullType(type.lowerIfFlexible())
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
override val delegate: SimpleType
|
||||
get() = original
|
||||
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = false
|
||||
|
||||
override val isTypeVariable: Boolean
|
||||
get() = delegate.constructor is NewTypeVariableConstructor ||
|
||||
delegate.constructor.declarationDescriptor is TypeParameterDescriptor
|
||||
|
||||
override fun substitutionResult(replacement: KotlinType): KotlinType =
|
||||
replacement.unwrap().makeDefinitelyNotNullOrNotNull()
|
||||
|
||||
override fun replaceAnnotations(newAnnotations: Annotations): DefinitelyNotNullType =
|
||||
DefinitelyNotNullType(delegate.replaceAnnotations(newAnnotations))
|
||||
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType =
|
||||
if (newNullability) delegate.makeNullableAsSpecified(newNullability) else this
|
||||
|
||||
override fun toString(): String = "$delegate!!"
|
||||
}
|
||||
|
||||
val KotlinType.isDefinitelyNotNullType: Boolean
|
||||
get() = unwrap() is DefinitelyNotNullType
|
||||
|
||||
fun SimpleType.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleType =
|
||||
DefinitelyNotNullType.makeDefinitelyNotNull(this) ?: makeNullableAsSpecified(false)
|
||||
|
||||
fun UnwrappedType.makeDefinitelyNotNullOrNotNull(): UnwrappedType =
|
||||
DefinitelyNotNullType.makeDefinitelyNotNull(this) ?: makeNullableAsSpecified(false)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -395,6 +395,11 @@ public class TypeUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unwrappedType instanceof DefinitelyNotNullType &&
|
||||
contains(((DefinitelyNotNullType) unwrappedType).getOriginal(), isSpecialType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeConstructor typeConstructor = type.getConstructor();
|
||||
if (typeConstructor instanceof IntersectionTypeConstructor) {
|
||||
IntersectionTypeConstructor intersectionTypeConstructor = (IntersectionTypeConstructor) typeConstructor;
|
||||
|
||||
@@ -86,12 +86,15 @@ object TypeIntersector {
|
||||
/**
|
||||
* resultNullability. Value description:
|
||||
* ACCEPT_NULL means that all types marked nullable
|
||||
* NOT_NULL means that there is one type which is subtype of Any => all types can be marked not nullable
|
||||
*
|
||||
* NOT_NULL means that there is one type which is subtype of Any => all types can be made definitely not null,
|
||||
* making types definitely not null (not just not null) makes sense when we have intersection of type parameters like {T!! & S}
|
||||
*
|
||||
* UNKNOWN means, that we do not know, i.e. more precisely, all singleClassifier types marked nullable if any,
|
||||
* and other types is captured types or type parameters without not-null upper bound. Example: `String? & T` such types we should leave as is.
|
||||
*/
|
||||
val correctNullability = inputTypes.mapTo(LinkedHashSet()) {
|
||||
if (resultNullability == ResultNullability.NOT_NULL) it.makeNullableAsSpecified(false) else it
|
||||
if (resultNullability == ResultNullability.NOT_NULL) it.makeSimpleTypeDefinitelyNotNullOrNotNull() else it
|
||||
}
|
||||
|
||||
return intersectTypesWithoutIntersectionType(correctNullability)
|
||||
@@ -154,15 +157,10 @@ object TypeIntersector {
|
||||
abstract fun combine(nextType: UnwrappedType): ResultNullability
|
||||
|
||||
protected val UnwrappedType.resultNullability: ResultNullability
|
||||
get() {
|
||||
if (isMarkedNullable) return ACCEPT_NULL
|
||||
|
||||
if (NullabilityChecker.isSubtypeOfAny(this)) {
|
||||
return NOT_NULL
|
||||
}
|
||||
else {
|
||||
return UNKNOWN
|
||||
}
|
||||
get() = when {
|
||||
isMarkedNullable -> ACCEPT_NULL
|
||||
NullabilityChecker.isSubtypeOfAny(this) -> NOT_NULL
|
||||
else -> UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ fun prepareArgumentTypeRegardingCaptureTypes(argumentType: UnwrappedType): Unwra
|
||||
return intersectTypes(preparedSuperTypes).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
||||
}
|
||||
if (simpleType is NewCapturedType) {
|
||||
// todo may be we should respect flexible capture types also...
|
||||
// todo may be we should respect flexible/definitelyNotNull captured types also...
|
||||
return simpleType.constructor.supertypes.takeIf { it.isNotEmpty() }?.let {
|
||||
intersectTypes(it).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
||||
} ?: argumentType.builtIns.nullableAnyType
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,6 +53,7 @@ object StrictEqualityTypeChecker {
|
||||
|
||||
fun strictEqualTypes(a: SimpleType, b: SimpleType): Boolean {
|
||||
if (a.isMarkedNullable != b.isMarkedNullable
|
||||
|| a.isDefinitelyNotNullType != b.isDefinitelyNotNullType
|
||||
|| a.constructor != b.constructor
|
||||
|| a.arguments.size != b.arguments.size
|
||||
) {
|
||||
@@ -111,7 +112,9 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
lowerIfFlexible().isMarkedNullable != upperIfFlexible().isMarkedNullable
|
||||
|
||||
private fun isCommonDenotableType(type: KotlinType) =
|
||||
type.constructor.isDenotable && !type.isDynamic() && type.lowerIfFlexible().constructor == type.upperIfFlexible().constructor
|
||||
type.constructor.isDenotable &&
|
||||
!type.isDynamic() && !type.isDefinitelyNotNullType &&
|
||||
type.lowerIfFlexible().constructor == type.upperIfFlexible().constructor
|
||||
|
||||
fun TypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean {
|
||||
if (subType === superType) return true
|
||||
@@ -407,13 +410,19 @@ object NullabilityChecker {
|
||||
// superType is actually nullable
|
||||
if (superType.isMarkedNullable) return true
|
||||
|
||||
// i.e. subType is definitely not null
|
||||
if (subType.isDefinitelyNotNullType) return true
|
||||
|
||||
// i.e. subType is not-nullable
|
||||
if (hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true
|
||||
|
||||
// i.e. subType hasn't not-null supertype and isn't definitely not-null, but superType is definitely not-null
|
||||
if (superType.isDefinitelyNotNullType) return false
|
||||
|
||||
// i.e subType hasn't not-null supertype, but superType has
|
||||
if (hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false
|
||||
|
||||
// both superType and subType hasn't not-null supertype.
|
||||
// both superType and subType hasn't not-null supertype and are not definitely not null.
|
||||
|
||||
/**
|
||||
* If we still don't know, it means, that superType is not classType, for example -- type parameter.
|
||||
@@ -431,7 +440,7 @@ object NullabilityChecker {
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.hasNotNullSupertype(type: SimpleType, supertypesPolicy: SupertypesPolicy) =
|
||||
anySupertype(type, { it.isClassType && !it.isMarkedNullable }) {
|
||||
anySupertype(type, { (it.isClassType && !it.isMarkedNullable) || it.isDefinitelyNotNullType }) {
|
||||
if (it.isMarkedNullable) SupertypesPolicy.None else supertypesPolicy
|
||||
}
|
||||
|
||||
@@ -464,7 +473,7 @@ val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is
|
||||
val SimpleType.isSingleClassifierType: Boolean
|
||||
get() = !isError &&
|
||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType)
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType)
|
||||
|
||||
val SimpleType.isIntersectionType: Boolean
|
||||
get() = constructor is IntersectionTypeConstructor
|
||||
|
||||
Reference in New Issue
Block a user