diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt index 125af07e276..a6f496e274a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt @@ -6,31 +6,53 @@ package org.jetbrains.kotlin.ir.types import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.types.impl.makeTypeIntersection +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.types.AbstractTypeCheckerContext -import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker class IrTypeCheckerContext(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext, AbstractTypeCheckerContext() { - override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform { + require(type is IrSimpleType) + val parameters = extractTypeParameters((type.classifier as IrClassSymbol).owner).map { it.symbol } + val substitution = parameters.zip(type.arguments).toMap() return object : SupertypesPolicy.DoCustomTransform() { override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker { - return makeTypeProjection(type as IrType, Variance.INVARIANT) as SimpleTypeMarker + require(type is IrSimpleType) + + return substituteArguments(type) + } + + private fun substituteArguments(type: IrSimpleType): IrSimpleType { + val realArguments = type.arguments.map { + substitute(it) + }.toList() + + return IrSimpleTypeImpl(type.classifier, type.hasQuestionMark, realArguments, type.annotations) + } + + private fun substitute(type: IrTypeArgument): IrTypeArgument { + if (type is IrStarProjection) return type + + val actualType = (type as IrTypeProjection).type as IrSimpleType + substitution[actualType.classifier]?.let { return it } + return makeTypeProjection(substituteArguments(actualType), type.variance) } } } override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker) = super.isEqualTypeConstructors(a, b) - @Suppress("UNCHECKED_CAST") - override fun intersectTypes(types: List) = makeTypeIntersection(types as List) override val isErrorTypeEqualsToAnything = false override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = false + + override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext { + return IrTypeCheckerContext(irBuiltIns) + } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index de0df8a701f..9f40e3a0e6d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -7,19 +7,25 @@ package org.jetbrains.kotlin.ir.types import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.declarations.IrTypeParameter -import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol -import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.types.impl.makeTypeIntersection -import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.impl.* +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.checker.convertVariance import org.jetbrains.kotlin.types.model.* -interface IrTypeSystemContext : TypeSystemContext { + +private val NO_INFER_ANNOTATION_FQ_NAME = FqName("kotlin.internal.NoInfer") +private val EXACT_ANNOTATION_FQ_NAME = FqName("kotlin.internal.Exact") + +interface IrTypeSystemContext : TypeSystemInferenceExtensionContext { val irBuiltIns: IrBuiltIns @@ -29,6 +35,8 @@ interface IrTypeSystemContext : TypeSystemContext { override fun KotlinTypeMarker.isError() = this is IrErrorType + override fun SimpleTypeMarker.isStubType() = false + override fun FlexibleTypeMarker.asDynamicType() = this as? IrDynamicType override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? = null @@ -47,7 +55,7 @@ interface IrTypeSystemContext : TypeSystemContext { override fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker? = null - override fun SimpleTypeMarker.isMarkedNullable(): Boolean = (this as IrSimpleType).hasQuestionMark + override fun SimpleTypeMarker.isMarkedNullable(): Boolean = (this as IrSimpleType).containsNull() override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker { val simpleType = this as IrSimpleType @@ -75,13 +83,11 @@ interface IrTypeSystemContext : TypeSystemContext { override fun TypeArgumentMarker.getType() = (this as IrTypeProjection).type private fun getTypeParameters(typeConstructor: TypeConstructorMarker): List { - val ownTypeParameterContainer = when(typeConstructor) { - is IrTypeParameterSymbol -> (typeConstructor.owner.parent as IrTypeParametersContainer) - is IrClassSymbol -> typeConstructor.owner + return when (typeConstructor) { + is IrTypeParameterSymbol -> emptyList() + is IrClassSymbol -> typeConstructor.owner.typeParameters else -> error("unsupported type constructor") } - - return ownTypeParameterContainer.typeParameters } override fun TypeConstructorMarker.parametersCount() = getTypeParameters(this).size @@ -110,9 +116,11 @@ interface IrTypeSystemContext : TypeSystemContext { override fun TypeParameterMarker.getTypeConstructor() = this as IrTypeParameterSymbol - override fun isEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker) = (c1 === c2) + override fun isEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker) = FqNameEqualityChecker.areEqual( + c1 as IrClassifierSymbol, c2 as IrClassifierSymbol + ) - override fun TypeConstructorMarker.isDenotable() = false + override fun TypeConstructorMarker.isDenotable() = true override fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean { val classSymbol = this as? IrClassSymbol ?: return false @@ -129,16 +137,17 @@ interface IrTypeSystemContext : TypeSystemContext { * * See https://jetbrains.github.io/kotlin-spec/#type-capturing */ + override fun captureFromArguments(type: SimpleTypeMarker, status: CaptureStatus): SimpleTypeMarker? { // TODO: is that correct? require(type is IrSimpleType) - val classifier = type.classifier as IrClassSymbol + val classifier = type.classifier as? IrClassSymbol ?: return null val typeArguments = type.arguments if (!classifier.isBound) return null - val typeParameters = classifier.owner.typeParameters + val typeParameters = extractTypeParameters(classifier.owner) require(typeArguments.size == typeParameters.size) @@ -157,7 +166,10 @@ interface IrTypeSystemContext : TypeSystemContext { val additionalBounds = if (argument is IrTypeProjection && argument.variance == Variance.OUT_VARIANCE) listOf(argument.type) else emptyList() - newArguments += makeTypeProjection(makeTypeIntersection(parameter.superTypes + additionalBounds), Variance.INVARIANT) + newArguments += makeTypeProjection( + makeTypeIntersection(parameter.superTypes + additionalBounds), + Variance.INVARIANT + ) } return IrSimpleTypeImpl(type.classifier, type.hasQuestionMark, newArguments, type.annotations) @@ -171,8 +183,171 @@ interface IrTypeSystemContext : TypeSystemContext { override fun KotlinTypeMarker.isNotNullNothing(): Boolean { val simpleType = this as? IrSimpleType ?: return false - return simpleType.classifier === irBuiltIns.nothingClass && !simpleType.hasQuestionMark + return simpleType == irBuiltIns.nothingType && !simpleType.hasQuestionMark } override fun SimpleTypeMarker.isSingleClassifierType() = true + + override fun SimpleTypeMarker.possibleIntegerTypes() = irBuiltIns.run { + setOf(byteType, shortType, intType, longType) + } + + override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor() = false + + override fun nullableNothingType() = irBuiltIns.nothingNType as IrSimpleType + + override fun nullableAnyType() = irBuiltIns.anyNType as IrSimpleType + + override fun nothingType() = irBuiltIns.nothingType as IrSimpleType + + override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker { + require(lowerBound == nothingType()) + require(upperBound == nullableAnyType()) + return IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT) + } + + override fun createSimpleType( + constructor: TypeConstructorMarker, + arguments: List, + nullable: Boolean + ): SimpleTypeMarker = IrSimpleTypeImpl(constructor as IrClassifierSymbol, nullable, arguments.map { it as IrTypeArgument }, emptyList()) + + private fun TypeVariance.convertVariance(): Variance { + return when (this) { + TypeVariance.INV -> Variance.INVARIANT + TypeVariance.IN -> Variance.IN_VARIANCE + TypeVariance.OUT -> Variance.OUT_VARIANCE + } + } + + override fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker = + makeTypeProjection(type as IrType, variance.convertVariance()) + + override fun createStarProjection(typeParameter: TypeParameterMarker) = IrStarProjectionImpl + + override fun KotlinTypeMarker.canHaveUndefinedNullability() = this is IrSimpleType && classifier is IrTypeParameterSymbol + + override fun SimpleTypeMarker.typeDepth() = 2 + + override fun KotlinTypeMarker.typeDepth() = if (this is IrStarProjection) 1 else 0 + + override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List): SimpleTypeMarker? = + irBuiltIns.intType as IrSimpleType + + override fun KotlinTypeMarker.contains(predicate: (KotlinTypeMarker) -> Boolean) = predicate(this) + + override fun TypeConstructorMarker.isUnitTypeConstructor() = isEqualTypeConstructors(this, irBuiltIns.unitClass) + + override fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker = irBuiltIns.intType + + override fun Collection.singleBestRepresentative(): KotlinTypeMarker? { + if (this.size == 1) return this.first() + + return this.firstOrNull { candidate -> + this.all { other -> + // We consider error types equal to anything here, so that intersections like + // {Array, Array<[ERROR]>} work correctly + candidate == other || other is IrErrorType + } + } + } + + override fun KotlinTypeMarker.isUnit() = (this as IrType) == irBuiltIns.unitType + + override fun KotlinTypeMarker.withNullability(nullable: Boolean) = if (this is IrSimpleType) + IrSimpleTypeImpl(classifier, true, arguments, annotations) + else this + + override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker { + error("Captured Type is not supported for IrType") + } + + override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker { + error("Captured Type is not supported for IrType") + } + + override fun createCapturedType( + constructorProjection: TypeArgumentMarker, + constructorSupertypes: List, + lowerType: KotlinTypeMarker?, + captureStatus: CaptureStatus + ): CapturedTypeMarker { + error("Captured Type is not supported for IrType") + } + + override fun createStubType(typeVariable: TypeVariableMarker) = error("Stub type is not supported for IrTypes") + + override fun KotlinTypeMarker.removeAnnotations() = with(this as IrType) { + if (annotations.isEmpty()) this + else { + when { + this is IrDynamicType -> IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT) + this is IrSimpleType -> IrSimpleTypeImpl(classifier, hasQuestionMark, arguments, emptyList()) + else -> this + } + } + } + + override fun SimpleTypeMarker.replaceArguments(newArguments: List): SimpleTypeMarker = with(this as IrSimpleType) { + IrSimpleTypeImpl(classifier, hasQuestionMark, newArguments.map { it as IrTypeArgument }, annotations) + } + + override fun KotlinTypeMarker.hasExactAnnotation(): Boolean = with(this as IrType) { + annotations.hasAnnotation(EXACT_ANNOTATION_FQ_NAME) + } + + override fun KotlinTypeMarker.hasNoInferAnnotation(): Boolean = with(this as IrType) { + annotations.hasAnnotation(NO_INFER_ANNOTATION_FQ_NAME) + } + + override fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker = + error("freshTypeConstructor is not supported for IrType") + + override fun CapturedTypeMarker.typeConstructorProjection() = + error("typeConstructorProjection is not supported for IrType") + + override fun KotlinTypeMarker.isNullableType() = this is IrDynamicType || this is IrSimpleType && hasQuestionMark + + override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker = error("DefinitelyNotNullTypeMarker is not supported for IrType") + + override fun typeSubstitutorByTypeConstructor(map: Map): TypeSubstitutorMarker { + TODO("not implemented") + } + + override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker { + TODO("not implemented") + } + + override fun TypeVariableMarker.defaultType(): SimpleTypeMarker = error("defaultType is not supported for IrType") + + @Suppress("UNCHECKED_CAST") + override fun intersectTypes(types: List): SimpleTypeMarker = + makeTypeIntersection(types as List) as SimpleTypeMarker + + + @Suppress("UNCHECKED_CAST") + override fun intersectTypes(types: List): KotlinTypeMarker = + makeTypeIntersection(types as List) +} + +fun extractTypeParameters(klass: IrTypeParametersContainer): List { + val result = mutableListOf() + var current: IrTypeParametersContainer? = klass + while (current != null) { + result += current.typeParameters + current = + when (current) { + is IrClass -> when { + current.isInner -> current.parent as IrClass + current.visibility == Visibilities.LOCAL -> current.parent as? IrTypeParametersContainer + else -> null + } + is IrConstructor -> current.parent as IrClass + is IrFunction -> if (current.visibility == Visibilities.LOCAL || current.dispatchReceiverParameter != null) { + current.parent as? IrTypeParametersContainer + } else null + else -> null + } + } + return result } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt index 9a01576a059..e8386eb35d0 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt @@ -5,11 +5,15 @@ package org.jetbrains.kotlin.ir.types +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.utils.DFS fun IrClassifierSymbol.superTypes() = when (this) { @@ -59,3 +63,13 @@ fun Collection.commonSuperclass(): IrClassifierSymbol { ) { it.owner.render() }}" ) } + +fun IrType.isSubtypeOf(superType: IrType, irBuiltIns: IrBuiltIns): Boolean { + return AbstractTypeChecker.isSubtypeOf(IrTypeCheckerContext(irBuiltIns) as AbstractTypeCheckerContext, this, superType) +} + +fun Collection.commonSupertype(irBuiltIns: IrBuiltIns): IrType { + return NewCommonSuperTypeCalculator.run { + IrTypeCheckerContext(irBuiltIns).commonSuperType(map { it }) as IrType + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/impl/IrSimpleTypeImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/impl/IrSimpleTypeImpl.kt index b3ccd8298e8..bc1e74f27ef 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/impl/IrSimpleTypeImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/impl/IrSimpleTypeImpl.kt @@ -99,6 +99,8 @@ fun makeTypeProjection(type: IrType, variance: Variance): IrTypeProjection = } -fun makeTypeIntersection(types: List) = - if (types.size == 1) types[1] - else TODO("Not implemented") \ No newline at end of file +fun makeTypeIntersection(types: List): IrType = + with(types.map { makeTypeProjection(it, Variance.INVARIANT).type }.distinct()) { + if (size == 1) return single() + else first { !(it.isAny() || it.isNullableAny()) } + } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt index 79bf5a1555e..ffed3ee9ffd 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt @@ -47,6 +47,12 @@ fun IrType.isPrimitiveType(): Boolean = KotlinBuiltIns.FQ_NAMES.fqNameToPrimitiv fun IrType.isNullablePrimitiveType(): Boolean = KotlinBuiltIns.FQ_NAMES.fqNameToPrimitiveType.keys.any { isNullableClassType(it) } fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false +fun IrType.containsNull(): Boolean = when { + this is IrDynamicType -> true + this is IrStarProjection -> true + this is IrSimpleType -> hasQuestionMark || classifier.superTypes().any { it.containsNull() } + else -> false +} fun IrType.isUnit() = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.unit) fun IrType.isNullableUnit() = isNullableClassType(KotlinBuiltIns.FQ_NAMES.unit) @@ -58,6 +64,10 @@ fun IrType.isByte(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._byte) fun IrType.isShort(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._short) fun IrType.isInt(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._int) fun IrType.isLong(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._long) +fun IrType.isUByte(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.uByteFqName.toUnsafe()) +fun IrType.isUShort(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.uShortFqName.toUnsafe()) +fun IrType.isUInt(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.uIntFqName.toUnsafe()) +fun IrType.isULong(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.uLongFqName.toUnsafe()) fun IrType.isFloat(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._float) fun IrType.isDouble(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES._double) fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.number)