Make type-system KotlinType-independent
- Port NewKotlinTypeChecker.equalTypes - Decouple new-type transform from isSubtypeOf - Port isSubtypeForSameConstructor - Port checkSubtypeForSpecialCases - Port isSubTypeOf without internals - Port anySupertype - Port isSubtypeForSameConstructor, findCorrespondingSupertypes - Port isSubtypeOfForSingleClassifierType - Port NullabilityChecker - Reorder checks for performance
This commit is contained in:
+6
-3
@@ -40,9 +40,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -277,9 +278,11 @@ class CoroutineInferenceSupport(
|
||||
|
||||
private class CoroutineTypeCheckerContext(
|
||||
private val allowOnlyTrivialConstraints: Boolean
|
||||
) : TypeCheckerContext(errorTypeEqualsToAnything = true) {
|
||||
) : ClassicTypeCheckerContext(errorTypeEqualsToAnything = true) {
|
||||
|
||||
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||
override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
|
||||
require(subType is UnwrappedType)
|
||||
require(superType is UnwrappedType)
|
||||
val typeTemplate = subType as? TypeTemplate ?: superType as? TypeTemplate
|
||||
typeTemplate?.coroutineInferenceData?.addConstraint(subType, superType, allowOnlyTrivialConstraints)
|
||||
return null
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ object NewCommonSuperTypeCalculator {
|
||||
nullable = false
|
||||
)
|
||||
|
||||
val typeCheckerContext = TypeCheckerContext(false)
|
||||
val typeCheckerContext = ClassicTypeCheckerContext(false)
|
||||
|
||||
/**
|
||||
* Sometimes one type can have several supertypes with given type constructor, suppose A <: List<Int> and A <: List<Double>.
|
||||
|
||||
+1
-1
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
+1
-1
@@ -22,9 +22,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.LOWER
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.UPPER
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||
|
||||
+15
-4
@@ -11,10 +11,13 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory.flexibleType
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.CapturedTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
|
||||
abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
|
||||
|
||||
abstract fun isMyTypeVariable(type: SimpleType): Boolean
|
||||
|
||||
@@ -23,7 +26,13 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
|
||||
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType)
|
||||
|
||||
override fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when {
|
||||
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy {
|
||||
require(subType is SimpleType)
|
||||
require(superType is NewCapturedType)
|
||||
return getLowerCapturedTypePolicy(subType, superType)
|
||||
}
|
||||
|
||||
private fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when {
|
||||
isMyTypeVariable(subType) -> LowerCapturedTypePolicy.SKIP_LOWER
|
||||
subType.contains { it.anyBound(this::isMyTypeVariable) } -> LowerCapturedTypePolicy.CHECK_ONLY_LOWER
|
||||
else -> LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER
|
||||
@@ -35,7 +44,9 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
* then we can get wrong result.
|
||||
* override val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.TAKE_FIRST_FOR_SUBTYPING
|
||||
*/
|
||||
override final fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||
final override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
|
||||
require(subType is UnwrappedType)
|
||||
require(superType is UnwrappedType)
|
||||
val hasNoInfer = subType.isTypeVariableWithNoInfer() || superType.isTypeVariableWithNoInfer()
|
||||
if (hasNoInfer) return true
|
||||
|
||||
@@ -199,7 +210,7 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
val notTypeVariables = subIntersectionTypes.filterNot(this::isMyTypeVariable)
|
||||
|
||||
// todo: may be we can do better then that.
|
||||
if (notTypeVariables.isNotEmpty() && NewKotlinTypeChecker.isSubtypeOf(intersectTypes(notTypeVariables), superType)) {
|
||||
if (notTypeVariables.isNotEmpty() && NewKotlinTypeChecker.isSubtypeOf(intersectTypes(notTypeVariables) as KotlinType, superType)) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
@@ -302,7 +302,7 @@ object ExpectedActualResolver {
|
||||
if (b == null) return false
|
||||
|
||||
with(NewKotlinTypeChecker) {
|
||||
val context = object : TypeCheckerContext(false) {
|
||||
val context = object : ClassicTypeCheckerContext(false) {
|
||||
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return isExpectedClassAndActualTypeAlias(a, b, platformModule) ||
|
||||
isExpectedClassAndActualTypeAlias(b, a, platformModule) ||
|
||||
|
||||
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
|
||||
@@ -820,14 +820,18 @@ public abstract class KotlinBuiltIns {
|
||||
}
|
||||
|
||||
private static boolean isConstructedFromGivenClass(@NotNull KotlinType type, @NotNull FqNameUnsafe fqName) {
|
||||
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
return descriptor instanceof ClassDescriptor && classFqNameEquals(descriptor, fqName);
|
||||
return isTypeConstructorForGivenClass(type.getConstructor(), fqName);
|
||||
}
|
||||
|
||||
public static boolean isConstructedFromGivenClass(@NotNull KotlinType type, @NotNull FqName fqName) {
|
||||
return isConstructedFromGivenClass(type, fqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isTypeConstructorForGivenClass(@NotNull TypeConstructor typeConstructor, @NotNull FqNameUnsafe fqName) {
|
||||
ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
|
||||
return descriptor instanceof ClassDescriptor && classFqNameEquals(descriptor, fqName);
|
||||
}
|
||||
|
||||
private static boolean classFqNameEquals(@NotNull ClassifierDescriptor descriptor, @NotNull FqNameUnsafe fqName) {
|
||||
// Quick check to avoid creation of full FqName instance
|
||||
return descriptor.getName().equals(fqName.shortName()) &&
|
||||
|
||||
@@ -20,11 +20,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
||||
import org.jetbrains.kotlin.types.Variance;
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterIM;
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TypeParameterDescriptor extends ClassifierDescriptor, TypeParameterIM {
|
||||
public interface TypeParameterDescriptor extends ClassifierDescriptor, TypeParameterMarker {
|
||||
boolean isReified();
|
||||
|
||||
@NotNull
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
|
||||
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||
import org.jetbrains.kotlin.types.model.CapturedTypeIM
|
||||
import org.jetbrains.kotlin.types.model.CapturedTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
interface CapturedTypeConstructor : TypeConstructor {
|
||||
@@ -69,7 +69,7 @@ class CapturedType(
|
||||
override val constructor: CapturedTypeConstructor = CapturedTypeConstructorImpl(typeProjection),
|
||||
override val isMarkedNullable: Boolean = false,
|
||||
override val annotations: Annotations = Annotations.EMPTY
|
||||
) : SimpleType(), SubtypingRepresentatives, CapturedTypeIM {
|
||||
) : SimpleType(), SubtypingRepresentatives, CapturedTypeMarker {
|
||||
override val arguments: List<TypeProjection>
|
||||
get() = listOf()
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.FlexibleTypeIM
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeIM
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeIM
|
||||
import org.jetbrains.kotlin.types.model.FlexibleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeArgumentListMarker
|
||||
|
||||
/**
|
||||
* [KotlinType] has only two direct subclasses: [WrappedType] and [UnwrappedType].
|
||||
@@ -43,7 +44,7 @@ import org.jetbrains.kotlin.types.model.SimpleTypeIM
|
||||
*
|
||||
* For type creation see [KotlinTypeFactory].
|
||||
*/
|
||||
sealed class KotlinType : Annotated, KotlinTypeIM {
|
||||
sealed class KotlinType : Annotated, KotlinTypeMarker {
|
||||
|
||||
abstract val constructor: TypeConstructor
|
||||
abstract val arguments: List<TypeProjection>
|
||||
@@ -122,7 +123,7 @@ sealed class UnwrappedType: KotlinType() {
|
||||
* then all your types are simple.
|
||||
* Or more precisely, all instances are subclasses of [SimpleType] or [WrappedType] (which contains [SimpleType] inside).
|
||||
*/
|
||||
abstract class SimpleType : UnwrappedType(), SimpleTypeIM {
|
||||
abstract class SimpleType : UnwrappedType(), SimpleTypeMarker, TypeArgumentListMarker {
|
||||
abstract override fun replaceAnnotations(newAnnotations: Annotations): SimpleType
|
||||
abstract override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType
|
||||
|
||||
@@ -141,7 +142,7 @@ abstract class SimpleType : UnwrappedType(), SimpleTypeIM {
|
||||
|
||||
// lowerBound is a subtype of upperBound
|
||||
abstract class FlexibleType(val lowerBound: SimpleType, val upperBound: SimpleType) :
|
||||
UnwrappedType(), SubtypingRepresentatives, FlexibleTypeIM {
|
||||
UnwrappedType(), SubtypingRepresentatives, FlexibleTypeMarker {
|
||||
|
||||
abstract val delegate: SimpleType
|
||||
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.types.model.RawTypeIM
|
||||
import org.jetbrains.kotlin.types.model.RawTypeMarker
|
||||
|
||||
interface RawType : RawTypeIM
|
||||
interface RawType : RawTypeMarker
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
|
||||
import org.jetbrains.kotlin.types.checker.NullabilityChecker
|
||||
import org.jetbrains.kotlin.types.model.DefinitelyNotNullTypeIM
|
||||
import org.jetbrains.kotlin.types.model.DefinitelyNotNullTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.canHaveUndefinedNullability
|
||||
|
||||
abstract class DelegatingSimpleType : SimpleType() {
|
||||
@@ -62,7 +62,7 @@ class LazyWrappedType(storageManager: StorageManager, computation: () -> KotlinT
|
||||
}
|
||||
|
||||
class DefinitelyNotNullType private constructor(val original: SimpleType) : DelegatingSimpleType(), CustomTypeVariable,
|
||||
DefinitelyNotNullTypeIM {
|
||||
DefinitelyNotNullTypeMarker {
|
||||
|
||||
companion object {
|
||||
internal fun makeDefinitelyNotNull(type: UnwrappedType): DefinitelyNotNullType? {
|
||||
|
||||
@@ -22,12 +22,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorIM;
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface TypeConstructor extends TypeConstructorIM {
|
||||
public interface TypeConstructor extends TypeConstructorMarker {
|
||||
/**
|
||||
* It may differ from ClassDescriptor.declaredParameters if the class is inner, in such case
|
||||
* it also contains additional parameters from outer declarations.
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package org.jetbrains.kotlin.types;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.types.model.TypeArgumentIM;
|
||||
import org.jetbrains.kotlin.types.model.TypeArgumentMarker;
|
||||
|
||||
public interface TypeProjection extends TypeArgumentIM {
|
||||
public interface TypeProjection extends TypeArgumentMarker {
|
||||
@NotNull
|
||||
Variance getProjectionKind();
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewType
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowedTypeVariable: Boolean = true) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
|
||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return org.jetbrains.kotlin.types.checker.intersectTypes(types as List<UnwrappedType>)
|
||||
}
|
||||
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return super.prepareType(transformToNewType((type as KotlinType).unwrap()))
|
||||
}
|
||||
|
||||
override val isErrorTypeEqualsToAnything: Boolean
|
||||
get() = errorTypeEqualsToAnything
|
||||
|
||||
override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean {
|
||||
require(a is TypeConstructor, a::errorMessage)
|
||||
require(b is TypeConstructor, b::errorMessage)
|
||||
return areEqualTypeConstructors(a, b)
|
||||
}
|
||||
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return a == b
|
||||
}
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
|
||||
require(type is SimpleType, type::errorMessage)
|
||||
|
||||
val substitutor = TypeConstructorSubstitution.create(type).buildSubstitutor()
|
||||
|
||||
return object : SupertypesPolicy.DoCustomTransform() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker {
|
||||
return substitutor.safeSubstitute(
|
||||
type.lowerBoundIfFlexible() as KotlinType,
|
||||
Variance.INVARIANT
|
||||
).asSimpleType()!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor
|
||||
}
|
||||
|
||||
private fun Any.errorMessage(): String {
|
||||
return "ClassicTypeCheckerContext couldn't handle ${this::class} $this"
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
|
||||
interface ClassicTypeSystemContext : TypeSystemContext {
|
||||
override fun TypeConstructorMarker.isDenotable(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this.isDenotable
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.makeNullableAsSpecified(nullable)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isError(): Boolean {
|
||||
require(this is KotlinType, this::errorMessage)
|
||||
return this.isError
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isStubType(): Boolean {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this is StubType
|
||||
}
|
||||
|
||||
override fun CapturedTypeMarker.lowerType(): KotlinTypeMarker? {
|
||||
require(this is NewCapturedType, this::errorMessage)
|
||||
return this.lowerType
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isIntersection(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this is IntersectionTypeConstructor
|
||||
}
|
||||
|
||||
override fun identicalArguments(a: SimpleTypeMarker, b: SimpleTypeMarker): Boolean {
|
||||
require(a is SimpleType, a::errorMessage)
|
||||
require(b is SimpleType, b::errorMessage)
|
||||
return a.arguments === b.arguments
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker? {
|
||||
require(this is KotlinType, this::errorMessage)
|
||||
return this.unwrap() as? SimpleType
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker? {
|
||||
require(this is KotlinType, this::errorMessage)
|
||||
return this.unwrap() as? FlexibleType
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
||||
require(this is FlexibleType, this::errorMessage)
|
||||
return this as? DynamicType
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? {
|
||||
require(this is FlexibleType, this::errorMessage)
|
||||
return this as? RawType
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker {
|
||||
require(this is FlexibleType, this::errorMessage)
|
||||
return this.upperBound
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker {
|
||||
require(this is FlexibleType, this::errorMessage)
|
||||
return this.lowerBound
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker? {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this as? NewCapturedType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this as? DefinitelyNotNullType
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isMarkedNullable(): Boolean {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.isMarkedNullable
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.constructor
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.argumentsCount(): Int {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.arguments.size
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.arguments[index]
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.isStarProjection(): Boolean {
|
||||
require(this is TypeProjection, this::errorMessage)
|
||||
return this.isStarProjection
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.getVariance(): TypeVariance {
|
||||
require(this is TypeProjection, this::errorMessage)
|
||||
return this.projectionKind.convertVariance()
|
||||
}
|
||||
|
||||
private fun Variance.convertVariance(): TypeVariance {
|
||||
return when (this) {
|
||||
Variance.INVARIANT -> TypeVariance.INV
|
||||
Variance.IN_VARIANCE -> TypeVariance.IN
|
||||
Variance.OUT_VARIANCE -> TypeVariance.OUT
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeArgumentMarker.getType(): KotlinTypeMarker {
|
||||
require(this is TypeProjection, this::errorMessage)
|
||||
return this.type.unwrap()
|
||||
}
|
||||
|
||||
|
||||
override fun TypeConstructorMarker.parametersCount(): Int {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this.parameters.size
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getParameter(index: Int): TypeParameterMarker {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this.parameters[index]
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker> {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this.supertypes
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getVariance(): TypeVariance {
|
||||
require(this is TypeParameterDescriptor, this::errorMessage)
|
||||
return this.variance.convertVariance()
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.upperBoundCount(): Int {
|
||||
require(this is TypeParameterDescriptor, this::errorMessage)
|
||||
return this.upperBounds.size
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getUpperBound(index: Int): KotlinTypeMarker {
|
||||
require(this is TypeParameterDescriptor, this::errorMessage)
|
||||
return this.upperBounds[index]
|
||||
}
|
||||
|
||||
override fun TypeParameterMarker.getTypeConstructor(): TypeConstructorMarker {
|
||||
require(this is TypeParameterDescriptor, this::errorMessage)
|
||||
return this.typeConstructor
|
||||
}
|
||||
|
||||
override fun isEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor, c1::errorMessage)
|
||||
require(c2 is TypeConstructor, c2::errorMessage)
|
||||
return c1 == c2
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return declarationDescriptor is ClassDescriptor
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
val classDescriptor = declarationDescriptor as? ClassDescriptor ?: return false
|
||||
return classDescriptor.isFinalClass &&
|
||||
classDescriptor.kind != ClassKind.ENUM_ENTRY &&
|
||||
classDescriptor.kind != ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
|
||||
override fun TypeArgumentListMarker.get(index: Int): TypeArgumentMarker {
|
||||
return when (this) {
|
||||
is SimpleTypeMarker -> getArgument(index)
|
||||
is ArgumentList -> get(index)
|
||||
else -> error("unknown type argument list type: $this, ${this::class}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeArgumentListMarker.size(): Int {
|
||||
return when (this) {
|
||||
is SimpleTypeMarker -> argumentsCount()
|
||||
is ArgumentList -> size
|
||||
else -> error("unknown type argument list type: $this, ${this::class}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
||||
require(type is SimpleType, type::errorMessage)
|
||||
return org.jetbrains.kotlin.types.checker.captureFromArguments(type, status)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isAnyConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return KotlinBuiltIns.isTypeConstructorForGivenClass(this, FQ_NAMES.any)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isNothingConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return KotlinBuiltIns.isTypeConstructorForGivenClass(this, FQ_NAMES.nothing)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker {
|
||||
require(this is KotlinType, this::errorMessage)
|
||||
return this.asTypeProjection()
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* SingleClassifierType is one of the following types:
|
||||
* - classType
|
||||
* - type for type parameter
|
||||
* - captured type
|
||||
*
|
||||
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
|
||||
*/
|
||||
override fun SimpleTypeMarker.isSingleClassifierType(): Boolean {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return !isError &&
|
||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isNotNullNothing(): Boolean {
|
||||
require(this is KotlinType, this::errorMessage)
|
||||
return typeConstructor().isNothingConstructor() && !TypeUtils.isNullableType(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun Any.errorMessage(): String {
|
||||
return "ClassicTypeSystemContext couldn't handle: $this, ${this::class}"
|
||||
}
|
||||
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.CapturedTypeIM
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.model.CapturedTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.utils.DO_NOTHING_2
|
||||
@@ -110,12 +111,6 @@ fun captureFromArguments(
|
||||
return KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable)
|
||||
}
|
||||
|
||||
enum class CaptureStatus {
|
||||
FOR_SUBTYPING,
|
||||
FOR_INCORPORATION,
|
||||
FROM_EXPRESSION
|
||||
}
|
||||
|
||||
/**
|
||||
* Now [lowerType] is not null only for in projections.
|
||||
* Example: `Inv<in String>` For `in String` we create CapturedType with [lowerType] = String.
|
||||
@@ -130,7 +125,7 @@ class NewCapturedType(
|
||||
val lowerType: UnwrappedType?, // todo check lower type for nullable captured types
|
||||
override val annotations: Annotations = Annotations.EMPTY,
|
||||
override val isMarkedNullable: Boolean = false
|
||||
) : SimpleType(), CapturedTypeIM {
|
||||
) : SimpleType(), CapturedTypeMarker {
|
||||
internal constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
|
||||
this(captureStatus, NewCapturedTypeConstructor(projection), lowerType)
|
||||
|
||||
|
||||
@@ -16,121 +16,57 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isFinalClass
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorImpl
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.LowerCapturedTypePolicy.*
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SeveralSupertypesWithSameConstructorPolicy.*
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SupertypesPolicy
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasNotNullSupertype
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object StrictEqualityTypeChecker {
|
||||
|
||||
private val context = object : ClassicTypeSystemContext {}
|
||||
/**
|
||||
* String! != String & A<String!> != A<String>, also A<in Nothing> != A<out Any?>
|
||||
* also A<*> != A<out Any?>
|
||||
* different error types non-equals even errorTypeEqualToAnything
|
||||
*/
|
||||
fun strictEqualTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
|
||||
if (a === b) return true
|
||||
|
||||
if (a is SimpleType && b is SimpleType) return strictEqualTypes(a, b)
|
||||
if (a is FlexibleType && b is FlexibleType) {
|
||||
return strictEqualTypes(a.lowerBound, b.lowerBound) &&
|
||||
strictEqualTypes(a.upperBound, b.upperBound)
|
||||
}
|
||||
return false
|
||||
return AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (a.arguments === b.arguments) return true
|
||||
|
||||
for (i in a.arguments.indices) {
|
||||
val aArg = a.arguments[i]
|
||||
val bArg = b.arguments[i]
|
||||
if (aArg.isStarProjection != bArg.isStarProjection) return false
|
||||
|
||||
// both non-star
|
||||
if (!aArg.isStarProjection) {
|
||||
if (aArg.projectionKind != bArg.projectionKind) return false
|
||||
if (!strictEqualTypes(aArg.type.unwrap(), bArg.type.unwrap())) return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object ErrorTypesAreEqualToAnything : KotlinTypeChecker {
|
||||
override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean =
|
||||
NewKotlinTypeChecker.run { TypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) }
|
||||
NewKotlinTypeChecker.run { ClassicTypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) }
|
||||
|
||||
override fun equalTypes(a: KotlinType, b: KotlinType): Boolean =
|
||||
NewKotlinTypeChecker.run { TypeCheckerContext(true).equalTypes(a.unwrap(), b.unwrap()) }
|
||||
NewKotlinTypeChecker.run { ClassicTypeCheckerContext(true).equalTypes(a.unwrap(), b.unwrap()) }
|
||||
}
|
||||
|
||||
object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean =
|
||||
TypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
|
||||
ClassicTypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
|
||||
|
||||
override fun equalTypes(a: KotlinType, b: KotlinType): Boolean =
|
||||
TypeCheckerContext(false).equalTypes(a.unwrap(), b.unwrap())
|
||||
ClassicTypeCheckerContext(false).equalTypes(a.unwrap(), b.unwrap())
|
||||
|
||||
fun TypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
|
||||
if (a === b) return true
|
||||
|
||||
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
|
||||
if (!areEqualTypeConstructors(a.constructor, b.constructor)) return false
|
||||
if (a.arguments.isEmpty()) {
|
||||
if (a.hasFlexibleNullability() || b.hasFlexibleNullability()) return true
|
||||
|
||||
return a.isMarkedNullable == b.isMarkedNullable
|
||||
}
|
||||
}
|
||||
|
||||
return isSubtypeOf(a, b) && isSubtypeOf(b, a)
|
||||
fun ClassicTypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
|
||||
return AbstractTypeChecker.equalTypes(this, a, b)
|
||||
}
|
||||
|
||||
private fun KotlinType.hasFlexibleNullability() =
|
||||
lowerIfFlexible().isMarkedNullable != upperIfFlexible().isMarkedNullable
|
||||
|
||||
private fun isCommonDenotableType(type: KotlinType) =
|
||||
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
|
||||
val newSubType = transformToNewType(subType)
|
||||
val newSuperType = transformToNewType(superType)
|
||||
|
||||
checkSubtypeForSpecialCases(newSubType.lowerIfFlexible(), newSuperType.upperIfFlexible())?.let {
|
||||
addSubtypeConstraint(newSubType, newSuperType)
|
||||
return it
|
||||
}
|
||||
|
||||
// we should add constraints with flexible types, otherwise we never get flexible type as answer in constraint system
|
||||
addSubtypeConstraint(newSubType, newSuperType)?.let { return it }
|
||||
|
||||
return isSubtypeOfForSingleClassifierType(newSubType.lowerIfFlexible(), newSuperType.upperIfFlexible())
|
||||
fun ClassicTypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(this, subType, superType)
|
||||
}
|
||||
|
||||
fun transformToNewType(type: SimpleType): SimpleType {
|
||||
@@ -142,20 +78,36 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
|
||||
// it is incorrect calculate this type directly because of recursive star projections
|
||||
if (constructor.newTypeConstructor == null) {
|
||||
constructor.newTypeConstructor = NewCapturedTypeConstructor(constructor.projection, constructor.supertypes.map { it.unwrap() })
|
||||
constructor.newTypeConstructor =
|
||||
NewCapturedTypeConstructor(constructor.projection, constructor.supertypes.map { it.unwrap() })
|
||||
}
|
||||
return NewCapturedType(CaptureStatus.FOR_SUBTYPING, constructor.newTypeConstructor!!,
|
||||
lowerType, type.annotations, type.isMarkedNullable)
|
||||
return NewCapturedType(
|
||||
CaptureStatus.FOR_SUBTYPING, constructor.newTypeConstructor!!,
|
||||
lowerType, type.annotations, type.isMarkedNullable
|
||||
)
|
||||
}
|
||||
|
||||
is IntegerValueTypeConstructor -> {
|
||||
val newConstructor = IntersectionTypeConstructor(constructor.supertypes.map { TypeUtils.makeNullableAsSpecified(it, type.isMarkedNullable) })
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(type.annotations, newConstructor, listOf(), false, type.memberScope)
|
||||
val newConstructor =
|
||||
IntersectionTypeConstructor(constructor.supertypes.map { TypeUtils.makeNullableAsSpecified(it, type.isMarkedNullable) })
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
type.annotations,
|
||||
newConstructor,
|
||||
listOf(),
|
||||
false,
|
||||
type.memberScope
|
||||
)
|
||||
}
|
||||
|
||||
is IntersectionTypeConstructor -> if (type.isMarkedNullable) {
|
||||
val newConstructor = constructor.transformComponents(transform = { it.makeNullable() }) ?: constructor
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(type.annotations, newConstructor, listOf(), false, newConstructor.createScopeForKotlinType())
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
type.annotations,
|
||||
newConstructor,
|
||||
listOf(),
|
||||
false,
|
||||
newConstructor.createScopeForKotlinType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,188 +115,27 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
}
|
||||
|
||||
fun transformToNewType(type: UnwrappedType): UnwrappedType =
|
||||
when (type) {
|
||||
is SimpleType -> transformToNewType(type)
|
||||
is FlexibleType -> {
|
||||
val newLower = transformToNewType(type.lowerBound)
|
||||
val newUpper = transformToNewType(type.upperBound)
|
||||
if (newLower !== type.lowerBound || newUpper !== type.upperBound) {
|
||||
KotlinTypeFactory.flexibleType(newLower, newUpper)
|
||||
}
|
||||
else {
|
||||
type
|
||||
}
|
||||
when (type) {
|
||||
is SimpleType -> transformToNewType(type)
|
||||
is FlexibleType -> {
|
||||
val newLower = transformToNewType(type.lowerBound)
|
||||
val newUpper = transformToNewType(type.upperBound)
|
||||
if (newLower !== type.lowerBound || newUpper !== type.upperBound) {
|
||||
KotlinTypeFactory.flexibleType(newLower, newUpper)
|
||||
} else {
|
||||
type
|
||||
}
|
||||
}.inheritEnhancement(type)
|
||||
|
||||
private fun TypeCheckerContext.checkSubtypeForSpecialCases(subType: SimpleType, superType: SimpleType): Boolean? {
|
||||
if (subType.isError || superType.isError) {
|
||||
if (errorTypeEqualsToAnything) return true
|
||||
|
||||
if (subType.isMarkedNullable && !superType.isMarkedNullable) return false
|
||||
|
||||
return StrictEqualityTypeChecker.strictEqualTypes(subType.makeNullableAsSpecified(false), superType.makeNullableAsSpecified(false))
|
||||
}
|
||||
|
||||
if (subType is StubType || superType is StubType) return true
|
||||
|
||||
if (superType is NewCapturedType && superType.lowerType != null) {
|
||||
when (getLowerCapturedTypePolicy(subType, superType)) {
|
||||
CHECK_ONLY_LOWER -> return isSubtypeOf(subType, superType.lowerType)
|
||||
CHECK_SUBTYPE_AND_LOWER -> if(isSubtypeOf(subType, superType.lowerType)) return true
|
||||
SKIP_LOWER -> { /*do nothing*/ }
|
||||
}
|
||||
}
|
||||
}.inheritEnhancement(type)
|
||||
|
||||
(superType.constructor as? IntersectionTypeConstructor)?.let {
|
||||
assert(!superType.isMarkedNullable) { "Intersection type should not be marked nullable!: $superType" }
|
||||
return it.supertypes.all { isSubtypeOf(subType, it.unwrap()) }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.hasNothingSupertype(type: SimpleType) = // todo add tests
|
||||
anySupertype(type, KotlinBuiltIns::isNothingOrNullableNothing) {
|
||||
if (it.isClassType) {
|
||||
SupertypesPolicy.None
|
||||
}
|
||||
else {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.isSubtypeOfForSingleClassifierType(subType: SimpleType, superType: SimpleType): Boolean {
|
||||
assert(subType.isSingleClassifierType || subType.isIntersectionType || subType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType || superType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
|
||||
if (!NullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
|
||||
|
||||
val superConstructor = superType.constructor
|
||||
|
||||
if (subType.constructor == superConstructor && superConstructor.parameters.isEmpty()) return true
|
||||
if (superType.isAnyOrNullableAny()) return true
|
||||
|
||||
val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor)
|
||||
when (supertypesWithSameConstructor.size) {
|
||||
0 -> return hasNothingSupertype(subType) // todo Nothing & Array<Number> <: Array<String>
|
||||
1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType)
|
||||
|
||||
else -> { // at least 2 supertypes with same constructors. Such case is rare
|
||||
when (sameConstructorPolicy) {
|
||||
FORCE_NOT_SUBTYPE -> return false
|
||||
TAKE_FIRST_FOR_SUBTYPING -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().arguments, superType)
|
||||
|
||||
CHECK_ANY_OF_THEM,
|
||||
INTERSECT_ARGUMENTS_AND_CHECK_AGAIN ->
|
||||
if (supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.arguments, superType) }) return true
|
||||
}
|
||||
|
||||
if (sameConstructorPolicy != INTERSECT_ARGUMENTS_AND_CHECK_AGAIN) return false
|
||||
|
||||
val newArguments = superConstructor.parameters.mapIndexed { index, _ ->
|
||||
val allProjections = supertypesWithSameConstructor.map {
|
||||
it.arguments.getOrNull(index)?.takeIf { it.projectionKind == Variance.INVARIANT }?.type?.unwrap()
|
||||
?: error("Incorrect type: $it, subType: $subType, superType: $superType")
|
||||
}
|
||||
|
||||
// todo discuss
|
||||
intersectTypes(allProjections).asTypeProjection()
|
||||
}
|
||||
|
||||
return isSubtypeForSameConstructor(newArguments, superType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.collectAndFilter(classType: SimpleType, constructor: TypeConstructor) =
|
||||
selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor))
|
||||
|
||||
// nullability was checked earlier via nullabilityChecker
|
||||
// should be used only if you really sure that it is correct
|
||||
fun TypeCheckerContext.findCorrespondingSupertypes(
|
||||
baseType: SimpleType,
|
||||
constructor: TypeConstructor
|
||||
fun ClassicTypeCheckerContext.findCorrespondingSupertypes(
|
||||
baseType: SimpleType,
|
||||
constructor: TypeConstructor
|
||||
): List<SimpleType> {
|
||||
if (baseType.isClassType) {
|
||||
return collectAndFilter(baseType, constructor)
|
||||
return AbstractTypeChecker.run {
|
||||
findCorrespondingSupertypes(baseType, constructor) as List<SimpleType>
|
||||
}
|
||||
|
||||
// i.e. superType is not a classType
|
||||
if (constructor.declarationDescriptor !is ClassDescriptor) {
|
||||
return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor)
|
||||
}
|
||||
|
||||
// todo add tests
|
||||
val classTypeSupertypes = SmartList<SimpleType>()
|
||||
anySupertype(baseType, { false }) {
|
||||
if (it.isClassType) {
|
||||
classTypeSupertypes.add(it)
|
||||
SupertypesPolicy.None
|
||||
}
|
||||
else {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
}
|
||||
|
||||
return classTypeSupertypes.flatMap { collectAndFilter(it, constructor) }
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor(
|
||||
baseType: SimpleType,
|
||||
constructor: TypeConstructor
|
||||
): List<SimpleType> {
|
||||
if (constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.isCommonFinalClass == true) {
|
||||
return if (areEqualTypeConstructors(baseType.constructor, constructor))
|
||||
listOf(captureFromArguments(baseType, CaptureStatus.FOR_SUBTYPING) ?: baseType)
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val result: MutableList<SimpleType> = SmartList()
|
||||
|
||||
anySupertype(baseType, { false }) {
|
||||
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
|
||||
|
||||
when {
|
||||
areEqualTypeConstructors(current.constructor, constructor) -> {
|
||||
result.add(current)
|
||||
SupertypesPolicy.None
|
||||
}
|
||||
current.arguments.isEmpty() -> {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
else -> {
|
||||
SupertypesPolicy.LowerIfFlexibleWithCustomSubstitutor(TypeConstructorSubstitution.create(current).buildSubstitutor())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private val ClassDescriptor.isCommonFinalClass: Boolean
|
||||
get() = isFinalClass && kind != ClassKind.ENUM_ENTRY && kind != ClassKind.ANNOTATION_CLASS
|
||||
|
||||
/**
|
||||
* If we have several paths to some interface, we should prefer pure kotlin path.
|
||||
* Example:
|
||||
*
|
||||
* class MyList : AbstractList<String>(), MutableList<String>
|
||||
*
|
||||
* We should see `String` in `get` function and others, also MyList is not subtype of MutableList<String?>
|
||||
*
|
||||
* More tests: javaAndKotlinSuperType & purelyImplementedCollection folder
|
||||
*/
|
||||
private fun selectOnlyPureKotlinSupertypes(supertypes: List<SimpleType>): List<SimpleType> {
|
||||
if (supertypes.size < 2) return supertypes
|
||||
|
||||
val allPureSupertypes = supertypes.filter { it.arguments.all { !it.type.isFlexible() } }
|
||||
return if (allPureSupertypes.isNotEmpty()) allPureSupertypes else supertypes
|
||||
}
|
||||
|
||||
fun effectiveVariance(declared: Variance, useSite: Variance): Variance? {
|
||||
@@ -358,112 +149,28 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.isSubtypeForSameConstructor(
|
||||
capturedSubArguments: List<TypeProjection>,
|
||||
superType: SimpleType
|
||||
): Boolean {
|
||||
|
||||
if (capturedSubArguments === superType.arguments) return true
|
||||
|
||||
val parameters = superType.constructor.parameters
|
||||
|
||||
for (index in parameters.indices) {
|
||||
val superProjection = superType.arguments[index] // todo error index
|
||||
if (superProjection.isStarProjection) continue // A<B> <: A<*>
|
||||
|
||||
val superArgumentType = superProjection.type.unwrap()
|
||||
val subArgumentType = capturedSubArguments[index].let {
|
||||
assert(it.projectionKind == Variance.INVARIANT) { "Incorrect sub argument: $it" }
|
||||
it.type.unwrap()
|
||||
}
|
||||
|
||||
val variance = effectiveVariance(parameters[index].variance, superProjection.projectionKind)
|
||||
?: return errorTypeEqualsToAnything // todo exception?
|
||||
|
||||
val correctArgument = runWithArgumentsSettings(subArgumentType) {
|
||||
when (variance) {
|
||||
Variance.INVARIANT -> equalTypes(subArgumentType, superArgumentType)
|
||||
Variance.OUT_VARIANCE -> isSubtypeOf(subArgumentType, superArgumentType)
|
||||
Variance.IN_VARIANCE -> isSubtypeOf(superArgumentType, subArgumentType)
|
||||
}
|
||||
}
|
||||
if (!correctArgument) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object NullabilityChecker {
|
||||
|
||||
// this method checks only nullability
|
||||
fun isPossibleSubtype(context: TypeCheckerContext, subType: SimpleType, superType: SimpleType): Boolean =
|
||||
context.runIsPossibleSubtype(subType, superType)
|
||||
|
||||
fun isSubtypeOfAny(type: UnwrappedType): Boolean =
|
||||
TypeCheckerContext(false).hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
|
||||
ClassicTypeCheckerContext(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) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType || superType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
|
||||
// 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 and are not definitely not null.
|
||||
|
||||
/**
|
||||
* If we still don't know, it means, that superType is not classType, for example -- type parameter.
|
||||
*
|
||||
* For captured types with lower bound this function can give to you false result. Example:
|
||||
* class A<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
|
||||
* isPossibleSubtype(Number, Q) = false.
|
||||
* Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types)
|
||||
*/
|
||||
|
||||
// classType cannot has special type in supertype list
|
||||
if (subType.isClassType) return false
|
||||
|
||||
return hasPathByNotMarkedNullableNodes(subType, superType.constructor)
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.hasNotNullSupertype(type: SimpleType, supertypesPolicy: SupertypesPolicy) =
|
||||
anySupertype(type, { (it.isClassType && !it.isMarkedNullable) || it.isDefinitelyNotNullType }) {
|
||||
if (it.isMarkedNullable) SupertypesPolicy.None else supertypesPolicy
|
||||
}
|
||||
|
||||
private fun TypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleType, end: TypeConstructor) =
|
||||
anySupertype(start, { it.isNothing() || (!it.isMarkedNullable && it.constructor == end) }) {
|
||||
if (it.isMarkedNullable) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
|
||||
ClassicTypeCheckerContext(false).hasPathByNotMarkedNullableNodes(start, end)
|
||||
}
|
||||
|
||||
fun UnwrappedType.hasSupertypeWithGivenTypeConstructor(typeConstructor: TypeConstructor) =
|
||||
TypeCheckerContext(false).anySupertype(lowerIfFlexible(), { it.constructor == typeConstructor }, { SupertypesPolicy.LowerIfFlexible })
|
||||
ClassicTypeCheckerContext(false).anySupertype(lowerIfFlexible(), {
|
||||
require(it is SimpleType)
|
||||
it.constructor == typeConstructor
|
||||
}, { SupertypesPolicy.LowerIfFlexible })
|
||||
|
||||
fun UnwrappedType.anySuperTypeConstructor(predicate: (TypeConstructor) -> Boolean) =
|
||||
TypeCheckerContext(false).anySupertype(lowerIfFlexible(), { predicate(it.constructor) }, { SupertypesPolicy.LowerIfFlexible })
|
||||
ClassicTypeCheckerContext(false).anySupertype(lowerIfFlexible(), {
|
||||
require(it is SimpleType)
|
||||
predicate(it.constructor)
|
||||
}, { SupertypesPolicy.LowerIfFlexible })
|
||||
|
||||
/**
|
||||
* ClassType means that type constructor for this type is type for real class or interface
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import java.util.*
|
||||
|
||||
open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowedTypeVariable: Boolean = true) {
|
||||
protected var argumentsDepth = 0
|
||||
|
||||
private var supertypesLocked = false
|
||||
private var supertypesDeque: ArrayDeque<SimpleType>? = null
|
||||
private var supertypesSet: MutableSet<SimpleType>? = null
|
||||
|
||||
open fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? = null
|
||||
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return a == b
|
||||
}
|
||||
|
||||
open fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER
|
||||
open val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
|
||||
|
||||
internal inline fun <T> runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T {
|
||||
if (argumentsDepth > 100) {
|
||||
error("Arguments depth is too high. Some related argument: $subArgument")
|
||||
}
|
||||
|
||||
argumentsDepth++
|
||||
val result = f()
|
||||
argumentsDepth--
|
||||
return result
|
||||
}
|
||||
|
||||
private fun initialize() {
|
||||
assert(!supertypesLocked)
|
||||
supertypesLocked = true
|
||||
|
||||
if (supertypesDeque == null) {
|
||||
supertypesDeque = ArrayDeque(4)
|
||||
}
|
||||
if (supertypesSet == null) {
|
||||
supertypesSet = SmartSet.create()
|
||||
}
|
||||
}
|
||||
|
||||
private fun clear() {
|
||||
supertypesDeque!!.clear()
|
||||
supertypesSet!!.clear()
|
||||
supertypesLocked = false
|
||||
}
|
||||
|
||||
internal inline fun anySupertype(
|
||||
start: SimpleType,
|
||||
predicate: (SimpleType) -> Boolean,
|
||||
supertypesPolicy: (SimpleType) -> SupertypesPolicy
|
||||
): Boolean {
|
||||
if (predicate(start)) return true
|
||||
|
||||
initialize()
|
||||
|
||||
val deque = supertypesDeque!!
|
||||
val visitedSupertypes = supertypesSet!!
|
||||
|
||||
deque.push(start)
|
||||
while (deque.isNotEmpty()) {
|
||||
if (visitedSupertypes.size > 1000) {
|
||||
error("Too many supertypes for type: $start. Supertypes = ${visitedSupertypes.joinToString()}")
|
||||
}
|
||||
val current = deque.pop()
|
||||
if (!visitedSupertypes.add(current)) continue
|
||||
|
||||
val policy = supertypesPolicy(current).takeIf { it != SupertypesPolicy.None } ?: continue
|
||||
for (supertype in current.constructor.supertypes) {
|
||||
val newType = policy.transformType(supertype)
|
||||
if (predicate(newType)) {
|
||||
clear()
|
||||
return true
|
||||
}
|
||||
deque.add(newType)
|
||||
}
|
||||
}
|
||||
|
||||
clear()
|
||||
return false
|
||||
}
|
||||
|
||||
internal sealed class SupertypesPolicy {
|
||||
abstract fun transformType(type: KotlinType): SimpleType
|
||||
|
||||
object None : SupertypesPolicy() {
|
||||
override fun transformType(type: KotlinType) = throw UnsupportedOperationException("Should not be called")
|
||||
}
|
||||
|
||||
object UpperIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(type: KotlinType) = type.upperIfFlexible()
|
||||
}
|
||||
|
||||
object LowerIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(type: KotlinType) = type.lowerIfFlexible()
|
||||
}
|
||||
|
||||
class LowerIfFlexibleWithCustomSubstitutor(val substitutor: TypeSubstitutor): SupertypesPolicy() {
|
||||
override fun transformType(type: KotlinType) =
|
||||
substitutor.safeSubstitute(type.lowerIfFlexible(), Variance.INVARIANT).asSimpleType()
|
||||
}
|
||||
}
|
||||
|
||||
enum class SeveralSupertypesWithSameConstructorPolicy {
|
||||
TAKE_FIRST_FOR_SUBTYPING,
|
||||
FORCE_NOT_SUBTYPE,
|
||||
CHECK_ANY_OF_THEM,
|
||||
INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
|
||||
}
|
||||
|
||||
enum class LowerCapturedTypePolicy {
|
||||
CHECK_ONLY_LOWER,
|
||||
CHECK_SUBTYPE_AND_LOWER,
|
||||
SKIP_LOWER
|
||||
}
|
||||
|
||||
val UnwrappedType.isAllowedTypeVariable: Boolean get() = allowedTypeVariable && constructor is NewTypeVariableConstructor
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
||||
import org.jetbrains.kotlin.types.model.DynamicTypeIM
|
||||
import org.jetbrains.kotlin.types.model.DynamicTypeMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
open class DynamicTypesSettings {
|
||||
@@ -40,7 +40,7 @@ fun createDynamicType(builtIns: KotlinBuiltIns) = DynamicType(builtIns, Annotati
|
||||
class DynamicType(
|
||||
builtIns: KotlinBuiltIns,
|
||||
override val annotations: Annotations
|
||||
) : FlexibleType(builtIns.nothingType, builtIns.nullableAnyType), DynamicTypeIM {
|
||||
) : FlexibleType(builtIns.nothingType, builtIns.nullableAnyType), DynamicTypeMarker {
|
||||
override val delegate: SimpleType get() = upperBound
|
||||
|
||||
// Nullability has no effect on dynamics
|
||||
|
||||
+7
-7
@@ -5,12 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeIM
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeIM
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
||||
|
||||
object AbstractStrictEqualityTypeChecker {
|
||||
fun strictEqualTypes(context: TypeSystemContext, a: KotlinTypeIM, b: KotlinTypeIM) = context.strictEqualTypesInternal(a, b)
|
||||
fun strictEqualTypes(context: TypeSystemContext, a: KotlinTypeMarker, b: KotlinTypeMarker) = context.strictEqualTypesInternal(a, b)
|
||||
|
||||
/**
|
||||
* Note that:
|
||||
@@ -21,7 +21,7 @@ object AbstractStrictEqualityTypeChecker {
|
||||
*
|
||||
* Also different error types are not equal even if errorTypeEqualToAnything is true
|
||||
*/
|
||||
private fun TypeSystemContext.strictEqualTypesInternal(a: KotlinTypeIM, b: KotlinTypeIM): Boolean {
|
||||
private fun TypeSystemContext.strictEqualTypesInternal(a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean {
|
||||
if (a === b) return true
|
||||
|
||||
val simpleA = a.asSimpleType()
|
||||
@@ -37,11 +37,11 @@ object AbstractStrictEqualityTypeChecker {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun TypeSystemContext.strictEqualSimpleTypes(a: SimpleTypeIM, b: SimpleTypeIM): Boolean {
|
||||
if (a.isMarkedNullable() != b.isMarkedNullable()
|
||||
private fun TypeSystemContext.strictEqualSimpleTypes(a: SimpleTypeMarker, b: SimpleTypeMarker): Boolean {
|
||||
if (a.argumentsCount() != b.argumentsCount()
|
||||
|| a.isMarkedNullable() != b.isMarkedNullable()
|
||||
|| (a.asDefinitelyNotNullType() == null) != (b.asDefinitelyNotNullType() == null)
|
||||
|| !isEqualTypeConstructors(a.typeConstructor(), b.typeConstructor())
|
||||
|| a.argumentsCount() != b.argumentsCount()
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,3 +5,486 @@
|
||||
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.LowerCapturedTypePolicy.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SeveralSupertypesWithSameConstructorPolicy
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import java.util.*
|
||||
|
||||
|
||||
abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
|
||||
|
||||
abstract fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform
|
||||
|
||||
abstract fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean
|
||||
|
||||
abstract fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker
|
||||
|
||||
open fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return type
|
||||
}
|
||||
|
||||
abstract val isErrorTypeEqualsToAnything: Boolean
|
||||
|
||||
protected var argumentsDepth = 0
|
||||
|
||||
|
||||
internal inline fun <T> runWithArgumentsSettings(subArgument: KotlinTypeMarker, f: AbstractTypeCheckerContext.() -> T): T {
|
||||
if (argumentsDepth > 100) {
|
||||
error("Arguments depth is too high. Some related argument: $subArgument")
|
||||
}
|
||||
|
||||
argumentsDepth++
|
||||
val result = f()
|
||||
argumentsDepth--
|
||||
return result
|
||||
}
|
||||
|
||||
open fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = CHECK_SUBTYPE_AND_LOWER
|
||||
open fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? = null
|
||||
open val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
|
||||
|
||||
enum class SeveralSupertypesWithSameConstructorPolicy {
|
||||
TAKE_FIRST_FOR_SUBTYPING,
|
||||
FORCE_NOT_SUBTYPE,
|
||||
CHECK_ANY_OF_THEM,
|
||||
INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
|
||||
}
|
||||
|
||||
enum class LowerCapturedTypePolicy {
|
||||
CHECK_ONLY_LOWER,
|
||||
CHECK_SUBTYPE_AND_LOWER,
|
||||
SKIP_LOWER
|
||||
}
|
||||
|
||||
private var supertypesLocked = false
|
||||
|
||||
var supertypesDeque: ArrayDeque<SimpleTypeMarker>? = null
|
||||
private set
|
||||
var supertypesSet: MutableSet<SimpleTypeMarker>? = null
|
||||
private set
|
||||
|
||||
|
||||
fun initialize() {
|
||||
assert(!supertypesLocked)
|
||||
supertypesLocked = true
|
||||
|
||||
if (supertypesDeque == null) {
|
||||
supertypesDeque = ArrayDeque(4)
|
||||
}
|
||||
if (supertypesSet == null) {
|
||||
supertypesSet = SmartSet.create()
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
supertypesDeque!!.clear()
|
||||
supertypesSet!!.clear()
|
||||
supertypesLocked = false
|
||||
}
|
||||
|
||||
inline fun anySupertype(
|
||||
start: SimpleTypeMarker,
|
||||
predicate: (SimpleTypeMarker) -> Boolean,
|
||||
supertypesPolicy: (SimpleTypeMarker) -> SupertypesPolicy
|
||||
): Boolean {
|
||||
if (predicate(start)) return true
|
||||
|
||||
initialize()
|
||||
|
||||
val deque = supertypesDeque!!
|
||||
val visitedSupertypes = supertypesSet!!
|
||||
|
||||
deque.push(start)
|
||||
while (deque.isNotEmpty()) {
|
||||
if (visitedSupertypes.size > 1000) {
|
||||
error("Too many supertypes for type: $start. Supertypes = ${visitedSupertypes.joinToString()}")
|
||||
}
|
||||
val current = deque.pop()
|
||||
if (!visitedSupertypes.add(current)) continue
|
||||
|
||||
val policy = supertypesPolicy(current).takeIf { it != SupertypesPolicy.None } ?: continue
|
||||
for (supertype in current.typeConstructor().supertypes()) {
|
||||
val newType = policy.transformType(this, supertype)
|
||||
if (predicate(newType)) {
|
||||
clear()
|
||||
return true
|
||||
}
|
||||
deque.add(newType)
|
||||
}
|
||||
}
|
||||
|
||||
clear()
|
||||
return false
|
||||
}
|
||||
|
||||
sealed class SupertypesPolicy {
|
||||
abstract fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker
|
||||
|
||||
object None : SupertypesPolicy() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
|
||||
throw UnsupportedOperationException("Should not be called")
|
||||
}
|
||||
|
||||
object UpperIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
|
||||
with(context) { type.upperBoundIfFlexible() }
|
||||
}
|
||||
|
||||
object LowerIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
|
||||
with(context) { type.lowerBoundIfFlexible() }
|
||||
}
|
||||
|
||||
abstract class DoCustomTransform : SupertypesPolicy()
|
||||
}
|
||||
|
||||
abstract val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||
}
|
||||
|
||||
object AbstractTypeChecker {
|
||||
fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
|
||||
if (subType === superType) return true
|
||||
return context.completeIsSubTypeOf(context.prepareType(subType), context.prepareType(superType))
|
||||
}
|
||||
|
||||
fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = with(context) {
|
||||
if (a === b) return true
|
||||
|
||||
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
|
||||
val simpleA = a.lowerBoundIfFlexible()
|
||||
if (!areEqualTypeConstructors(a.typeConstructor(), b.typeConstructor())) return false
|
||||
if (simpleA.argumentsCount() == 0) {
|
||||
if (a.hasFlexibleNullability() || b.hasFlexibleNullability()) return true
|
||||
|
||||
return simpleA.isMarkedNullable() == b.lowerBoundIfFlexible().isMarkedNullable()
|
||||
}
|
||||
}
|
||||
|
||||
return isSubtypeOf(context, a, b) && isSubtypeOf(context, b, a)
|
||||
}
|
||||
|
||||
|
||||
private fun AbstractTypeCheckerContext.completeIsSubTypeOf(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
|
||||
checkSubtypeForSpecialCases(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
addSubtypeConstraint(subType, superType)
|
||||
return it
|
||||
}
|
||||
|
||||
// we should add constraints with flexible types, otherwise we never get flexible type as answer in constraint system
|
||||
addSubtypeConstraint(subType, superType)?.let { return it }
|
||||
|
||||
return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker) = // todo add tests
|
||||
anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
|
||||
if (it.isClassType()) {
|
||||
SupertypesPolicy.None
|
||||
} else {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.isSubtypeOfForSingleClassifierType(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean {
|
||||
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
|
||||
if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
|
||||
|
||||
val superConstructor = superType.typeConstructor()
|
||||
|
||||
if (isEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
|
||||
if (superType.typeConstructor().isAnyConstructor()) return true
|
||||
|
||||
val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor)
|
||||
when (supertypesWithSameConstructor.size) {
|
||||
0 -> return hasNothingSupertype(subType) // todo Nothing & Array<Number> <: Array<String>
|
||||
1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType)
|
||||
|
||||
else -> { // at least 2 supertypes with same constructors. Such case is rare
|
||||
when (sameConstructorPolicy) {
|
||||
SeveralSupertypesWithSameConstructorPolicy.FORCE_NOT_SUBTYPE -> return false
|
||||
SeveralSupertypesWithSameConstructorPolicy.TAKE_FIRST_FOR_SUBTYPING -> return isSubtypeForSameConstructor(
|
||||
supertypesWithSameConstructor.first().asArgumentList(),
|
||||
superType
|
||||
)
|
||||
|
||||
SeveralSupertypesWithSameConstructorPolicy.CHECK_ANY_OF_THEM,
|
||||
SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN ->
|
||||
if (supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.asArgumentList(), superType) }) return true
|
||||
}
|
||||
|
||||
if (sameConstructorPolicy != SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN) return false
|
||||
|
||||
|
||||
val newArguments = ArgumentList(superConstructor.parametersCount())
|
||||
for (index in 0 until superConstructor.parametersCount()) {
|
||||
val allProjections = supertypesWithSameConstructor.map {
|
||||
it.getArgumentOrNull(index)?.takeIf { it.getVariance() == TypeVariance.INV }?.getType()
|
||||
?: error("Incorrect type: $it, subType: $subType, superType: $superType")
|
||||
}
|
||||
|
||||
// todo discuss
|
||||
val intersection = intersectTypes(allProjections).asTypeArgument()
|
||||
newArguments.add(intersection)
|
||||
}
|
||||
|
||||
return isSubtypeForSameConstructor(newArguments, superType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun AbstractTypeCheckerContext.isSubtypeForSameConstructor(
|
||||
capturedSubArguments: TypeArgumentListMarker,
|
||||
superType: SimpleTypeMarker
|
||||
): Boolean {
|
||||
// No way to check, as no index sometimes
|
||||
//if (capturedSubArguments === superType.arguments) return true
|
||||
|
||||
//val parameters = superType.constructor.parameters
|
||||
val superTypeConstructor = superType.typeConstructor()
|
||||
for (index in 0 until superTypeConstructor.parametersCount()) {
|
||||
val superProjection = superType.getArgument(index) // todo error index
|
||||
if (superProjection.isStarProjection()) continue // A<B> <: A<*>
|
||||
|
||||
val superArgumentType = superProjection.getType()
|
||||
val subArgumentType = capturedSubArguments[index].let {
|
||||
assert(it.getVariance() == TypeVariance.INV) { "Incorrect sub argument: $it" }
|
||||
it.getType()
|
||||
}
|
||||
|
||||
val variance = effectiveVariance(superTypeConstructor.getParameter(index).getVariance(), superProjection.getVariance())
|
||||
?: return isErrorTypeEqualsToAnything // todo exception?
|
||||
|
||||
val correctArgument = runWithArgumentsSettings(subArgumentType) {
|
||||
when (variance) {
|
||||
TypeVariance.INV -> equalTypes(this, subArgumentType, superArgumentType)
|
||||
TypeVariance.OUT -> isSubtypeOf(this, subArgumentType, superArgumentType)
|
||||
TypeVariance.IN -> isSubtypeOf(this, superArgumentType, subArgumentType)
|
||||
}
|
||||
}
|
||||
if (!correctArgument) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean =
|
||||
type.typeConstructor().isDenotable() &&
|
||||
!type.isDynamic() && !type.isDefinitelyNotNullType() &&
|
||||
type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor()
|
||||
|
||||
private fun effectiveVariance(declared: TypeVariance, useSite: TypeVariance): TypeVariance? {
|
||||
if (declared == TypeVariance.INV) return useSite
|
||||
if (useSite == TypeVariance.INV) return declared
|
||||
|
||||
// both not INVARIANT
|
||||
if (declared == useSite) return declared
|
||||
|
||||
// composite In with Out
|
||||
return null
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.checkSubtypeForSpecialCases(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean? {
|
||||
if (subType.isError() || superType.isError()) {
|
||||
if (isErrorTypeEqualsToAnything) return true
|
||||
|
||||
if (subType.isMarkedNullable() && !superType.isMarkedNullable()) return false
|
||||
|
||||
return AbstractStrictEqualityTypeChecker.strictEqualTypes(
|
||||
this,
|
||||
subType.withNullability(false),
|
||||
superType.withNullability(false)
|
||||
)
|
||||
}
|
||||
|
||||
if (subType.isStubType() || superType.isStubType()) return true
|
||||
|
||||
val superTypeCaptured = superType.asCapturedType()
|
||||
val lowerType = superTypeCaptured?.lowerType()
|
||||
if (superTypeCaptured != null && lowerType != null) {
|
||||
when (getLowerCapturedTypePolicy(subType, superTypeCaptured)) {
|
||||
CHECK_ONLY_LOWER -> return isSubtypeOf(this, subType, lowerType)
|
||||
CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(this, subType, lowerType)) return true
|
||||
SKIP_LOWER -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
val superTypeConstructor = superType.typeConstructor()
|
||||
if (superTypeConstructor.isIntersection()) {
|
||||
assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" }
|
||||
|
||||
return superTypeConstructor.supertypes().all { isSubtypeOf(this, subType, it) }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private inline fun TypeArgumentListMarker.all(
|
||||
context: AbstractTypeCheckerContext,
|
||||
crossinline predicate: (TypeArgumentMarker) -> Boolean
|
||||
): Boolean = with(context) {
|
||||
repeat(size()) { index ->
|
||||
if (!predicate(get(index))) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private fun AbstractTypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor(
|
||||
baseType: SimpleTypeMarker,
|
||||
constructor: TypeConstructorMarker
|
||||
): List<SimpleTypeMarker> {
|
||||
if (constructor.isCommonFinalClassConstructor()) {
|
||||
return if (areEqualTypeConstructors(baseType.typeConstructor(), constructor))
|
||||
listOf(captureFromArguments(baseType, CaptureStatus.FOR_SUBTYPING) ?: baseType)
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val result: MutableList<SimpleTypeMarker> = SmartList()
|
||||
|
||||
anySupertype(baseType, { false }) {
|
||||
|
||||
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
|
||||
|
||||
when {
|
||||
areEqualTypeConstructors(current.typeConstructor(), constructor) -> {
|
||||
result.add(current)
|
||||
SupertypesPolicy.None
|
||||
}
|
||||
current.argumentsCount() == 0 -> {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
else -> {
|
||||
substitutionSupertypePolicy(current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.collectAndFilter(classType: SimpleTypeMarker, constructor: TypeConstructorMarker) =
|
||||
selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor))
|
||||
|
||||
|
||||
/**
|
||||
* If we have several paths to some interface, we should prefer pure kotlin path.
|
||||
* Example:
|
||||
*
|
||||
* class MyList : AbstractList<String>(), MutableList<String>
|
||||
*
|
||||
* We should see `String` in `get` function and others, also MyList is not subtype of MutableList<String?>
|
||||
*
|
||||
* More tests: javaAndKotlinSuperType & purelyImplementedCollection folder
|
||||
*/
|
||||
private fun AbstractTypeCheckerContext.selectOnlyPureKotlinSupertypes(supertypes: List<SimpleTypeMarker>): List<SimpleTypeMarker> {
|
||||
if (supertypes.size < 2) return supertypes
|
||||
|
||||
val allPureSupertypes = supertypes.filter {
|
||||
it.asArgumentList().all(this) { it.getType().asFlexibleType() == null }
|
||||
}
|
||||
return if (allPureSupertypes.isNotEmpty()) allPureSupertypes else supertypes
|
||||
}
|
||||
|
||||
|
||||
// nullability was checked earlier via nullabilityChecker
|
||||
// should be used only if you really sure that it is correct
|
||||
fun AbstractTypeCheckerContext.findCorrespondingSupertypes(
|
||||
baseType: SimpleTypeMarker,
|
||||
constructor: TypeConstructorMarker
|
||||
): List<SimpleTypeMarker> {
|
||||
if (baseType.isClassType()) {
|
||||
return collectAndFilter(baseType, constructor)
|
||||
}
|
||||
|
||||
// i.e. superType is not a classType
|
||||
if (!constructor.isClassTypeConstructor()) {
|
||||
return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor)
|
||||
}
|
||||
|
||||
// todo add tests
|
||||
val classTypeSupertypes = SmartList<SimpleTypeMarker>()
|
||||
anySupertype(baseType, { false }) {
|
||||
if (it.isClassType()) {
|
||||
classTypeSupertypes.add(it)
|
||||
SupertypesPolicy.None
|
||||
} else {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
}
|
||||
|
||||
return classTypeSupertypes.flatMap { collectAndFilter(it, constructor) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object AbstractNullabilityChecker {
|
||||
// this method checks only nullability
|
||||
fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
|
||||
context.runIsPossibleSubtype(subType, superType)
|
||||
|
||||
private fun AbstractTypeCheckerContext.runIsPossibleSubtype(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean {
|
||||
// it makes for case String? & Any <: String
|
||||
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
|
||||
// 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 and are not definitely not null.
|
||||
|
||||
/**
|
||||
* If we still don't know, it means, that superType is not classType, for example -- type parameter.
|
||||
*
|
||||
* For captured types with lower bound this function can give to you false result. Example:
|
||||
* class A<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
|
||||
* isPossibleSubtype(Number, Q) = false.
|
||||
* Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types)
|
||||
*/
|
||||
|
||||
// classType cannot has special type in supertype list
|
||||
if (subType.isClassType()) return false
|
||||
|
||||
return hasPathByNotMarkedNullableNodes(subType, superType.typeConstructor())
|
||||
}
|
||||
|
||||
fun AbstractTypeCheckerContext.hasNotNullSupertype(type: SimpleTypeMarker, supertypesPolicy: SupertypesPolicy) =
|
||||
anySupertype(type, {
|
||||
(it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType()
|
||||
}) {
|
||||
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy
|
||||
}
|
||||
|
||||
fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
|
||||
anySupertype(start, {
|
||||
it.isNotNullNothing() || (!it.isMarkedNullable() && isEqualTypeConstructors(it.typeConstructor(), end))
|
||||
}) {
|
||||
if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.model
|
||||
|
||||
interface KotlinTypeIM
|
||||
interface TypeArgumentIM
|
||||
interface TypeConstructorIM
|
||||
interface TypeParameterIM
|
||||
interface KotlinTypeMarker
|
||||
interface TypeArgumentMarker
|
||||
interface TypeConstructorMarker
|
||||
interface TypeParameterMarker
|
||||
|
||||
interface SimpleTypeIM : KotlinTypeIM
|
||||
interface CapturedTypeIM : SimpleTypeIM
|
||||
interface DefinitelyNotNullTypeIM : SimpleTypeIM
|
||||
interface SimpleTypeMarker : KotlinTypeMarker
|
||||
interface CapturedTypeMarker : SimpleTypeMarker
|
||||
interface DefinitelyNotNullTypeMarker : SimpleTypeMarker
|
||||
|
||||
interface FlexibleTypeIM : KotlinTypeIM
|
||||
interface DynamicTypeIM : FlexibleTypeIM
|
||||
interface RawTypeIM : FlexibleTypeIM
|
||||
interface FlexibleTypeMarker : KotlinTypeMarker
|
||||
interface DynamicTypeMarker : FlexibleTypeMarker
|
||||
interface RawTypeMarker : FlexibleTypeMarker
|
||||
|
||||
interface TypeArgumentListMarker
|
||||
|
||||
|
||||
enum class TypeVariance {
|
||||
@@ -30,41 +32,110 @@ interface TypeSystemOptimizationContext {
|
||||
/**
|
||||
* @return true is a.arguments == b.arguments, or false if not supported
|
||||
*/
|
||||
fun identicalArguments(a: SimpleTypeIM, b: SimpleTypeIM) = false
|
||||
fun identicalArguments(a: SimpleTypeMarker, b: SimpleTypeMarker) = false
|
||||
}
|
||||
|
||||
|
||||
class ArgumentList(initialSize: Int) : ArrayList<TypeArgumentMarker>(initialSize), TypeArgumentListMarker
|
||||
|
||||
|
||||
interface TypeSystemContext : TypeSystemOptimizationContext {
|
||||
fun KotlinTypeIM.asSimpleType(): SimpleTypeIM?
|
||||
fun KotlinTypeIM.asFlexibleType(): FlexibleTypeIM?
|
||||
fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker?
|
||||
fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker?
|
||||
|
||||
fun FlexibleTypeIM.asDynamicType(): DynamicTypeIM?
|
||||
fun FlexibleTypeIM.asRawType(): RawTypeIM?
|
||||
fun KotlinTypeMarker.isError(): Boolean
|
||||
|
||||
fun FlexibleTypeIM.upperBound(): SimpleTypeIM
|
||||
fun FlexibleTypeIM.lowerBound(): SimpleTypeIM
|
||||
fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker?
|
||||
|
||||
fun SimpleTypeIM.asCapturedType(): CapturedTypeIM?
|
||||
fun SimpleTypeIM.asDefinitelyNotNullType(): DefinitelyNotNullTypeIM?
|
||||
fun SimpleTypeIM.isMarkedNullable(): Boolean
|
||||
fun SimpleTypeIM.typeConstructor(): TypeConstructorIM
|
||||
fun FlexibleTypeMarker.asRawType(): RawTypeMarker?
|
||||
fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker
|
||||
|
||||
fun SimpleTypeIM.argumentsCount(): Int
|
||||
fun SimpleTypeIM.getArgument(index: Int): TypeArgumentIM
|
||||
fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker
|
||||
fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker?
|
||||
|
||||
fun TypeArgumentIM.isStarProjection(): Boolean
|
||||
fun TypeArgumentIM.getVariance(): TypeVariance
|
||||
fun TypeArgumentIM.getType(): KotlinTypeIM
|
||||
fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker?
|
||||
fun SimpleTypeMarker.isMarkedNullable(): Boolean
|
||||
fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker
|
||||
fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker
|
||||
|
||||
fun TypeConstructorIM.isErrorTypeConstructor(): Boolean
|
||||
fun TypeConstructorIM.parametersCount(): Int
|
||||
fun TypeConstructorIM.getParameter(index: Int): TypeParameterIM
|
||||
fun TypeConstructorIM.supertypesCount(): Int
|
||||
fun TypeConstructorIM.getSupertype(index: Int): KotlinTypeIM
|
||||
fun SimpleTypeMarker.argumentsCount(): Int
|
||||
fun SimpleTypeMarker.getArgument(index: Int): TypeArgumentMarker
|
||||
|
||||
fun TypeParameterIM.getVariance(): TypeVariance
|
||||
fun TypeParameterIM.upperBoundCount(): Int
|
||||
fun TypeParameterIM.getUpperBound(index: Int): KotlinTypeIM
|
||||
fun TypeParameterIM.getTypeConstructor(): TypeConstructorIM
|
||||
fun SimpleTypeMarker.getArgumentOrNull(index: Int): TypeArgumentMarker? {
|
||||
if (index in 0 until argumentsCount()) return getArgument(index)
|
||||
return null
|
||||
}
|
||||
|
||||
fun isEqualTypeConstructors(c1: TypeConstructorIM, c2: TypeConstructorIM): Boolean
|
||||
fun SimpleTypeMarker.isStubType(): Boolean = false
|
||||
|
||||
fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker
|
||||
|
||||
fun CapturedTypeMarker.lowerType(): KotlinTypeMarker?
|
||||
|
||||
fun TypeArgumentMarker.isStarProjection(): Boolean
|
||||
fun TypeArgumentMarker.getVariance(): TypeVariance
|
||||
fun TypeArgumentMarker.getType(): KotlinTypeMarker
|
||||
|
||||
fun TypeConstructorMarker.parametersCount(): Int
|
||||
fun TypeConstructorMarker.getParameter(index: Int): TypeParameterMarker
|
||||
fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker>
|
||||
fun TypeConstructorMarker.isIntersection(): Boolean
|
||||
fun TypeConstructorMarker.isClassTypeConstructor(): Boolean
|
||||
|
||||
fun TypeParameterMarker.getVariance(): TypeVariance
|
||||
fun TypeParameterMarker.upperBoundCount(): Int
|
||||
fun TypeParameterMarker.getUpperBound(index: Int): KotlinTypeMarker
|
||||
fun TypeParameterMarker.getTypeConstructor(): TypeConstructorMarker
|
||||
|
||||
fun isEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean
|
||||
|
||||
fun TypeConstructorMarker.isDenotable(): Boolean
|
||||
|
||||
fun KotlinTypeMarker.lowerBoundIfFlexible(): SimpleTypeMarker = this.asFlexibleType()?.lowerBound() ?: this.asSimpleType()!!
|
||||
fun KotlinTypeMarker.upperBoundIfFlexible(): SimpleTypeMarker = this.asFlexibleType()?.upperBound() ?: this.asSimpleType()!!
|
||||
|
||||
fun KotlinTypeMarker.isDynamic(): Boolean = asFlexibleType()?.asDynamicType() != null
|
||||
fun KotlinTypeMarker.isDefinitelyNotNullType(): Boolean = asSimpleType()?.asDefinitelyNotNullType() != null
|
||||
|
||||
fun KotlinTypeMarker.hasFlexibleNullability() =
|
||||
lowerBoundIfFlexible().isMarkedNullable() != upperBoundIfFlexible().isMarkedNullable()
|
||||
|
||||
fun KotlinTypeMarker.typeConstructor(): TypeConstructorMarker =
|
||||
(asSimpleType() ?: lowerBoundIfFlexible()).typeConstructor()
|
||||
|
||||
fun SimpleTypeMarker.isClassType(): Boolean = typeConstructor().isClassTypeConstructor()
|
||||
|
||||
fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean
|
||||
|
||||
fun captureFromArguments(
|
||||
type: SimpleTypeMarker,
|
||||
status: CaptureStatus
|
||||
): SimpleTypeMarker?
|
||||
|
||||
fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker
|
||||
|
||||
fun TypeArgumentListMarker.size(): Int
|
||||
operator fun TypeArgumentListMarker.get(index: Int): TypeArgumentMarker
|
||||
|
||||
fun TypeConstructorMarker.isAnyConstructor(): Boolean
|
||||
fun TypeConstructorMarker.isNothingConstructor(): Boolean
|
||||
|
||||
fun KotlinTypeMarker.isNotNullNothing(): Boolean
|
||||
|
||||
/**
|
||||
*
|
||||
* SingleClassifierType is one of the following types:
|
||||
* - classType
|
||||
* - type for type parameter
|
||||
* - captured type
|
||||
*
|
||||
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
|
||||
*/
|
||||
fun SimpleTypeMarker.isSingleClassifierType(): Boolean
|
||||
}
|
||||
|
||||
enum class CaptureStatus {
|
||||
FOR_SUBTYPING,
|
||||
FOR_INCORPORATION,
|
||||
FROM_EXPRESSION
|
||||
}
|
||||
+2
-2
@@ -69,7 +69,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
@@ -85,7 +85,7 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
|
||||
private var KtExpression.isOccurrence: Boolean by NotNullablePsiCopyableUserDataProperty(Key.create("OCCURRENCE"), false)
|
||||
|
||||
private class TypeCheckerImpl(private val project: Project) : KotlinTypeChecker by KotlinTypeChecker.DEFAULT {
|
||||
private inner class ContextImpl : TypeCheckerContext(false) {
|
||||
private inner class ContextImpl : ClassicTypeCheckerContext(false) {
|
||||
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return compareDescriptors(project, a.declarationDescriptor, b.declarationDescriptor)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user