[FIR] Add implementation of intersection types to Fir type system

This commit is contained in:
Dmitriy Novozhilov
2019-07-29 09:59:33 +03:00
parent 1708a34eb8
commit 637fb55a7b
17 changed files with 350 additions and 26 deletions
@@ -173,4 +173,53 @@ class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(),
get() = original.typeArguments get() = original.typeArguments
override val nullability: ConeNullability override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL get() = ConeNullability.NOT_NULL
}
/*
* Contract of the intersection type: it is flat. It means that
* intersection type can not contains another intersection types
* inside it. To keep this contract construct new intersection types
* only via ConeTypeIntersector
*/
class ConeIntersectionType(
val constructor: ConeIntersectionTypeConstructor
) : ConeKotlinType(), SimpleTypeMarker {
override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = emptyArray()
override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL
val intersectedTypes: Collection<ConeKotlinType> get() = constructor.intersectedTypes
val statusMap: Map<ConeKotlinType, ConeIntersectionTypeConstructor.IntersectionStatus> get() = constructor.statusMap
}
class ConeIntersectionTypeConstructor(
val intersectedTypes: Collection<ConeKotlinType>,
val statusMap: Map<ConeKotlinType, IntersectionStatus>
) : TypeConstructorMarker {
val supertypes: Collection<ConeKotlinType> get() = intersectedTypes
/*
* IMPORTANT: use this method only for types from intersectedTypes
*/
fun getStatus(type: ConeKotlinType): IntersectionStatus {
return statusMap[type] ?: error("")
}
enum class IntersectionStatus {
FROM_INFERENCE,
FROM_SMARTCAST
}
}
fun ConeIntersectionTypeConstructor.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionTypeConstructor {
val newStatusMap = mutableMapOf<ConeKotlinType, ConeIntersectionTypeConstructor.IntersectionStatus>()
val newTypes = intersectedTypes.map { type ->
val newType = func(type)
// TODO: what if some types squash? What status should we choose?
newStatusMap[newType] = getStatus(type)
newType
}
return ConeIntersectionTypeConstructor(newTypes, newStatusMap)
} }
@@ -39,5 +39,12 @@ fun ConeKotlinType.render(): String {
append(">") append(">")
} }
} }
is ConeIntersectionType -> {
intersectedTypes.joinToString(
separator = " & ",
prefix = "it(",
postfix = ")"
)
}
} + nullabilitySuffix } + nullabilitySuffix
} }
@@ -599,6 +599,12 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
} }
} }
private fun FlowContent.generate(intersectionType: ConeIntersectionType) {
+"("
generateList(intersectionType.intersectedTypes.toList(), " & ") { generate(it) }
+")"
}
private fun FlowContent.generate(type: ConeClassType) { private fun FlowContent.generate(type: ConeClassType) {
resolved { resolved {
symbolRef(type.lookupTag.toSymbol(session)) { symbolRef(type.lookupTag.toSymbol(session)) {
@@ -704,6 +710,7 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
is ConeFlexibleType -> resolved { generate(type) } is ConeFlexibleType -> resolved { generate(type) }
is ConeCapturedType -> inlineUnsupported(type) is ConeCapturedType -> inlineUnsupported(type)
is ConeDefinitelyNotNullType -> inlineUnsupported(type) is ConeDefinitelyNotNullType -> inlineUnsupported(type)
is ConeIntersectionType -> resolved { generate(type) }
} }
if (type.typeArguments.isNotEmpty()) { if (type.typeArguments.isNotEmpty()) {
+"<" +"<"
@@ -58,6 +58,10 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla
} }
is ConeCapturedType -> TODO() is ConeCapturedType -> TODO()
is ConeDefinitelyNotNullType -> TODO() is ConeDefinitelyNotNullType -> TODO()
is ConeIntersectionType -> {
// TODO: add intersectionTypeApproximation
intersectedTypes.first().toIrType(session, declarationStorage)
}
} }
} }
@@ -164,6 +164,13 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T
is ConeIntersectionType -> when (nullability) {
ConeNullability.NULLABLE -> ConeIntersectionType(constructor.mapTypes {
it.withNullability(nullability)
})
ConeNullability.UNKNOWN -> this // TODO: is that correct?
ConeNullability.NOT_NULL -> this
} as T
else -> error("sealed: ${this::class}") else -> error("sealed: ${this::class}")
} }
} }
@@ -38,6 +38,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
) )
} }
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession) is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession)
is ConeIntersectionType -> FirCompositeScope(intersectedTypes.mapNotNullTo(mutableListOf()) { it.scope(useSiteSession, scopeSession) })
else -> error("Failed type ${this}") else -> error("Failed type ${this}")
} }
} }
@@ -75,9 +75,23 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
is ConeFlexibleType -> this.substituteBounds() is ConeFlexibleType -> this.substituteBounds()
is ConeCapturedType -> return null is ConeCapturedType -> return null
is ConeDefinitelyNotNullType -> this.substituteOriginal() is ConeDefinitelyNotNullType -> this.substituteOriginal()
is ConeIntersectionType -> this.substituteIntersectedTypes()
} }
} }
private fun ConeIntersectionType.substituteIntersectedTypes(): ConeIntersectionType? {
val substitutedTypes = ArrayList<ConeKotlinType>(intersectedTypes.size)
var somethingIsSubstituted = false
for (type in intersectedTypes) {
val substitutedType = substituteOrNull(type)?.also {
somethingIsSubstituted = true
} ?: type
substitutedTypes += substitutedType
}
if (!somethingIsSubstituted) return null
return ConeIntersectionType(ConeIntersectionTypeConstructor(substitutedTypes, statusMap))
}
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? { private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? {
TODO() TODO()
} }
@@ -60,6 +60,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is ConeCapturedType -> this is ConeCapturedType -> this
is ConeLookupTagBasedType -> this is ConeLookupTagBasedType -> this
is ConeDefinitelyNotNullType -> this is ConeDefinitelyNotNullType -> this
is ConeIntersectionType -> this
is ConeFlexibleType -> null is ConeFlexibleType -> null
else -> error("Unknown simpleType: $this") else -> error("Unknown simpleType: $this")
} }
@@ -128,6 +129,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
typeArguments, typeArguments,
nullable nullable
) )
is ConeIntersectionType -> this.withNullability(ConeNullability.create(nullable))
else -> error("!") else -> error("!")
} }
} }
@@ -139,6 +141,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor() is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor()
?: ErrorTypeConstructor("Failed to expand alias: ${this}") ?: ErrorTypeConstructor("Failed to expand alias: ${this}")
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}") is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
is ConeIntersectionType -> constructor
else -> error("?: ${this}") else -> error("?: ${this}")
} }
@@ -199,7 +202,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
override fun TypeConstructorMarker.parametersCount(): Int { override fun TypeConstructorMarker.parametersCount(): Int {
//require(this is ConeSymbol) //require(this is ConeSymbol)
return when (this) { return when (this) {
is ConeTypeParameterSymbol, is ConeCapturedTypeConstructor, is ErrorTypeConstructor, is ConeTypeVariableTypeConstructor -> 0 is ConeTypeParameterSymbol,
is ConeCapturedTypeConstructor,
is ErrorTypeConstructor,
is ConeTypeVariableTypeConstructor,
is ConeIntersectionTypeConstructor -> 0
is FirClassSymbol -> fir.typeParameters.size is FirClassSymbol -> fir.typeParameters.size
is FirTypeAliasSymbol -> fir.typeParameters.size is FirTypeAliasSymbol -> fir.typeParameters.size
else -> error("?!:10") else -> error("?!:10")
@@ -225,12 +232,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is FirClassSymbol -> fir.superConeTypes is FirClassSymbol -> fir.superConeTypes
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType) is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
is ConeCapturedTypeConstructor -> supertypes!! is ConeCapturedTypeConstructor -> supertypes!!
is ConeIntersectionTypeConstructor -> intersectedTypes
else -> error("?!:13") else -> error("?!:13")
} }
} }
override fun TypeConstructorMarker.isIntersection(): Boolean { override fun TypeConstructorMarker.isIntersection(): Boolean {
return false // TODO return this is ConeIntersectionTypeConstructor
} }
override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean { override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean {
@@ -269,8 +277,9 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
override fun TypeConstructorMarker.isDenotable(): Boolean { override fun TypeConstructorMarker.isDenotable(): Boolean {
//TODO //TODO
return when (this) { return when (this) {
is ConeCapturedTypeConstructor -> false is ConeCapturedTypeConstructor,
is ConeTypeVariableTypeConstructor -> false is ConeTypeVariableTypeConstructor,
is ConeIntersectionTypeConstructor -> false
is ConeSymbol -> true is ConeSymbol -> true
else -> true else -> true
} }
@@ -351,6 +360,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
if (isError()) return false if (isError()) return false
if (this is ConeCapturedType) return true if (this is ConeCapturedType) return true
if (this is ConeTypeVariableType) return false if (this is ConeTypeVariableType) return false
if (this is ConeIntersectionType) return false
require(this is ConeLookupTagBasedType) require(this is ConeLookupTagBasedType)
val typeConstructor = this.typeConstructor() val typeConstructor = this.typeConstructor()
return typeConstructor is FirClassSymbol || return typeConstructor is FirClassSymbol ||
@@ -370,11 +380,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
} }
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker { override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
return types.first() // TODO: proper implementation @Suppress("UNCHECKED_CAST")
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>) as SimpleTypeMarker
} }
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker { override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
return types.first() // TODO: proper implementation @Suppress("UNCHECKED_CAST")
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>)
} }
private fun prepareClassLikeType( private fun prepareClassLikeType(
@@ -0,0 +1,185 @@
/*
* Copyright 2010-2019 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.fir.resolve.calls.ConeInferenceContext
import org.jetbrains.kotlin.fir.types.ConeIntersectionTypeConstructor.IntersectionStatus
import org.jetbrains.kotlin.types.AbstractTypeChecker
import java.util.*
import kotlin.collections.LinkedHashSet
object ConeTypeIntersector {
fun intersectTypes(context: ConeTypeContext, types: List<ConeKotlinType>): ConeKotlinType {
require(context is ConeInferenceContext)
return intersectTypes(context, types, types.map { IntersectionStatus.FROM_INFERENCE })
}
private fun intersectTypes(
context: ConeInferenceContext,
types: List<ConeKotlinType>,
intersectionStatus: List<IntersectionStatus>
): ConeKotlinType {
assert(types.size == intersectionStatus.size)
when (types.size) {
0 -> error("Expected some types")
1 -> return types.single()
}
val inputTypes = mutableListOf<ConeKotlinType>()
val statusMap = mutableMapOf<ConeKotlinType, IntersectionStatus>()
flatIntersectionTypes(types, intersectionStatus, inputTypes, statusMap)
/**
* resultNullability. Value description:
* ACCEPT_NULL means that all types marked nullable
*
* NOT_NULL means that there is one type which is subtype of Any => all types can be made definitely not null,
* making types definitely not null (not just not null) makes sense when we have intersection of type parameters like {T!! & S}
*
* UNKNOWN means, that we do not know, i.e. more precisely, all singleClassifier types marked nullable if any,
* and other types is captured types or type parameters without not-null upper bound. Example: `String? & T` such types we should leave as is.
*/
val resultNullability = inputTypes.fold(ResultNullability.START) { nullability, nextType ->
nullability.combine(nextType.type, context)
}
val inputTypesWithCorrectNullability = inputTypes.mapTo(LinkedHashSet()) {
if (resultNullability == ResultNullability.NOT_NULL) with(context) {
val resultType = it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType
statusMap[resultType] = statusMap.remove(it)!!
resultType
} else it
}
return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability, statusMap)
}
private fun intersectTypesWithoutIntersectionType(
context: ConeTypeContext,
inputTypes: Set<ConeKotlinType>,
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
): ConeKotlinType {
if (inputTypes.size == 1) return inputTypes.single().type
// Any and Nothing should leave
// Note that duplicates should be dropped because we have Set here.
val errorMessage = { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" }
val filteredEqualTypes = filterTypes(inputTypes) { lower, upper ->
/*
* Here we drop types from intersection set for cases like that:
*
* interface A
* interface B : A
*
* type = (A & B & ...)
*
* We want to drop A from that set, because it's useless for type checking. But in case if
* A came from inference and B came from smartcast we want to safe both types in intersection
*/
isStrictSupertype(context, lower, upper) && statusMap[lower]!! <= statusMap[upper]!!
}
assert(filteredEqualTypes.isNotEmpty(), errorMessage)
// TODO
// IntegerLiteralTypeConstructor.findIntersectionType(filteredEqualTypes)?.let { return it }
val filteredSuperAndEqualTypes = filterTypes(filteredEqualTypes) { a, b ->
AbstractTypeChecker.equalTypes(context, a, b)
}
assert(filteredSuperAndEqualTypes.isNotEmpty(), errorMessage)
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
val constructor = ConeIntersectionTypeConstructor(
filteredSuperAndEqualTypes,
filteredSuperAndEqualTypes.associateWithTo(mutableMapOf()) { statusMap[it]!! }
)
return ConeIntersectionType(constructor)
}
private fun filterTypes(
inputTypes: Collection<ConeKotlinType>,
predicate: (lower: ConeKotlinType, upper: ConeKotlinType) -> Boolean
): List<ConeKotlinType> {
val filteredTypes = ArrayList(inputTypes)
val iterator = filteredTypes.iterator()
while (iterator.hasNext()) {
val upper = iterator.next()
val shouldFilter = filteredTypes.any { lower -> lower !== upper && predicate(lower, upper) }
if (shouldFilter) iterator.remove()
}
return filteredTypes
}
private fun isStrictSupertype(context: ConeTypeContext, subtype: ConeKotlinType, supertype: ConeKotlinType): Boolean {
return with(AbstractTypeChecker) {
isSubtypeOf(context, subtype, supertype) && !isSubtypeOf(context, supertype, subtype)
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun MutableMap<ConeKotlinType, IntersectionStatus>.updateStatus(type: ConeKotlinType, status: IntersectionStatus) {
// We should keep status FROM_SMARTCAST for correct diagnostic reporting
val existingStatus = get(type)
if (existingStatus == null) {
put(type, status)
} else {
put(type, minOf(status, existingStatus))
}
}
private fun flatIntersectionTypes(
inputTypes: List<ConeKotlinType>,
intersectionStatus: List<IntersectionStatus>,
typeCollector: MutableList<ConeKotlinType>,
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
) {
for ((inputType, status) in inputTypes.zip(intersectionStatus)) {
if (inputType is ConeIntersectionType) {
for (type in inputType.intersectedTypes) {
typeCollector += type
statusMap.updateStatus(type, status)
}
} else {
typeCollector += inputType
statusMap.updateStatus(inputType, status)
}
}
}
private enum class ResultNullability {
START {
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
nextType.resultNullability(context)
},
ACCEPT_NULL {
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
nextType.resultNullability(context)
},
// example: type parameter without not-null supertype
UNKNOWN {
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability =
nextType.resultNullability(context).let {
if (it == ACCEPT_NULL) this else it
}
},
NOT_NULL {
override fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability = this
};
abstract fun combine(nextType: ConeKotlinType, context: ConeTypeContext): ResultNullability
protected fun ConeKotlinType.resultNullability(context: ConeTypeContext): ResultNullability =
when {
isMarkedNullable -> ACCEPT_NULL
ConeNullabilityChecker.isSubtypeOfAny(context, this) -> NOT_NULL
else -> UNKNOWN
}
}
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2019 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.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
object ConeNullabilityChecker {
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
val actualType = with(context) { type.lowerBoundIfFlexible() }
return with(AbstractNullabilityChecker) {
context.newBaseTypeCheckerContext(false)
.hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible)
}
}
}
@@ -0,0 +1,14 @@
interface A
interface B
class Clazz1 : A, B
class Clazz2 : A, B
fun <K> select(x: K, y: K): K
fun test() = select(Clazz1(), Clazz2())
fun <T> makeNull(x: T): T? = null
fun testNull() = makeNull(select(Clazz1(), Clazz2()))
@@ -19,9 +19,9 @@ FILE: intersectionTypes.kt
public final fun test(): R|it(A & B)| { public final fun test(): R|it(A & B)| {
^test R|/select|<R|it(A & B)|>(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|()) ^test R|/select|<R|it(A & B)|>(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|())
} }
public final fun <T> makeNull(x: R|T|): R|T|? { public final fun <T> makeNull(x: R|T|): R|T?| {
^makeNull Null(null) ^makeNull Null(null)
} }
public final fun testNull(): R|it(A & B)| { public final fun testNull(): R|it(A? & B?)| {
^testNull R|/makeNull|<R|it(A & B)|>(R|/select|<R|it(A & B)|>(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|())) ^testNull R|/makeNull|<R|it(A & B)|>(R|/select|<R|it(A & B)|>(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|()))
} }
@@ -94,6 +94,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
runTest("compiler/fir/resolve/testData/resolve/genericFunctions.kt"); runTest("compiler/fir/resolve/testData/resolve/genericFunctions.kt");
} }
@TestMetadata("intersectionTypes.kt")
public void testIntersectionTypes() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/intersectionTypes.kt");
}
@TestMetadata("nestedClass.kt") @TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception { public void testNestedClass() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/nestedClass.kt"); runTest("compiler/fir/resolve/testData/resolve/nestedClass.kt");
@@ -34,7 +34,7 @@ FILE fqName:<root> fileName:/intersectionType1_NI.kt
RETURN type=kotlin.Nothing from='public final fun foo <T> (a: kotlin.Array<<root>.In<T of <root>.foo>>, b: kotlin.Array<<root>.In<kotlin.String>>): kotlin.Boolean declared in <root>' RETURN type=kotlin.Nothing from='public final fun foo <T> (a: kotlin.Array<<root>.In<T of <root>.foo>>, b: kotlin.Array<<root>.In<kotlin.String>>): kotlin.Boolean declared in <root>'
CALL 'public final fun ofType <K> (y: kotlin.Any?): kotlin.Boolean [inline] declared in <root>' type=kotlin.Boolean origin=null CALL 'public final fun ofType <K> (y: kotlin.Any?): kotlin.Boolean [inline] declared in <root>' type=kotlin.Boolean origin=null
$receiver: CALL 'public final fun get (index: kotlin.Int): <root>.In<T of <root>.foo> declared in kotlin.Array' type=<root>.In<T of <root>.foo> origin=null $receiver: CALL 'public final fun get (index: kotlin.Int): <root>.In<T of <root>.foo> declared in kotlin.Array' type=<root>.In<T of <root>.foo> origin=null
$this: CALL 'public final fun select <S> (x: S of <root>.select, y: S of <root>.select): S of <root>.select declared in <root>' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null $this: CALL 'public final fun select <S> (x: S of <root>.select, y: S of <root>.select): S of <root>.select declared in <root>' type=kotlin.Array<out <root>.In<T of <root>.foo>> origin=null
<S>: <none> <S>: <none>
x: GET_VAR 'a: kotlin.Array<<root>.In<T of <root>.foo>> declared in <root>.foo' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null x: GET_VAR 'a: kotlin.Array<<root>.In<T of <root>.foo>> declared in <root>.foo' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null
y: GET_VAR 'b: kotlin.Array<<root>.In<kotlin.String>> declared in <root>.foo' type=kotlin.Array<<root>.In<kotlin.String>> origin=null y: GET_VAR 'b: kotlin.Array<<root>.In<kotlin.String>> declared in <root>.foo' type=kotlin.Array<<root>.In<kotlin.String>> origin=null
@@ -34,7 +34,7 @@ FILE fqName:<root> fileName:/intersectionType1_OI.kt
RETURN type=kotlin.Nothing from='public final fun foo <T> (a: kotlin.Array<<root>.In<T of <root>.foo>>, b: kotlin.Array<<root>.In<kotlin.String>>): kotlin.Boolean declared in <root>' RETURN type=kotlin.Nothing from='public final fun foo <T> (a: kotlin.Array<<root>.In<T of <root>.foo>>, b: kotlin.Array<<root>.In<kotlin.String>>): kotlin.Boolean declared in <root>'
CALL 'public final fun ofType <K> (y: kotlin.Any?): kotlin.Boolean [inline] declared in <root>' type=kotlin.Boolean origin=null CALL 'public final fun ofType <K> (y: kotlin.Any?): kotlin.Boolean [inline] declared in <root>' type=kotlin.Boolean origin=null
$receiver: CALL 'public final fun get (index: kotlin.Int): <root>.In<T of <root>.foo> declared in kotlin.Array' type=<root>.In<T of <root>.foo> origin=null $receiver: CALL 'public final fun get (index: kotlin.Int): <root>.In<T of <root>.foo> declared in kotlin.Array' type=<root>.In<T of <root>.foo> origin=null
$this: CALL 'public final fun select <S> (x: S of <root>.select, y: S of <root>.select): S of <root>.select declared in <root>' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null $this: CALL 'public final fun select <S> (x: S of <root>.select, y: S of <root>.select): S of <root>.select declared in <root>' type=kotlin.Array<out <root>.In<T of <root>.foo>> origin=null
<S>: <none> <S>: <none>
x: GET_VAR 'a: kotlin.Array<<root>.In<T of <root>.foo>> declared in <root>.foo' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null x: GET_VAR 'a: kotlin.Array<<root>.In<T of <root>.foo>> declared in <root>.foo' type=kotlin.Array<<root>.In<T of <root>.foo>> origin=null
y: GET_VAR 'b: kotlin.Array<<root>.In<kotlin.String>> declared in <root>.foo' type=kotlin.Array<<root>.In<kotlin.String>> origin=null y: GET_VAR 'b: kotlin.Array<<root>.In<kotlin.String>> declared in <root>.foo' type=kotlin.Array<<root>.In<kotlin.String>> origin=null
@@ -75,24 +75,24 @@ FILE fqName:<root> fileName:/intersectionType2_NI.kt
RETURN type=kotlin.Nothing from='public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' RETURN type=kotlin.Nothing from='public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>'
CALL 'public abstract fun invoke (): T of <root>.run declared in kotlin.Function0' type=T of <root>.run origin=null CALL 'public abstract fun invoke (): T of <root>.run declared in kotlin.Function0' type=T of <root>.run origin=null
$this: GET_VAR 'fn: kotlin.Function0<T of <root>.run> declared in <root>.run' type=kotlin.Function0<T of <root>.run> origin=null $this: GET_VAR 'fn: kotlin.Function0<T of <root>.run> declared in <root>.run' type=kotlin.Function0<T of <root>.run> origin=null
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.B FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.Foo
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun foo (): <root>.B declared in <root>' RETURN type=kotlin.Nothing from='public final fun foo (): <root>.Foo declared in <root>'
CALL 'public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' type=<root>.B origin=null CALL 'public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' type=<root>.Foo origin=null
<T>: <none> <T>: <none>
fn: FUN_EXPR type=kotlin.Function0<<root>.B> origin=LAMBDA fn: FUN_EXPR type=kotlin.Function0<<root>.Foo> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.B FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.Foo
BLOCK_BODY BLOCK_BODY
VAR name:mm type:<root>.B [val] VAR name:mm type:<root>.B [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null
VAR name:nn type:<root>.C [val] VAR name:nn type:<root>.C [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
VAR name:c type:<root>.B [val] VAR name:c type:<root>.Foo [val]
WHEN type=<root>.B origin=IF WHEN type=<root>.Foo origin=IF
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val mm: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null then: GET_VAR 'val mm: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val nn: <root>.C [val] declared in <root>.foo.<anonymous>' type=<root>.C origin=null then: GET_VAR 'val nn: <root>.C [val] declared in <root>.foo.<anonymous>' type=<root>.C origin=null
GET_VAR 'val c: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null GET_VAR 'val c: <root>.Foo [val] declared in <root>.foo.<anonymous>' type=<root>.Foo origin=null
@@ -75,24 +75,24 @@ FILE fqName:<root> fileName:/intersectionType2_OI.kt
RETURN type=kotlin.Nothing from='public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' RETURN type=kotlin.Nothing from='public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>'
CALL 'public abstract fun invoke (): T of <root>.run declared in kotlin.Function0' type=T of <root>.run origin=null CALL 'public abstract fun invoke (): T of <root>.run declared in kotlin.Function0' type=T of <root>.run origin=null
$this: GET_VAR 'fn: kotlin.Function0<T of <root>.run> declared in <root>.run' type=kotlin.Function0<T of <root>.run> origin=null $this: GET_VAR 'fn: kotlin.Function0<T of <root>.run> declared in <root>.run' type=kotlin.Function0<T of <root>.run> origin=null
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.B FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.Foo
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun foo (): <root>.B declared in <root>' RETURN type=kotlin.Nothing from='public final fun foo (): <root>.Foo declared in <root>'
CALL 'public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' type=<root>.B origin=null CALL 'public final fun run <T> (fn: kotlin.Function0<T of <root>.run>): T of <root>.run declared in <root>' type=<root>.Foo origin=null
<T>: <none> <T>: <none>
fn: FUN_EXPR type=kotlin.Function0<<root>.B> origin=LAMBDA fn: FUN_EXPR type=kotlin.Function0<<root>.Foo> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.B FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.Foo
BLOCK_BODY BLOCK_BODY
VAR name:mm type:<root>.B [val] VAR name:mm type:<root>.B [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null
VAR name:nn type:<root>.C [val] VAR name:nn type:<root>.C [val]
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
VAR name:c type:<root>.B [val] VAR name:c type:<root>.Foo [val]
WHEN type=<root>.B origin=IF WHEN type=<root>.Foo origin=IF
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val mm: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null then: GET_VAR 'val mm: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null
BRANCH BRANCH
if: CONST Boolean type=kotlin.Boolean value=true if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'val nn: <root>.C [val] declared in <root>.foo.<anonymous>' type=<root>.C origin=null then: GET_VAR 'val nn: <root>.C [val] declared in <root>.foo.<anonymous>' type=<root>.C origin=null
GET_VAR 'val c: <root>.B [val] declared in <root>.foo.<anonymous>' type=<root>.B origin=null GET_VAR 'val c: <root>.Foo [val] declared in <root>.foo.<anonymous>' type=<root>.Foo origin=null