[Core API] Introduce KotlinType.refine

The most interesting part happens in SimpleType.refine, other types
either don't implement refinement at all (they return just 'this',
mainly it's some special types, like ErrorType and such) or implement
it trivially via recursion (those are "composite" types)

SimpleType.refine captures so-called refinement factory, which is essentially
an injected callback which tells how to reconstruct the type with new
(refined) memberScope.

We have to inject callback because we express quite different types with
SimpleTypeImpl, and some of them need different refinement logic.
Another possible implementation approach (more invasive one) would be
to extract those types in separate subtypes of KotlinType and implement
'refine' via overrides.

The most meaningful callbacks are injected from
'AbstractClassDescriptor.defaultType' and from 'KotlinTypeFactory'.
This commit is contained in:
Dmitry Savvinov
2019-07-10 13:47:16 +03:00
parent c12f5f6055
commit 1d61d75225
21 changed files with 364 additions and 39 deletions
@@ -24,9 +24,12 @@ import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.jetbrains.kotlin.types.typeUtil.builtIns
class RawTypeImpl(lowerBound: SimpleType, upperBound: SimpleType) : FlexibleType(lowerBound, upperBound), RawType {
@@ -80,6 +83,12 @@ class RawTypeImpl(lowerBound: SimpleType, upperBound: SimpleType) : FlexibleType
if (newLower == newUpper) return newLower
return renderer.renderFlexibleType(newLower, newUpper, builtIns)
}
@TypeRefinement
@UseExperimental(TypeRefinement::class)
override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): FlexibleType {
return RawTypeImpl(kotlinTypeRefiner.refineType(lowerBound) as SimpleType, kotlinTypeRefiner.refineType(upperBound) as SimpleType)
}
}
internal object RawSubstitution : TypeSubstitution() {
@@ -124,13 +133,20 @@ internal object RawSubstitution : TypeSubstitution() {
if (type.isError) return ErrorUtils.createErrorType("Raw error type: ${type.constructor}") to false
val memberScope = declaration.getMemberScope(RawSubstitution)
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
type.annotations, type.constructor,
type.constructor.parameters.map { parameter ->
computeProjection(parameter, attr)
},
type.isMarkedNullable, declaration.getMemberScope(RawSubstitution)
) to true
type.isMarkedNullable, memberScope
) factory@{ kotlinTypeRefiner ->
val classId = (declaration as? ClassDescriptor)?.classId ?: return@factory memberScope
kotlinTypeRefiner
.findClassAcrossModuleDependencies(classId)
?.getRefinedMemberScopeIfPossible(RawSubstitution, moduleDescriptor) ?: memberScope
} to true
}
fun computeProjection(
@@ -150,13 +166,13 @@ internal object RawSubstitution : TypeSubstitution() {
)
JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND, JavaTypeFlexibility.INFLEXIBLE -> {
if (!parameter.variance.allowsOutPosition)
// in T -> Comparable<Nothing>
// in T -> Comparable<Nothing>
TypeProjectionImpl(Variance.INVARIANT, parameter.builtIns.nothingType)
else if (erasedUpperBound.constructor.parameters.isNotEmpty())
// T : Enum<E> -> out Enum<*>
// T : Enum<E> -> out Enum<*>
TypeProjectionImpl(Variance.OUT_VARIANCE, erasedUpperBound)
else
// T : String -> *
// T : String -> *
makeStarProjection(parameter, attr)
}
}
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
@@ -253,4 +254,7 @@ internal class NotNullTypeParameter(override val delegate: SimpleType) : NotNull
override fun replaceAnnotations(newAnnotations: Annotations) = NotNullTypeParameter(delegate.replaceAnnotations(newAnnotations))
override fun makeNullableAsSpecified(newNullability: Boolean) =
if (newNullability) delegate.makeNullableAsSpecified(true) else this
@TypeRefinement
override fun replaceDelegate(delegate: SimpleType) = NotNullTypeParameter(delegate)
}