diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt index b4d46683a3b..abe1c9437ea 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index 799370ad982..976aadbd11f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -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 and A <: List. diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt index 731441e386c..4148f3f228d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintIncorporator.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt index e23c8d24d53..ae1205baf80 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt index 79e78bfab6c..29030b62832 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt @@ -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 } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt index c918d1840a0..aa2c1e85e04 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt @@ -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) || diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt index 9f82cb0a48a..4aa391bd2a3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt @@ -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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 31255cde30a..20bd8b5b41f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -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()) && diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeParameterDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeParameterDescriptor.java index 92515194cec..ce0f1a12010 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeParameterDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeParameterDescriptor.java @@ -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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt index fa1323338be..d06a1e53ed5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/CapturedTypeConstructor.kt @@ -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 get() = listOf() diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt index b2345aaac6e..f960f886911 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinType.kt @@ -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 @@ -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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/RawType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/RawType.kt index 4bc82f3942a..177084f6b6c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/RawType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/RawType.kt @@ -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 \ No newline at end of file +interface RawType : RawTypeMarker \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt index eee6d30d432..2cafc763c2f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/SpecialTypes.kt @@ -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? { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java index e5008d51119..39dce87095b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java @@ -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. diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeProjection.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeProjection.java index 3cc4cc59bc8..24a4aafe6ed 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeProjection.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeProjection.java @@ -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(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt new file mode 100644 index 00000000000..769cbf73e67 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt @@ -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 { + @Suppress("UNCHECKED_CAST") + return org.jetbrains.kotlin.types.checker.intersectTypes(types as List) + } + + 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" +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt new file mode 100644 index 00000000000..fbc2663fe5b --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -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 { + 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}" +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt index fea9eec6d63..526c502171e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt @@ -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` 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) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 2bc244dce62..f5fffed6092 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -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 != A, also A != A * also A<*> != A * 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 <: Array - 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 { - if (baseType.isClassType) { - return collectAndFilter(baseType, constructor) + return AbstractTypeChecker.run { + findCorrespondingSupertypes(baseType, constructor) as List } - - // i.e. superType is not a classType - if (constructor.declarationDescriptor !is ClassDescriptor) { - return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor) - } - - // todo add tests - val classTypeSupertypes = SmartList() - 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 { - if (constructor.declarationDescriptor.safeAs()?.isCommonFinalClass == true) { - return if (areEqualTypeConstructors(baseType.constructor, constructor)) - listOf(captureFromArguments(baseType, CaptureStatus.FOR_SUBTYPING) ?: baseType) - else - emptyList() - } - - val result: MutableList = 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(), MutableList - * - * We should see `String` in `get` function and others, also MyList is not subtype of MutableList - * - * More tests: javaAndKotlinSuperType & purelyImplementedCollection folder - */ - private fun selectOnlyPureKotlinSupertypes(supertypes: List): List { - 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, - 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 <: 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, A => \exist Q : Number <: Q. A - * 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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt deleted file mode 100644 index 0ee3302c8ee..00000000000 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/TypeCheckerContext.kt +++ /dev/null @@ -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? = null - private var supertypesSet: MutableSet? = 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 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 -} diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt index 27f5a724eb8..a8f0035b081 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/dynamicTypes.kt @@ -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 diff --git a/core/type-system/src/org/jetbrains/kotlin/types/AbstractStrictEqualityTypeChecker.kt b/core/type-system/src/org/jetbrains/kotlin/types/AbstractStrictEqualityTypeChecker.kt index 63fea3cfdca..cf84b86004a 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/AbstractStrictEqualityTypeChecker.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/AbstractStrictEqualityTypeChecker.kt @@ -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 } diff --git a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index de3b1010617..be0e9aca1c0 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -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 + + open fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { + return type + } + + abstract val isErrorTypeEqualsToAnything: Boolean + + protected var argumentsDepth = 0 + + + internal inline fun 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? = null + private set + var supertypesSet: MutableSet? = 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 <: Array + 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 <: 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 { + if (constructor.isCommonFinalClassConstructor()) { + return if (areEqualTypeConstructors(baseType.typeConstructor(), constructor)) + listOf(captureFromArguments(baseType, CaptureStatus.FOR_SUBTYPING) ?: baseType) + else + emptyList() + } + + val result: MutableList = 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(), MutableList + * + * We should see `String` in `get` function and others, also MyList is not subtype of MutableList + * + * More tests: javaAndKotlinSuperType & purelyImplementedCollection folder + */ + private fun AbstractTypeCheckerContext.selectOnlyPureKotlinSupertypes(supertypes: List): List { + 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 { + 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() + 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, A => \exist Q : Number <: Q. A + * 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 + } +} \ No newline at end of file diff --git a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index c5b762226e0..f8ece07e32c 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -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(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 + 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 } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt index 903cb3c9250..915cc2a50e5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt @@ -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) }