diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index 56ecfd2d540..98e101ab2b4 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt @@ -173,4 +173,53 @@ class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(), get() = original.typeArguments override val nullability: ConeNullability 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 + get() = emptyArray() + + override val nullability: ConeNullability + get() = ConeNullability.NOT_NULL + + val intersectedTypes: Collection get() = constructor.intersectedTypes + val statusMap: Map get() = constructor.statusMap +} + +class ConeIntersectionTypeConstructor( + val intersectedTypes: Collection, + val statusMap: Map +) : TypeConstructorMarker { + val supertypes: Collection 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() + 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) } \ No newline at end of file diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/TypeRenderer.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/TypeRenderer.kt index ae7bef7b86d..f8b278e5528 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/TypeRenderer.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/TypeRenderer.kt @@ -39,5 +39,12 @@ fun ConeKotlinType.render(): String { append(">") } } + is ConeIntersectionType -> { + intersectedTypes.joinToString( + separator = " & ", + prefix = "it(", + postfix = ")" + ) + } } + nullabilitySuffix } diff --git a/compiler/fir/dump/src/org/jetbrains/kotlin/fir/dump/HtmlFirDump.kt b/compiler/fir/dump/src/org/jetbrains/kotlin/fir/dump/HtmlFirDump.kt index 0c4e7af4c42..b2ea888529a 100644 --- a/compiler/fir/dump/src/org/jetbrains/kotlin/fir/dump/HtmlFirDump.kt +++ b/compiler/fir/dump/src/org/jetbrains/kotlin/fir/dump/HtmlFirDump.kt @@ -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) { resolved { symbolRef(type.lookupTag.toSymbol(session)) { @@ -704,6 +710,7 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver is ConeFlexibleType -> resolved { generate(type) } is ConeCapturedType -> inlineUnsupported(type) is ConeDefinitelyNotNullType -> inlineUnsupported(type) + is ConeIntersectionType -> resolved { generate(type) } } if (type.typeArguments.isNotEmpty()) { +"<" diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 3d3c57234c5..d8324967275 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -58,6 +58,10 @@ fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDecla } is ConeCapturedType -> TODO() is ConeDefinitelyNotNullType -> TODO() + is ConeIntersectionType -> { + // TODO: add intersectionTypeApproximation + intersectedTypes.first().toIrType(session, declarationStorage) + } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 59490b38d0a..8a5afb57f78 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -164,6 +164,13 @@ fun T.withNullability(nullability: ConeNullability): T { is ConeFlexibleType -> ConeFlexibleType(lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) 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}") } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt index 531dd264791..1d08d96604d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt @@ -38,6 +38,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession) ) } is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession) + is ConeIntersectionType -> FirCompositeScope(intersectedTypes.mapNotNullTo(mutableListOf()) { it.scope(useSiteSession, scopeSession) }) else -> error("Failed type ${this}") } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt index 073fd2bd697..1f031204198 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/ConeSubstitutor.kt @@ -75,9 +75,23 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { is ConeFlexibleType -> this.substituteBounds() is ConeCapturedType -> return null is ConeDefinitelyNotNullType -> this.substituteOriginal() + is ConeIntersectionType -> this.substituteIntersectedTypes() } } + private fun ConeIntersectionType.substituteIntersectedTypes(): ConeIntersectionType? { + val substitutedTypes = ArrayList(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? { TODO() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index ce7c7fca250..42c9e972533 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -60,6 +60,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty is ConeCapturedType -> this is ConeLookupTagBasedType -> this is ConeDefinitelyNotNullType -> this + is ConeIntersectionType -> this is ConeFlexibleType -> null else -> error("Unknown simpleType: $this") } @@ -128,6 +129,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty typeArguments, nullable ) + is ConeIntersectionType -> this.withNullability(ConeNullability.create(nullable)) else -> error("!") } } @@ -139,6 +141,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor() ?: ErrorTypeConstructor("Failed to expand alias: ${this}") is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}") + is ConeIntersectionType -> constructor else -> error("?: ${this}") } @@ -199,7 +202,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty override fun TypeConstructorMarker.parametersCount(): Int { //require(this is ConeSymbol) 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 FirTypeAliasSymbol -> fir.typeParameters.size else -> error("?!:10") @@ -225,12 +232,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty is FirClassSymbol -> fir.superConeTypes is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType) is ConeCapturedTypeConstructor -> supertypes!! + is ConeIntersectionTypeConstructor -> intersectedTypes else -> error("?!:13") } } override fun TypeConstructorMarker.isIntersection(): Boolean { - return false // TODO + return this is ConeIntersectionTypeConstructor } override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean { @@ -269,8 +277,9 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty override fun TypeConstructorMarker.isDenotable(): Boolean { //TODO return when (this) { - is ConeCapturedTypeConstructor -> false - is ConeTypeVariableTypeConstructor -> false + is ConeCapturedTypeConstructor, + is ConeTypeVariableTypeConstructor, + is ConeIntersectionTypeConstructor -> false is ConeSymbol -> true else -> true } @@ -351,6 +360,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty if (isError()) return false if (this is ConeCapturedType) return true if (this is ConeTypeVariableType) return false + if (this is ConeIntersectionType) return false require(this is ConeLookupTagBasedType) val typeConstructor = this.typeConstructor() return typeConstructor is FirClassSymbol || @@ -370,11 +380,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty } override fun intersectTypes(types: List): SimpleTypeMarker { - return types.first() // TODO: proper implementation + @Suppress("UNCHECKED_CAST") + return ConeTypeIntersector.intersectTypes(this, types as List) as SimpleTypeMarker } override fun intersectTypes(types: List): KotlinTypeMarker { - return types.first() // TODO: proper implementation + @Suppress("UNCHECKED_CAST") + return ConeTypeIntersector.intersectTypes(this, types as List) } private fun prepareClassLikeType( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt new file mode 100644 index 00000000000..4fb1baf0f75 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt @@ -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 { + require(context is ConeInferenceContext) + return intersectTypes(context, types, types.map { IntersectionStatus.FROM_INFERENCE }) + } + + private fun intersectTypes( + context: ConeInferenceContext, + types: List, + intersectionStatus: List + ): ConeKotlinType { + assert(types.size == intersectionStatus.size) + + when (types.size) { + 0 -> error("Expected some types") + 1 -> return types.single() + } + + val inputTypes = mutableListOf() + val statusMap = mutableMapOf() + 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, + statusMap: MutableMap + ): 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, + predicate: (lower: ConeKotlinType, upper: ConeKotlinType) -> Boolean + ): List { + 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.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, + intersectionStatus: List, + typeCollector: MutableList, + statusMap: MutableMap + ) { + 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 + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt new file mode 100644 index 00000000000..ce2aedcb618 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/intersectionTypes.kt b/compiler/fir/resolve/testData/resolve/intersectionTypes.kt new file mode 100644 index 00000000000..96ce7df60d9 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/intersectionTypes.kt @@ -0,0 +1,14 @@ +interface A + +interface B + +class Clazz1 : A, B +class Clazz2 : A, B + +fun select(x: K, y: K): K + +fun test() = select(Clazz1(), Clazz2()) + +fun makeNull(x: T): T? = null + +fun testNull() = makeNull(select(Clazz1(), Clazz2())) \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/intersectionTypes.txt b/compiler/fir/resolve/testData/resolve/intersectionTypes.txt index 4d7759be1c0..c1b24d926d3 100644 --- a/compiler/fir/resolve/testData/resolve/intersectionTypes.txt +++ b/compiler/fir/resolve/testData/resolve/intersectionTypes.txt @@ -19,9 +19,9 @@ FILE: intersectionTypes.kt public final fun test(): R|it(A & B)| { ^test R|/select|(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|()) } - public final fun makeNull(x: R|T|): R|T|? { + public final fun makeNull(x: R|T|): R|T?| { ^makeNull Null(null) } - public final fun testNull(): R|it(A & B)| { + public final fun testNull(): R|it(A? & B?)| { ^testNull R|/makeNull|(R|/select|(R|/Clazz1.Clazz1|(), R|/Clazz2.Clazz2|())) } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index 2be4be3193d..67c3f787af6 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -94,6 +94,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase { 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") public void testNestedClass() throws Exception { runTest("compiler/fir/resolve/testData/resolve/nestedClass.kt"); diff --git a/compiler/testData/ir/irText/types/intersectionType1_NI.fir.txt b/compiler/testData/ir/irText/types/intersectionType1_NI.fir.txt index d6d41289953..13f8c458068 100644 --- a/compiler/testData/ir/irText/types/intersectionType1_NI.fir.txt +++ b/compiler/testData/ir/irText/types/intersectionType1_NI.fir.txt @@ -34,7 +34,7 @@ FILE fqName: fileName:/intersectionType1_NI.kt RETURN type=kotlin.Nothing from='public final fun foo (a: kotlin.Array<.In.foo>>, b: kotlin.Array<.In>): kotlin.Boolean declared in ' CALL 'public final fun ofType (y: kotlin.Any?): kotlin.Boolean [inline] declared in ' type=kotlin.Boolean origin=null $receiver: CALL 'public final fun get (index: kotlin.Int): .In.foo> declared in kotlin.Array' type=.In.foo> origin=null - $this: CALL 'public final fun select (x: S of .select, y: S of .select): S of .select declared in ' type=kotlin.Array<.In.foo>> origin=null + $this: CALL 'public final fun select (x: S of .select, y: S of .select): S of .select declared in ' type=kotlin.Array.In.foo>> origin=null : x: GET_VAR 'a: kotlin.Array<.In.foo>> declared in .foo' type=kotlin.Array<.In.foo>> origin=null y: GET_VAR 'b: kotlin.Array<.In> declared in .foo' type=kotlin.Array<.In> origin=null diff --git a/compiler/testData/ir/irText/types/intersectionType1_OI.fir.txt b/compiler/testData/ir/irText/types/intersectionType1_OI.fir.txt index 939eafa058f..a460eab0281 100644 --- a/compiler/testData/ir/irText/types/intersectionType1_OI.fir.txt +++ b/compiler/testData/ir/irText/types/intersectionType1_OI.fir.txt @@ -34,7 +34,7 @@ FILE fqName: fileName:/intersectionType1_OI.kt RETURN type=kotlin.Nothing from='public final fun foo (a: kotlin.Array<.In.foo>>, b: kotlin.Array<.In>): kotlin.Boolean declared in ' CALL 'public final fun ofType (y: kotlin.Any?): kotlin.Boolean [inline] declared in ' type=kotlin.Boolean origin=null $receiver: CALL 'public final fun get (index: kotlin.Int): .In.foo> declared in kotlin.Array' type=.In.foo> origin=null - $this: CALL 'public final fun select (x: S of .select, y: S of .select): S of .select declared in ' type=kotlin.Array<.In.foo>> origin=null + $this: CALL 'public final fun select (x: S of .select, y: S of .select): S of .select declared in ' type=kotlin.Array.In.foo>> origin=null : x: GET_VAR 'a: kotlin.Array<.In.foo>> declared in .foo' type=kotlin.Array<.In.foo>> origin=null y: GET_VAR 'b: kotlin.Array<.In> declared in .foo' type=kotlin.Array<.In> origin=null diff --git a/compiler/testData/ir/irText/types/intersectionType2_NI.fir.txt b/compiler/testData/ir/irText/types/intersectionType2_NI.fir.txt index 4e723c57c78..f0bb3a91a0e 100644 --- a/compiler/testData/ir/irText/types/intersectionType2_NI.fir.txt +++ b/compiler/testData/ir/irText/types/intersectionType2_NI.fir.txt @@ -75,24 +75,24 @@ FILE fqName: fileName:/intersectionType2_NI.kt RETURN type=kotlin.Nothing from='public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' CALL 'public abstract fun invoke (): T of .run declared in kotlin.Function0' type=T of .run origin=null $this: GET_VAR 'fn: kotlin.Function0.run> declared in .run' type=kotlin.Function0.run> origin=null - FUN name:foo visibility:public modality:FINAL <> () returnType:.B + FUN name:foo visibility:public modality:FINAL <> () returnType:.Foo BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun foo (): .B declared in ' - CALL 'public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' type=.B origin=null + RETURN type=kotlin.Nothing from='public final fun foo (): .Foo declared in ' + CALL 'public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' type=.Foo origin=null : - fn: FUN_EXPR type=kotlin.Function0<.B> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:.B + fn: FUN_EXPR type=kotlin.Function0<.Foo> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:.Foo BLOCK_BODY VAR name:mm type:.B [val] CONSTRUCTOR_CALL 'public constructor () [primary] declared in .B' type=.B origin=null VAR name:nn type:.C [val] CONSTRUCTOR_CALL 'public constructor () [primary] declared in .C' type=.C origin=null - VAR name:c type:.B [val] - WHEN type=.B origin=IF + VAR name:c type:.Foo [val] + WHEN type=.Foo origin=IF BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: GET_VAR 'val mm: .B [val] declared in .foo.' type=.B origin=null BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: GET_VAR 'val nn: .C [val] declared in .foo.' type=.C origin=null - GET_VAR 'val c: .B [val] declared in .foo.' type=.B origin=null + GET_VAR 'val c: .Foo [val] declared in .foo.' type=.Foo origin=null diff --git a/compiler/testData/ir/irText/types/intersectionType2_OI.fir.txt b/compiler/testData/ir/irText/types/intersectionType2_OI.fir.txt index 2458b15c566..c7dc4a3486a 100644 --- a/compiler/testData/ir/irText/types/intersectionType2_OI.fir.txt +++ b/compiler/testData/ir/irText/types/intersectionType2_OI.fir.txt @@ -75,24 +75,24 @@ FILE fqName: fileName:/intersectionType2_OI.kt RETURN type=kotlin.Nothing from='public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' CALL 'public abstract fun invoke (): T of .run declared in kotlin.Function0' type=T of .run origin=null $this: GET_VAR 'fn: kotlin.Function0.run> declared in .run' type=kotlin.Function0.run> origin=null - FUN name:foo visibility:public modality:FINAL <> () returnType:.B + FUN name:foo visibility:public modality:FINAL <> () returnType:.Foo BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun foo (): .B declared in ' - CALL 'public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' type=.B origin=null + RETURN type=kotlin.Nothing from='public final fun foo (): .Foo declared in ' + CALL 'public final fun run (fn: kotlin.Function0.run>): T of .run declared in ' type=.Foo origin=null : - fn: FUN_EXPR type=kotlin.Function0<.B> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:.B + fn: FUN_EXPR type=kotlin.Function0<.Foo> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:.Foo BLOCK_BODY VAR name:mm type:.B [val] CONSTRUCTOR_CALL 'public constructor () [primary] declared in .B' type=.B origin=null VAR name:nn type:.C [val] CONSTRUCTOR_CALL 'public constructor () [primary] declared in .C' type=.C origin=null - VAR name:c type:.B [val] - WHEN type=.B origin=IF + VAR name:c type:.Foo [val] + WHEN type=.Foo origin=IF BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: GET_VAR 'val mm: .B [val] declared in .foo.' type=.B origin=null BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: GET_VAR 'val nn: .C [val] declared in .foo.' type=.C origin=null - GET_VAR 'val c: .B [val] declared in .foo.' type=.B origin=null + GET_VAR 'val c: .Foo [val] declared in .foo.' type=.Foo origin=null