Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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 org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
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.FlexibleTypeBoundsChecker.areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.model.CapturedTypeMarker
import org.jetbrains.kotlin.types.TypeRefinement
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.builtIns
private class CapturedArguments(val capturedArguments: List, private val originalType: KotlinType) {
fun isSuitableForType(type: KotlinType): Boolean {
val areArgumentsMatched = type.arguments.withIndex().all { (i, typeArgumentsType) ->
originalType.arguments.size > i && typeArgumentsType == originalType.arguments[i]
}
if (!areArgumentsMatched) return false
val areConstructorsMatched = originalType.constructor == type.constructor
|| areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability(originalType, type)
if (!areConstructorsMatched) return false
return true
}
}
// 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 arguments in the intersection types in specific way:
* 1) Firstly, we create captured arguments for all type arguments grouped by a type constructor* and a type argument's type.
* It means, that we create only one captured argument for two types `Foo<*>` and `Foo<*>?` within a flexible type, for instance.
* * In addition to grouping by type constructors, we look at possibility locating of two types in different bounds of the same flexible type.
* This is necessary in order to create the same captured arguments,
* for example, for `MutableList` in the lower bound of the flexible type and for `List` in the upper one.
* Example: MutableList<*>..List<*>? -> MutableList..List?, Captured1(*) and Captured2(*) are the same.
* 2) Secondly, we replace type arguments with captured arguments by given a type constructor and type arguments.
*/
val capturedArgumentsByComponents = captureArgumentsForIntersectionType(type) ?: return null
// We reuse `TypeToCapture` for some types, suitability to reuse defines by `isSuitableForType`
fun findCorrespondingCapturedArgumentsForType(type: KotlinType) =
capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type) }?.capturedArguments
fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: UnwrappedType): List {
return if (typeToReplace.constructor is IntersectionTypeConstructor) {
typeToReplace.constructor.supertypes.map { componentType ->
val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType)
?: return@map componentType.asSimpleType()
componentType.unwrap().replaceArguments(capturedArguments)
}
} else {
val capturedArguments = findCorrespondingCapturedArgumentsForType(typeToReplace)
?: return listOf(typeToReplace.asSimpleType())
listOf(typeToReplace.unwrap().replaceArguments(capturedArguments))
}
}
return if (type is FlexibleType) {
val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound))
.makeNullableAsSpecified(type.lowerBound.isMarkedNullable)
val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound))
.makeNullableAsSpecified(type.upperBound.isMarkedNullable)
KotlinTypeFactory.flexibleType(lowerIntersectedType, upperIntersectedType)
} else {
intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(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(type: KotlinType): List? {
// It's possible to have one of the bounds as non-intersection type
fun getTypesToCapture(type: KotlinType) =
if (type.constructor is IntersectionTypeConstructor) type.constructor.supertypes else listOf(type)
val filteredTypesToCapture =
if (type is FlexibleType) {
val typesToCapture = getTypesToCapture(type.lowerBound) + getTypesToCapture(type.upperBound)
typesToCapture.distinctBy { (FlexibleTypeBoundsChecker.getBaseBoundFqNameByMutability(it) ?: it.constructor) to it.arguments }
} else type.constructor.supertypes
var changed = false
val capturedArgumentsByTypes = filteredTypesToCapture.mapNotNull { typeToCapture ->
val capturedArguments = captureArguments(typeToCapture.unwrap(), CaptureStatus.FROM_EXPRESSION)
?: return@mapNotNull null
changed = true
CapturedArguments(capturedArguments, originalType = typeToCapture)
}
if (!changed) return null
return capturedArgumentsByTypes
}
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()) {
KotlinTypePreparator.Default.prepareType(substitutor.safeSubstitute(it, Variance.INVARIANT).unwrap())
}
if (!oldProjection.isStarProjection && oldProjection.projectionKind == Variance.OUT_VARIANCE) {
capturedTypeSupertypes += KotlinTypePreparator.Default.prepareType(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)"
}