From c12f5f6055523810d6ed47bbf23c875da006c1d5 Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Wed, 10 Jul 2019 13:22:06 +0300 Subject: [PATCH] [Core API] Introduce TypeConstructor.refine This commit introduces TypeConstructor.refine method. It's implementation can be roughly split in three parts: - trivial implementations which just return 'this': mostly, it used for typeConstructors which can not be refined at all (e.g. IntegerValueTypeConstructor and other special cases of constructors) - delegating implementations which call 'refine' recursively for component typeConstructors -- obviously, they are used in composite typeConstructors (like IntersectionTypeConstructor) - finally, the most interesting one is in 'AbstractTypeConstructor' which returns lightweight wrapper called 'ModuleViewTypeConstructor'. The idea here is to propagate refinement to supertypes without eagerly computing them all. VERY IMPORTANT CAVEAT of TypeConstructor.refine is that call to this method CAN NOT add new supertypes, so returned supertypes are not entirely "valid". See the KDoc for TypeConstructor.refine for details --- .../calls/inference/CoroutineInferenceUtil.kt | 5 ++ .../calls/inference/model/TypeVariable.kt | 5 ++ .../impl/AbstractTypeAliasDescriptor.kt | 5 ++ .../inference/CapturedTypeConstructor.kt | 4 ++ .../IntegerLiteralTypeConstructor.kt | 19 +++++--- .../constants/IntegerValueTypeConstructor.kt | 9 ++-- .../kotlin/types/AbstractTypeConstructor.kt | 48 ++++++++++++++++++- .../jetbrains/kotlin/types/ErrorUtils.java | 13 +++++ .../kotlin/types/FunctionPlaceholders.kt | 5 ++ .../types/IntersectionTypeConstructor.kt | 6 +++ .../kotlin/types/TypeConstructor.java | 25 ++++++++++ .../kotlin/types/checker/NewCapturedType.kt | 4 ++ 12 files changed, 136 insertions(+), 12 deletions(-) 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 ad49be73958..b7583d0b14b 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,10 +40,12 @@ 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.ClassicTypeCheckerContext +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker 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.refinement.TypeRefinement import org.jetbrains.kotlin.types.typeUtil.* import javax.inject.Inject @@ -64,6 +66,9 @@ class TypeTemplate( override fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions) = "~${renderer.renderType(typeVariable.type)}" + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = this } class CoroutineInferenceData { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt index 973578518c8..0c83fe044ff 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt @@ -27,8 +27,10 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinTypeFactory import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.model.TypeVariableMarker +import org.jetbrains.kotlin.types.refinement.TypeRefinement class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debugName: String) : TypeConstructor, @@ -41,6 +43,9 @@ class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debu override fun getBuiltIns() = builtIns + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = this + override fun toString() = "TypeVariable($debugName)" } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt index 66acd73396d..74473890d7f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt @@ -112,5 +112,10 @@ abstract class AbstractTypeAliasDescriptor( declarationDescriptor.builtIns override fun toString(): String = "[typealias ${declarationDescriptor.name.asString()}]" + + // There must be @TypeRefinement, but there is a bug with anonymous objects and experimental annotations + // See KT-31728 + @UseExperimental(TypeRefinement::class) + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor? = this } } 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 d06a1e53ed5..04a4f973e91 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 @@ -62,6 +62,10 @@ class CapturedTypeConstructorImpl( override fun toString() = "CapturedTypeConstructor($projection)" override fun getBuiltIns(): KotlinBuiltIns = projection.type.constructor.builtIns + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = + CapturedTypeConstructorImpl(projection.refine(kotlinTypeRefiner)) } class CapturedType( diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt index 8df527713c0..4a6122f19b7 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt @@ -11,7 +11,8 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.types.* -import java.lang.IllegalStateException +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.refinement.TypeRefinement class IntegerLiteralTypeConstructor : TypeConstructor { companion object { @@ -64,7 +65,7 @@ class IntegerLiteralTypeConstructor : TypeConstructor { private fun fold(left: IntegerLiteralTypeConstructor, right: SimpleType): SimpleType? = if (right in left.possibleTypes) right else null - + } private val value: Long @@ -74,7 +75,7 @@ class IntegerLiteralTypeConstructor : TypeConstructor { constructor(value: Long, module: ModuleDescriptor, parameters: CompileTimeConstant.Parameters) { this.value = value this.module = module - + val possibleTypes = mutableSetOf() fun checkBoundsAndAddPossibleType(value: Long, kotlinType: KotlinType) { @@ -143,15 +144,15 @@ class IntegerLiteralTypeConstructor : TypeConstructor { builtIns.longType in possibleTypes -> builtIns.longType builtIns.byteType in possibleTypes -> builtIns.byteType builtIns.shortType in possibleTypes -> builtIns.shortType - + module.uIntType in possibleTypes -> module.uIntType module.uLongType in possibleTypes -> module.uLongType module.uByteType in possibleTypes -> module.uByteType module.uShortType in possibleTypes -> module.uShortType - + else -> throw IllegalStateException() } - + override fun getParameters(): List = emptyList() @@ -165,6 +166,9 @@ class IntegerLiteralTypeConstructor : TypeConstructor { override fun getBuiltIns(): KotlinBuiltIns = module.builtIns + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = this + override fun toString(): String { return "IntegerLiteralType${valueToString()}" } @@ -172,4 +176,5 @@ class IntegerLiteralTypeConstructor : TypeConstructor { fun checkConstructor(constructor: TypeConstructor): Boolean = possibleTypes.any { it.constructor == constructor } private fun valueToString(): String = "[${possibleTypes.joinToString(",") { it.toString() }}]" -} \ No newline at end of file + +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt index 8add786a3ae..17ac74326df 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt @@ -17,14 +17,12 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.UnsignedTypes import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.refinement.TypeRefinement import java.util.* class IntegerValueTypeConstructor( @@ -95,6 +93,9 @@ class IntegerValueTypeConstructor( return module.builtIns } + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = this + override fun toString() = "IntegerValueType($value)" } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt index 1a37d4f799e..b0425c938f3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt @@ -16,12 +16,58 @@ package org.jetbrains.kotlin.types -import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.checker.refineTypes +import org.jetbrains.kotlin.types.refinement.TypeRefinement abstract class AbstractTypeConstructor(storageManager: StorageManager) : TypeConstructor { override fun getSupertypes() = supertypes().supertypesWithoutCycles + abstract override fun getDeclarationDescriptor(): ClassifierDescriptor + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = ModuleViewTypeConstructor(kotlinTypeRefiner) + + @TypeRefinement + private inner class ModuleViewTypeConstructor( + private val kotlinTypeRefiner: KotlinTypeRefiner + ) : TypeConstructor { + /* NB: it is important to use PUBLICATION here instead of 'storageManager.createLazyValue { ... }' + + The reason is that 'storageManager' can be a storage manager from DefaultBuiltIns (e.g. is this type constructor + is type constructor of some built-in class like 'Int'). Therefore, call to refined supertypes would result in + the following order of acquiring locks: DefaultBuiltIns lock -> Sources lock + + Obviously, a lot of code acquires locks in different order (sources lock first, then built-ins lock), so that would + result in deadlock + */ + private val refinedSupertypes by lazy(LazyThreadSafetyMode.PUBLICATION) { + @UseExperimental(TypeRefinement::class) + kotlinTypeRefiner.refineTypes(this@AbstractTypeConstructor.getSupertypes()) + } + + override fun getParameters(): List = this@AbstractTypeConstructor.parameters + + override fun getSupertypes(): List = refinedSupertypes + + override fun isFinal(): Boolean = this@AbstractTypeConstructor.isFinal + override fun isDenotable(): Boolean = this@AbstractTypeConstructor.isDenotable + + override fun getDeclarationDescriptor() = this@AbstractTypeConstructor.declarationDescriptor + + override fun getBuiltIns(): KotlinBuiltIns = this@AbstractTypeConstructor.builtIns + + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = + this@AbstractTypeConstructor.refine(kotlinTypeRefiner) + + override fun equals(other: Any?) = this@AbstractTypeConstructor.equals(other) + override fun hashCode() = this@AbstractTypeConstructor.hashCode() + override fun toString() = this@AbstractTypeConstructor.toString() + } + // In current version diagnostic about loops in supertypes is reported on each vertex (supertype reference) that lies on the cycle. // To achieve that we store both versions of supertypes --- before and after loops disconnection. // The first one is used for computation of neighbours in supertypes graph (see Companion.computeNeighbours) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index ec66fbc6f06..4c1adc37fc1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -523,6 +523,13 @@ public class ErrorUtils { public String toString() { return debugName; } + + @TypeRefinement + @Override + @NotNull + public TypeConstructor refine(@NotNull KotlinTypeRefiner kotlinTypeRefiner) { + return this; + } }; } @@ -615,6 +622,12 @@ public class ErrorUtils { public KotlinBuiltIns getBuiltIns() { return DescriptorUtilsKt.getBuiltIns(typeParameterDescriptor); } + + @NotNull + @Override + public TypeConstructor refine(@NotNull KotlinTypeRefiner kotlinTypeRefiner) { + return this; + } } private ErrorUtils() {} diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/FunctionPlaceholders.kt b/core/descriptors/src/org/jetbrains/kotlin/types/FunctionPlaceholders.kt index b248787e467..0579da2b481 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/FunctionPlaceholders.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/FunctionPlaceholders.kt @@ -19,6 +19,8 @@ package org.jetbrains.kotlin.types import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.refinement.TypeRefinement class FunctionPlaceholders(private val builtIns: KotlinBuiltIns) { fun createFunctionPlaceholderType( @@ -71,4 +73,7 @@ class FunctionPlaceholderTypeConstructor( override fun getBuiltIns(): KotlinBuiltIns { return kotlinBuiltIns } + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = this } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt index fb66f13d1fc..533cc63f58c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/IntersectionTypeConstructor.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.refinement.TypeRefinement import java.util.* class IntersectionTypeConstructor(typesToIntersect: Collection) : TypeConstructor { @@ -67,6 +69,10 @@ class IntersectionTypeConstructor(typesToIntersect: Collection) : Ty ) override fun hashCode(): Int = hashCode + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = + IntersectionTypeConstructor(intersectedTypes.map { it.refine(kotlinTypeRefiner) }) } inline fun IntersectionTypeConstructor.transformComponents( diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java index 39dce87095b..9b08a4d2b9c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeConstructor.java @@ -22,7 +22,9 @@ 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.checker.KotlinTypeRefiner; import org.jetbrains.kotlin.types.model.TypeConstructorMarker; +import org.jetbrains.kotlin.types.refinement.TypeRefinement; import java.util.Collection; import java.util.List; @@ -58,4 +60,27 @@ public interface TypeConstructor extends TypeConstructorMarker { @NotNull KotlinBuiltIns getBuiltIns(); + + /** + * Returns TypeConstructor, refined with passed refined, if that makes sense for this specific typeConstructor + * + * Contract: + * - returned TypeConstructor has refined supertypes, i.e. it has correct supertypes resolved as if + * we were looking at them from refiner's module + * - IT DOES NOT ADD PLATFORM DECLARED SUPERTYPES!!!!!!!! + * - all other similar sources of KotlinTypes/Descriptors should return refined instances as well + * + * That method is part of internal refinement infrastructure, so IT SHOULD NOT BE CALLED from anywhere except + * methods from refinement (like methods of KotlinTypeRefinerImpl or KotlinType.refine + * + * Implementation notice: + * - the most interesting part happens in 'AbstractTypeConstructor': it returns 'ModuleViewTypeConstructor', which + * will refine supertypes when queried for them + * - also, there are several typeConstructors, which do not inherit AbstractTypeConstructor, but have some component + * types/descriptors (e.g. IntersectionTypeConstructor) -- they refine their content manually by recursing using refiner + * - finally, most special typeConstructors have no meaningful refinement and return null (i.e. UninferredTypeParameterConstructor) + */ + @TypeRefinement + @NotNull + TypeConstructor refine(@NotNull KotlinTypeRefiner kotlinTypeRefiner); } 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 d8bacde6526..94da3aa9416 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt @@ -158,5 +158,9 @@ class NewCapturedTypeConstructor(override val projection: TypeProjection, privat override fun getDeclarationDescriptor(): ClassifierDescriptor? = null override fun getBuiltIns(): KotlinBuiltIns = projection.type.builtIns + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = + NewCapturedTypeConstructor(projection.refine(kotlinTypeRefiner), supertypes?.map { it.refine(kotlinTypeRefiner) }) + override fun toString() = "CapturedType($projection)" }