[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
This commit is contained in:
Dmitry Savvinov
2019-07-10 13:22:06 +03:00
parent c20d565d93
commit c12f5f6055
12 changed files with 136 additions and 12 deletions
@@ -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 {
@@ -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)"
}
@@ -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
}
}
@@ -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(
@@ -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<KotlinType>()
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<TypeParameterDescriptor> = 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() }}]"
}
}
@@ -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)"
}
@@ -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<TypeParameterDescriptor> = this@AbstractTypeConstructor.parameters
override fun getSupertypes(): List<KotlinType> = 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)
@@ -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() {}
@@ -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
}
@@ -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<KotlinType>) : TypeConstructor {
@@ -67,6 +69,10 @@ class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : Ty
)
override fun hashCode(): Int = hashCode
@TypeRefinement
override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) =
IntersectionTypeConstructor(intersectedTypes.map { it.refine(kotlinTypeRefiner) })
}
inline fun IntersectionTypeConstructor.transformComponents(
@@ -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);
}
@@ -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)"
}