[NI] Introduce DefinitelyNotNullType as type for T!! or {T & Any}
This commit is contained in:
+8
-4
@@ -74,16 +74,17 @@ interface NewTypeSubstitutor {
|
|||||||
if (typeConstructor is NewCapturedTypeConstructor) {
|
if (typeConstructor is NewCapturedTypeConstructor) {
|
||||||
if (!runCapturedChecks) return null
|
if (!runCapturedChecks) return null
|
||||||
|
|
||||||
assert(type is NewCapturedType) { // KT-16147
|
assert(type is NewCapturedType || (type is DefinitelyNotNullType && type.original is NewCapturedType)) { // KT-16147
|
||||||
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
|
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
|
||||||
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
|
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
|
||||||
}
|
}
|
||||||
val lower = (type as NewCapturedType).lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
|
val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType
|
||||||
|
val lower = capturedType.lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
|
||||||
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " +
|
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " +
|
||||||
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
|
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
|
||||||
"original lower type: '${type.lowerType}")
|
"original lower type: '${capturedType.lowerType}")
|
||||||
|
|
||||||
type.constructor.supertypes.forEach { supertype ->
|
typeConstructor.supertypes.forEach { supertype ->
|
||||||
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
|
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
|
||||||
throw IllegalStateException("Illegal type substitutor: $this, " +
|
throw IllegalStateException("Illegal type substitutor: $this, " +
|
||||||
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
|
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
|
||||||
@@ -111,6 +112,9 @@ interface NewTypeSubstitutor {
|
|||||||
if (type.isMarkedNullable) {
|
if (type.isMarkedNullable) {
|
||||||
replacement = replacement.makeNullableAsSpecified(true)
|
replacement = replacement.makeNullableAsSpecified(true)
|
||||||
}
|
}
|
||||||
|
if (type.isDefinitelyNotNullType) {
|
||||||
|
replacement = replacement.makeDefinitelyNotNullOrNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
return replacement
|
return replacement
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-21
@@ -139,17 +139,9 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Foo <: T! -- (Foo & Any .. Foo) <: T
|
// Foo <: T! -- (Foo & Any .. Foo) <: T
|
||||||
// T <: T! -- (T..T?) <: T
|
|
||||||
// we can't use constraint (T & Any .. T) in the latter, because non-platform type with type variables is incorrect
|
|
||||||
private fun addLowerConstraintWithSimpleSubtype(typeVariable: FlexibleType, subType: SimpleType) {
|
private fun addLowerConstraintWithSimpleSubtype(typeVariable: FlexibleType, subType: SimpleType) {
|
||||||
assertFlexibleTypeVariable(typeVariable)
|
assertFlexibleTypeVariable(typeVariable)
|
||||||
|
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(subType.makeSimpleTypeDefinitelyNotNullOrNotNull(), subType))
|
||||||
val constraintType = if (isMyTypeVariable(subType))
|
|
||||||
KotlinTypeFactory.flexibleType(subType.makeNullableAsSpecified(false), subType.makeNullableAsSpecified(true))
|
|
||||||
else
|
|
||||||
KotlinTypeFactory.flexibleType(subType.definitelyNotNull(), subType)
|
|
||||||
|
|
||||||
addLowerConstraint(typeVariable.constructor, constraintType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Foo..Bar) <: T! -- (Foo & Any .. Bar) <: T
|
// (Foo..Bar) <: T! -- (Foo & Any .. Bar) <: T
|
||||||
@@ -159,28 +151,18 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
|||||||
val lowerBound = subType.lowerBound
|
val lowerBound = subType.lowerBound
|
||||||
val upperBound = subType.upperBound
|
val upperBound = subType.upperBound
|
||||||
|
|
||||||
if (isMyTypeVariable(lowerBound) || isMyTypeVariable(upperBound)) {
|
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(lowerBound.makeSimpleTypeDefinitelyNotNullOrNotNull(), upperBound))
|
||||||
assertFlexibleTypeVariable(subType)
|
|
||||||
// This means that we are trying to add constraint like T! <: A!
|
|
||||||
addLowerConstraint(typeVariable.constructor, subType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(lowerBound.definitelyNotNull(), upperBound))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Foo <: T or
|
// Foo <: T or
|
||||||
// Foo <: T? -- Foo & Any <: T
|
// Foo <: T? -- Foo & Any <: T
|
||||||
private fun addLowerConstraintForSimpleType(typeVariable: SimpleType, subType: UnwrappedType) {
|
private fun addLowerConstraintForSimpleType(typeVariable: SimpleType, subType: UnwrappedType) {
|
||||||
if (typeVariable.isMarkedNullable)
|
if (typeVariable.isMarkedNullable)
|
||||||
addLowerConstraint(typeVariable.constructor, subType.definitelyNotNull())
|
addLowerConstraint(typeVariable.constructor, subType.makeDefinitelyNotNullOrNotNull())
|
||||||
else
|
else
|
||||||
addLowerConstraint(typeVariable.constructor, subType)
|
addLowerConstraint(typeVariable.constructor, subType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun UnwrappedType.definitelyNotNull(): UnwrappedType = intersectTypes(listOf(this, this.builtIns.anyType))
|
|
||||||
private fun SimpleType.definitelyNotNull(): SimpleType = intersectTypes(listOf(this, this.builtIns.anyType))
|
|
||||||
|
|
||||||
private fun assertFlexibleTypeVariable(typeVariable: FlexibleType) {
|
private fun assertFlexibleTypeVariable(typeVariable: FlexibleType) {
|
||||||
assert(typeVariable.lowerBound.constructor == typeVariable.upperBound.constructor) {
|
assert(typeVariable.lowerBound.constructor == typeVariable.upperBound.constructor) {
|
||||||
"Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)"
|
"Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)"
|
||||||
@@ -196,6 +178,9 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
|||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val typeVariable = typeVariable.lowerIfFlexible()
|
val typeVariable = typeVariable.lowerIfFlexible()
|
||||||
|
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val superType = if (typeVariable is DefinitelyNotNullType) superType.makeNullableAsSpecified(true) else superType
|
||||||
|
|
||||||
addUpperConstraint(typeVariable.constructor, superType)
|
addUpperConstraint(typeVariable.constructor, superType)
|
||||||
|
|
||||||
if (typeVariable.isMarkedNullable) {
|
if (typeVariable.isMarkedNullable) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ open class TypeApproximatorConfiguration {
|
|||||||
open val dynamic get() = false // DynamicType
|
open val dynamic get() = false // DynamicType
|
||||||
open val rawType get() = false // RawTypeImpl
|
open val rawType get() = false // RawTypeImpl
|
||||||
open val errorType get() = false
|
open val errorType get() = false
|
||||||
|
open val definitelyNotNullType get() = true
|
||||||
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
||||||
|
|
||||||
open val typeVariable: (TypeVariableTypeConstructor) -> Boolean = { false }
|
open val typeVariable: (TypeVariableTypeConstructor) -> Boolean = { false }
|
||||||
@@ -61,6 +62,7 @@ open class TypeApproximatorConfiguration {
|
|||||||
object PublicDeclaration : AllFlexibleSameValue() {
|
object PublicDeclaration : AllFlexibleSameValue() {
|
||||||
override val allFlexible get() = true
|
override val allFlexible get() = true
|
||||||
override val errorType get() = true
|
override val errorType get() = true
|
||||||
|
override val definitelyNotNullType get() = false
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||||
@@ -262,6 +264,10 @@ class TypeApproximator {
|
|||||||
return approximateParametrizedType(type, conf, toSuper, depth + 1)
|
return approximateParametrizedType(type, conf, toSuper, depth + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type is DefinitelyNotNullType) {
|
||||||
|
return approximateDefinitelyNotNullType(type, conf, toSuper, depth)
|
||||||
|
}
|
||||||
|
|
||||||
val typeConstructor = type.constructor
|
val typeConstructor = type.constructor
|
||||||
|
|
||||||
if (typeConstructor is NewCapturedTypeConstructor) {
|
if (typeConstructor is NewCapturedTypeConstructor) {
|
||||||
@@ -283,6 +289,24 @@ class TypeApproximator {
|
|||||||
return null // simple classifier type
|
return null // simple classifier type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun approximateDefinitelyNotNullType(
|
||||||
|
type: DefinitelyNotNullType,
|
||||||
|
conf: TypeApproximatorConfiguration,
|
||||||
|
toSuper: Boolean,
|
||||||
|
depth: Int
|
||||||
|
): UnwrappedType? {
|
||||||
|
val approximatedOriginalType = approximateTo(type.original, conf, toSuper, depth)
|
||||||
|
return if (conf.definitelyNotNullType) {
|
||||||
|
approximatedOriginalType?.makeDefinitelyNotNullOrNotNull()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (toSuper)
|
||||||
|
(approximatedOriginalType ?: type.original).makeNullableAsSpecified(false)
|
||||||
|
else
|
||||||
|
type.defaultResult(toSuper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
|
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
|
||||||
when (effectiveVariance) {
|
when (effectiveVariance) {
|
||||||
Variance.OUT_VARIANCE -> toSuper
|
Variance.OUT_VARIANCE -> toSuper
|
||||||
@@ -364,7 +388,7 @@ class TypeApproximator {
|
|||||||
* Note that for case Inv<C> we will chose Inv<in Int>, because it is more informative then Inv<out Any?>.
|
* Note that for case Inv<C> we will chose Inv<in Int>, because it is more informative then Inv<out Any?>.
|
||||||
* May be we should do the same for deeper types, but not now.
|
* May be we should do the same for deeper types, but not now.
|
||||||
*/
|
*/
|
||||||
if (argumentType is NewCapturedType) {
|
if (argumentType.constructor is NewCapturedTypeConstructor) {
|
||||||
val subType = approximateToSubType(argumentType, conf, depth) ?: continue@loop
|
val subType = approximateToSubType(argumentType, conf, depth) ?: continue@loop
|
||||||
if (!subType.isTrivialSub()) {
|
if (!subType.isTrivialSub()) {
|
||||||
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, subType)
|
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, subType)
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,9 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.types
|
package org.jetbrains.kotlin.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
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() {
|
abstract class DelegatingSimpleType : SimpleType() {
|
||||||
protected abstract val delegate: SimpleType
|
protected abstract val delegate: SimpleType
|
||||||
@@ -55,3 +59,64 @@ class LazyWrappedType(storageManager: StorageManager, computation: () -> KotlinT
|
|||||||
|
|
||||||
override fun isComputed(): Boolean = lazyValue.isComputed()
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -395,6 +395,11 @@ public class TypeUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unwrappedType instanceof DefinitelyNotNullType &&
|
||||||
|
contains(((DefinitelyNotNullType) unwrappedType).getOriginal(), isSpecialType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
TypeConstructor typeConstructor = type.getConstructor();
|
TypeConstructor typeConstructor = type.getConstructor();
|
||||||
if (typeConstructor instanceof IntersectionTypeConstructor) {
|
if (typeConstructor instanceof IntersectionTypeConstructor) {
|
||||||
IntersectionTypeConstructor intersectionTypeConstructor = (IntersectionTypeConstructor) typeConstructor;
|
IntersectionTypeConstructor intersectionTypeConstructor = (IntersectionTypeConstructor) typeConstructor;
|
||||||
|
|||||||
@@ -86,12 +86,15 @@ object TypeIntersector {
|
|||||||
/**
|
/**
|
||||||
* resultNullability. Value description:
|
* resultNullability. Value description:
|
||||||
* ACCEPT_NULL means that all types marked nullable
|
* 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,
|
* 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.
|
* 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()) {
|
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)
|
return intersectTypesWithoutIntersectionType(correctNullability)
|
||||||
@@ -154,15 +157,10 @@ object TypeIntersector {
|
|||||||
abstract fun combine(nextType: UnwrappedType): ResultNullability
|
abstract fun combine(nextType: UnwrappedType): ResultNullability
|
||||||
|
|
||||||
protected val UnwrappedType.resultNullability: ResultNullability
|
protected val UnwrappedType.resultNullability: ResultNullability
|
||||||
get() {
|
get() = when {
|
||||||
if (isMarkedNullable) return ACCEPT_NULL
|
isMarkedNullable -> ACCEPT_NULL
|
||||||
|
NullabilityChecker.isSubtypeOfAny(this) -> NOT_NULL
|
||||||
if (NullabilityChecker.isSubtypeOfAny(this)) {
|
else -> UNKNOWN
|
||||||
return NOT_NULL
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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)
|
return intersectTypes(preparedSuperTypes).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
||||||
}
|
}
|
||||||
if (simpleType is NewCapturedType) {
|
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 {
|
return simpleType.constructor.supertypes.takeIf { it.isNotEmpty() }?.let {
|
||||||
intersectTypes(it).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
intersectTypes(it).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
||||||
} ?: argumentType.builtIns.nullableAnyType
|
} ?: 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 {
|
fun strictEqualTypes(a: SimpleType, b: SimpleType): Boolean {
|
||||||
if (a.isMarkedNullable != b.isMarkedNullable
|
if (a.isMarkedNullable != b.isMarkedNullable
|
||||||
|
|| a.isDefinitelyNotNullType != b.isDefinitelyNotNullType
|
||||||
|| a.constructor != b.constructor
|
|| a.constructor != b.constructor
|
||||||
|| a.arguments.size != b.arguments.size
|
|| a.arguments.size != b.arguments.size
|
||||||
) {
|
) {
|
||||||
@@ -111,7 +112,9 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
|||||||
lowerIfFlexible().isMarkedNullable != upperIfFlexible().isMarkedNullable
|
lowerIfFlexible().isMarkedNullable != upperIfFlexible().isMarkedNullable
|
||||||
|
|
||||||
private fun isCommonDenotableType(type: KotlinType) =
|
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 {
|
fun TypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean {
|
||||||
if (subType === superType) return true
|
if (subType === superType) return true
|
||||||
@@ -407,13 +410,19 @@ object NullabilityChecker {
|
|||||||
// superType is actually nullable
|
// superType is actually nullable
|
||||||
if (superType.isMarkedNullable) return true
|
if (superType.isMarkedNullable) return true
|
||||||
|
|
||||||
|
// i.e. subType is definitely not null
|
||||||
|
if (subType.isDefinitelyNotNullType) return true
|
||||||
|
|
||||||
// i.e. subType is not-nullable
|
// i.e. subType is not-nullable
|
||||||
if (hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true
|
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
|
// i.e subType hasn't not-null supertype, but superType has
|
||||||
if (hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false
|
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.
|
* 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) =
|
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
|
if (it.isMarkedNullable) SupertypesPolicy.None else supertypesPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +473,7 @@ val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is
|
|||||||
val SimpleType.isSingleClassifierType: Boolean
|
val SimpleType.isSingleClassifierType: Boolean
|
||||||
get() = !isError &&
|
get() = !isError &&
|
||||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
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
|
val SimpleType.isIntersectionType: Boolean
|
||||||
get() = constructor is IntersectionTypeConstructor
|
get() = constructor is IntersectionTypeConstructor
|
||||||
|
|||||||
Reference in New Issue
Block a user