[K2, MPP] Restore ir functions actualization by argument types instead of full signatures

Refactor IrActualizer
This commit is contained in:
Ivan Kochurkin
2023-03-09 20:14:08 +01:00
committed by Space Team
parent d99b4c78d2
commit ec34b9fa7b
6 changed files with 193 additions and 154 deletions
@@ -6,15 +6,12 @@
package org.jetbrains.kotlin.backend.common.actualizer package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.backend.common.ir.isExpect
import org.jetbrains.kotlin.backend.common.ir.isProperExpect
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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
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.name.FqName
@@ -26,110 +23,119 @@ internal class ExpectActualCollector(
) { ) {
fun collect(): Pair<Map<IrSymbol, IrSymbol>, Map<FqName, FqName>> { fun collect(): Pair<Map<IrSymbol, IrSymbol>, Map<FqName, FqName>> {
val result = mutableMapOf<IrSymbol, IrSymbol>() val result = mutableMapOf<IrSymbol, IrSymbol>()
// Collect and link classifiers at first to make it possible to expand type aliases on the callables linking // Collect and link classes at first to make it possible to expand type aliases on the members linking
val (allActualDeclarations, typeAliasMap) = result.appendExpectActualClassifiersMap() val (actualMembers, expectActualTypeAliasMap) = result.appendExpectActualClassMap()
result.appendExpectActualCallablesMap(allActualDeclarations, typeAliasMap) result.appendExpectActualMemberMap(actualMembers, expectActualTypeAliasMap)
return result to typeAliasMap return result to expectActualTypeAliasMap
} }
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassifiersMap(): Pair<Set<IrDeclaration>, Map<FqName, FqName>> { private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualClassMap(): Pair<List<IrDeclarationBase>, Map<FqName, FqName>> {
val actualClassifiers = mutableMapOf<String, IrSymbol>() val actualClasses = mutableMapOf<String, IrClassSymbol>()
// There is no list for builtins declarations; that's why they are being collected from typealiases // There is no list for builtins declarations; that's why they are being collected from typealiases
val allActualDeclarations = mutableSetOf<IrDeclaration>() val actualMembers = mutableListOf<IrDeclarationBase>()
val typeAliasMap = mutableMapOf<FqName, FqName>() // It's used to link members from expect class that have typealias actual 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
for (fragment in fragmentsWithActuals) { val actualClassesAndMembersCollector = ActualClassesAndMembersCollector(actualClasses, actualMembers, expectActualTypeAliasMap)
ActualClassifiersCollector(actualClassifiers, allActualDeclarations, typeAliasMap).visitModuleFragment(fragment, false) fragmentsWithActuals.forEach { actualClassesAndMembersCollector.collect(it) }
}
val linkCollector = ClassifiersLinkCollector(this, actualClassifiers, typeAliasMap, diagnosticsReporter) val linkCollector = ClassLinksCollector(this, actualClasses, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { linkCollector.visitModuleFragment(it) } dependentFragments.forEach { linkCollector.visitModuleFragment(it) }
return allActualDeclarations to typeAliasMap return actualMembers to expectActualTypeAliasMap
} }
private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualCallablesMap( private fun MutableMap<IrSymbol, IrSymbol>.appendExpectActualMemberMap(
allActualDeclarations: Set<IrDeclaration>, actualMembers: List<IrDeclarationBase>,
typeAliasMap: Map<FqName, FqName> expectActualTypeAliasMap: Map<FqName, FqName>
) { ) {
val actualMembers = mutableMapOf<String, IrDeclarationBase>() val actualMembersMap = mutableMapOf<String, MutableList<IrDeclarationBase>>()
for (actualMember in actualMembers) {
collectActualCallables(this, actualMembers, typeAliasMap, allActualDeclarations) actualMembersMap.getOrPut(generateIrElementFullNameFromExpect(actualMember, expectActualTypeAliasMap)) { mutableListOf() }
val collector = CallablesLinkCollector(this, actualMembers, typeAliasMap, diagnosticsReporter) .add(actualMember)
}
val collector = MemberLinksCollector(this, actualMembersMap, expectActualTypeAliasMap, diagnosticsReporter)
dependentFragments.forEach { collector.visitModuleFragment(it) } dependentFragments.forEach { collector.visitModuleFragment(it) }
} }
} }
private class ActualClassifiersCollector( private class ActualClassesAndMembersCollector(
private val actualClassifiers: MutableMap<String, IrSymbol>, private val actualClasses: MutableMap<String, IrClassSymbol>,
private val allActualClassifiers: MutableSet<IrDeclaration>, private val actualMembers: MutableList<IrDeclarationBase>,
private val typeAliasMap: MutableMap<FqName, FqName> private val expectActualTypeAliasMap: MutableMap<FqName, FqName>
) : IrElementVisitor<Unit, Boolean> { ) {
override fun visitTypeAlias(declaration: IrTypeAlias, data: Boolean) { private val visitedActualClasses = mutableSetOf<IrClass>()
if (declaration.isActual) {
val expandedTypeSymbol = declaration.expandedType.classifierOrFail fun collect(element: IrElement) {
actualClassifiers[generateIrElementFullName(declaration)] = expandedTypeSymbol when (element) {
if (expandedTypeSymbol is IrClassSymbol) { is IrModuleFragment -> {
allActualClassifiers.add(expandedTypeSymbol.owner) for (file in element.files) {
typeAliasMap[declaration.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName collect(file)
}
}
is IrTypeAlias -> {
if (!element.isActual) return
val expandedTypeSymbol = element.expandedType.classifierOrFail as IrClassSymbol
addActualClass(element, expandedTypeSymbol)
collect(expandedTypeSymbol.owner)
expectActualTypeAliasMap[element.kotlinFqName] = expandedTypeSymbol.owner.kotlinFqName
}
is IrClass -> {
if (element.isExpect || !visitedActualClasses.add(element)) return
addActualClass(element, element.symbol)
for (declaration in element.declarations) {
collect(declaration)
}
}
is IrDeclarationContainer -> {
for (declaration in element.declarations) {
collect(declaration)
}
}
is IrEnumEntry -> {
actualMembers.add(element) // If enum entry is located inside expect enum, then this code is not executed
}
is IrProperty -> {
if (element.isExpect) return
actualMembers.add(element)
}
is IrFunction -> {
if (element.isExpect) return
actualMembers.add(element)
} }
} }
visitElement(declaration, data)
} }
override fun visitClass(declaration: IrClass, data: Boolean) { private fun addActualClass(classOrTypeAlias: IrElement, classSymbol: IrClassSymbol) {
if (!data && !declaration.isExpect) { actualClasses[generateActualIrClassOrTypeAliasFullName(classOrTypeAlias)] = classSymbol
actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
}
visitDeclaration(declaration, data)
}
override fun visitEnumEntry(declaration: IrEnumEntry, data: Boolean) {
if (!data && !declaration.isExpect) {
actualClassifiers[generateIrElementFullName(declaration)] = declaration.symbol
}
visitDeclaration(declaration, data)
}
override fun visitDeclaration(declaration: IrDeclarationBase, data: Boolean) {
if (!data && !declaration.isExpect) {
allActualClassifiers.add(declaration)
}
visitElement(declaration, data || declaration.isExpect)
}
override fun visitElement(element: IrElement, data: Boolean) {
element.acceptChildren(this, data)
} }
} }
private class ClassifiersLinkCollector( private class ClassLinksCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>, private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val actualClassifiers: Map<String, IrSymbol>, private val actualClasses: Map<String, IrClassSymbol>,
private val typeAliasMap: Map<FqName, FqName>, private val expectActualTypeAliasMap: Map<FqName, FqName>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) : IrElementVisitorVoid { ) : IrElementVisitorVoid {
private fun addLinkOrReportMissing(expectElement: IrDeclaration) {
val actualClassifier = actualClassifiers[generateIrElementFullName(expectElement, expectActualMap, typeAliasMap)]
if (actualClassifier != null) {
expectActualMap[expectElement.symbol] = actualClassifier
} else if (!expectElement.containsOptionalExpectation()) {
diagnosticsReporter.reportMissingActual(expectElement)
}
}
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
if (declaration.isExpect) { if (!declaration.isExpect) return
addLinkOrReportMissing(declaration)
}
visitElement(declaration)
}
override fun visitEnumEntry(declaration: IrEnumEntry) { val actualClassSymbol = actualClasses[generateIrElementFullNameFromExpect(declaration, expectActualTypeAliasMap)]
if (declaration.isProperExpect) { if (actualClassSymbol != null) {
addLinkOrReportMissing(declaration) expectActualMap[declaration.symbol] = actualClassSymbol
val actualClass = actualClassSymbol.owner
for (expectTypeParameter in declaration.typeParameters) {
actualClass.typeParameters.firstOrNull { it.name == expectTypeParameter.name }?.let { actualTypeParameter ->
expectActualMap[expectTypeParameter.symbol] = actualTypeParameter.symbol
}
}
} else if (!declaration.containsOptionalExpectation()) {
diagnosticsReporter.reportMissingActual(declaration)
} }
visitElement(declaration) visitElement(declaration)
} }
@@ -138,44 +144,26 @@ private class ClassifiersLinkCollector(
} }
} }
private fun collectActualCallables( private class MemberLinksCollector(
expectActualMap: MutableMap<IrSymbol, IrSymbol>,
actualMembers: MutableMap<String, IrDeclarationBase>,
typeAliasMap: Map<FqName, FqName>,
allActualDeclarations: Set<IrDeclaration>,
) {
fun collectActualsCallables(declaration: IrDeclaration) {
when (declaration) {
is IrFunction,
is IrProperty -> {
actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)] = declaration as IrDeclarationBase
}
is IrClass -> {
for (member in declaration.declarations) {
collectActualsCallables(member)
}
}
}
}
for (actualDeclaration in allActualDeclarations) {
collectActualsCallables(actualDeclaration)
}
}
private class CallablesLinkCollector(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>, private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val actualMembers: Map<String, IrDeclarationBase>, private val actualMembers: Map<String, List<IrDeclarationBase>>,
private val typeAliasMap: Map<FqName, FqName>, private val typeAliasMap: Map<FqName, FqName>,
private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext private val diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) : IrElementVisitorVoid { ) : IrElementVisitorVoid {
override fun visitFunction(declaration: IrFunction) = addLink(declaration) override fun visitFunction(declaration: IrFunction) {
if (declaration.isExpect) addLink(declaration)
}
override fun visitProperty(declaration: IrProperty) = addLink(declaration) override fun visitProperty(declaration: IrProperty) {
if (declaration.isExpect) addLink(declaration)
}
override fun visitEnumEntry(declaration: IrEnumEntry) {
if ((declaration.parent as IrClass).isExpect) addLink(declaration)
}
private fun addLink(declaration: IrDeclarationBase) { private fun addLink(declaration: IrDeclarationBase) {
if (!declaration.isExpect) return val actualMember = actualMembers.getMatch(declaration, expectActualMap, typeAliasMap)
val actualMember = actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)]
if (actualMember != null) { if (actualMember != null) {
expectActualMap[declaration.symbol] = actualMember.symbol expectActualMap[declaration.symbol] = actualMember.symbol
if (declaration is IrProperty) { if (declaration is IrProperty) {
@@ -20,10 +20,10 @@ object IrActualizer {
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
) { ) {
val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings) val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings)
val (expectActualMap, typeAliasMap) = ExpectActualCollector(mainFragment, dependentFragments, ktDiagnosticReporter).collect() val (expectActualMap, expectActualTypeAliasMap) = ExpectActualCollector(mainFragment, dependentFragments, ktDiagnosticReporter).collect()
FunctionDefaultParametersActualizer(expectActualMap).actualize() FunctionDefaultParametersActualizer(expectActualMap).actualize()
removeExpectDeclarations(dependentFragments, expectActualMap) removeExpectDeclarations(dependentFragments, expectActualMap)
addMissingFakeOverrides(expectActualMap, dependentFragments, typeAliasMap, ktDiagnosticReporter) addMissingFakeOverrides(expectActualMap, dependentFragments, expectActualTypeAliasMap, ktDiagnosticReporter)
linkExpectToActual(expectActualMap, dependentFragments) linkExpectToActual(expectActualMap, dependentFragments)
mergeIrFragments(mainFragment, dependentFragments) mergeIrFragments(mainFragment, dependentFragments)
} }
@@ -48,10 +48,14 @@ object IrActualizer {
private fun addMissingFakeOverrides( private fun addMissingFakeOverrides(
expectActualMap: Map<IrSymbol, IrSymbol>, expectActualMap: Map<IrSymbol, IrSymbol>,
dependentFragments: List<IrModuleFragment>, dependentFragments: List<IrModuleFragment>,
typeAliasMap: Map<FqName, FqName>, expectActualTypeAliasMap: Map<FqName, FqName>,
diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext diagnosticsReporter: KtDiagnosticReporterWithImplicitIrBasedContext
) { ) {
MissingFakeOverridesAdder(expectActualMap, typeAliasMap, diagnosticsReporter).apply { dependentFragments.forEach { visitModuleFragment(it) } } MissingFakeOverridesAdder(
expectActualMap,
expectActualTypeAliasMap,
diagnosticsReporter
).apply { dependentFragments.forEach { visitModuleFragment(it) } }
} }
private fun linkExpectToActual(expectActualMap: Map<IrSymbol, IrSymbol>, dependentFragments: List<IrModuleFragment>) { private fun linkExpectToActual(expectActualMap: Map<IrSymbol, IrSymbol>, dependentFragments: List<IrModuleFragment>) {
@@ -12,27 +12,95 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
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.IrType import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.module import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
import org.jetbrains.kotlin.utils.addToStdlib.runIf
fun generateIrElementFullName( fun Map<String, List<IrDeclaration>>.getMatch(
expectDeclaration: IrDeclaration,
expectActualTypesMap: Map<IrSymbol, IrSymbol>,
expectActualTypeAliasMap: Map<FqName, FqName>
): IrDeclaration? {
val members = this[generateIrElementFullNameFromExpect(expectDeclaration, expectActualTypeAliasMap)] ?: return null
return if (expectDeclaration is IrFunction) {
members.firstNotNullOfOrNull { runIf(expectDeclaration.match(it as IrFunction, expectActualTypesMap)) { it } }
} else {
members.singleOrNull()
}
}
private fun IrFunction.match(actualFunction: IrFunction, expectActualTypesMap: Map<IrSymbol, IrSymbol>): Boolean {
fun checkParameter(
expectParameter: IrValueParameter?,
actualParameter: IrValueParameter?,
typeParametersMap: Map<IrTypeParameterSymbol, IrTypeParameterSymbol>
): Boolean {
if (expectParameter == null) {
return actualParameter == null
}
if (actualParameter == null) {
return false
}
val actualizedParameterTypeSymbol = expectParameter.type.classifierOrFail.let {
var mappedSymbol: IrSymbol? = null
if (it is IrTypeParameterSymbol) {
mappedSymbol = typeParametersMap[it]
}
if (mappedSymbol == null) {
mappedSymbol = expectActualTypesMap[it] ?: it
}
mappedSymbol
}
if (actualizedParameterTypeSymbol != actualParameter.type.classifierOrFail) {
return false
}
return true
}
if (valueParameters.size != actualFunction.valueParameters.size || typeParameters.size != actualFunction.typeParameters.size) {
return false
}
val typeParametersMap = mutableMapOf<IrTypeParameterSymbol, IrTypeParameterSymbol>()
for ((expectTypeParameter, actualTypeParameter) in typeParameters.zip(actualFunction.typeParameters)) {
if (expectTypeParameter.name != actualTypeParameter.name) {
return false
}
typeParametersMap[expectTypeParameter.symbol] = actualTypeParameter.symbol
}
if (!checkParameter(extensionReceiverParameter, actualFunction.extensionReceiverParameter, typeParametersMap)) {
return false
}
for ((expectParameter, actualParameter) in valueParameters.zip(actualFunction.valueParameters)) {
if (!checkParameter(expectParameter, actualParameter, typeParametersMap)) {
return false
}
}
return true
}
fun generateActualIrClassOrTypeAliasFullName(declaration: IrElement) = generateIrElementFullNameFromExpect(declaration, emptyMap())
fun generateIrElementFullNameFromExpect(
declaration: IrElement, declaration: IrElement,
expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null, expectActualTypeAliasMap: Map<FqName, FqName>
typeAliasMap: Map<FqName, FqName>? = null
): String { ): String {
return StringBuilder().apply { appendElementFullName(declaration, this, expectActualTypesMap, typeAliasMap) }.toString() return StringBuilder().apply { appendElementFullName(declaration, this, expectActualTypeAliasMap) }.toString()
} }
private fun appendElementFullName( private fun appendElementFullName(
declaration: IrElement, declaration: IrElement,
result: StringBuilder, result: StringBuilder,
expectActualTypesMap: Map<IrSymbol, IrSymbol>? = null, expectActualTypeAliasMap: Map<FqName, FqName>
expectActualTypeAliasMap: Map<FqName, FqName>? = null
) { ) {
if (declaration !is IrDeclarationBase) return if (declaration !is IrDeclarationBase) return
@@ -47,7 +115,7 @@ private fun appendElementFullName(
continue continue
} }
} }
val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap?.get(it) ?: it).asString() } val parentString = parent.kotlinFqName.let { (expectActualTypeAliasMap[it] ?: it).asString() }
if (parentString.isNotEmpty()) { if (parentString.isNotEmpty()) {
parents.add(parentString) parents.add(parentString)
} }
@@ -64,27 +132,7 @@ private fun appendElementFullName(
} }
if (declaration is IrFunction) { if (declaration is IrFunction) {
fun appendType(type: IrType) { result.append("()")
val typeClassifier = type.classifierOrFail
val actualizedTypeSymbol = expectActualTypesMap?.get(typeClassifier) ?: typeClassifier
appendElementFullName(actualizedTypeSymbol.owner, result, expectActualTypesMap)
}
val extensionReceiverType = declaration.extensionReceiverParameter?.type
if (extensionReceiverType != null) {
result.append('[')
appendType(extensionReceiverType)
result.append(']')
}
result.append('(')
for ((index, parameter) in declaration.valueParameters.withIndex()) {
appendType(parameter.type)
if (index < declaration.valueParameters.size - 1) {
result.append(',')
}
}
result.append(')')
} }
} }
@@ -39,9 +39,12 @@ class MissingFakeOverridesAdder(
private fun processSupertypes(declaration: IrClass) { private fun processSupertypes(declaration: IrClass) {
val members by lazy(LazyThreadSafetyMode.NONE) { val members by lazy(LazyThreadSafetyMode.NONE) {
declaration.declarations.filter { !it.isBuiltinMember() }.associateBy { val notBuiltinMembers = declaration.declarations.filter { !it.isBuiltinMember() }
generateIrElementFullName(it, expectActualMap, typeAliasMap) val result = mutableMapOf<String, MutableList<IrDeclaration>>()
for (member in notBuiltinMembers) {
result.getOrPut(generateIrElementFullNameFromExpect(member, typeAliasMap)) { mutableListOf() }.add(member)
} }
result
} }
for (superType in declaration.superTypes) { for (superType in declaration.superTypes) {
@@ -68,15 +71,11 @@ class MissingFakeOverridesAdder(
} }
} }
private fun addFakeOverride( private fun addFakeOverride(actualMember: IrDeclaration, members: Map<String, List<IrDeclaration>>, declaration: IrClass) {
actualMember: IrDeclaration,
members: Map<String, IrDeclaration>,
declaration: IrClass
) {
when (actualMember) { when (actualMember) {
is IrFunctionImpl, is IrFunctionImpl,
is IrPropertyImpl -> { is IrPropertyImpl -> {
if (members[generateIrElementFullName(actualMember, expectActualMap, typeAliasMap)] != null) { if (members.getMatch(actualMember, expectActualMap, typeAliasMap) != null) {
diagnosticsReporter.reportManyInterfacesMembersNotImplemented(declaration, actualMember as IrDeclarationWithName) diagnosticsReporter.reportManyInterfacesMembersNotImplemented(declaration, actualMember as IrDeclarationWithName)
return return
} }
@@ -2,7 +2,7 @@
// FILE: common.kt // FILE: common.kt
<!NO_ACTUAL_FOR_EXPECT{JVM}!>expect enum class Foo { <!NO_ACTUAL_FOR_EXPECT{JVM}!>expect enum class Foo {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>ENTRY<!> ENTRY
}<!> }<!>
expect enum class _TimeUnit expect enum class _TimeUnit
@@ -8,7 +8,7 @@ expect class Foo {
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun f2(s: List<String>?): MutableMap<Boolean?, Foo><!> <!NO_ACTUAL_FOR_EXPECT{JVM}!>fun f2(s: List<String>?): MutableMap<Boolean?, Foo><!>
<!NO_ACTUAL_FOR_EXPECT{JVM}!>fun <T : Set<Number>> f3(t: T): T?<!> fun <T : Set<Number>> f3(t: T): T?
} }
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)