[FIR] Add implementation of intersection types to Fir type system
This commit is contained in:
@@ -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<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(">")
|
||||
}
|
||||
}
|
||||
is ConeIntersectionType -> {
|
||||
intersectedTypes.joinToString(
|
||||
separator = " & ",
|
||||
prefix = "it(",
|
||||
postfix = ")"
|
||||
)
|
||||
}
|
||||
} + 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) {
|
||||
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()) {
|
||||
+"<"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,13 @@ fun <T : ConeKotlinType> 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}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}")
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -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<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? {
|
||||
TODO()
|
||||
}
|
||||
|
||||
@@ -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>): 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 {
|
||||
return types.first() // TODO: proper implementation
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>)
|
||||
}
|
||||
|
||||
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)| {
|
||||
^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)
|
||||
}
|
||||
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|()))
|
||||
}
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
@@ -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>'
|
||||
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
|
||||
$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>
|
||||
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
|
||||
|
||||
@@ -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>'
|
||||
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
|
||||
$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>
|
||||
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
|
||||
|
||||
@@ -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>'
|
||||
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
|
||||
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.B
|
||||
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.Foo
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun foo (): <root>.B 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
|
||||
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>.Foo origin=null
|
||||
<T>: <none>
|
||||
fn: FUN_EXPR type=kotlin.Function0<<root>.B> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.B
|
||||
fn: FUN_EXPR type=kotlin.Function0<<root>.Foo> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.Foo
|
||||
BLOCK_BODY
|
||||
VAR name:mm type:<root>.B [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null
|
||||
VAR name:nn type:<root>.C [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
|
||||
VAR name:c type:<root>.B [val]
|
||||
WHEN type=<root>.B origin=IF
|
||||
VAR name:c type:<root>.Foo [val]
|
||||
WHEN type=<root>.Foo origin=IF
|
||||
BRANCH
|
||||
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
|
||||
BRANCH
|
||||
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
|
||||
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>'
|
||||
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
|
||||
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.B
|
||||
FUN name:foo visibility:public modality:FINAL <> () returnType:<root>.Foo
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun foo (): <root>.B 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
|
||||
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>.Foo origin=null
|
||||
<T>: <none>
|
||||
fn: FUN_EXPR type=kotlin.Function0<<root>.B> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.B
|
||||
fn: FUN_EXPR type=kotlin.Function0<<root>.Foo> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:<root>.Foo
|
||||
BLOCK_BODY
|
||||
VAR name:mm type:<root>.B [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.B' type=<root>.B origin=null
|
||||
VAR name:nn type:<root>.C [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
|
||||
VAR name:c type:<root>.B [val]
|
||||
WHEN type=<root>.B origin=IF
|
||||
VAR name:c type:<root>.Foo [val]
|
||||
WHEN type=<root>.Foo origin=IF
|
||||
BRANCH
|
||||
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
|
||||
BRANCH
|
||||
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
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user