kotlin.reflect.jvm.internal.impl.types.checker.NewCapturedType.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-reflect Show documentation
Show all versions of kotlin-reflect Show documentation
Kotlin Full Reflection Library
/*
* Copyright 2010-2017 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 kotlin.reflect.jvm.internal.impl.types.checker
import kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns
import kotlin.reflect.jvm.internal.impl.descriptors.ClassifierDescriptor
import kotlin.reflect.jvm.internal.impl.descriptors.TypeParameterDescriptor
import kotlin.reflect.jvm.internal.impl.descriptors.annotations.Annotations
import kotlin.reflect.jvm.internal.impl.resolve.calls.inference.CapturedTypeConstructor
import kotlin.reflect.jvm.internal.impl.resolve.scopes.MemberScope
import kotlin.reflect.jvm.internal.impl.types.*
import kotlin.reflect.jvm.internal.impl.types.model.CaptureStatus
import kotlin.reflect.jvm.internal.impl.types.model.CapturedTypeMarker
import kotlin.reflect.jvm.internal.impl.types.refinement.TypeRefinement
import kotlin.reflect.jvm.internal.impl.types.typeUtil.asTypeProjection
import kotlin.reflect.jvm.internal.impl.types.typeUtil.builtIns
// null means that type should be leaved as is
fun prepareArgumentTypeRegardingCaptureTypes(argumentType: UnwrappedType): UnwrappedType? {
return if (argumentType is NewCapturedType) null else captureFromExpression(argumentType)
}
fun captureFromExpression(type: UnwrappedType): UnwrappedType? {
val typeConstructor = type.constructor
if (typeConstructor !is IntersectionTypeConstructor) {
return captureFromArguments(type, CaptureStatus.FROM_EXPRESSION)
}
/*
* We capture intersection types in two stages:
* capture type arguments for each component and replace it in the original type after that.
* This is to substitute captured types into flexible types properly:
* we should have the same captured types both for lower bound and for upper one.
*
* Example:
* The original type: ({Comparable<*> & java.io.Serializable}..{Comparable<*>? & java.io.Serializable?})
* Result of capturing arguments by components: [[CapturedType(*)], null]
* The resulting type: ({Comparable & java.io.Serializable}..{Comparable? & java.io.Serializable?})
*/
val capturedArgumentsByComponents = captureArgumentsForIntersectionType(typeConstructor) ?: return null
fun replaceArgumentsByComponents(typeToReplace: UnwrappedType) =
typeToReplace.constructor.supertypes.mapIndexed { i, componentType ->
val capturedArguments = capturedArgumentsByComponents[i] ?: return@mapIndexed componentType.asSimpleType()
componentType.unwrap().replaceArguments(capturedArguments)
}
return if (type is FlexibleType) {
val lowerIntersectedType =
intersectTypes(replaceArgumentsByComponents(type.lowerBound)).makeNullableAsSpecified(type.lowerBound.isMarkedNullable)
val upperIntersectedType =
intersectTypes(replaceArgumentsByComponents(type.upperBound)).makeNullableAsSpecified(type.upperBound.isMarkedNullable)
KotlinTypeFactory.flexibleType(lowerIntersectedType, upperIntersectedType)
} else {
intersectTypes(replaceArgumentsByComponents(type)).makeNullableAsSpecified(type.isMarkedNullable)
}
}
// this function suppose that input type is simple classifier type
internal fun captureFromArguments(type: SimpleType, status: CaptureStatus) =
captureArguments(type, status)?.let { type.replaceArguments(it) }
private fun captureArgumentsForIntersectionType(typeConstructor: TypeConstructor): List?>? {
var changed = false
val capturedArgumentsByComponents = typeConstructor.supertypes.map { supertype ->
captureArguments(supertype.unwrap(), CaptureStatus.FROM_EXPRESSION)?.apply { changed = true }
}
if (!changed) return null
return capturedArgumentsByComponents
}
private fun captureFromArguments(type: UnwrappedType, status: CaptureStatus): UnwrappedType? {
val capturedArguments = captureArguments(type, status) ?: return null
return if (type is FlexibleType) {
KotlinTypeFactory.flexibleType(
type.lowerBound.replaceArguments(capturedArguments),
type.upperBound.replaceArguments(capturedArguments)
)
} else {
type.replaceArguments(capturedArguments)
}
}
private fun UnwrappedType.replaceArguments(arguments: List) =
KotlinTypeFactory.simpleType(annotations, constructor, arguments, isMarkedNullable)
private fun captureArguments(type: UnwrappedType, status: CaptureStatus): List? {
if (type.arguments.size != type.constructor.parameters.size) return null
val arguments = type.arguments
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return null
val capturedArguments = arguments.zip(type.constructor.parameters).map { (projection, parameter) ->
if (projection.projectionKind == Variance.INVARIANT) return@map projection
val lowerType =
if (!projection.isStarProjection && projection.projectionKind == Variance.IN_VARIANCE) {
projection.type.unwrap()
} else {
null
}
NewCapturedType(status, lowerType, projection, parameter).asTypeProjection() // todo optimization: do not create type projection
}
val substitutor = TypeConstructorSubstitution.create(type.constructor, capturedArguments).buildSubstitutor()
for (index in arguments.indices) {
val oldProjection = arguments[index]
val newProjection = capturedArguments[index]
if (oldProjection.projectionKind == Variance.INVARIANT) continue
val capturedTypeSupertypes = type.constructor.parameters[index].upperBounds.mapTo(mutableListOf()) {
NewKotlinTypeChecker.Default.transformToNewType(substitutor.safeSubstitute(it, Variance.INVARIANT).unwrap())
}
if (!oldProjection.isStarProjection && oldProjection.projectionKind == Variance.OUT_VARIANCE) {
capturedTypeSupertypes += NewKotlinTypeChecker.Default.transformToNewType(oldProjection.type.unwrap())
}
val capturedType = newProjection.type as NewCapturedType
capturedType.constructor.initializeSupertypes(capturedTypeSupertypes)
}
return capturedArguments
}
/**
* Now [lowerType] is not null only for in projections.
* Example: `Inv` For `in String` we create CapturedType with [lowerType] = String.
*
* TODO: interface D, D<*, List> -> D>
* We should set [lowerType] for Q as Number. For this we should use constraint system.
*
*/
class NewCapturedType(
val captureStatus: CaptureStatus,
override val constructor: NewCapturedTypeConstructor,
val lowerType: UnwrappedType?, // todo check lower type for nullable captured types
override val annotations: Annotations = Annotations.EMPTY,
override val isMarkedNullable: Boolean = false,
val isProjectionNotNull: Boolean = false
) : SimpleType(), CapturedTypeMarker {
internal constructor(
captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection, typeParameter: TypeParameterDescriptor
) : this(captureStatus, NewCapturedTypeConstructor(projection, typeParameter = typeParameter), lowerType)
override val arguments: List get() = listOf()
override val memberScope: MemberScope // todo what about foo().bar() where foo() return captured type?
get() = ErrorUtils.createErrorScope("No member resolution should be done on captured type!", true)
override fun replaceAnnotations(newAnnotations: Annotations) =
NewCapturedType(captureStatus, constructor, lowerType, newAnnotations, isMarkedNullable)
override fun makeNullableAsSpecified(newNullability: Boolean) =
NewCapturedType(captureStatus, constructor, lowerType, annotations, newNullability)
@TypeRefinement
override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) =
NewCapturedType(
captureStatus,
constructor.refine(kotlinTypeRefiner),
lowerType?.let { kotlinTypeRefiner.refineType(it).unwrap() },
annotations,
isMarkedNullable
)
}
class NewCapturedTypeConstructor(
override val projection: TypeProjection,
private var supertypesComputation: (() -> List)? = null,
private val original: NewCapturedTypeConstructor? = null,
val typeParameter: TypeParameterDescriptor? = null
) : CapturedTypeConstructor {
constructor(
projection: TypeProjection,
supertypes: List,
original: NewCapturedTypeConstructor? = null
) : this(projection, { supertypes }, original)
private val _supertypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
supertypesComputation?.invoke()
}
fun initializeSupertypes(supertypes: List) {
assert(this.supertypesComputation == null) {
"Already initialized! oldValue = ${this.supertypesComputation}, newValue = $supertypes"
}
this.supertypesComputation = { supertypes }
}
override fun getSupertypes() = _supertypes ?: emptyList()
override fun getParameters(): List = emptyList()
override fun isFinal() = false
override fun isDenotable() = false
override fun getDeclarationDescriptor(): ClassifierDescriptor? = null
override fun getBuiltIns(): KotlinBuiltIns = projection.type.builtIns
@TypeRefinement
override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) =
NewCapturedTypeConstructor(
projection.refine(kotlinTypeRefiner),
supertypesComputation?.let {
{
supertypes.map { it.refine(kotlinTypeRefiner) }
}
},
original ?: this,
typeParameter = typeParameter
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as NewCapturedTypeConstructor
return (original ?: this) === (other.original ?: other)
}
override fun hashCode(): Int = original?.hashCode() ?: super.hashCode()
override fun toString() = "CapturedType($projection)"
}