[FIR] Implement capturing of cone types same as for kotlin types

This commit is contained in:
Dmitriy Novozhilov
2021-02-03 11:44:55 +03:00
parent 5ce36a528e
commit 373bc578fb
9 changed files with 243 additions and 73 deletions
@@ -14,10 +14,12 @@ object StandardClassIds {
val BASE_KOTLIN_PACKAGE = FqName("kotlin")
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 ClassId.unsignedId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier("U" + shortClassName.identifier))
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 String.collectionsId() = ClassId(BASE_COLLECTIONS_PACKAGE, Name.identifier(this))
val Nothing = "Nothing".baseId()
val Unit = "Unit".baseId()
@@ -85,6 +87,25 @@ object StandardClassIds {
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()
}
@@ -143,7 +143,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
if (types.any { it.isEmpty() }) return mutableSetOf()
val intersectedTypes = types.map {
if (it.size > 1) {
context.intersectTypes(it.toList()) as ConeKotlinType
context.intersectTypes(it.toList())
} else {
assert(it.size == 1) { "We've already checked each set of types is not empty." }
it.single()
@@ -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
}
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
return type
}
override fun createErrorType(debugName: String): ConeClassErrorType {
return ConeClassErrorType(ConeIntermediateDiagnostic(debugName))
}
@@ -228,9 +228,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
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()
//require(this is ConeSymbol)
return when (this) {
is ConeTypeVariableTypeConstructor -> emptyList()
is ConeTypeParameterLookupTag -> symbol.fir.bounds.map { it.coneType }
@@ -307,56 +306,14 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
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? {
require(type is ConeKotlinType)
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 type.withArguments(newArguments)
return captureFromArgumentsInternal(type, status) as SimpleTypeMarker?
}
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
@@ -392,10 +349,6 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
typeConstructor is ConeTypeParameterLookupTag
}
override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? {
TODO("not implemented")
}
override fun SimpleTypeMarker.isPrimitiveType(): Boolean {
if (this is ConeClassLikeType) {
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
}
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
override fun intersectTypes(types: List<KotlinTypeMarker>): ConeKotlinType {
@Suppress("UNCHECKED_CAST")
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.diagnostics.ConeSimpleDiagnostic
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.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
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.AbstractTypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.model.*
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
return when (types.size) {
@@ -322,3 +325,159 @@ private fun FirTypeRef.hideLocalTypeIfNeeded(
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
}
}
@@ -7,4 +7,4 @@ class A<T>
fun <T1> A<T1>.foo() = X1
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<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
<!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<!>.propNullableAny
<!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<!>.funNullableAny()
<!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 { <!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 { propNullableAny }
<!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 { 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<!>.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<!>.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<!><!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<!>.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<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
<!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<!>.propNullableAny
<!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<!>.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<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
<!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<!>.propNullableAny
<!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<!>.funNullableAny()
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>
<!DEBUG_INFO_EXPRESSION_TYPE("V")!>v<!>.<!INAPPLICABLE_CANDIDATE!>equals<!>(null)
<!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<!>.propNullableAny
<!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<!>.funNullableAny()
}