[FIR] Implement capturing of cone types same as for kotlin types
This commit is contained in:
@@ -14,10 +14,12 @@ object StandardClassIds {
|
|||||||
|
|
||||||
val BASE_KOTLIN_PACKAGE = FqName("kotlin")
|
val BASE_KOTLIN_PACKAGE = FqName("kotlin")
|
||||||
val BASE_REFLECT_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("reflect"))
|
val BASE_REFLECT_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("reflect"))
|
||||||
|
val BASE_COLLECTIONS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("collections"))
|
||||||
private fun String.baseId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier(this))
|
private fun String.baseId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier(this))
|
||||||
private fun ClassId.unsignedId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier("U" + shortClassName.identifier))
|
private fun ClassId.unsignedId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier("U" + shortClassName.identifier))
|
||||||
private fun String.reflectId() = ClassId(BASE_REFLECT_PACKAGE, Name.identifier(this))
|
private fun String.reflectId() = ClassId(BASE_REFLECT_PACKAGE, Name.identifier(this))
|
||||||
private fun Name.primitiveArrayId() = ClassId(Array.packageFqName, Name.identifier(identifier + Array.shortClassName.identifier))
|
private fun Name.primitiveArrayId() = ClassId(Array.packageFqName, Name.identifier(identifier + Array.shortClassName.identifier))
|
||||||
|
private fun String.collectionsId() = ClassId(BASE_COLLECTIONS_PACKAGE, Name.identifier(this))
|
||||||
|
|
||||||
val Nothing = "Nothing".baseId()
|
val Nothing = "Nothing".baseId()
|
||||||
val Unit = "Unit".baseId()
|
val Unit = "Unit".baseId()
|
||||||
@@ -85,6 +87,25 @@ object StandardClassIds {
|
|||||||
return "Function$n".baseId()
|
return "Function$n".baseId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Iterator = "Iterator".collectionsId()
|
||||||
|
val Iterable = "Iterable".collectionsId()
|
||||||
|
val Collection = "Collection".collectionsId()
|
||||||
|
val List = "List".collectionsId()
|
||||||
|
val ListIterator = "ListIterator".collectionsId()
|
||||||
|
val Set = "Set".collectionsId()
|
||||||
|
val Map = "Map".collectionsId()
|
||||||
|
val MutableIterator = "MutableIterator".collectionsId()
|
||||||
|
|
||||||
|
val MutableIterable = "MutableIterable".collectionsId()
|
||||||
|
val MutableCollection = "MutableCollection".collectionsId()
|
||||||
|
val MutableList = "MutableList".collectionsId()
|
||||||
|
val MutableListIterator = "MutableListIterator".collectionsId()
|
||||||
|
val MutableSet = "MutableSet".collectionsId()
|
||||||
|
val MutableMap = "MutableMap".collectionsId()
|
||||||
|
|
||||||
|
val MapEntry = Map.createNestedClassId(Name.identifier("Entry"))
|
||||||
|
val MutableMapEntry = MutableMap.createNestedClassId(Name.identifier("MutableEntry"))
|
||||||
|
|
||||||
val Suppress = "Suppress".baseId()
|
val Suppress = "Suppress".baseId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
if (types.any { it.isEmpty() }) return mutableSetOf()
|
if (types.any { it.isEmpty() }) return mutableSetOf()
|
||||||
val intersectedTypes = types.map {
|
val intersectedTypes = types.map {
|
||||||
if (it.size > 1) {
|
if (it.size > 1) {
|
||||||
context.intersectTypes(it.toList()) as ConeKotlinType
|
context.intersectTypes(it.toList())
|
||||||
} else {
|
} else {
|
||||||
assert(it.size == 1) { "We've already checked each set of types is not empty." }
|
assert(it.size == 1) { "We've already checked each set of types is not empty." }
|
||||||
it.single()
|
it.single()
|
||||||
|
|||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
object ConeFlexibleTypeBoundsChecker {
|
||||||
|
private val fqNames = StandardNames.FqNames
|
||||||
|
private val baseTypesToMutableEquivalent = mapOf(
|
||||||
|
StandardClassIds.Iterable to StandardClassIds.MutableIterable,
|
||||||
|
StandardClassIds.Iterator to StandardClassIds.MutableIterator,
|
||||||
|
StandardClassIds.ListIterator to StandardClassIds.MutableListIterator,
|
||||||
|
StandardClassIds.List to StandardClassIds.MutableList,
|
||||||
|
StandardClassIds.Collection to StandardClassIds.MutableCollection,
|
||||||
|
StandardClassIds.Set to StandardClassIds.MutableSet,
|
||||||
|
StandardClassIds.Map to StandardClassIds.MutableMap,
|
||||||
|
StandardClassIds.MapEntry to StandardClassIds.MutableMapEntry
|
||||||
|
)
|
||||||
|
private val mutableToBaseMap = baseTypesToMutableEquivalent.entries.associateBy({ it.value }) { it.key }
|
||||||
|
|
||||||
|
fun areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability(a: ConeKotlinType, b: ConeKotlinType): Boolean {
|
||||||
|
val classId = a.classId ?: return false
|
||||||
|
val possiblePairBound = (baseTypesToMutableEquivalent[classId] ?: mutableToBaseMap[classId]) ?: return false
|
||||||
|
|
||||||
|
return possiblePairBound == b.classId
|
||||||
|
}
|
||||||
|
|
||||||
|
// We consider base bounds as not mutable collections
|
||||||
|
fun getBaseBoundFqNameByMutability(a: ConeKotlinType): ClassId? {
|
||||||
|
val classId = a.classId ?: return null
|
||||||
|
|
||||||
|
if (classId in baseTypesToMutableEquivalent) return classId
|
||||||
|
|
||||||
|
return mutableToBaseMap[classId]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -340,10 +340,6 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
|
||||||
return type
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createErrorType(debugName: String): ConeClassErrorType {
|
override fun createErrorType(debugName: String): ConeClassErrorType {
|
||||||
return ConeClassErrorType(ConeIntermediateDiagnostic(debugName))
|
return ConeClassErrorType(ConeIntermediateDiagnostic(debugName))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,9 +228,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
|
|
||||||
private fun TypeConstructorMarker.toClassLikeSymbol(): FirClassLikeSymbol<*>? = (this as? ConeClassLikeLookupTag)?.toSymbol(session)
|
private fun TypeConstructorMarker.toClassLikeSymbol(): FirClassLikeSymbol<*>? = (this as? ConeClassLikeLookupTag)?.toSymbol(session)
|
||||||
|
|
||||||
override fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker> {
|
override fun TypeConstructorMarker.supertypes(): Collection<ConeKotlinType> {
|
||||||
if (this is ErrorTypeConstructor) return emptyList()
|
if (this is ErrorTypeConstructor) return emptyList()
|
||||||
//require(this is ConeSymbol)
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeTypeVariableTypeConstructor -> emptyList()
|
is ConeTypeVariableTypeConstructor -> emptyList()
|
||||||
is ConeTypeParameterLookupTag -> symbol.fir.bounds.map { it.coneType }
|
is ConeTypeParameterLookupTag -> symbol.fir.bounds.map { it.coneType }
|
||||||
@@ -307,56 +306,14 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
fir.classKind != ClassKind.ANNOTATION_CLASS
|
fir.classKind != ClassKind.ANNOTATION_CLASS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
||||||
|
require(type is ConeKotlinType)
|
||||||
|
return captureFromExpressionInternal(type)
|
||||||
|
}
|
||||||
|
|
||||||
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? {
|
||||||
require(type is ConeKotlinType)
|
require(type is ConeKotlinType)
|
||||||
val argumentsCount = type.typeArguments.size
|
return captureFromArgumentsInternal(type, status) as SimpleTypeMarker?
|
||||||
if (argumentsCount == 0) return null
|
|
||||||
|
|
||||||
val typeConstructor = type.typeConstructor()
|
|
||||||
if (argumentsCount != typeConstructor.parametersCount()) return null
|
|
||||||
|
|
||||||
if (type.typeArguments.all { it !is ConeStarProjection && it.kind == ProjectionKind.INVARIANT }) return null
|
|
||||||
|
|
||||||
val newArguments = Array(argumentsCount) { index ->
|
|
||||||
val argument = type.typeArguments[index]
|
|
||||||
if (argument !is ConeStarProjection && argument.kind == ProjectionKind.INVARIANT) return@Array argument
|
|
||||||
|
|
||||||
val lowerType = if (argument !is ConeStarProjection && argument.getVariance() == TypeVariance.IN) {
|
|
||||||
(argument as ConeKotlinTypeProjection).type
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
ConeCapturedType(status, lowerType, argument, typeConstructor.getParameter(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
val substitutor = substitutorByMap((0 until argumentsCount).map { index ->
|
|
||||||
(typeConstructor.getParameter(index) as ConeTypeParameterLookupTag).symbol to (newArguments[index] as ConeKotlinType)
|
|
||||||
}.toMap())
|
|
||||||
|
|
||||||
for (index in 0 until argumentsCount) {
|
|
||||||
val oldArgument = type.typeArguments[index]
|
|
||||||
val newArgument = newArguments[index]
|
|
||||||
|
|
||||||
if (oldArgument !is ConeStarProjection && oldArgument.kind == ProjectionKind.INVARIANT) continue
|
|
||||||
|
|
||||||
val parameter = typeConstructor.getParameter(index)
|
|
||||||
val upperBounds = (0 until parameter.upperBoundCount()).mapTo(mutableListOf()) { paramIndex ->
|
|
||||||
substitutor.safeSubstitute(
|
|
||||||
this as TypeSystemInferenceExtensionContext, parameter.getUpperBound(paramIndex)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!oldArgument.isStarProjection() && oldArgument.getVariance() == TypeVariance.OUT) {
|
|
||||||
upperBounds += oldArgument.getType()
|
|
||||||
}
|
|
||||||
|
|
||||||
require(newArgument is ConeCapturedType)
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
newArgument.constructor.supertypes = upperBounds as List<ConeKotlinType>
|
|
||||||
}
|
|
||||||
|
|
||||||
return type.withArguments(newArguments)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
|
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
|
||||||
@@ -392,10 +349,6 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
typeConstructor is ConeTypeParameterLookupTag
|
typeConstructor is ConeTypeParameterLookupTag
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
|
|
||||||
TODO("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
|
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
|
||||||
if (this is ConeClassLikeType) {
|
if (this is ConeClassLikeType) {
|
||||||
return StandardClassIds.primitiveTypes.contains(this.lookupTag.classId)
|
return StandardClassIds.primitiveTypes.contains(this.lookupTag.classId)
|
||||||
@@ -417,7 +370,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>) as SimpleTypeMarker
|
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>) as SimpleTypeMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
override fun intersectTypes(types: List<KotlinTypeMarker>): ConeKotlinType {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>)
|
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.classId
|
import org.jetbrains.kotlin.fir.declarations.classId
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
@@ -22,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
|||||||
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
|
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
||||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
|
||||||
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
|
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
|
||||||
return when (types.size) {
|
return when (types.size) {
|
||||||
@@ -322,3 +325,159 @@ private fun FirTypeRef.hideLocalTypeIfNeeded(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ConeTypeContext.captureFromArgumentsInternal(type: ConeKotlinType, status: CaptureStatus): ConeKotlinType? {
|
||||||
|
val capturedArguments = captureArguments(type, status) ?: return null
|
||||||
|
return if (type is ConeFlexibleType) {
|
||||||
|
ConeFlexibleType(
|
||||||
|
type.lowerBound.withArguments(capturedArguments),
|
||||||
|
type.upperBound.withArguments(capturedArguments),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
type.withArguments(capturedArguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeTypeContext.captureArguments(type: ConeKotlinType, status: CaptureStatus): Array<ConeTypeProjection>? {
|
||||||
|
val argumentsCount = type.typeArguments.size
|
||||||
|
if (argumentsCount == 0) return null
|
||||||
|
|
||||||
|
val typeConstructor = type.typeConstructor()
|
||||||
|
if (argumentsCount != typeConstructor.parametersCount()) return null
|
||||||
|
|
||||||
|
if (type.typeArguments.all { it !is ConeStarProjection && it.kind == ProjectionKind.INVARIANT }) return null
|
||||||
|
|
||||||
|
val newArguments = Array(argumentsCount) { index ->
|
||||||
|
val argument = type.typeArguments[index]
|
||||||
|
if (argument !is ConeStarProjection && argument.kind == ProjectionKind.INVARIANT) return@Array argument
|
||||||
|
|
||||||
|
val lowerType = if (argument !is ConeStarProjection && argument.getVariance() == TypeVariance.IN) {
|
||||||
|
(argument as ConeKotlinTypeProjection).type
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
ConeCapturedType(status, lowerType, argument, typeConstructor.getParameter(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
val substitutor = substitutorByMap((0 until argumentsCount).map { index ->
|
||||||
|
(typeConstructor.getParameter(index) as ConeTypeParameterLookupTag).symbol to (newArguments[index] as ConeKotlinType)
|
||||||
|
}.toMap())
|
||||||
|
|
||||||
|
for (index in 0 until argumentsCount) {
|
||||||
|
val oldArgument = type.typeArguments[index]
|
||||||
|
val newArgument = newArguments[index]
|
||||||
|
|
||||||
|
if (oldArgument !is ConeStarProjection && oldArgument.kind == ProjectionKind.INVARIANT) continue
|
||||||
|
|
||||||
|
val parameter = typeConstructor.getParameter(index)
|
||||||
|
val upperBounds = (0 until parameter.upperBoundCount()).mapTo(mutableListOf()) { paramIndex ->
|
||||||
|
substitutor.safeSubstitute(
|
||||||
|
this as TypeSystemInferenceExtensionContext, parameter.getUpperBound(paramIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oldArgument.isStarProjection() && oldArgument.getVariance() == TypeVariance.OUT) {
|
||||||
|
upperBounds += oldArgument.getType()
|
||||||
|
}
|
||||||
|
|
||||||
|
require(newArgument is ConeCapturedType)
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
newArgument.constructor.supertypes = upperBounds as List<ConeKotlinType>
|
||||||
|
}
|
||||||
|
return newArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKotlinType? {
|
||||||
|
if (type !is ConeIntersectionType && type !is ConeFlexibleType) {
|
||||||
|
return captureFromArgumentsInternal(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<Captured1(*)>..List<Captured2(*)>?, 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: ConeKotlinType) =
|
||||||
|
capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments
|
||||||
|
|
||||||
|
fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeKotlinType): List<ConeKotlinType> {
|
||||||
|
return if (typeToReplace is ConeIntersectionType) {
|
||||||
|
typeToReplace.intersectedTypes.map { componentType ->
|
||||||
|
val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType)
|
||||||
|
?: return@map componentType
|
||||||
|
componentType.withArguments(capturedArguments)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val capturedArguments = findCorrespondingCapturedArgumentsForType(typeToReplace)
|
||||||
|
?: return listOf(typeToReplace)
|
||||||
|
listOf(typeToReplace.withArguments(capturedArguments))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (type is ConeFlexibleType) {
|
||||||
|
val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound))
|
||||||
|
.withNullability(type.lowerBound.isMarkedNullable) as ConeKotlinType
|
||||||
|
val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound))
|
||||||
|
.withNullability(type.upperBound.isMarkedNullable) as ConeKotlinType
|
||||||
|
|
||||||
|
ConeFlexibleType(lowerIntersectedType, upperIntersectedType)
|
||||||
|
} else {
|
||||||
|
intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeTypeContext.captureArgumentsForIntersectionType(type: ConeKotlinType): List<CapturedArguments>? {
|
||||||
|
// It's possible to have one of the bounds as non-intersection type
|
||||||
|
fun getTypesToCapture(type: ConeKotlinType) =
|
||||||
|
if (type is ConeIntersectionType) type.intersectedTypes else listOf(type)
|
||||||
|
|
||||||
|
val filteredTypesToCapture =
|
||||||
|
when (type) {
|
||||||
|
is ConeFlexibleType -> {
|
||||||
|
val typesToCapture = getTypesToCapture(type.lowerBound) + getTypesToCapture(type.upperBound)
|
||||||
|
typesToCapture.distinctBy {
|
||||||
|
(ConeFlexibleTypeBoundsChecker.getBaseBoundFqNameByMutability(it) ?: it.typeConstructor(this)) to it.typeArguments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ConeIntersectionType -> type.intersectedTypes
|
||||||
|
else -> error("Should not be here")
|
||||||
|
}
|
||||||
|
|
||||||
|
var changed = false
|
||||||
|
|
||||||
|
val capturedArgumentsByTypes = filteredTypesToCapture.mapNotNull { typeToCapture ->
|
||||||
|
val capturedArguments = captureArguments(typeToCapture, CaptureStatus.FROM_EXPRESSION)
|
||||||
|
?: return@mapNotNull null
|
||||||
|
changed = true
|
||||||
|
CapturedArguments(capturedArguments, originalType = typeToCapture)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) return null
|
||||||
|
|
||||||
|
return capturedArgumentsByTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CapturedArguments(val capturedArguments: Array<ConeTypeProjection>, private val originalType: ConeKotlinType) {
|
||||||
|
fun isSuitableForType(type: ConeKotlinType, context: ConeTypeContext): Boolean {
|
||||||
|
val areArgumentsMatched = type.typeArguments.withIndex().all { (i, typeArgumentsType) ->
|
||||||
|
originalType.typeArguments.size > i && typeArgumentsType == originalType.typeArguments[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!areArgumentsMatched) return false
|
||||||
|
|
||||||
|
val areConstructorsMatched = originalType.typeConstructor(context) == type.typeConstructor(context)
|
||||||
|
|| ConeFlexibleTypeBoundsChecker.areTypesMayBeLowerAndUpperBoundsOfSameFlexibleTypeByMutability(originalType, type)
|
||||||
|
|
||||||
|
if (!areConstructorsMatched) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,4 +7,4 @@ class A<T>
|
|||||||
fun <T1> A<T1>.foo() = X1
|
fun <T1> A<T1>.foo() = X1
|
||||||
fun <T2> A<out T2>.foo() = X2
|
fun <T2> A<out T2>.foo() = X2
|
||||||
|
|
||||||
fun <T> A<out T>.test() = foo() // TODO fix constraint system
|
fun <T> A<out T>.test() = <!AMBIGUITY!>foo<!>() // TODO fix constraint system
|
||||||
|
|||||||
@@ -10,29 +10,29 @@ fun <T> case_1(x: T) {
|
|||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!><!UNSAFE_CALL!>.<!>propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>propAny<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!><!UNSAFE_CALL!>.<!>funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>funAny<!>()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propT }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propT }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!UNSAFE_CALL!>propAny<!> }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!INAPPLICABLE_CANDIDATE!>propAny<!> }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propNullableT }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propNullableT }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propNullableAny }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { propNullableAny }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funT() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funT() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!UNSAFE_CALL!>funAny<!>() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { <!INAPPLICABLE_CANDIDATE!>funAny<!>() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funNullableT() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funNullableT() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funNullableAny(); <!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.apply { funNullableAny(); <!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null) }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propT }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propT }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!><!UNSAFE_CALL!>.<!>propAny }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.<!INAPPLICABLE_CANDIDATE!>propAny<!> }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propNullableT }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propNullableT }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propNullableAny }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.propNullableAny }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funT() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funT() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!><!UNSAFE_CALL!>.<!>funAny() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.<!INAPPLICABLE_CANDIDATE!>funAny<!>() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funNullableT() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funNullableT() }
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funNullableAny() }
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.also { <!DEBUG_INFO_EXPRESSION_TYPE("T")!>it<!>.funNullableAny() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,11 +246,11 @@ fun <T>case_18(x: T, f: Boolean) {
|
|||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!><!UNSAFE_CALL!>.<!>propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>propAny<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!><!UNSAFE_CALL!>.<!>funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.<!INAPPLICABLE_CANDIDATE!>funAny<!>()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T")!>x<!>.funNullableAny()
|
||||||
}
|
}
|
||||||
@@ -263,21 +263,21 @@ fun <K, V>case_19(map: MutableMap<K, V>, y: Nothing?) {
|
|||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!><!UNSAFE_CALL!>.<!>propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.<!INAPPLICABLE_CANDIDATE!>propAny<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!><!UNSAFE_CALL!>.<!>funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.<!INAPPLICABLE_CANDIDATE!>funAny<!>()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>k<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!><!UNSAFE_CALL!>.<!>propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.<!INAPPLICABLE_CANDIDATE!>propAny<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!><!UNSAFE_CALL!>.<!>funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.<!INAPPLICABLE_CANDIDATE!>funAny<!>()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.funNullableAny()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user