diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt index fc3e2f841f0..dc2747b7b0f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.types.areCompatibleExpectActualTypes import org.jetbrains.kotlin.fir.types.createExpectActualTypeParameterSubstitutor import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility +import org.jetbrains.kotlin.utils.zipIfSizesAreEqual object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() { override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { @@ -34,12 +35,16 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() { val expectTypeParameters = expectFunctionSymbol.getContainingClassSymbol(expectFunctionSymbol.moduleData.session) ?.typeParameterSymbols.orEmpty() val actualClassTypeParameters = actualFunctionSymbol.getContainingClassSymbol(context.session)?.typeParameterSymbols.orEmpty() - val parentSubstitutor = - createExpectActualTypeParameterSubstitutor(expectTypeParameters, actualClassTypeParameters, context.session) + + val parentSubstitutor = createExpectActualTypeParameterSubstitutor( + // It's responsibility of AbstractExpectActualCompatibilityChecker to report that + (expectTypeParameters zipIfSizesAreEqual actualClassTypeParameters) ?: return, + context.session + ) val substitutor = createExpectActualTypeParameterSubstitutor( - expectFunctionSymbol.typeParameterSymbols, - actualFunctionSymbol.typeParameterSymbols, + // It's responsibility of AbstractExpectActualCompatibilityChecker to check that + (expectFunctionSymbol.typeParameterSymbols zipIfSizesAreEqual actualFunctionSymbol.typeParameterSymbols) ?: return, context.session, parentSubstitutor ) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt index fb5ed751dcc..983813126b6 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt @@ -13,12 +13,11 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.types.AbstractTypeChecker fun createExpectActualTypeParameterSubstitutor( - expectedTypeParameters: List, - actualTypeParameters: List, + expectActualTypeParameters: List>, useSiteSession: FirSession, parentSubstitutor: ConeSubstitutor? = null ): ConeSubstitutor { - val substitution = expectedTypeParameters.zip(actualTypeParameters).associate { (expectedParameterSymbol, actualParameterSymbol) -> + val substitution = expectActualTypeParameters.associate { (expectedParameterSymbol, actualParameterSymbol) -> expectedParameterSymbol to actualParameterSymbol.toLookupTag().constructType(emptyArray(), isNullable = false) } val substitutor = ConeSubstitutorByMap( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt index dc8bcbaf179..98bce662b8d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualMatchingContextImpl.kt @@ -36,8 +36,6 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.TypeSystemContext -import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -import org.jetbrains.kotlin.utils.addToStdlib.castAll class FirExpectActualMatchingContextImpl private constructor( private val actualSession: FirSession, @@ -147,15 +145,13 @@ class FirExpectActualMatchingContextImpl private constructor( override val PropertySymbolMarker.setter: FunctionSymbolMarker? get() = asSymbol().setterSymbol - @OptIn(UnsafeCastFunction::class) override fun createExpectActualTypeParameterSubstitutor( - expectTypeParameters: List, - actualTypeParameters: List, + expectActualTypeParameters: List>, parentSubstitutor: TypeSubstitutorMarker?, ): TypeSubstitutorMarker { + @Suppress("UNCHECKED_CAST") return createExpectActualTypeParameterSubstitutor( - expectTypeParameters.castAll(), - actualTypeParameters.castAll(), + expectActualTypeParameters as List>, actualSession, parentSubstitutor as ConeSubstitutor? ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt index 0d8b5a447c3..dcfac877aac 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.mpp.CallableSymbolMarker import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility +import org.jetbrains.kotlin.utils.zipIfSizesAreEqual object FirExpectActualResolver { fun findExpectForActual( @@ -46,14 +47,8 @@ object FirExpectActualResolver { val expectTypeParameters = expectContainingClass?.typeParameterSymbols.orEmpty() val actualTypeParameters = actualContainingClass?.typeParameterSymbols.orEmpty() - parentSubstitutor = when (expectTypeParameters.size == actualTypeParameters.size) { - true -> createExpectActualTypeParameterSubstitutor( - expectTypeParameters, - actualTypeParameters, - useSiteSession, - ) - false -> null - } + parentSubstitutor = (expectTypeParameters zipIfSizesAreEqual actualTypeParameters) + ?.let { createExpectActualTypeParameterSubstitutor(it, useSiteSession) } when (actualSymbol) { is FirConstructorSymbol -> expectContainingClass?.getConstructors(scopeSession) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt index 32b256aa268..24c6c06d033 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrExpectActualMatchingContext.kt @@ -37,8 +37,6 @@ import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.TypeSystemContext -import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -import org.jetbrains.kotlin.utils.addToStdlib.castAll import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled internal abstract class IrExpectActualMatchingContext( @@ -238,16 +236,14 @@ internal abstract class IrExpectActualMatchingContext( override val PropertySymbolMarker.setter: FunctionSymbolMarker? get() = asIr().setter?.symbol - @OptIn(UnsafeCastFunction::class) override fun createExpectActualTypeParameterSubstitutor( - expectTypeParameters: List, - actualTypeParameters: List, + expectActualTypeParameters: List>, parentSubstitutor: TypeSubstitutorMarker?, ): TypeSubstitutorMarker { - val expectParameters = expectTypeParameters.castAll() - val actualParameters = actualTypeParameters.castAll() - val actualTypes = actualParameters.map { it.owner.defaultType } - val substitutor = IrTypeSubstitutor(expectParameters, actualTypes, allowEmptySubstitution = true) + val typeParametersToArguments = expectActualTypeParameters.associate { (expect, actual) -> + (expect as IrTypeParameterSymbol) to (actual as IrTypeParameterSymbol).owner.defaultType + } + val substitutor = IrTypeSubstitutor(typeParametersToArguments, allowEmptySubstitution = true) return when (parentSubstitutor) { null -> substitutor is AbstractIrTypeSubstitutor -> IrChainedSubstitutor(parentSubstitutor, substitutor) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/WrapInlineDeclarationsWithReifiedTypeParametersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/WrapInlineDeclarationsWithReifiedTypeParametersLowering.kt index 0f5e0b2bd32..567f49fb059 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/WrapInlineDeclarationsWithReifiedTypeParametersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/WrapInlineDeclarationsWithReifiedTypeParametersLowering.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl +import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrTypeArgument import org.jetbrains.kotlin.ir.types.IrTypeSubstitutor import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET @@ -50,11 +51,8 @@ class WrapInlineDeclarationsWithReifiedTypeParametersLowering(val context: Backe if (!owner.isInlineFunWithReifiedParameter()) { return expression } - val substitutionMap = expression.typeSubstitutionMap.entries - val typeSubstitutor = IrTypeSubstitutor( - substitutionMap.map { it.key }, - substitutionMap.map { it.value as IrTypeArgument }, - ) + @Suppress("UNCHECKED_CAST") + val typeSubstitutor = IrTypeSubstitutor(expression.typeSubstitutionMap as Map) val function = irFactory.buildFun { name = Name.identifier("${owner.name}${"$"}wrap") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSubstitutor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSubstitutor.kt index 517909ff53e..6a385cc813f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSubstitutor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSubstitutor.kt @@ -65,12 +65,15 @@ abstract class BaseIrTypeSubstitutor : AbstractIrTypeSubstitutor() { } class IrTypeSubstitutor( - typeParameters: List, - typeArguments: List, - private val allowEmptySubstitution: Boolean = false, + private val substitution: Map, + private val allowEmptySubstitution: Boolean = false ) : BaseIrTypeSubstitutor() { - init { - assert(typeParameters.size == typeArguments.size) { + constructor( + typeParameters: List, + typeArguments: List, + allowEmptySubstitution: Boolean = false, + ) : this(typeParameters.zip(typeArguments).toMap(), allowEmptySubstitution) { + check(typeParameters.size == typeArguments.size) { "Unexpected number of type arguments: ${typeArguments.size}\n" + "Type parameters are:\n" + typeParameters.joinToString(separator = "\n") { it.owner.render() } + @@ -79,8 +82,6 @@ class IrTypeSubstitutor( } } - private val substitution = typeParameters.zip(typeArguments).toMap() - override fun getSubstitutionArgument(typeParameter: IrTypeParameterSymbol): IrTypeArgument = substitution[typeParameter] ?: typeParameter.takeIf { allowEmptySubstitution }?.owner?.defaultType 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 345459b306b..a29b0f81a28 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 @@ -595,17 +595,12 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon } override fun typeSubstitutorByTypeConstructor(map: Map): TypeSubstitutorMarker { - val typeParameters = mutableListOf() - val typeArguments = mutableListOf() - for ((key, value) in map) { - typeParameters += key as IrTypeParameterSymbol - typeArguments += value as IrTypeArgument - } - return IrTypeSubstitutor(typeParameters, typeArguments) + @Suppress("UNCHECKED_CAST") + return IrTypeSubstitutor(map as Map) } override fun createEmptySubstitutor(): TypeSubstitutorMarker { - return IrTypeSubstitutor(emptyList(), emptyList()) + return IrTypeSubstitutor(emptyMap()) } override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt index b21345d3061..42657347f88 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt @@ -208,8 +208,6 @@ class IrBodyDeserializer( return IrSimpleTypeBuilder().apply { classifier = klass.symbol }.buildSimpleType() } - val typeArguments = ArrayList(typeParameters.size) - val typeParameterSymbols = ArrayList(typeParameters.size) val rawType = with(IrSimpleTypeBuilder()) { arguments = typeParameters.memoryOptimizedMap { classifier = it.symbol @@ -219,15 +217,15 @@ class IrBodyDeserializer( buildSimpleType() } + val typeParametersToArguments = HashMap(typeParameters.size) for (i in typeParameters.indices) { val typeParameter = typeParameters[i] val callTypeArgument = constructorCall.getTypeArgument(i) ?: error("No type argument for id $i") val typeArgument = makeTypeProjection(callTypeArgument, typeParameter.variance) - typeArguments.add(typeArgument) - typeParameterSymbols.add(typeParameter.symbol) + typeParametersToArguments[typeParameter.symbol] = typeArgument } - val substitutor = IrTypeSubstitutor(typeParameterSymbols, typeArguments) + val substitutor = IrTypeSubstitutor(typeParametersToArguments) return substitutor.substitute(rawType) as IrSimpleType } } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt index 1a27593c876..4b76a4b3530 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualCompatibilityChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addToStdlib.enumMapOf import org.jetbrains.kotlin.utils.addToStdlib.enumSetOf import org.jetbrains.kotlin.utils.keysToMap +import org.jetbrains.kotlin.utils.zipIfSizesAreEqual import java.util.* object AbstractExpectActualCompatibilityChecker { @@ -124,8 +125,8 @@ object AbstractExpectActualCompatibilityChecker { } val substitutor = createExpectActualTypeParameterSubstitutor( - expectTypeParameterSymbols, - actualTypeParameterSymbols, + (expectTypeParameterSymbols zipIfSizesAreEqual actualTypeParameterSymbols) + ?: error("expect/actual type parameters sizes are checked above"), parentSubstitutor ) @@ -348,8 +349,8 @@ object AbstractExpectActualCompatibilityChecker { } val substitutor = createExpectActualTypeParameterSubstitutor( - expectedTypeParameters, - actualTypeParameters, + (expectedTypeParameters zipIfSizesAreEqual actualTypeParameters) + ?: error("expect/actual type parameters sizes are checked above"), parentSubstitutor ) diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt index 463a88b859f..1b940350504 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ExpectActualMatchingContext.kt @@ -103,8 +103,7 @@ interface ExpectActualMatchingContext : TypeSystemC val PropertySymbolMarker.setter: FunctionSymbolMarker? fun createExpectActualTypeParameterSubstitutor( - expectTypeParameters: List, - actualTypeParameters: List, + expectActualTypeParameters: List>, parentSubstitutor: TypeSubstitutorMarker? ): TypeSubstitutorMarker diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt index 8deedaa1a99..695bc8354c6 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt @@ -22,6 +22,9 @@ fun Iterable.keysToMap(value: (K) -> V): Map { return associateBy({ it }, value) } +infix fun Collection.zipIfSizesAreEqual(other: Collection): List>? = + if (size == other.size) zip(other) else null + fun Iterable.keysToMapExceptNulls(value: (K) -> V?): Map { val map = LinkedHashMap() for (k in this) {