[IR] Use common expect/actual matching algorithm in IR actualizer

^KT-58578 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-06-06 17:27:03 +03:00
committed by Space Team
parent 62534f43c9
commit ba41e8ec38
52 changed files with 1130 additions and 440 deletions
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.cli.common.fir.FirDiagnosticsCompilerResultsReporter
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.constant.EvaluatedConstTracker import org.jetbrains.kotlin.constant.EvaluatedConstTracker
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
@@ -36,6 +35,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
@@ -217,6 +217,7 @@ fun transformFirToIr(
visibilityConverter = Fir2IrVisibilityConverter.Default, visibilityConverter = Fir2IrVisibilityConverter.Default,
kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance, kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance,
diagnosticReporter = diagnosticsReporter, diagnosticReporter = diagnosticsReporter,
actualizerTypeContextProvider = ::IrTypeSystemContextImpl,
fir2IrResultPostCompute = { fir2IrResultPostCompute = {
(this.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = librariesDescriptors } (this.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = librariesDescriptors }
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.pipeline
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizedResult import org.jetbrains.kotlin.backend.common.actualizer.IrActualizedResult
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -20,10 +21,12 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.signaturer.FirMangler import org.jetbrains.kotlin.fir.signaturer.FirMangler
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.util.IdSignatureComposer import org.jetbrains.kotlin.ir.util.IdSignatureComposer
import org.jetbrains.kotlin.ir.util.KotlinMangler import org.jetbrains.kotlin.ir.util.KotlinMangler
@@ -57,6 +60,7 @@ fun FirResult.convertToIrAndActualizeForJvm(
visibilityConverter = FirJvmVisibilityConverter, visibilityConverter = FirJvmVisibilityConverter,
diagnosticReporter = diagnosticReporter, diagnosticReporter = diagnosticReporter,
kotlinBuiltIns = DefaultBuiltIns.Instance, kotlinBuiltIns = DefaultBuiltIns.Instance,
actualizerTypeContextProvider = ::JvmIrTypeSystemContext,
) )
fun signatureComposerForJvmFir2Ir(generateSignatures: Boolean): IdSignatureComposer { fun signatureComposerForJvmFir2Ir(generateSignatures: Boolean): IdSignatureComposer {
@@ -78,6 +82,7 @@ fun FirResult.convertToIrAndActualize(
visibilityConverter: Fir2IrVisibilityConverter, visibilityConverter: Fir2IrVisibilityConverter,
kotlinBuiltIns: KotlinBuiltIns, kotlinBuiltIns: KotlinBuiltIns,
diagnosticReporter: DiagnosticReporter, diagnosticReporter: DiagnosticReporter,
actualizerTypeContextProvider: (IrBuiltIns) -> IrTypeSystemContext,
fir2IrResultPostCompute: Fir2IrResult.() -> Unit = {}, fir2IrResultPostCompute: Fir2IrResult.() -> Unit = {},
): Fir2IrActualizedResult { ): Fir2IrActualizedResult {
val fir2IrResult: Fir2IrResult val fir2IrResult: Fir2IrResult
@@ -140,6 +145,7 @@ fun FirResult.convertToIrAndActualize(
fir2IrResult.irModuleFragment, fir2IrResult.irModuleFragment,
commonIrOutputs.map { it.irModuleFragment }, commonIrOutputs.map { it.irModuleFragment },
diagnosticReporter, diagnosticReporter,
actualizerTypeContextProvider(fir2IrResult.irModuleFragment.irBuiltins),
fir2IrConfiguration.languageVersionSettings fir2IrConfiguration.languageVersionSettings
) )
} }
@@ -70,6 +70,13 @@ open class KtDiagnosticReporterWithContext(
} }
} }
fun <A : Any, B : Any, C : Any> report(factory: KtDiagnosticFactory3<A, B, C>, a: A, b: B, c: C) {
sourceElement?.let {
reportOn(it, factory, a, b, c, this)
checkAndCommitReportsOn(it, this)
}
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is DiagnosticContextImpl) return false if (other !is DiagnosticContextImpl) return false
@@ -6,18 +6,24 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.INCOMPATIBILITY
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.error0
import org.jetbrains.kotlin.diagnostics.error2 import org.jetbrains.kotlin.diagnostics.error2
import org.jetbrains.kotlin.diagnostics.error3
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
import org.jetbrains.kotlin.diagnostics.rendering.Renderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.MODULE_WITH_PLATFORM import org.jetbrains.kotlin.diagnostics.rendering.Renderers.MODULE_WITH_PLATFORM
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
object CommonBackendErrors { object CommonBackendErrors {
val NO_ACTUAL_FOR_EXPECT by error2<PsiElement, String, ModuleDescriptor>() val NO_ACTUAL_FOR_EXPECT by error2<PsiElement, String, ModuleDescriptor>()
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>() val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>()
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>() val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<PsiElement, String, String>()
val INCOMPATIBLE_MATCHING by error3<PsiElement, String, String, ExpectActualCompatibility.Incompatible<*>>()
init { init {
RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages) RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages)
@@ -44,5 +50,18 @@ object KtDefaultCommonBackendErrorMessages : BaseDiagnosticRendererFactory() {
STRING, STRING,
STRING, STRING,
) )
map.put(
CommonBackendErrors.INCOMPATIBLE_MATCHING,
"Expect declaration `{0}` doesn''t match actual `{1}` because {2}",
STRING,
STRING,
INCOMPATIBILITY
)
}
}
object BackendDiagnosticRenderers {
val INCOMPATIBILITY = Renderer<ExpectActualCompatibility.Incompatible<*>> {
it.reason ?: "<unknown>"
} }
} }
@@ -8,13 +8,18 @@ package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.backend.common.CommonBackendErrors import org.jetbrains.kotlin.backend.common.CommonBackendErrors
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
/** /**
* It adds fake overrides to non-expect classes inside common or multi-platform module, * It adds fake overrides to non-expect classes inside common or multi-platform module,
@@ -27,9 +32,11 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
*/ */
internal class ActualFakeOverridesAdder( internal class ActualFakeOverridesAdder(
private val expectActualMap: Map<IrSymbol, IrSymbol>, private val expectActualMap: Map<IrSymbol, IrSymbol>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val expectToActualClassMap: Map<ClassId, IrClassSymbol>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext,
private val typeSystemContext: IrTypeSystemContext
) : IrElementVisitorVoid { ) : IrElementVisitorVoid {
private val missingActualMembersMap = mutableMapOf<IrClass, MutableMap<String, MutableList<IrDeclaration>>>() private val missingActualMembersMap = mutableMapOf<IrClass, FakeOverrideInfo>()
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
extractMissingActualMembersFromSupertypes(declaration) extractMissingActualMembersFromSupertypes(declaration)
@@ -40,20 +47,20 @@ internal class ActualFakeOverridesAdder(
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
private fun extractMissingActualMembersFromSupertypes(klass: IrClass): Map<String, MutableList<IrDeclaration>> { private fun extractMissingActualMembersFromSupertypes(klass: IrClass): FakeOverrideInfo {
missingActualMembersMap[klass]?.let { return it } missingActualMembersMap[klass]?.let { return it }
val missingActualMembers = mutableMapOf<String, MutableList<IrDeclaration>>() val missingActualMembers = FakeOverrideInfo()
missingActualMembersMap[klass] = missingActualMembers missingActualMembersMap[klass] = missingActualMembers
// New members from supertypes are only relevant for not expect (ordinary) classes // New members from supertypes are only relevant for not expect (ordinary) classes
// New members from the current class are only relevant for actualized expect classes // New members from the current class are only relevant for actualized expect classes
val processedMembers = mutableMapOf<String, MutableList<IrDeclaration>>() val processedMembers = FakeOverrideInfo()
for (superType in klass.superTypes) { for (superType in klass.superTypes) {
val membersFromSupertype = extractMissingActualMembersFromSupertypes(superType.classifierOrFail.owner as IrClass) val membersFromSupertype = extractMissingActualMembersFromSupertypes(superType.classifierOrFail.owner as IrClass)
if (!klass.isExpect) { if (!klass.isExpect) {
missingActualMembers.appendMissingMembersToNotExpectClass(klass, membersFromSupertype, processedMembers) appendMissingMembersToNotExpectClass(missingActualMembers, klass, membersFromSupertype.allSymbols(), processedMembers)
} }
} }
@@ -64,22 +71,35 @@ internal class ActualFakeOverridesAdder(
return missingActualMembers return missingActualMembers
} }
private fun MutableMap<String, MutableList<IrDeclaration>>.appendMissingMembersToNotExpectClass( private fun appendMissingMembersToNotExpectClass(
fakeOverrideInfo: FakeOverrideInfo,
klass: IrClass, klass: IrClass,
membersFromSupertype: Map<String, MutableList<IrDeclaration>>, membersFromSupertype: List<IrSymbol>,
processedMembers: MutableMap<String, MutableList<IrDeclaration>> processedMembers: FakeOverrideInfo
) { ) {
for (memberFromSupertype in membersFromSupertype.flatMap { it.value }) { for (symbolFromSupertype in membersFromSupertype) {
val memberFromSupertype = symbolFromSupertype.owner as IrDeclaration
val newMember = createFakeOverrideMember(listOf(memberFromSupertype), klass) val newMember = createFakeOverrideMember(listOf(memberFromSupertype), klass)
val name = newMember.getFunctionOrPropertyName() val matchingFakeOverrides = collectActualCallablesMatchingToSpecificExpect(
if (getMatches(name, newMember, expectActualMap).isEmpty()) { newMember.symbol,
fakeOverrideInfo.getMembersForActual(newMember),
expectToActualClassMap,
typeSystemContext
)
if (matchingFakeOverrides.isEmpty()) {
processedMembers.addMember(memberFromSupertype as IrOverridableDeclaration<*>) processedMembers.addMember(memberFromSupertype as IrOverridableDeclaration<*>)
addMember(newMember) fakeOverrideInfo.addMember(newMember)
klass.addMember(newMember) klass.addMember(newMember)
} else { } else {
val baseMember = processedMembers.getMatches(name, newMember, expectActualMap).single() val baseMembers = collectActualCallablesMatchingToSpecificExpect(
newMember.symbol,
processedMembers.getMembersForActual(newMember),
expectToActualClassMap,
typeSystemContext
)
val errorFactory = val errorFactory =
if ((baseMember.parent as IrClass).isInterface && (memberFromSupertype.parent as IrClass).isInterface) if (baseMembers.all { ((it.owner as IrDeclaration).parent as IrClass).isInterface } && (memberFromSupertype.parent as IrClass).isInterface)
CommonBackendErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED CommonBackendErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED
else else
CommonBackendErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED CommonBackendErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
@@ -92,7 +112,7 @@ internal class ActualFakeOverridesAdder(
} }
} }
private fun MutableMap<String, MutableList<IrDeclaration>>.appendMissingMembersFromActualizedExpectClass( private fun FakeOverrideInfo.appendMissingMembersFromActualizedExpectClass(
expectClass: IrClass, expectClass: IrClass,
actualClass: IrClass, actualClass: IrClass,
) { ) {
@@ -110,11 +130,31 @@ internal class ActualFakeOverridesAdder(
} }
} }
private fun MutableMap<String, MutableList<IrDeclaration>>.addMember(member: IrOverridableDeclaration<*>) { private class FakeOverrideInfo {
getOrPut(member.getFunctionOrPropertyName()) { mutableListOf() }.add(member) val functionsByName: MutableMap<Name, MutableList<IrSymbol>> = mutableMapOf()
} val propertiesByName: MutableMap<Name, MutableList<IrSymbol>> = mutableMapOf()
private fun IrOverridableDeclaration<*>.getFunctionOrPropertyName(): String { fun allSymbols(): List<IrSymbol> {
return (this as IrDeclarationWithName).name.asString() + (if (this is IrSimpleFunction) "()" else "") return buildList {
functionsByName.values.flatMapTo(this) { it }
propertiesByName.values.flatMapTo(this) { it }
}
}
private fun getCorrespondingMap(member: IrOverridableDeclaration<*>): MutableMap<Name, MutableList<IrSymbol>> {
return when (member) {
is IrFunction -> functionsByName
is IrProperty -> propertiesByName
else -> error("Unsupported declaration type: $member")
}
}
fun addMember(member: IrOverridableDeclaration<*>) {
getCorrespondingMap(member).getOrPut(member.name) { mutableListOf() } += member.symbol
}
fun getMembersForActual(actualMember: IrOverridableDeclaration<*>): List<IrSymbol> {
return getCorrespondingMap(actualMember)[actualMember.name].orEmpty()
}
} }
} }
@@ -8,66 +8,97 @@ package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.ir.util.callableId
import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.classIdOrFail
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
/**
* This class is used to collect mapping between all expect and actuals declarations, which are declared in passed module fragments
* It does not process any declarations which may appear after actualization of supertypes (like fake-overrides in classes with
* expect supertypes)
*
* The main method of this class, `collect` returns a pair of two values:
* - `expectToActualMap` is the main storage of all mapped declarations. Key is symbol of expect declaration and the value is symbol of
* corresponding actual declaration
* - `classActualizationInfo` is a storage which keeps information about types (class) actualization, which can be used later for type
* refinement if needed
*
* If some declarations didn't match (or there was missing/actual) then corresponding declarations won't be stored in `expectToActualMap`.
* Instead of that an error will be reported to `diagnosticReporter`
*/
internal class ExpectActualCollector( internal class ExpectActualCollector(
private val mainFragment: IrModuleFragment, private val mainFragment: IrModuleFragment,
private val dependentFragments: List<IrModuleFragment>, private val dependentFragments: List<IrModuleFragment>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val typeSystemContext: IrTypeSystemContext,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext,
) { ) {
fun collect(): MutableMap<IrSymbol, IrSymbol> { data class Result(val expectToActualMap: MutableMap<IrSymbol, IrSymbol>, val classActualizationInfo: ClassActualizationInfo)
fun collect(): Result {
val result = mutableMapOf<IrSymbol, IrSymbol>() val result = mutableMapOf<IrSymbol, IrSymbol>()
// Collect and link classes at first to make it possible to expand type aliases on the members linking // Collect and link classes at first to make it possible to expand type aliases on the members linking
val (actualMembers, expectActualTypeAliasMap) = result.appendExpectActualClassMap() val actualDeclarations = collectActualDeclarations()
result.appendExpectActualMemberMap(actualMembers, expectActualTypeAliasMap) matchAllExpectDeclarations(result, actualDeclarations)
return result return Result(result, actualDeclarations)
} }
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassMap(): Pair<List<IrDeclarationBase>, Map<FqName, FqName>> { private fun collectActualDeclarations(): ClassActualizationInfo {
val actualClasses = mutableMapOf<String, IrClassSymbol>()
// There is no list for builtins declarations; that's why they are being collected from typealiases
val actualMembers = mutableListOf<IrDeclarationBase>()
val expectActualTypeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual
val fragmentsWithActuals = dependentFragments.drop(1) + mainFragment val fragmentsWithActuals = dependentFragments.drop(1) + mainFragment
val actualClassesAndMembersCollector = ActualClassesAndMembersCollector(actualClasses, actualMembers, expectActualTypeAliasMap) return ActualDeclarationsCollector.collectActualsFromFragments(fragmentsWithActuals)
fragmentsWithActuals.forEach { actualClassesAndMembersCollector.collect(it) }
val linkCollector = ClassLinksCollector(this, actualClasses, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { linkCollector.visitModuleFragment(it) }
return actualMembers to expectActualTypeAliasMap
} }
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualMemberMap( private fun matchAllExpectDeclarations(
actualMembers: List<IrDeclarationBase>, destination: MutableMap<IrSymbol, IrSymbol>,
expectActualTypeAliasMap: Map<FqName, FqName> classActualizationInfo: ClassActualizationInfo,
) { ) {
val actualMembersMap = mutableMapOf<String, MutableList<IrDeclarationBase>>() val linkCollector = ExpectActualLinkCollector(destination, classActualizationInfo, typeSystemContext, diagnosticsReporter)
for (actualMember in actualMembers) { dependentFragments.forEach { linkCollector.visitModuleFragment(it) }
actualMembersMap.getOrPut(generateIrElementFullNameFromExpect(actualMember, expectActualTypeAliasMap)) { mutableListOf() }
.add(actualMember)
}
val collector = MemberLinksCollector(this, actualMembersMap, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { collector.visitModuleFragment(it) }
} }
} }
private class ActualClassesAndMembersCollector( internal data class ClassActualizationInfo(
private val actualClasses: MutableMap<String, IrClassSymbol>, // mapping from classId of actual class/typealias to itself/typealias expansion
private val actualMembers: MutableList<IrDeclarationBase>, val actualClasses: Map<ClassId, IrClassSymbol>,
private val expectActualTypeAliasMap: MutableMap<FqName, FqName> // mapping from classId to actual typealias
val actualTypeAliases: Map<ClassId, IrTypeAliasSymbol>,
val actualTopLevels: Map<CallableId, List<IrDeclarationWithName>>,
) { ) {
fun getActualWithoutExpansion(classId: ClassId): IrSymbol? {
return actualTypeAliases[classId] ?: actualClasses[classId]
}
}
private class ActualDeclarationsCollector {
companion object {
fun collectActualsFromFragments(fragments: List<IrModuleFragment>): ClassActualizationInfo {
val collector = ActualDeclarationsCollector()
for (fragment in fragments) {
collector.collect(fragment)
}
return ClassActualizationInfo(
collector.actualClasses,
collector.actualTypeAliasesWithoutExpansion,
collector.actualTopLevels
)
}
}
private val actualClasses: MutableMap<ClassId, IrClassSymbol> = mutableMapOf()
private val actualTypeAliasesWithoutExpansion: MutableMap<ClassId, IrTypeAliasSymbol> = mutableMapOf()
private val actualTopLevels: MutableMap<CallableId, MutableList<IrDeclarationWithName>> = mutableMapOf()
private val visitedActualClasses = mutableSetOf<IrClass>() private val visitedActualClasses = mutableSetOf<IrClass>()
fun collect(element: IrElement) { private fun collect(element: IrElement) {
when (element) { when (element) {
is IrModuleFragment -> { is IrModuleFragment -> {
for (file in element.files) { for (file in element.files) {
@@ -77,16 +108,18 @@ private class ActualClassesAndMembersCollector(
is IrTypeAlias -> { is IrTypeAlias -> {
if (!element.isActual) return if (!element.isActual) return
val classId = element.classIdOrFail
val expandedTypeSymbol = element.expandedType.classifierOrFail as IrClassSymbol val expandedTypeSymbol = element.expandedType.classifierOrFail as IrClassSymbol
addActualClass(element, expandedTypeSymbol)
collect(expandedTypeSymbol.owner)
expectActualTypeAliasMap[element.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName actualClasses[classId] = expandedTypeSymbol
actualTypeAliasesWithoutExpansion[classId] = element.symbol
collect(expandedTypeSymbol.owner)
} }
is IrClass -> { is IrClass -> {
if (element.isExpect || !visitedActualClasses.add(element)) return if (element.isExpect || !visitedActualClasses.add(element)) return
addActualClass(element, element.symbol) actualClasses[element.classIdOrFail] = element.symbol
for (declaration in element.declarations) { for (declaration in element.declarations) {
collect(declaration) collect(declaration)
} }
@@ -97,101 +130,99 @@ private class ActualClassesAndMembersCollector(
} }
} }
is IrEnumEntry -> { is IrEnumEntry -> {
actualMembers.add(element) // If enum entry is located inside expect enum, then this code is not executed recordActualCallable(element, element.callableId) // If enum entry is located inside expect enum, then this code is not executed
} }
is IrProperty -> { is IrProperty -> {
if (element.isExpect) return if (element.isExpect) return
actualMembers.add(element) recordActualCallable(element, element.callableId)
} }
is IrFunction -> { is IrFunction -> {
if (element.isExpect) return if (element.isExpect) return
actualMembers.add(element) recordActualCallable(element, element.callableId)
} }
} }
} }
private fun addActualClass(classOrTypeAlias: IrElement, classSymbol: IrClassSymbol) { private fun recordActualCallable(callableDeclaration: IrDeclarationWithName, callableId: CallableId) {
actualClasses[generateActualIrClassOrTypeAliasFullName(classOrTypeAlias)] = classSymbol if (callableId.classId == null) {
actualTopLevels
.getOrPut(callableId) { mutableListOf() }
.add(callableDeclaration)
}
} }
} }
private class ClassLinksCollector( private class ExpectActualLinkCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>, private val destination: MutableMap<IrSymbol, IrSymbol>,
private val actualClasses: Map<String, IrClassSymbol>, private val classActualizationInfo: ClassActualizationInfo,
private val expectActualTypeAliasMap: Map<FqName, FqName>, typeSystemContext: IrTypeSystemContext,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext,
) : IrElementVisitorVoid { ) : IrElementVisitorVoid {
private val context = MatchingContext(typeSystemContext)
override fun visitFunction(declaration: IrFunction) {
if (declaration.isExpect) {
matchExpectCallable(declaration, declaration.callableId)
}
}
override fun visitProperty(declaration: IrProperty) {
if (declaration.isExpect) {
matchExpectCallable(declaration, declaration.callableId)
}
}
private fun matchExpectCallable(declaration: IrDeclarationWithName, callableId: CallableId) {
val actualSymbols = classActualizationInfo.actualTopLevels[callableId]?.map { it.symbol }.orEmpty()
matchExpectDeclaration(declaration.symbol, actualSymbols)
}
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
if (!declaration.isExpect) return if (!declaration.isExpect) return
val classId = declaration.classIdOrFail
val expectClassSymbol = declaration.symbol
val actualClassLikeSymbol = classActualizationInfo.getActualWithoutExpansion(classId)
matchExpectDeclaration(expectClassSymbol, listOfNotNull(actualClassLikeSymbol))
}
val actualClassSymbol = actualClasses[generateIrElementFullNameFromExpect(declaration, expectActualTypeAliasMap)] private fun matchExpectDeclaration(expectSymbol: IrSymbol, actualSymbols: List<IrSymbol>) {
if (actualClassSymbol != null) { AbstractExpectActualCompatibilityChecker.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectActualMap[declaration.symbol] = actualClassSymbol expectSymbol,
expectActualMap.appendTypeParametersMap(declaration, actualClassSymbol.owner) actualSymbols,
} else if (!declaration.containsOptionalExpectation()) { context
diagnosticsReporter.reportMissingActual(declaration) )
}
visitElement(declaration)
} }
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
}
private class MemberLinksCollector( private inner class MatchingContext(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>, typeSystemContext: IrTypeSystemContext,
private val actualMembers: Map<String, List<IrDeclarationBase>>, ) : IrExpectActualMatchingContext(typeSystemContext, classActualizationInfo.actualClasses) {
private val typeAliasMap: Map<FqName, FqName>, override fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol) {
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext destination[expectClassSymbol] = actualClassSymbol
) : IrElementVisitorVoid { recordActualForExpectDeclaration(expectClassSymbol, actualClassSymbol, destination)
override fun visitFunction(declaration: IrFunction) { }
if (declaration.isExpect) addLink(declaration)
}
override fun visitProperty(declaration: IrProperty) { override fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol) {
if (declaration.isExpect) addLink(declaration) recordActualForExpectDeclaration(expectSymbol, actualSymbol, destination)
} }
override fun visitEnumEntry(declaration: IrEnumEntry) { override fun onMismatchedMembersFromClassScope(
if ((declaration.parent as IrClass).isExpect) addLink(declaration) expectSymbol: DeclarationSymbolMarker,
} actualSymbolsByIncompatibility: Map<ExpectActualCompatibility.Incompatible<*>, List<DeclarationSymbolMarker>>,
) {
private fun addLink(expectDeclaration: IrDeclarationBase) { require(expectSymbol is IrSymbol)
val actualMemberMatches = actualMembers.getMatches(expectDeclaration, expectActualMap, typeAliasMap) if (actualSymbolsByIncompatibility.isEmpty() && !expectSymbol.owner.containsOptionalExpectation()) {
when { diagnosticsReporter.reportMissingActual(expectSymbol)
actualMemberMatches.size == 1 -> {
expectActualMap.addLink(expectDeclaration, actualMemberMatches.single())
} }
actualMemberMatches.size > 1 -> { for ((incompatibility, actualMemberSymbols) in actualSymbolsByIncompatibility) {
// TODO: report AMBIGUOUS_ACTUALS here, see KT-57932 for (actualSymbol in actualMemberSymbols) {
} require(actualSymbol is IrSymbol)
(expectDeclaration.parent as? IrClass)?.isExpect == false && expectDeclaration.isFakeOverride -> { diagnosticsReporter.reportIncompatibleExpectActual(expectSymbol, actualSymbol, incompatibility)
// Remaining expect fake override members from not expect classes will be actualized in FakeOverridesTransformer
// It occurs in a separated step because they require filled expectActualMap for members from expect classes
}
else -> {
if (shouldReportMissingActual(expectDeclaration)) {
diagnosticsReporter.reportMissingActual(expectDeclaration)
} }
} }
} }
} }
private fun shouldReportMissingActual(declaration: IrDeclarationBase): Boolean {
return !declaration.parent.containsOptionalExpectation() && !(declaration is IrConstructor && declaration.isPrimary)
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
}
fun MutableMap<IrSymbol, IrSymbol>.appendTypeParametersMap(
expectTypeParametersContainer: IrTypeParametersContainer,
actualTypeParametersContainer: IrTypeParametersContainer
) {
expectTypeParametersContainer.typeParameters.zip(actualTypeParametersContainer.typeParameters)
.forEach { (expectTypeParameter, actualTypeParameter) -> this[expectTypeParameter.symbol] = actualTypeParameter.symbol }
} }
@@ -47,7 +47,7 @@ internal class FakeOverridesActualizer(private val expectActualMap: MutableMap<I
val actualizedOverrides = overriddenSymbols.map { (it.owner as IrDeclaration).actualize() } val actualizedOverrides = overriddenSymbols.map { (it.owner as IrDeclaration).actualize() }
val actualFakeOverride = createFakeOverrideMember(actualizedOverrides, parent as IrClass) val actualFakeOverride = createFakeOverrideMember(actualizedOverrides, parent as IrClass)
expectActualMap.addLink(this as IrDeclarationBase, actualFakeOverride) recordActualForExpectDeclaration(this.symbol, actualFakeOverride.symbol, expectActualMap)
return actualFakeOverride return actualFakeOverride
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper
data class IrActualizedResult(val actualizedExpectDeclarations: List<IrDeclaration>) data class IrActualizedResult(val actualizedExpectDeclarations: List<IrDeclaration>)
@@ -19,15 +20,17 @@ object IrActualizer {
mainFragment: IrModuleFragment, mainFragment: IrModuleFragment,
dependentFragments: List<IrModuleFragment>, dependentFragments: List<IrModuleFragment>,
diagnosticReporter: DiagnosticReporter, diagnosticReporter: DiagnosticReporter,
typeSystemContext: IrTypeSystemContext,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
): IrActualizedResult { ): IrActualizedResult {
val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings) val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings)
// The ir modules processing is performed phase-to-phase: // The ir modules processing is performed phase-to-phase:
// 1. Collect expect-actual links for classes and their members from dependent fragments // 1. Collect expect-actual links for classes and their members from dependent fragments
val expectActualMap = ExpectActualCollector( val (expectActualMap, actualDeclarations) = ExpectActualCollector(
mainFragment, mainFragment,
dependentFragments, dependentFragments,
typeSystemContext,
ktDiagnosticReporter ktDiagnosticReporter
).collect() ).collect()
@@ -44,7 +47,9 @@ object IrActualizer {
// taken from these non-expect classes actualized super classes. // taken from these non-expect classes actualized super classes.
ActualFakeOverridesAdder( ActualFakeOverridesAdder(
expectActualMap, expectActualMap,
ktDiagnosticReporter actualDeclarations.actualClasses,
ktDiagnosticReporter,
typeSystemContext
).apply { dependentFragments.forEach { visitModuleFragment(it) } } ).apply { dependentFragments.forEach { visitModuleFragment(it) } }
// 5. Copy and actualize function parameter default values from expect functions // 5. Copy and actualize function parameter default values from expect functions
@@ -13,182 +13,89 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
private val FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME = StandardClassIds.Annotations.FlexibleNullability.asSingleFqName() internal fun collectActualCallablesMatchingToSpecificExpect(
expectSymbol: IrSymbol,
actualSymbols: List<IrSymbol>,
expectToActualClassMap: Map<ClassId, IrClassSymbol>,
typeSystemContext: IrTypeSystemContext,
): List<IrSymbol> {
val baseExpectSymbol = expectSymbol
val matchingActuals = mutableListOf<IrSymbol>()
val context = object : IrExpectActualMatchingContext(typeSystemContext, expectToActualClassMap) {
override fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol) {
shouldNotBeCalled()
}
internal fun Map<String, List<IrDeclaration>>.getMatches( override fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol) {
expectDeclaration: IrDeclaration, require(expectSymbol == baseExpectSymbol)
expectActualTypesMap: Map<IrSymbol, IrSymbol>, matchingActuals += actualSymbol
expectActualTypeAliasMap: Map<FqName, FqName> }
): List<IrDeclaration> =
getMatches(generateIrElementFullNameFromExpect(expectDeclaration, expectActualTypeAliasMap), expectDeclaration, expectActualTypesMap)
internal fun Map<String, List<IrDeclaration>>.getMatches(
mainSignature: String,
expectDeclaration: IrDeclaration,
expectActualTypesMap: Map<IrSymbol, IrSymbol>
): List<IrDeclaration> {
val members = this[mainSignature] ?: return emptyList()
return when (expectDeclaration) {
is IrFunction -> members.getMatches(expectDeclaration, expectActualTypesMap) { it as IrFunction }
is IrProperty -> members.getMatches(expectDeclaration, expectActualTypesMap) { (it as IrProperty).getter!! }
else -> members
} }
AbstractExpectActualCompatibilityChecker.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectSymbol,
actualSymbols,
context
)
return matchingActuals
} }
private inline fun List<IrDeclaration>.getMatches( internal fun recordActualForExpectDeclaration(
expect: IrDeclaration, expectSymbol: IrSymbol,
expectActualTypesMap: Map<IrSymbol, IrSymbol>, actualSymbol: IrSymbol,
functionExtractor: (IrDeclaration) -> IrFunction destination: MutableMap<IrSymbol, IrSymbol>,
): List<IrDeclaration> {
val expectFunction = functionExtractor(expect)
return filter { expectFunction.match(functionExtractor(it), expectActualTypesMap) }
}
private fun IrFunction.match(actualFunction: IrFunction, expectActualTypesMap: Map<IrSymbol, IrSymbol>): Boolean {
fun getActualizedTypeClassifierSymbol(
expectParameter: IrValueParameter,
localTypeParametersMap: Map<IrTypeParameterSymbol, IrTypeParameterSymbol>? = null
): IrSymbol {
return expectParameter.type.classifierOrFail.let {
val localMappedSymbol = if (localTypeParametersMap != null && it is IrTypeParameterSymbol) {
localTypeParametersMap[it]
} else {
null
}
localMappedSymbol ?: expectActualTypesMap[it] ?: it
}
}
fun checkParameter(
expectParameter: IrValueParameter?,
actualParameter: IrValueParameter?,
localTypeParametersMap: Map<IrTypeParameterSymbol, IrTypeParameterSymbol>
): Boolean {
if (expectParameter == null) {
return actualParameter == null
}
if (actualParameter == null) {
return false
}
if (expectParameter.type is IrDynamicType || actualParameter.type is IrDynamicType) {
return true
}
if (expectParameter.type.isNullable() != actualParameter.type.isNullable() &&
!expectParameter.type.annotations.hasAnnotation(FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME) &&
!actualParameter.type.annotations.hasAnnotation(FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME)
) {
return false
}
if (getActualizedTypeClassifierSymbol(expectParameter, localTypeParametersMap) !=
getActualizedTypeClassifierSymbol(actualParameter)
) {
return false
}
return true
}
if (valueParameters.size != actualFunction.valueParameters.size || typeParameters.size != actualFunction.typeParameters.size) {
return false
}
val localTypeParametersMap = mutableMapOf<IrTypeParameterSymbol, IrTypeParameterSymbol>()
for ((expectTypeParameter, actualTypeParameter) in typeParameters.zip(actualFunction.typeParameters)) {
if (expectTypeParameter.name != actualTypeParameter.name) {
return false
}
localTypeParametersMap[expectTypeParameter.symbol] = actualTypeParameter.symbol
}
if (!checkParameter(extensionReceiverParameter, actualFunction.extensionReceiverParameter, localTypeParametersMap)) {
return false
}
for ((expectParameter, actualParameter) in valueParameters.zip(actualFunction.valueParameters)) {
if (!checkParameter(expectParameter, actualParameter, localTypeParametersMap)) {
return false
}
}
return true
}
internal fun generateActualIrClassOrTypeAliasFullName(declaration: IrElement) = generateIrElementFullNameFromExpect(declaration, emptyMap())
internal fun generateIrElementFullNameFromExpect(
declaration: IrElement,
expectActualTypeAliasMap: Map<FqName, FqName>
): String {
return buildString { appendElementFullName(declaration, this, expectActualTypeAliasMap) }
}
private fun appendElementFullName(
declaration: IrElement,
result: StringBuilder,
expectActualTypeAliasMap: Map<FqName, FqName>
) { ) {
if (declaration !is IrDeclarationBase) return val expectDeclaration = expectSymbol.owner as IrDeclarationBase
val actualDeclaration = actualSymbol.owner as IrDeclaration
val registeredActual = destination.put(expectSymbol, actualSymbol)
require(registeredActual == null || registeredActual == actualSymbol) {
"""
Expect symbol already has registered mapping
val parents = mutableListOf<String>() Expect declaration: ${expectDeclaration.render()}
var parent: IrDeclarationParent? = declaration.parent Actual declaration: ${actualDeclaration.render()}
while (parent != null) { Already registered: ${registeredActual!!.owner.render()}
if (parent is IrDeclarationWithName) { """.trimIndent()
val parentParent = parent.parent }
if (parentParent is IrClass) { if (expectDeclaration is IrTypeParametersContainer) {
parents.add(parent.name.asString()) recordTypeParametersMapping(destination, expectDeclaration, actualDeclaration as IrTypeParametersContainer)
parent = parentParent }
continue if (expectDeclaration is IrProperty) {
} val actualProperty = actualDeclaration as IrProperty
expectDeclaration.getter!!.let {
val getter = actualProperty.getter!!
destination[it.symbol] = getter.symbol
recordTypeParametersMapping(destination, it, getter)
} }
val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap[it] ?: it).asString() } expectDeclaration.setter?.symbol?.let { destination[it] = actualProperty.setter!!.symbol }
if (parentString.isNotEmpty()) {
parents.add(parentString)
}
parent = null
}
if (parents.isNotEmpty()) {
result.append(parents.asReversed().joinToString(separator = "."))
result.append('.')
}
if (declaration is IrDeclarationWithName) {
result.append(declaration.name)
}
if (declaration is IrFunction) {
result.append("()")
} }
} }
internal fun MutableMap<IrSymbol, IrSymbol>.addLink(expectMember: IrDeclarationBase, actualMember: IrDeclaration) { private fun recordTypeParametersMapping(
this[expectMember.symbol] = actualMember.symbol destination: MutableMap<IrSymbol, IrSymbol>,
if (expectMember is IrProperty) { expectTypeParametersContainer: IrTypeParametersContainer,
val actualProperty = actualMember as IrProperty actualTypeParametersContainer: IrTypeParametersContainer
expectMember.getter!!.let { ) {
val getter = actualProperty.getter!! expectTypeParametersContainer.typeParameters
this[it.symbol] = getter.symbol .zip(actualTypeParametersContainer.typeParameters)
this.appendTypeParametersMap(it, getter) .forEach { (expectTypeParameter, actualTypeParameter) ->
destination[expectTypeParameter.symbol] = actualTypeParameter.symbol
} }
expectMember.setter?.symbol?.let { this[it] = actualProperty.setter!!.symbol } }
} else if (expectMember is IrFunction) {
this.appendTypeParametersMap(expectMember, actualMember as IrFunction) internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportMissingActual(expectSymbol: IrSymbol) {
} reportMissingActual(expectSymbol.owner as IrDeclaration)
} }
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
@@ -200,6 +107,21 @@ internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportMissingActual(
) )
} }
internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportIncompatibleExpectActual(
expectSymbol: IrSymbol,
actualSymbol: IrSymbol,
incompatibility: ExpectActualCompatibility.Incompatible<*>
) {
val expectDeclaration = expectSymbol.owner as IrDeclaration
val actualDeclaration = actualSymbol.owner as IrDeclaration
at(expectDeclaration).report(
CommonBackendErrors.INCOMPATIBLE_MATCHING,
expectDeclaration.getNameWithAssert().asString(),
actualDeclaration.getNameWithAssert().asString(),
incompatibility
)
}
internal fun IrElement.containsOptionalExpectation(): Boolean { internal fun IrElement.containsOptionalExpectation(): Boolean {
return this is IrClass && return this is IrClass &&
this.kind == ClassKind.ANNOTATION_CLASS && this.kind == ClassKind.ANNOTATION_CLASS &&
@@ -0,0 +1,401 @@
/*
* Copyright 2010-2023 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.backend.common.actualizer
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrTypeBase
import org.jetbrains.kotlin.ir.types.impl.IrTypeProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.*
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(
val typeContext: IrTypeSystemContext,
val expectToActualClassMap: Map<ClassId, IrClassSymbol>
) : ExpectActualMatchingContext<IrSymbol>, TypeSystemContext by typeContext {
private inline fun <R> CallableSymbolMarker.processIr(
onFunction: (IrFunction) -> R,
onProperty: (IrProperty) -> R,
onField: (IrField) -> R,
onValueParameter: (IrValueParameter) -> R,
onEnumEntry: (IrEnumEntry) -> R,
): R {
return when (this) {
is IrFunctionSymbol -> onFunction(owner)
is IrPropertySymbol -> onProperty(owner)
is IrFieldSymbol -> onField(owner)
is IrValueParameterSymbol -> onValueParameter(owner)
is IrEnumEntrySymbol -> onEnumEntry(owner)
else -> error("Unsupported declaration: $this")
}
}
private inline fun <R> ClassLikeSymbolMarker.processIr(
onClass: (IrClass) -> R,
onTypeAlias: (IrTypeAlias) -> R,
): R {
return when (this) {
is IrClassSymbol -> onClass(owner)
is IrTypeAliasSymbol -> onTypeAlias(owner)
else -> error("Unsupported declaration: $this")
}
}
private fun DeclarationSymbolMarker.asIr(): IrDeclaration = (this as IrSymbol).owner as IrDeclaration
private fun FunctionSymbolMarker.asIr(): IrFunction = (this as IrFunctionSymbol).owner
private fun PropertySymbolMarker.asIr(): IrProperty = (this as IrPropertySymbol).owner
private fun ValueParameterSymbolMarker.asIr(): IrValueParameter = (this as IrValueParameterSymbol).owner
private fun TypeParameterSymbolMarker.asIr(): IrTypeParameter = (this as IrTypeParameterSymbol).owner
private fun RegularClassSymbolMarker.asIr(): IrClass = (this as IrClassSymbol).owner
private fun TypeAliasSymbolMarker.asIr(): IrTypeAlias = (this as IrTypeAliasSymbol).owner
private inline fun <reified T : IrDeclaration> DeclarationSymbolMarker.safeAsIr(): T? = (this as IrSymbol).owner as? T
override val shouldCheckReturnTypesOfCallables: Boolean
get() = true
override val innerClassesCapturesOuterTypeParameters: Boolean
get() = false
override val RegularClassSymbolMarker.classId: ClassId
get() = asIr().classIdOrFail
override val TypeAliasSymbolMarker.classId: ClassId
get() = asIr().classIdOrFail
override val CallableSymbolMarker.callableId: CallableId
get() = processIr(
onFunction = { it.callableId },
onProperty = { it.callableId },
onField = { it.callableId },
onValueParameter = { shouldNotBeCalled() },
onEnumEntry = { it.callableId }
)
override val TypeParameterSymbolMarker.parameterName: Name
get() = asIr().name
override val ValueParameterSymbolMarker.parameterName: Name
get() = asIr().name
override fun TypeAliasSymbolMarker.expandToRegularClass(): RegularClassSymbolMarker? {
return asIr().expandedType.getClass()?.symbol
}
override val RegularClassSymbolMarker.classKind: ClassKind
get() = asIr().kind
override val RegularClassSymbolMarker.isCompanion: Boolean
get() = asIr().isCompanion
override val RegularClassSymbolMarker.isInner: Boolean
get() = asIr().isInner
override val RegularClassSymbolMarker.isInline: Boolean
get() = asIr().isValue
override val RegularClassSymbolMarker.isValue: Boolean
get() = asIr().isValue
override val RegularClassSymbolMarker.isFun: Boolean
get() = asIr().isFun
override val ClassLikeSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
get() {
val parameters = processIr(
onClass = { it.typeParameters },
onTypeAlias = { it.typeParameters },
)
return parameters.map { it.symbol }
}
override val ClassLikeSymbolMarker.modality: Modality
get() = processIr(
onClass = {
// For some reason kotlin annotations in IR have open modality and java annotations have final modality
// But since it's legal to actualize kotlin annotation class with java annotation class
// and effectively all annotation classes have the same modality, it's ok to always return one
// modality for all annotation classes (doesn't matter final or open)
if (it.isAnnotationClass) Modality.OPEN else it.modality
},
onTypeAlias = { Modality.FINAL }
)
override val ClassLikeSymbolMarker.visibility: Visibility
get() = safeAsIr<IrDeclarationWithVisibility>()!!.visibility.delegate
override val CallableSymbolMarker.modality: Modality?
get() = when (this) {
is IrConstructorSymbol -> Modality.FINAL
is IrSymbol -> (owner as? IrOverridableMember)?.modality
else -> shouldNotBeCalled()
}
override val CallableSymbolMarker.visibility: Visibility
get() = when (this) {
is IrEnumEntrySymbol -> Visibilities.Public
is IrSymbol -> (owner as IrDeclarationWithVisibility).visibility.delegate
else -> shouldNotBeCalled()
}
override val RegularClassSymbolMarker.superTypes: List<KotlinTypeMarker>
get() = asIr().superTypes
override val CallableSymbolMarker.isExpect: Boolean
get() = processIr(
onFunction = { it.isExpect },
onProperty = { it.isExpect },
onField = { false },
onValueParameter = { false },
onEnumEntry = { false }
)
override val CallableSymbolMarker.isInline: Boolean
get() = processIr(
onFunction = { it.isInline },
onProperty = { false }, // property can not be inline in IR. Its getter is inline instead
onField = { false },
onValueParameter = { false },
onEnumEntry = { false }
)
override val CallableSymbolMarker.isSuspend: Boolean
get() = processIr(
onFunction = { it.isSuspend },
onProperty = { false }, // property can not be suspend in IR. Its getter is suspend instead
onField = { false },
onValueParameter = { false },
onEnumEntry = { false }
)
override val CallableSymbolMarker.isExternal: Boolean
get() = safeAsIr<IrPossiblyExternalDeclaration>()?.isExternal ?: false
override val CallableSymbolMarker.isInfix: Boolean
get() = safeAsIr<IrSimpleFunction>()?.isInfix ?: false
override val CallableSymbolMarker.isOperator: Boolean
get() = safeAsIr<IrSimpleFunction>()?.isOperator ?: false
override val CallableSymbolMarker.isTailrec: Boolean
get() = safeAsIr<IrSimpleFunction>()?.isTailrec ?: false
override val PropertySymbolMarker.isVar: Boolean
get() = asIr().isVar
override val PropertySymbolMarker.isLateinit: Boolean
get() = asIr().isLateinit
override val PropertySymbolMarker.isConst: Boolean
get() = asIr().isConst
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
get() = asIr().setter?.symbol
@OptIn(UnsafeCastFunction::class)
override fun createExpectActualTypeParameterSubstitutor(
expectTypeParameters: List<TypeParameterSymbolMarker>,
actualTypeParameters: List<TypeParameterSymbolMarker>,
parentSubstitutor: TypeSubstitutorMarker?,
): TypeSubstitutorMarker {
val expectParameters = expectTypeParameters.castAll<IrTypeParameterSymbol>()
val actualParameters = actualTypeParameters.castAll<IrTypeParameterSymbol>()
val actualTypes = actualParameters.map { it.owner.defaultType }
val substitutor = IrTypeSubstitutor(expectParameters, actualTypes, typeContext.irBuiltIns, allowEmptySubstitution = true)
return when (parentSubstitutor) {
null -> substitutor
is AbstractIrTypeSubstitutor -> IrChainedSubstitutor(parentSubstitutor, substitutor)
else -> shouldNotBeCalled()
}
}
/*
* [isActualDeclaration] flag is needed to correctly determine scope for specific class
* In IR there are no scopes, all declarations are stored inside IrClass itself, so this flag
* has no sense in IR context
*/
override fun RegularClassSymbolMarker.collectAllMembers(isActualDeclaration: Boolean): List<DeclarationSymbolMarker> {
return asIr().declarations.filterNot { it is IrAnonymousInitializer }.map { it.symbol }
}
override fun RegularClassSymbolMarker.getMembersForExpectClass(name: Name): List<DeclarationSymbolMarker> {
return asIr().declarations.filter { it.getNameWithAssert() == name }.map { it.symbol }
}
override fun RegularClassSymbolMarker.collectEnumEntryNames(): List<Name> {
return asIr().declarations.filterIsInstance<IrEnumEntry>().map { it.name }
}
override val CallableSymbolMarker.dispatchReceiverType: KotlinTypeMarker?
get() = (asIr().parent as? IrClass)?.defaultType
override val CallableSymbolMarker.extensionReceiverType: KotlinTypeMarker?
get() = safeAsIr<IrFunction>()?.extensionReceiverParameter?.type
override val CallableSymbolMarker.returnType: KotlinTypeMarker
get() = processIr(
onFunction = { it.returnType },
onProperty = { it.getter?.returnType ?: it.backingField?.type ?: error("No type for property: $it") },
onField = { it.type },
onValueParameter = { it.type },
onEnumEntry = { it.parentAsClass.defaultType }
)
override val CallableSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
get() = processIr(
onFunction = { it.typeParameters.map { parameter -> parameter.symbol } },
onProperty = { it.getter?.symbol?.typeParameters.orEmpty() },
onField = { emptyList() },
onValueParameter = { emptyList() },
onEnumEntry = { emptyList() }
)
override val FunctionSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
get() = asIr().valueParameters.map { it.symbol }
override val ValueParameterSymbolMarker.isVararg: Boolean
get() = asIr().isVararg
override val ValueParameterSymbolMarker.isNoinline: Boolean
get() = asIr().isNoinline
override val ValueParameterSymbolMarker.isCrossinline: Boolean
get() = asIr().isCrossinline
override val ValueParameterSymbolMarker.hasDefaultValue: Boolean
get() = asIr().hasDefaultValue()
override fun CallableSymbolMarker.isAnnotationConstructor(): Boolean {
val irConstructor = safeAsIr<IrConstructor>() ?: return false
return irConstructor.constructedClass.isAnnotationClass
}
override val TypeParameterSymbolMarker.bounds: List<KotlinTypeMarker>
get() = asIr().superTypes
override val TypeParameterSymbolMarker.variance: Variance
get() = asIr().variance
override val TypeParameterSymbolMarker.isReified: Boolean
get() = asIr().isReified
override fun areCompatibleExpectActualTypes(expectType: KotlinTypeMarker?, actualType: KotlinTypeMarker?): Boolean {
if (expectType == null) return actualType == null
if (actualType == null) return false
/*
* Here we need to actualize both types, because of following situation:
*
* // MODULE: common
* expect fun foo(): S // (1)
* expect class S
*
* // MODULE: intermediate
* actual fun foo(): S = null!! // (2)
*
* // MODULE: platform
* actual typealias S = String
*
* When we match return types of (1) and (2) they both will have original type `S`, but from
* perspective of module `platform` it should be replaced with `String`
*/
val actualizedExpectType = actualizingSubstitutor.substitute(expectType as IrType)
val actualizedActualType = actualizingSubstitutor.substitute(actualType as IrType)
return AbstractTypeChecker.equalTypes(
typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false),
actualizedExpectType,
actualizedActualType
)
}
private val actualizingSubstitutor = ActualizingSubstitutor()
private inner class ActualizingSubstitutor : AbstractIrTypeSubstitutor() {
override fun substitute(type: IrType): IrType {
return substituteOrNull(type) ?: type
}
private fun substituteOrNull(type: IrType): IrType? {
if (type !is IrSimpleTypeImpl) return null
val newClassifier = (type.classifier.owner as? IrClass)?.let { expectToActualClassMap[it.classIdOrFail] }
val newArguments = ArrayList<IrTypeArgument>(type.arguments.size)
var argumentsChanged = false
for (argument in type.arguments) {
val newArgument = substituteArgumentOrNull(argument)
if (newArgument != null) {
newArguments += newArgument
argumentsChanged = true
} else {
newArguments += argument
}
}
if (newClassifier == null && !argumentsChanged) {
return null
}
return IrSimpleTypeImpl(
classifier = newClassifier ?: type.classifier,
type.nullability,
newArguments,
type.annotations,
type.abbreviation
)
}
private fun substituteArgumentOrNull(argument: IrTypeArgument): IrTypeArgument? {
return when (argument) {
is IrStarProjection -> null
is IrTypeProjection -> when (argument) {
is IrTypeProjectionImpl -> {
val newType = substituteOrNull(argument.type) ?: return null
makeTypeProjection(newType, argument.variance)
}
is IrTypeBase -> substituteOrNull(argument) as IrTypeBase?
else -> shouldNotBeCalled()
}
}
}
}
override fun RegularClassSymbolMarker.isNotSamInterface(): Boolean {
// TODO: is it correct for java classes?
return !asIr().isFun
}
override fun CallableSymbolMarker.shouldSkipMatching(containingExpectClass: RegularClassSymbolMarker): Boolean {
return false
}
override val CallableSymbolMarker.hasStableParameterNames: Boolean
get() = when (asIr().origin) {
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB,
-> false
else -> true
}
override fun onMatchedMembers(expectSymbol: DeclarationSymbolMarker, actualSymbol: DeclarationSymbolMarker) {
require(expectSymbol is IrSymbol)
require(actualSymbol is IrSymbol)
when (expectSymbol) {
is IrClassSymbol -> {
val actualClassSymbol = when (actualSymbol) {
is IrClassSymbol -> actualSymbol
is IrTypeAliasSymbol -> actualSymbol.owner.expandedType.getClass()!!.symbol
else -> actualSymbol.unexpectedSymbolKind<IrClassifierSymbol>()
}
onMatchedClasses(expectSymbol, actualClassSymbol)
}
else -> onMatchedCallables(expectSymbol, actualSymbol)
}
}
abstract fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol)
abstract fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol)
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrTypeAbbreviation import org.jetbrains.kotlin.ir.types.IrTypeAbbreviation
import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.types.model.TypeParameterMarker
@@ -46,7 +47,7 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker
* @see IdSignature * @see IdSignature
* @see SymbolTable * @see SymbolTable
*/ */
interface IrSymbol { interface IrSymbol : DeclarationSymbolMarker {
/** /**
* The declaration that this symbol refers to if it's bound. * The declaration that this symbol refers to if it's bound.
@@ -167,7 +168,7 @@ interface IrAnonymousInitializerSymbol : IrBindableSymbol<ClassDescriptor, IrAno
* *
* @see IrGetEnumValue * @see IrGetEnumValue
*/ */
interface IrEnumEntrySymbol : IrBindableSymbol<ClassDescriptor, IrEnumEntry> interface IrEnumEntrySymbol : IrBindableSymbol<ClassDescriptor, IrEnumEntry>, EnumEntrySymbolMarker
/** /**
* A symbol whose [owner] is [IrField]. * A symbol whose [owner] is [IrField].
@@ -175,7 +176,7 @@ interface IrEnumEntrySymbol : IrBindableSymbol<ClassDescriptor, IrEnumEntry>
* @see IrGetField * @see IrGetField
* @see IrSetField * @see IrSetField
*/ */
interface IrFieldSymbol : IrBindableSymbol<PropertyDescriptor, IrField> interface IrFieldSymbol : IrBindableSymbol<PropertyDescriptor, IrField>, FieldSymbolMarker
/** /**
* A symbol whose [owner] is [IrClass], [IrScript] or [IrTypeParameter]. * A symbol whose [owner] is [IrClass], [IrScript] or [IrTypeParameter].
@@ -195,7 +196,7 @@ sealed interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker {
* @see IrCall.superQualifierSymbol * @see IrCall.superQualifierSymbol
* @see IrFieldAccessExpression.superQualifierSymbol * @see IrFieldAccessExpression.superQualifierSymbol
*/ */
interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<ClassDescriptor, IrClass> interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<ClassDescriptor, IrClass>, RegularClassSymbolMarker
/** /**
* A symbol whose [owner] is [IrScript]. * A symbol whose [owner] is [IrScript].
@@ -205,7 +206,10 @@ interface IrScriptSymbol : IrClassifierSymbol, IrBindableSymbol<ScriptDescriptor
/** /**
* A symbol whose [owner] is [IrTypeParameter]. * A symbol whose [owner] is [IrTypeParameter].
*/ */
interface IrTypeParameterSymbol : IrClassifierSymbol, IrBindableSymbol<TypeParameterDescriptor, IrTypeParameter>, TypeParameterMarker interface IrTypeParameterSymbol : IrClassifierSymbol,
IrBindableSymbol<TypeParameterDescriptor, IrTypeParameter>,
TypeParameterMarker,
TypeParameterSymbolMarker
/** /**
* A symbol whose [owner] is [IrValueParameter] or [IrVariable]. * A symbol whose [owner] is [IrValueParameter] or [IrVariable].
@@ -223,7 +227,7 @@ sealed interface IrValueSymbol : IrSymbol {
/** /**
* A symbol whose [owner] is [IrValueParameter]. * A symbol whose [owner] is [IrValueParameter].
*/ */
interface IrValueParameterSymbol : IrValueSymbol, IrBindableSymbol<ParameterDescriptor, IrValueParameter> interface IrValueParameterSymbol : IrValueSymbol, IrBindableSymbol<ParameterDescriptor, IrValueParameter>, ValueParameterSymbolMarker
/** /**
* A symbol whose [owner] is [IrVariable]. * A symbol whose [owner] is [IrVariable].
@@ -247,7 +251,7 @@ sealed interface IrReturnTargetSymbol : IrSymbol {
* *
* @see IrFunctionReference * @see IrFunctionReference
*/ */
sealed interface IrFunctionSymbol : IrReturnTargetSymbol { sealed interface IrFunctionSymbol : IrReturnTargetSymbol, FunctionSymbolMarker {
override val owner: IrFunction override val owner: IrFunction
} }
@@ -256,14 +260,14 @@ sealed interface IrFunctionSymbol : IrReturnTargetSymbol {
* *
* @see IrConstructorCall * @see IrConstructorCall
*/ */
interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol<ClassConstructorDescriptor, IrConstructor> interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol<ClassConstructorDescriptor, IrConstructor>, ConstructorSymbolMarker
/** /**
* A symbol whose [owner] is [IrSimpleFunction]. * A symbol whose [owner] is [IrSimpleFunction].
* *
* @see IrCall * @see IrCall
*/ */
interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrSimpleFunction> interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrSimpleFunction>, SimpleFunctionSymbolMarker
/** /**
* A symbol whose [owner] is [IrReturnableBlock]. * A symbol whose [owner] is [IrReturnableBlock].
@@ -273,7 +277,7 @@ interface IrReturnableBlockSymbol : IrReturnTargetSymbol, IrBindableSymbol<Funct
/** /**
* A symbol whose [owner] is [IrProperty]. * A symbol whose [owner] is [IrProperty].
*/ */
interface IrPropertySymbol : IrBindableSymbol<PropertyDescriptor, IrProperty> interface IrPropertySymbol : IrBindableSymbol<PropertyDescriptor, IrProperty>, PropertySymbolMarker
/** /**
* A symbol whose [owner] is [IrLocalDelegatedProperty]. * A symbol whose [owner] is [IrLocalDelegatedProperty].
@@ -285,4 +289,4 @@ interface IrLocalDelegatedPropertySymbol : IrBindableSymbol<VariableDescriptorWi
* *
* @see IrTypeAbbreviation * @see IrTypeAbbreviation
*/ */
interface IrTypeAliasSymbol : IrBindableSymbol<TypeAliasDescriptor, IrTypeAlias> interface IrTypeAliasSymbol : IrBindableSymbol<TypeAliasDescriptor, IrTypeAlias>, TypeAliasSymbolMarker
@@ -13,8 +13,11 @@ import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.utils.memoryOptimizedMap import org.jetbrains.kotlin.utils.memoryOptimizedMap
abstract class AbstractIrTypeSubstitutor : TypeSubstitutorMarker {
abstract fun substitute(type: IrType): IrType
}
abstract class AbstractIrTypeSubstitutor(private val irBuiltIns: IrBuiltIns) : TypeSubstitutorMarker { abstract class BaseIrTypeSubstitutor(private val irBuiltIns: IrBuiltIns) : AbstractIrTypeSubstitutor() {
private fun IrType.typeParameterConstructor(): IrTypeParameterSymbol? { private fun IrType.typeParameterConstructor(): IrTypeParameterSymbol? {
return if (this is IrSimpleType) classifier as? IrTypeParameterSymbol return if (this is IrSimpleType) classifier as? IrTypeParameterSymbol
@@ -25,7 +28,7 @@ abstract class AbstractIrTypeSubstitutor(private val irBuiltIns: IrBuiltIns) : T
abstract fun isEmptySubstitution(): Boolean abstract fun isEmptySubstitution(): Boolean
fun substitute(type: IrType): IrType { final override fun substitute(type: IrType): IrType {
if (isEmptySubstitution()) return type if (isEmptySubstitution()) return type
return substituteType(type) return substituteType(type)
} }
@@ -63,8 +66,9 @@ abstract class AbstractIrTypeSubstitutor(private val irBuiltIns: IrBuiltIns) : T
class IrTypeSubstitutor( class IrTypeSubstitutor(
typeParameters: List<IrTypeParameterSymbol>, typeParameters: List<IrTypeParameterSymbol>,
typeArguments: List<IrTypeArgument>, typeArguments: List<IrTypeArgument>,
irBuiltIns: IrBuiltIns irBuiltIns: IrBuiltIns,
) : AbstractIrTypeSubstitutor(irBuiltIns) { private val allowEmptySubstitution: Boolean = false
) : BaseIrTypeSubstitutor(irBuiltIns) {
init { init {
assert(typeParameters.size == typeArguments.size) { assert(typeParameters.size == typeArguments.size) {
@@ -80,7 +84,8 @@ class IrTypeSubstitutor(
override fun getSubstitutionArgument(typeParameter: IrTypeParameterSymbol): IrTypeArgument = override fun getSubstitutionArgument(typeParameter: IrTypeParameterSymbol): IrTypeArgument =
substitution[typeParameter] substitution[typeParameter]
?: throw AssertionError("Unsubstituted type parameter: ${typeParameter.owner.render()}") ?: typeParameter.takeIf { allowEmptySubstitution }?.owner?.defaultType
?: error("Unsubstituted type parameter: ${typeParameter.owner.render()}")
override fun isEmptySubstitution(): Boolean = substitution.isEmpty() override fun isEmptySubstitution(): Boolean = substitution.isEmpty()
} }
@@ -90,7 +95,7 @@ class IrCapturedTypeSubstitutor(
typeArguments: List<IrTypeArgument>, typeArguments: List<IrTypeArgument>,
capturedTypes: List<IrCapturedType?>, capturedTypes: List<IrCapturedType?>,
irBuiltIns: IrBuiltIns irBuiltIns: IrBuiltIns
) : AbstractIrTypeSubstitutor(irBuiltIns) { ) : BaseIrTypeSubstitutor(irBuiltIns) {
init { init {
assert(typeArguments.size == typeParameters.size) assert(typeArguments.size == typeParameters.size)
@@ -108,3 +113,10 @@ class IrCapturedTypeSubstitutor(
override fun isEmptySubstitution(): Boolean = oldSubstitution.isEmpty() override fun isEmptySubstitution(): Boolean = oldSubstitution.isEmpty()
} }
class IrChainedSubstitutor(val first: AbstractIrTypeSubstitutor, val second: AbstractIrTypeSubstitutor) : AbstractIrTypeSubstitutor() {
override fun substitute(type: IrType): IrType {
val firstResult = first.substitute(type)
return second.substitute(firstResult)
}
}
@@ -169,7 +169,7 @@ val IrClassifierSymbol.defaultType: IrType
is IrScriptSymbol -> unexpectedSymbolKind<IrClassifierSymbol>() is IrScriptSymbol -> unexpectedSymbolKind<IrClassifierSymbol>()
} }
val IrTypeParameter.defaultType: IrType val IrTypeParameter.defaultType: IrSimpleType
get() = IrSimpleTypeImpl( get() = IrSimpleTypeImpl(
symbol, symbol,
SimpleTypeNullability.NOT_SPECIFIED, SimpleTypeNullability.NOT_SPECIFIED,
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.utils.filterIsInstanceAnd import org.jetbrains.kotlin.utils.filterIsInstanceAnd
import java.io.File import java.io.File
@@ -57,12 +54,49 @@ val IrDeclarationParent.kotlinFqName: FqName
} }
val IrClass.classId: ClassId? val IrClass.classId: ClassId?
get() = classIdImpl
val IrTypeAlias.classId: ClassId?
get() = classIdImpl
private val IrDeclarationWithName.classIdImpl: ClassId?
get() = when (val parent = this.parent) { get() = when (val parent = this.parent) {
is IrClass -> parent.classId?.createNestedClassId(this.name) is IrClass -> parent.classId?.createNestedClassId(this.name)
is IrPackageFragment -> ClassId.topLevel(parent.packageFqName.child(this.name)) is IrPackageFragment -> ClassId.topLevel(parent.packageFqName.child(this.name))
else -> null else -> null
} }
val IrClass.classIdOrFail: ClassId
get() = classIdOrFailImpl
val IrTypeAlias.classIdOrFail: ClassId
get() = classIdOrFailImpl
private val IrDeclarationWithName.classIdOrFailImpl: ClassId
get() = classIdImpl ?: error("No classId for $this")
val IrFunction.callableId: CallableId
get() = callableIdImpl
val IrProperty.callableId: CallableId
get() = callableIdImpl
val IrField.callableId: CallableId
get() = callableIdImpl
val IrEnumEntry.callableId: CallableId
get() = callableIdImpl
private val IrDeclarationWithName.callableIdImpl: CallableId
get() {
if (this.symbol is IrClassifierSymbol) error("Classifiers can not have callableId. Got $this")
return when (val parent = this.parent) {
is IrClass -> parent.classId?.let { CallableId(it, name) }
is IrPackageFragment -> CallableId(parent.packageFqName, name)
else -> null
} ?: error("$this has no callableId")
}
@Suppress("unused") @Suppress("unused")
@Deprecated( @Deprecated(
"This function is deprecated because it has confusing name and behavior. " + "This function is deprecated because it has confusing name and behavior. " +
@@ -802,7 +802,7 @@ open class DeepCopyIrTreeWithSymbols(
expression.value.transform() expression.value.transform()
).copyAttributes(expression) ).copyAttributes(expression)
private fun SymbolRemapper.getReferencedReturnTarget(returnTarget: IrReturnTargetSymbol) = private fun SymbolRemapper.getReferencedReturnTarget(returnTarget: IrReturnTargetSymbol): IrReturnTargetSymbol =
when (returnTarget) { when (returnTarget) {
is IrFunctionSymbol -> getReferencedFunction(returnTarget) is IrFunctionSymbol -> getReferencedFunction(returnTarget)
is IrReturnableBlockSymbol -> getReferencedReturnableBlock(returnTarget) is IrReturnableBlockSymbol -> getReferencedReturnableBlock(returnTarget)
@@ -29,7 +29,7 @@ object AbstractExpectActualCompatibilityChecker {
context: ExpectActualMatchingContext<T>, context: ExpectActualMatchingContext<T>,
): ExpectActualCompatibility<T> { ): ExpectActualCompatibility<T> {
val result = with(context) { val result = with(context) {
areCompatibleClassifiers(expectClassSymbol, actualClassLikeSymbol) areCompatibleClassifiers(expectClassSymbol, actualClassLikeSymbol, parentSubstitutor = null)
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return result as ExpectActualCompatibility<T> return result as ExpectActualCompatibility<T>
@@ -50,11 +50,29 @@ object AbstractExpectActualCompatibilityChecker {
return result as ExpectActualCompatibility<T> return result as ExpectActualCompatibility<T>
} }
fun <T : DeclarationSymbolMarker> matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectDeclaration: DeclarationSymbolMarker,
actualDeclarations: List<DeclarationSymbolMarker>,
context: ExpectActualMatchingContext<T>,
) {
with(context) {
matchSingleExpectAgainstPotentialActuals(
expectDeclaration,
actualDeclarations,
substitutor = null,
expectClassSymbol = null,
actualClassSymbol = null,
unfulfilled = null
)
}
}
context(ExpectActualMatchingContext<*>) context(ExpectActualMatchingContext<*>)
@Suppress("warnings") @Suppress("warnings")
private fun areCompatibleClassifiers( private fun areCompatibleClassifiers(
expectClassSymbol: RegularClassSymbolMarker, expectClassSymbol: RegularClassSymbolMarker,
actualClassLikeSymbol: ClassLikeSymbolMarker, actualClassLikeSymbol: ClassLikeSymbolMarker,
parentSubstitutor: TypeSubstitutorMarker?
): ExpectActualCompatibility<*> { ): ExpectActualCompatibility<*> {
// Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name // Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name
require(expectClassSymbol.name == actualClassLikeSymbol.name) { require(expectClassSymbol.name == actualClassLikeSymbol.name) {
@@ -95,7 +113,7 @@ object AbstractExpectActualCompatibilityChecker {
val substitutor = createExpectActualTypeParameterSubstitutor( val substitutor = createExpectActualTypeParameterSubstitutor(
expectTypeParameterSymbols, expectTypeParameterSymbols,
actualTypeParameterSymbols, actualTypeParameterSymbols,
parentSubstitutor = null parentSubstitutor
) )
areCompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols, substitutor).let { areCompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols, substitutor).let {
@@ -133,7 +151,7 @@ object AbstractExpectActualCompatibilityChecker {
actualClassSymbol: RegularClassSymbolMarker, actualClassSymbol: RegularClassSymbolMarker,
substitutor: TypeSubstitutorMarker, substitutor: TypeSubstitutorMarker,
): ExpectActualCompatibility<*> { ): ExpectActualCompatibility<*> {
val unfulfilled = arrayListOf<Pair<Any?, Map<Incompatible<Any?>, MutableCollection<Any?>>>>() val unfulfilled = arrayListOf<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>()
val actualMembersByName = actualClassSymbol.collectAllMembers(isActualDeclaration = true).groupBy { it.name } val actualMembersByName = actualClassSymbol.collectAllMembers(isActualDeclaration = true).groupBy { it.name }
@@ -145,31 +163,14 @@ object AbstractExpectActualCompatibilityChecker {
expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker
}.orEmpty() }.orEmpty()
val mapping = actualMembers.keysToMap { actualMember -> matchSingleExpectAgainstPotentialActuals(
when (expectMember) { expectMember,
is CallableSymbolMarker -> areCompatibleCallables( actualMembers,
expectMember, substitutor,
actualMember as CallableSymbolMarker, expectClassSymbol,
substitutor, actualClassSymbol,
expectClassSymbol, unfulfilled
actualClassSymbol )
)
is RegularClassSymbolMarker -> areCompatibleClassifiers(expectMember, actualMember as RegularClassSymbolMarker)
else -> error("Unsupported declaration: $expectMember ($actualMembers)")
}
}
if (mapping.values.any { it == ExpectActualCompatibility.Compatible }) continue
val incompatibilityMap = mutableMapOf<Incompatible<Any?>, MutableCollection<Any?>>()
for ((declaration, compatibility) in mapping) {
when (compatibility) {
ExpectActualCompatibility.Compatible -> continue@outer
is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(declaration)
}
}
unfulfilled.add(expectMember to incompatibilityMap)
} }
if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) { if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) {
@@ -186,6 +187,53 @@ object AbstractExpectActualCompatibilityChecker {
return Incompatible.ClassScopes(unfulfilled) return Incompatible.ClassScopes(unfulfilled)
} }
context(ExpectActualMatchingContext<*>)
private fun matchSingleExpectAgainstPotentialActuals(
expectMember: DeclarationSymbolMarker,
actualMembers: List<DeclarationSymbolMarker>,
substitutor: TypeSubstitutorMarker?,
expectClassSymbol: RegularClassSymbolMarker?,
actualClassSymbol: RegularClassSymbolMarker?,
unfulfilled: MutableList<Pair<DeclarationSymbolMarker, Map<Incompatible<*>, List<DeclarationSymbolMarker?>>>>?
) {
val mapping = actualMembers.keysToMap { actualMember ->
when (expectMember) {
is CallableSymbolMarker -> areCompatibleCallables(
expectMember,
actualMember as CallableSymbolMarker,
substitutor,
expectClassSymbol,
actualClassSymbol
)
is RegularClassSymbolMarker -> {
val parentSubstitutor = substitutor?.takeIf { !innerClassesCapturesOuterTypeParameters }
areCompatibleClassifiers(
expectMember,
actualMember as ClassLikeSymbolMarker,
parentSubstitutor
)
}
else -> error("Unsupported declaration: $expectMember ($actualMembers)")
}
}
val incompatibilityMap = mutableMapOf<Incompatible<*>, MutableList<DeclarationSymbolMarker>>()
for ((actualMember, compatibility) in mapping) {
when (compatibility) {
ExpectActualCompatibility.Compatible -> {
onMatchedMembers(expectMember, actualMember)
return
}
is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(actualMember)
}
}
unfulfilled?.add(expectMember to incompatibilityMap)
onMismatchedMembersFromClassScope(expectMember, incompatibilityMap)
}
context(ExpectActualMatchingContext<*>) context(ExpectActualMatchingContext<*>)
private fun areCompatibleCallables( private fun areCompatibleCallables(
expectDeclaration: CallableSymbolMarker, expectDeclaration: CallableSymbolMarker,
@@ -307,6 +355,10 @@ object AbstractExpectActualCompatibilityChecker {
actualDeclaration actualDeclaration
).let { if (it != ExpectActualCompatibility.Compatible) return it } ).let { if (it != ExpectActualCompatibility.Compatible) return it }
expectDeclaration is EnumEntrySymbolMarker && actualDeclaration is EnumEntrySymbolMarker -> {
// do nothing, entries are matched only by name
}
else -> error("Unsupported declarations: $expectDeclaration, $actualDeclaration") else -> error("Unsupported declarations: $expectDeclaration, $actualDeclaration")
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
@@ -20,6 +21,21 @@ import org.jetbrains.kotlin.types.model.TypeSystemContext
interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemContext { interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemContext {
val shouldCheckReturnTypesOfCallables: Boolean val shouldCheckReturnTypesOfCallables: Boolean
/*
* This flag indicates how are type parameters of inner classes stored in the specific implementation of RegularClassSymbolMarker
*
* class Outer<T> {
* inner class Inner<U>
* }
*
* If flag is set to `true` then `typeParameters` for class `Outer.Inner` contains both parameters: [U, R]
* Otherwise it contains only parameters of itself: [U]
*
* This flag is needed for proper calculation of substitutions for components of inner classes
*/
val innerClassesCapturesOuterTypeParameters: Boolean
get() = true
val RegularClassSymbolMarker.classId: ClassId val RegularClassSymbolMarker.classId: ClassId
val TypeAliasSymbolMarker.classId: ClassId val TypeAliasSymbolMarker.classId: ClassId
val CallableSymbolMarker.callableId: CallableId val CallableSymbolMarker.callableId: CallableId
@@ -100,10 +116,17 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
/* /*
* Determines should some declaration from expect class scope be checked * Determines should some declaration from expect class scope be checked
* - FE 1.0: skip fake overrides * - FE 1.0: skip fake overrides
* - FIR: skip nothing * - FIR: skip fake overrides
* - IR: skip nothing * - IR: skip nothing
*/ */
fun CallableSymbolMarker.shouldSkipMatching(containingExpectClass: RegularClassSymbolMarker): Boolean fun CallableSymbolMarker.shouldSkipMatching(containingExpectClass: RegularClassSymbolMarker): Boolean
val CallableSymbolMarker.hasStableParameterNames: Boolean val CallableSymbolMarker.hasStableParameterNames: Boolean
fun onMatchedMembers(expectSymbol: DeclarationSymbolMarker, actualSymbol: DeclarationSymbolMarker) {}
fun onMismatchedMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualCompatibility.Incompatible<*>, List<DeclarationSymbolMarker>>
) {}
} }
@@ -1,5 +1,6 @@
// LANGUAGE: +MultiPlatformProjects // LANGUAGE: +MultiPlatformProjects
// WITH_STDLIB // WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR // TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_K1: JVM_IR // IGNORE_BACKEND_K1: JVM_IR
// Ignore reason: expect/actual are not supported in K1 box tests // Ignore reason: expect/actual are not supported in K1 box tests
@@ -0,0 +1,49 @@
// !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT
// MODULE: m1-common
// FILE: common.kt
expect class A {
fun foo(p1: String = "common", p2: String = "common", p3: String)
}
expect class B {
fun foo(s: String)
}
interface I {
fun methodWithDefaultArg(s: String = "common")
}
expect class WithDefaultArgFromSuper : I {
override fun methodWithDefaultArg(s: String)
}
<!INCOMPATIBLE_MATCHING{JVM}!>expect open class WithIncompatibility {
fun foo(p: String = "common")
}<!>
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
class AImpl {
fun foo(p1: String = "impl", p2: String = "impl", p3: String) {}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias A = AImpl<!>
class BImpl {
fun foo(s: String = "impl") {}
}
actual typealias B = BImpl
class WithDefaultArgFromSuperImpl : I {
override fun methodWithDefaultArg(s: String) {}
}
actual typealias WithDefaultArgFromSuper = WithDefaultArgFromSuperImpl
class WithIncompatibilityImpl {
fun foo(p: String) {}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias WithIncompatibility = WithIncompatibilityImpl<!>
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT // !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -0,0 +1,34 @@
// MODULE: m1-common
// FILE: common.kt
<!INCOMPATIBLE_MATCHING{JVM}, INCOMPATIBLE_MATCHING{JVM}!>expect enum class Foo {
ENTRY
}<!>
expect enum class _TimeUnit
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias Foo = FooImpl
actual typealias _TimeUnit = java.util.concurrent.TimeUnit
// FILE: FooImpl.java
public enum FooImpl {
ENTRY("OK") {
@Override
public String getResult() {
return value;
}
};
protected final String value;
public FooImpl(String value) {
this.value = value;
}
public abstract String getResult();
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -0,0 +1,17 @@
// MODULE: m1-common
// FILE: common.kt
<!INCOMPATIBLE_MATCHING{JVM}, INCOMPATIBLE_MATCHING{JVM}!>expect enum class Foo {
ENTRY1,
ENTRY2,
ENTRY3;
}<!>
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual enum class Foo(val x: String) {
ENTRY1("1"),
ENTRY2("2"),
ENTRY3("3");
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -1,15 +1,15 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
// TODO: .fir.kt version is just a stub. // TODO: .fir.kt version is just a stub.
expect interface My { <!INCOMPATIBLE_MATCHING{JVM}!>expect interface My {
open fun openFunPositive() open fun openFunPositive()
open fun openFunNegative() <!INCOMPATIBLE_MATCHING{JVM}!>open fun openFunNegative()<!>
abstract fun abstractFun() abstract fun abstractFun()
open val openValPositive: Int open val openValPositive: Int
open val openValNegative: Int <!INCOMPATIBLE_MATCHING{JVM}!>open val openValNegative: Int<!>
abstract val abstractVal: Int abstract val abstractVal: Int
} }<!>
// MODULE: m1-jvm()()(m1-common) // MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -4,7 +4,7 @@
interface A interface A
interface B interface B
expect fun <T> List<T>.foo() where T : A, T : B <!INCOMPATIBLE_MATCHING{JVM}!>expect fun <T> List<T>.foo() where T : A, T : B<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -7,7 +7,7 @@ expect annotation class Foo3
expect annotation class Foo4 expect annotation class Foo4
expect annotation class Foo5() expect annotation class Foo5()
expect annotation class Foo6() expect annotation class Foo6()
expect annotation class Foo7() <!INCOMPATIBLE_MATCHING{JVM}!>expect annotation class Foo7<!INCOMPATIBLE_MATCHING{JVM}!>()<!><!>
@<!UNRESOLVED_REFERENCE!>Foo1<!> @<!UNRESOLVED_REFERENCE!>Foo1<!>
fun foo() {} fun foo() {}
@@ -5,9 +5,9 @@ expect class Foo1
expect class Foo2 expect class Foo2
expect class Foo3 expect class Foo3
expect class Bar1() <!INCOMPATIBLE_MATCHING{JVM}!>expect class Bar1<!INCOMPATIBLE_MATCHING{JVM}!>()<!><!>
expect class Bar2() <!INCOMPATIBLE_MATCHING{JVM}!>expect class Bar2<!INCOMPATIBLE_MATCHING{JVM}!>()<!><!>
expect class Bar3() <!INCOMPATIBLE_MATCHING{JVM}!>expect class Bar3<!INCOMPATIBLE_MATCHING{JVM}!>()<!><!>
expect class Bar4() expect class Bar4()
expect class Bar5() expect class Bar5()
expect class Bar6() expect class Bar6()
@@ -3,12 +3,12 @@
// FILE: common.kt // FILE: common.kt
expect fun foo1(x: Int) expect fun foo1(x: Int)
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect fun foo2(x: Int)<!> <!INCOMPATIBLE_MATCHING{JVM}, INCOMPATIBLE_MATCHING{JVM}!>expect fun foo2(x: Int)<!>
expect class NoArgConstructor() expect class NoArgConstructor()
expect fun foo3(): Int <!INCOMPATIBLE_MATCHING{JVM}!>expect fun foo3(): Int<!>
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect fun foo4(): Int<!> <!INCOMPATIBLE_MATCHING{JVM}!>expect fun foo4(): Int<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
@@ -5,9 +5,9 @@ expect fun interface F1 {
fun run() fun run()
} }
expect fun interface F2 { <!INCOMPATIBLE_MATCHING{JVM}!>expect fun interface F2 {
fun run() fun run()
} }<!>
expect fun interface F3 { expect fun interface F3 {
fun run() fun run()
@@ -21,9 +21,9 @@ expect fun interface F5 {
fun run() fun run()
} }
expect fun interface F6 { <!INCOMPATIBLE_MATCHING{JVM}!>expect fun interface F6 {
fun run() fun run()
} }<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
@@ -0,0 +1,37 @@
// !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT
// MODULE: m1-common
// FILE: common.kt
expect class C1
<!INCOMPATIBLE_MATCHING{JVM}!>expect interface C2<A><!>
<!INCOMPATIBLE_MATCHING{JVM}!>expect interface C3<B><!>
expect interface C4<D, E>
expect interface C5<F, G>
expect interface C6<H>
expect interface C7<I>
expect interface C8<J>
expect interface C9<K>
expect interface C10<L>
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
class A<T : A<T>>
class B<T>
actual typealias C1 = String
<!ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE!>actual typealias C2<A> = List<String><!>
<!ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE!>actual typealias C3<B> = List<B><!>
actual typealias C4<D, E> = MutableMap<D, E>
<!ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>actual typealias C5<F, G> = MutableMap<G, F><!>
<!ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>actual typealias C51 = MutableMap<String, String><!>
<!ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>actual typealias C52<F> = MutableMap<F, String><!>
<!ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>actual typealias C53<T> = A<A<T>><!>
<!ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION!>actual typealias C54<T> = B<List<String>><!>
actual typealias C6<H> = MutableList<H>
<!ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>actual typealias C7<I> = MutableList<out I><!>
<!ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>actual typealias C8<J> = MutableList<*><!>
<!ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE!>actual typealias C9<K> = MutableList<in K><!>
typealias Tmp<K> = MutableList<K>
<!ACTUAL_TYPE_ALIAS_NOT_TO_CLASS!>actual typealias C10<L> = Tmp<L><!>
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT // !DIAGNOSTICS: -ACTUAL_WITHOUT_EXPECT
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -2,20 +2,20 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
expect open class Container { <!INCOMPATIBLE_MATCHING{JVM}!>expect open class Container {
fun publicFun() fun publicFun()
internal fun internalFun1() internal fun internalFun1()
internal fun internalFun2() internal fun internalFun2()
internal fun internalFun3() <!INCOMPATIBLE_MATCHING{JVM}!>internal fun internalFun3()<!>
protected fun protectedFun1() protected fun protectedFun1()
protected fun protectedFun2() protected fun protectedFun2()
protected fun protectedFun3() <!INCOMPATIBLE_MATCHING{JVM}!>protected fun protectedFun3()<!>
open internal fun openInternalFun() <!INCOMPATIBLE_MATCHING{JVM}!>open internal fun openInternalFun()<!>
open fun openPublicFun() <!INCOMPATIBLE_MATCHING{JVM}!>open fun openPublicFun()<!>
} }<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
@@ -14,9 +14,9 @@ expect class C {
<!WRONG_MODIFIER_TARGET!>expect<!> inner class I <!WRONG_MODIFIER_TARGET!>expect<!> inner class I
} }
expect class D { <!INCOMPATIBLE_MATCHING{JVM}!>expect class D {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>class N<!> <!NO_ACTUAL_FOR_EXPECT{JVM}!>class N<!>
} }<!>
expect class E { expect class E {
class N class N
@@ -1,10 +1,10 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
expect class Foo { <!INCOMPATIBLE_MATCHING{JVM}!>expect class Foo {
fun bar(): String fun bar(): String
fun bas(f: Int) <!INCOMPATIBLE_MATCHING{JVM}!>fun bas(f: Int)<!>
} }<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -7,7 +7,7 @@ interface J
expect class Foo : I, C, J expect class Foo : I, C, J
<!SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C()<!> <!INCOMPATIBLE_MATCHING{JVM}, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C()<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -2,7 +2,7 @@
// FILE: common.kt // FILE: common.kt
class Foo { class Foo {
<!NON_ABSTRACT_FUNCTION_WITH_NO_BODY, NO_ACTUAL_FOR_EXPECT{JVM}!><!WRONG_MODIFIER_TARGET!>expect<!> fun bar(): String<!> <!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!><!WRONG_MODIFIER_TARGET!>expect<!> fun bar(): String<!>
} }
// MODULE: m1-jvm()()(m1-common) // MODULE: m1-jvm()()(m1-common)
@@ -26,7 +26,7 @@ interface KotlinXStringDemoInterface {
val value: String val value: String
} }
expect fun StringDemoInterface.plusK(): String <!INCOMPATIBLE_MATCHING{JS}!>expect fun StringDemoInterface.plusK(): String<!>
// MODULE: js()()(common, intermediate) // MODULE: js()()(common, intermediate)
// TARGET_PLATFORM: JS // TARGET_PLATFORM: JS
@@ -34,7 +34,7 @@ expect fun StringDemoInterface.plusK(): String
// FILE: StringDemoInterface.kt // FILE: StringDemoInterface.kt
actual typealias StringDemoInterface = KotlinXStringDemoInterface actual typealias StringDemoInterface = KotlinXStringDemoInterface
<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible: expect fun StringDemoInterface.plusK(): String")!>actual fun StringDemoInterface.plusK() = <!RESOLUTION_TO_CLASSIFIER!>StringValue<!>(value).plus("K").<!UNRESOLVED_REFERENCE!>value<!><!> <!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible: expect fun StringDemoInterface.plusK(): String")!>actual fun StringDemoIn<!INCOMPATIBLE_MATCHING!>terface.plusK() = <!RESOLUTION_TO_CLASSIFIER!>StringValue<!>(value).plus("K")<!>.<!UNRESOLVED_REFERENCE!>value<!><!>
// FILE: main.kt // FILE: main.kt
class StringDemo(override val value: String) : StringDemoInterface class StringDemo(override val value: String) : StringDemoInterface
@@ -3,10 +3,10 @@
// TARGET_PLATFORM: Common // TARGET_PLATFORM: Common
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect class CommonClass { <!NO_ACTUAL_FOR_EXPECT{JVM}!>expect class CommonClass {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun memberFun()<!> fun memberFun()
<!NO_ACTUAL_FOR_EXPECT{JVM}!>val memberProp: Int<!> val memberProp: Int
<!NO_ACTUAL_FOR_EXPECT{JVM}!>class Nested<!> class Nested
<!NO_ACTUAL_FOR_EXPECT{JVM}!>inner class Inner<!> inner class Inner
}<!> }<!>
<!ACTUAL_WITHOUT_EXPECT!>actual class CommonClass { <!ACTUAL_WITHOUT_EXPECT!>actual class CommonClass {
<!ACTUAL_WITHOUT_EXPECT!>actual fun memberFun() {}<!> <!ACTUAL_WITHOUT_EXPECT!>actual fun memberFun() {}<!>
@@ -13,8 +13,8 @@ val callableKind: Int = 1
expect fun <T> typeParameterCount() expect fun <T> typeParameterCount()
fun typeParameterCount() {} fun typeParameterCount() {}
<!NO_ACTUAL_FOR_EXPECT{JVM}, NO_ACTUAL_FOR_EXPECT{JVM}, NO_ACTUAL_FOR_EXPECT{JVM}, NO_ACTUAL_FOR_EXPECT{JVM}!>expect enum class EnumEntries { <!NO_ACTUAL_FOR_EXPECT{JVM}!>expect enum class EnumEntries {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>ONE,<!> <!NO_ACTUAL_FOR_EXPECT{JVM}!>TWO;<!> ONE, TWO;
}<!> }<!>
<!ACTUAL_WITHOUT_EXPECT!>actual enum class EnumEntries { <!ACTUAL_WITHOUT_EXPECT!>actual enum class EnumEntries {
ONE; ONE;
@@ -1,31 +0,0 @@
// MODULE: m1-common
// FILE: common.kt
expect class Foo {
constructor(p: Any)
fun f1(s: String): Int
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun f2(s: List<String>?): MutableMap<Boolean?, Foo><!>
fun <T : Set<Number>> f3(t: T): T?
}
// MODULE: m2-jvm()()(m1-common)
// FILE: FooImpl.java
import java.util.*;
public class FooImpl {
public FooImpl(Object p) {}
public final int f1(String s) { return 0; }
public final Map<Boolean, FooImpl> f2(List<String> s) { return null; }
public final <T extends Set<Number>> T f3(T t) { return null; }
}
// FILE: jvm.kt
actual typealias Foo = FooImpl
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -1,8 +1,8 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
expect class SomeClass<T> { <!INCOMPATIBLE_MATCHING{JVM}!>expect class SomeClass<T> {
fun foo() fun foo()
} }<!>
// MODULE: m1-jvm()()(m1-common) // MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -1,7 +1,7 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
inline expect fun inlineFun() <!INCOMPATIBLE_MATCHING{JVM}!>inline expect fun inlineFun()<!>
expect fun nonInlineFun() expect fun nonInlineFun()
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
@@ -3,15 +3,15 @@
// FILE: common.kt // FILE: common.kt
expect fun f1(s: () -> String) expect fun f1(s: () -> String)
expect inline fun f2(s: () -> String) <!INCOMPATIBLE_MATCHING{JVM}!>expect inline fun f2(s: () -> String)<!>
expect inline fun f3(noinline s: () -> String) expect inline fun f3(noinline s: () -> String)
expect fun f4(s: () -> String) expect fun f4(s: () -> String)
expect inline fun f5(s: () -> String) <!INCOMPATIBLE_MATCHING{JVM}!>expect inline fun f5(s: () -> String)<!>
expect inline fun f6(crossinline s: () -> String) expect inline fun f6(crossinline s: () -> String)
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect fun f7(x: Any)<!> <!INCOMPATIBLE_MATCHING{JVM}!>expect fun f7(x: Any)<!>
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect fun f8(vararg x: Any)<!> <!INCOMPATIBLE_MATCHING{JVM}!>expect fun f8(vararg x: Any)<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -1,20 +1,20 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
expect var v1: Boolean <!INCOMPATIBLE_MATCHING{JVM}!>expect var v1: Boolean<!>
expect var v2: Boolean expect var v2: Boolean
internal set internal set
expect var v3: Boolean <!INCOMPATIBLE_MATCHING{JVM}!>expect var v3: Boolean
internal set internal set<!>
expect open class C { <!INCOMPATIBLE_MATCHING{JVM}!>expect open class C {
var foo: Boolean <!INCOMPATIBLE_MATCHING{JVM}!>var foo: Boolean<!>
} }<!>
expect open class C2 { <!INCOMPATIBLE_MATCHING{JVM}!>expect open class C2 {
var foo: Boolean <!INCOMPATIBLE_MATCHING{JVM}!>var foo: Boolean<!>
} }<!>
// MODULE: m1-jvm()()(m1-common) // MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -6,8 +6,11 @@
package org.jetbrains.kotlin.test.backend.ir package org.jetbrains.kotlin.test.backend.ir
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer
import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
@@ -17,10 +20,16 @@ class ActualizerOnlyFacade(
) : AbstractTestFacade<IrBackendInput, IrBackendInput>() { ) : AbstractTestFacade<IrBackendInput, IrBackendInput>() {
override fun transform(module: TestModule, inputArtifact: IrBackendInput): IrBackendInput { override fun transform(module: TestModule, inputArtifact: IrBackendInput): IrBackendInput {
if (module.useIrActualizer()) { if (module.useIrActualizer()) {
val builtins = inputArtifact.irModuleFragment.irBuiltins
val typeSystemContext = when (module.targetPlatform.isJvm()) {
true -> JvmIrTypeSystemContext(builtins)
false -> IrTypeSystemContextImpl(builtins)
}
IrActualizer.actualize( IrActualizer.actualize(
inputArtifact.irModuleFragment, inputArtifact.irModuleFragment,
inputArtifact.dependentIrModuleFragments, inputArtifact.dependentIrModuleFragments,
inputArtifact.diagnosticReporter, inputArtifact.diagnosticReporter,
typeSystemContext,
testServices.compilerConfigurationProvider.getCompilerConfiguration(module).languageVersionSettings testServices.compilerConfigurationProvider.getCompilerConfiguration(module).languageVersionSettings
) )
} }
@@ -8,12 +8,14 @@ package org.jetbrains.kotlin.test.backend.ir
import org.jetbrains.kotlin.KtPsiSourceFile import org.jetbrains.kotlin.KtPsiSourceFile
import org.jetbrains.kotlin.backend.common.BackendException import org.jetbrains.kotlin.backend.common.BackendException
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer
import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext
import org.jetbrains.kotlin.backend.jvm.MultifileFacadeFileEntry import org.jetbrains.kotlin.backend.jvm.MultifileFacadeFileEntry
import org.jetbrains.kotlin.backend.jvm.lower.getFileClassInfoFromIrFile import org.jetbrains.kotlin.backend.jvm.lower.getFileClassInfoFromIrFile
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.ir.PsiIrFileEntry import org.jetbrains.kotlin.ir.PsiIrFileEntry
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.backend.classic.JavaCompilerFacade import org.jetbrains.kotlin.test.backend.classic.JavaCompilerFacade
@@ -40,6 +42,7 @@ class JvmIrBackendFacade(
inputArtifact.irModuleFragment, inputArtifact.irModuleFragment,
inputArtifact.dependentIrModuleFragments, inputArtifact.dependentIrModuleFragments,
inputArtifact.state.diagnosticReporter, inputArtifact.state.diagnosticReporter,
JvmIrTypeSystemContext(inputArtifact.irModuleFragment.irBuiltins),
inputArtifact.state.languageVersionSettings inputArtifact.state.languageVersionSettings
) )
} }
@@ -17,6 +17,8 @@ interface ConstructorSymbolMarker : FunctionSymbolMarker
interface SimpleFunctionSymbolMarker : FunctionSymbolMarker interface SimpleFunctionSymbolMarker : FunctionSymbolMarker
interface PropertySymbolMarker : CallableSymbolMarker interface PropertySymbolMarker : CallableSymbolMarker
interface ValueParameterSymbolMarker : CallableSymbolMarker interface ValueParameterSymbolMarker : CallableSymbolMarker
interface FieldSymbolMarker : CallableSymbolMarker
interface EnumEntrySymbolMarker : CallableSymbolMarker
interface ClassifierSymbolMarker : DeclarationSymbolMarker interface ClassifierSymbolMarker : DeclarationSymbolMarker
interface TypeParameterSymbolMarker : ClassifierSymbolMarker interface TypeParameterSymbolMarker : ClassifierSymbolMarker
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.resolve.multiplatform package org.jetbrains.kotlin.resolve.multiplatform
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
sealed class ExpectActualCompatibility<out D> { sealed class ExpectActualCompatibility<out D> {
// For IncompatibilityKind.STRONG `actual` declaration is considered as overload and error reports on expected declaration // For IncompatibilityKind.STRONG `actual` declaration is considered as overload and error reports on expected declaration
enum class IncompatibilityKind { enum class IncompatibilityKind {
@@ -95,3 +98,11 @@ sealed class ExpectActualCompatibility<out D> {
val ExpectActualCompatibility<*>.compatible: Boolean val ExpectActualCompatibility<*>.compatible: Boolean
get() = this == ExpectActualCompatibility.Compatible get() = this == ExpectActualCompatibility.Compatible
@OptIn(ExperimentalContracts::class)
fun ExpectActualCompatibility<*>.isIncompatible(): Boolean {
contract {
returns(true) implies (this@isIncompatible is ExpectActualCompatibility.Incompatible<*>)
}
return !compatible
}
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.JsFactories import org.jetbrains.kotlin.ir.backend.js.JsFactories
import org.jetbrains.kotlin.ir.backend.js.resolverLogger import org.jetbrains.kotlin.ir.backend.js.resolverLogger
import org.jetbrains.kotlin.ir.backend.js.serializeModuleIntoKlib import org.jetbrains.kotlin.ir.backend.js.serializeModuleIntoKlib
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.js.test.utils.JsIrIncrementalDataProvider import org.jetbrains.kotlin.js.test.utils.JsIrIncrementalDataProvider
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
@@ -71,6 +72,7 @@ class FirJsKlibBackendFacade(
inputArtifact.irModuleFragment, inputArtifact.irModuleFragment,
inputArtifact.dependentIrModuleFragments, inputArtifact.dependentIrModuleFragments,
diagnosticReporter, diagnosticReporter,
IrTypeSystemContextImpl(inputArtifact.irModuleFragment.irBuiltins),
configuration.languageVersionSettings configuration.languageVersionSettings
) )
} else { } else {
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.signaturer.Ir2FirManglerAdapter
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories
@@ -87,6 +88,7 @@ internal fun PhaseContext.fir2Ir(
visibilityConverter = Fir2IrVisibilityConverter.Default, visibilityConverter = Fir2IrVisibilityConverter.Default,
diagnosticReporter = diagnosticsReporter, diagnosticReporter = diagnosticsReporter,
kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance, kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance,
actualizerTypeContextProvider = ::IrTypeSystemContextImpl,
fir2IrResultPostCompute = { fir2IrResultPostCompute = {
// it's important to compare manglers before actualization, since IR will be actualized, while FIR won't // it's important to compare manglers before actualization, since IR will be actualized, while FIR won't
irModuleFragment.acceptVoid( irModuleFragment.acceptVoid(