[FIR2IR] Provide correct module data to FirModuleDescriptor

Properly implement friend modules visibility check

^KT-61384 Fixed
^KT-62475 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-10-11 12:52:04 +03:00
committed by Space Team
parent e3bab4a7da
commit c25cde8871
11 changed files with 73 additions and 48 deletions
@@ -554,7 +554,7 @@ class Fir2IrConverter(
typeContextProvider: (IrBuiltIns) -> IrTypeSystemContext typeContextProvider: (IrBuiltIns) -> IrTypeSystemContext
): Fir2IrResult { ): Fir2IrResult {
session.lazyDeclarationResolver.disableLazyResolveContractChecks() session.lazyDeclarationResolver.disableLazyResolveContractChecks()
val moduleDescriptor = FirModuleDescriptor(session, kotlinBuiltIns) val moduleDescriptor = FirModuleDescriptor.createSourceModuleDescriptor(session, kotlinBuiltIns)
val components = Fir2IrComponentsStorage( val components = Fir2IrComponentsStorage(
session, scopeSession, irFactory, fir2IrExtensions, fir2IrConfiguration, visibilityConverter, session, scopeSession, irFactory, fir2IrExtensions, fir2IrConfiguration, visibilityConverter,
{ irBuiltins -> { irBuiltins ->
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.name.*
@@ -48,19 +47,18 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.utils.threadLocal import org.jetbrains.kotlin.utils.threadLocal
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.fir.java.hasJvmFieldAnnotation
@OptIn(LeakedDeclarationCaches::class) @OptIn(LeakedDeclarationCaches::class)
class Fir2IrDeclarationStorage( class Fir2IrDeclarationStorage(
private val components: Fir2IrComponents, private val components: Fir2IrComponents,
private val moduleDescriptor: FirModuleDescriptor, private val sourceModuleDescriptor: FirModuleDescriptor,
commonMemberStorage: Fir2IrCommonMemberStorage commonMemberStorage: Fir2IrCommonMemberStorage
) : Fir2IrComponents by components { ) : Fir2IrComponents by components {
private val fragmentCache: ConcurrentHashMap<FqName, ExternalPackageFragments> = ConcurrentHashMap() private val fragmentCache: ConcurrentHashMap<FqName, ExternalPackageFragments> = ConcurrentHashMap()
private class ExternalPackageFragments( private class ExternalPackageFragments(
val fragmentForDependencies: IrExternalPackageFragment, val fragmentsForDependencies: ConcurrentHashMap<FirModuleData, IrExternalPackageFragment>,
val fragmentForPrecompiledBinaries: IrExternalPackageFragment val fragmentForPrecompiledBinaries: IrExternalPackageFragment
) )
@@ -156,32 +154,43 @@ class Fir2IrDeclarationStorage(
fun getIrExternalPackageFragment( fun getIrExternalPackageFragment(
fqName: FqName, fqName: FqName,
moduleData: FirModuleData,
firOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library firOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library
): IrExternalPackageFragment { ): IrExternalPackageFragment {
val fragments = fragmentCache.getOrPut(fqName) { val fragments = fragmentCache.getOrPut(fqName) {
val fragmentForDependencies = callablesGenerator.createExternalPackageFragment( val fragmentForPrecompiledBinaries = callablesGenerator.createExternalPackageFragment(fqName, sourceModuleDescriptor)
fqName, FirModuleDescriptor(session, moduleDescriptor.builtIns) ExternalPackageFragments(ConcurrentHashMap(), fragmentForPrecompiledBinaries)
)
val fragmentForPrecompiledBinaries = callablesGenerator.createExternalPackageFragment(fqName, moduleDescriptor)
ExternalPackageFragments(fragmentForDependencies, fragmentForPrecompiledBinaries)
} }
// Make sure that external package fragments have a different module descriptor. The module descriptors are compared // Make sure that external package fragments have a different module descriptor. The module descriptors are compared
// to determine if objects need regeneration because they are from different modules. // to determine if objects need regeneration because they are from different modules.
// But keep original module descriptor for the fragments coming from parts compiled on the previous incremental step // But keep original module descriptor for the fragments coming from parts compiled on the previous incremental step
return when (firOrigin) { return when (firOrigin) {
FirDeclarationOrigin.Precompiled -> fragments.fragmentForPrecompiledBinaries FirDeclarationOrigin.Precompiled -> fragments.fragmentForPrecompiledBinaries
else -> fragments.fragmentForDependencies else -> fragments.fragmentsForDependencies.getOrPut(moduleData) {
val moduleDescriptor = FirModuleDescriptor.createDependencyModuleDescriptor(
moduleData,
sourceModuleDescriptor.builtIns
)
callablesGenerator.createExternalPackageFragment(fqName, moduleDescriptor)
}
} }
} }
private fun getIrExternalOrBuiltInsPackageFragment(fqName: FqName, firOrigin: FirDeclarationOrigin): IrExternalPackageFragment { private fun getIrExternalOrBuiltInsPackageFragment(
fqName: FqName,
moduleData: FirModuleData,
firOrigin: FirDeclarationOrigin,
): IrExternalPackageFragment {
val isBuiltIn = fqName in BUILT_INS_PACKAGE_FQ_NAMES val isBuiltIn = fqName in BUILT_INS_PACKAGE_FQ_NAMES
return if (isBuiltIn) getIrBuiltInsPackageFragment(fqName) else getIrExternalPackageFragment(fqName, firOrigin) return when(isBuiltIn) {
true -> getIrBuiltInsPackageFragment(fqName)
false -> getIrExternalPackageFragment(fqName, moduleData, firOrigin)
}
} }
private fun getIrBuiltInsPackageFragment(fqName: FqName): IrExternalPackageFragment { private fun getIrBuiltInsPackageFragment(fqName: FqName): IrExternalPackageFragment {
return builtInsFragmentCache.getOrPut(fqName) { return builtInsFragmentCache.getOrPut(fqName) {
callablesGenerator.createExternalPackageFragment(FirBuiltInsPackageFragment(fqName, moduleDescriptor)) callablesGenerator.createExternalPackageFragment(FirBuiltInsPackageFragment(fqName, sourceModuleDescriptor))
} }
} }
@@ -1164,12 +1173,12 @@ class Fir2IrDeclarationStorage(
val parentPackage = when (firBasedSymbol) { val parentPackage = when (firBasedSymbol) {
is FirCallableSymbol<*> -> { is FirCallableSymbol<*> -> {
getIrExternalPackageFragment(packageFqName, firOrigin) getIrExternalPackageFragment(packageFqName, firBasedSymbol.moduleData, firOrigin)
} }
else -> { else -> {
// TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now, // TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now,
// which is not exact and can lead to some problems // which is not exact and can lead to some problems
getIrExternalOrBuiltInsPackageFragment(packageFqName, firOrigin) getIrExternalOrBuiltInsPackageFragment(packageFqName, firBasedSymbol.moduleData, firOrigin)
} }
} }
@@ -66,13 +66,11 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
val nameSegments = signature.nameSegments val nameSegments = signature.nameSegments
val topName = Name.identifier(nameSegments[0]) val topName = Name.identifier(nameSegments[0])
val packageFragment = declarationStorage.getIrExternalPackageFragment(packageFqName)
val firCandidates: List<FirDeclaration> val firCandidates: List<FirDeclaration>
val parent: IrDeclarationParent val parentClass: IrClass?
if (nameSegments.size == 1 && kind != SymbolKind.CLASS_SYMBOL) { if (nameSegments.size == 1 && kind != SymbolKind.CLASS_SYMBOL) {
firCandidates = symbolProvider.getTopLevelCallableSymbols(packageFqName, topName).map { it.fir } firCandidates = symbolProvider.getTopLevelCallableSymbols(packageFqName, topName).map { it.fir }
parent = packageFragment // TODO: need to insert file facade class on JVM parentClass = null // TODO: need to insert file facade class on JVM
} else { } else {
val topLevelClass = symbolProvider.getClassLikeSymbolByClassId(ClassId(packageFqName, topName))?.fir as? FirRegularClass val topLevelClass = symbolProvider.getClassLikeSymbolByClassId(ClassId(packageFqName, topName))?.fir as? FirRegularClass
?: return null ?: return null
@@ -95,28 +93,28 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
when (kind) { when (kind) {
SymbolKind.CLASS_SYMBOL -> { SymbolKind.CLASS_SYMBOL -> {
firCandidates = listOf(firClass) firCandidates = listOf(firClass)
parent = firParentClass?.let { findIrClass(it) } ?: packageFragment parentClass = firParentClass?.let { findIrClass(it) }
} }
SymbolKind.ENUM_ENTRY_SYMBOL -> { SymbolKind.ENUM_ENTRY_SYMBOL -> {
val lastName = Name.guessByFirstCharacter(nameSegments.last()) val lastName = Name.guessByFirstCharacter(nameSegments.last())
val firCandidate = firClass.declarations.singleOrNull { (it as? FirEnumEntry)?.name == lastName } val firCandidate = firClass.declarations.singleOrNull { (it as? FirEnumEntry)?.name == lastName }
firCandidates = firCandidate?.let { listOf(it) } ?: return null firCandidates = firCandidate?.let { listOf(it) } ?: return null
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
} }
SymbolKind.CONSTRUCTOR_SYMBOL -> { SymbolKind.CONSTRUCTOR_SYMBOL -> {
val constructors = mutableListOf<FirConstructor>() val constructors = mutableListOf<FirConstructor>()
scope.processDeclaredConstructors { constructors.add(it.fir) } scope.processDeclaredConstructors { constructors.add(it.fir) }
firCandidates = constructors firCandidates = constructors
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
} }
SymbolKind.FUNCTION_SYMBOL -> { SymbolKind.FUNCTION_SYMBOL -> {
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
val lastName = Name.guessByFirstCharacter(nameSegments.last()) val lastName = Name.guessByFirstCharacter(nameSegments.last())
val functions = mutableListOf<FirSimpleFunction>() val functions = mutableListOf<FirSimpleFunction>()
scope.processFunctionsByName(lastName) { functionSymbol -> scope.processFunctionsByName(lastName) { functionSymbol ->
val dispatchReceiverClassId = (functionSymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val dispatchReceiverClassId = (functionSymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId
val function = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) { val function = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) {
fakeOverrideGenerator.createFirFunctionFakeOverride(firClass, parent, functionSymbol, scope)!!.first fakeOverrideGenerator.createFirFunctionFakeOverride(firClass, parentClass, functionSymbol, scope)!!.first
} else functionSymbol.fir } else functionSymbol.fir
functions.add(function) functions.add(function)
} }
@@ -126,21 +124,21 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
firCandidates = functions firCandidates = functions
} }
SymbolKind.PROPERTY_SYMBOL -> { SymbolKind.PROPERTY_SYMBOL -> {
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
val lastName = Name.guessByFirstCharacter(nameSegments.last()) val lastName = Name.guessByFirstCharacter(nameSegments.last())
val properties = mutableListOf<FirVariable>() val properties = mutableListOf<FirVariable>()
scope.processPropertiesByName(lastName) { propertySymbol -> scope.processPropertiesByName(lastName) { propertySymbol ->
propertySymbol as FirPropertySymbol propertySymbol as FirPropertySymbol
val dispatchReceiverClassId = (propertySymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val dispatchReceiverClassId = (propertySymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId
val property = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) { val property = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) {
fakeOverrideGenerator.createFirPropertyFakeOverride(firClass, parent, propertySymbol, scope)!!.first fakeOverrideGenerator.createFirPropertyFakeOverride(firClass, parentClass, propertySymbol, scope)!!.first
} else propertySymbol.fir } else propertySymbol.fir
properties.add(property) properties.add(property)
} }
firCandidates = properties firCandidates = properties
} }
SymbolKind.FIELD_SYMBOL -> { SymbolKind.FIELD_SYMBOL -> {
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
val lastName = Name.guessByFirstCharacter(nameSegments.last()) val lastName = Name.guessByFirstCharacter(nameSegments.last())
val fields = mutableListOf<FirVariable>() val fields = mutableListOf<FirVariable>()
scope.processPropertiesByName(lastName) { propertySymbol -> scope.processPropertiesByName(lastName) { propertySymbol ->
@@ -154,13 +152,13 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
else -> { else -> {
val lastName = nameSegments.last() val lastName = nameSegments.last()
firCandidates = firClass.declarations.filter { it is FirCallableDeclaration && it.symbol.name.asString() == lastName } firCandidates = firClass.declarations.filter { it is FirCallableDeclaration && it.symbol.name.asString() == lastName }
parent = findIrClass(firClass) parentClass = findIrClass(firClass)
} }
} }
} }
val firDeclaration = findDeclarationByHash(firCandidates, signature.id) val firDeclaration = findDeclarationByHash(firCandidates, signature.id) ?: return null
?: return null val parent = parentClass ?: declarationStorage.getIrExternalPackageFragment(packageFqName, firDeclaration.moduleData)
return when (kind) { return when (kind) {
SymbolKind.CLASS_SYMBOL -> { SymbolKind.CLASS_SYMBOL -> {
@@ -699,7 +699,7 @@ class IrBuiltInsOverFir(
private fun findIrParent(firSymbol: FirCallableSymbol<*>): IrDeclarationParent? { private fun findIrParent(firSymbol: FirCallableSymbol<*>): IrDeclarationParent? {
return when (val containingClassLookupTag = firSymbol.containingClassLookupTag()) { return when (val containingClassLookupTag = firSymbol.containingClassLookupTag()) {
null -> components.declarationStorage.getIrExternalPackageFragment(firSymbol.callableId.packageName) null -> components.declarationStorage.getIrExternalPackageFragment(firSymbol.callableId.packageName, firSymbol.moduleData)
else -> components.classifierStorage.findIrClass(containingClassLookupTag) else -> components.classifierStorage.findIrClass(containingClassLookupTag)
} }
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -468,7 +469,9 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
val parentId = classId.outerClassId val parentId = classId.outerClassId
val parentClass = parentId?.let { createIrClassForNotFoundClass(it.toLookupTag()) } val parentClass = parentId?.let { createIrClassForNotFoundClass(it.toLookupTag()) }
val irParent = parentClass ?: declarationStorage.getIrExternalPackageFragment(classId.packageFqName) val irParent = parentClass ?: declarationStorage.getIrExternalPackageFragment(
classId.packageFqName, session.moduleData.dependencies.first()
)
return symbolTable.declareClassIfNotExists(signature, { IrClassPublicSymbolImpl(signature) }) { return symbolTable.declareClassIfNotExists(signature, { IrClassPublicSymbolImpl(signature) }) {
irFactory.createClass( irFactory.createClass(
@@ -5,46 +5,66 @@
package org.jetbrains.kotlin.fir.descriptors package org.jetbrains.kotlin.fir.descriptors
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
class FirModuleDescriptor( class FirModuleDescriptor private constructor(
val session: FirSession, val session: FirSession,
val moduleData: FirModuleData,
override val builtIns: KotlinBuiltIns override val builtIns: KotlinBuiltIns
) : ModuleDescriptor { ) : ModuleDescriptor {
companion object {
fun createSourceModuleDescriptor(session: FirSession, builtIns: KotlinBuiltIns): FirModuleDescriptor {
require(session.kind == FirSession.Kind.Source)
return FirModuleDescriptor(session, session.moduleData, builtIns)
}
fun createDependencyModuleDescriptor(moduleData: FirModuleData, builtIns: KotlinBuiltIns): FirModuleDescriptor {
// We may create dependency module descriptor for java sources, which have source session and source module data
return FirModuleDescriptor(moduleData.session, moduleData, builtIns)
}
}
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean { override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
return false if (targetModule !is FirModuleDescriptor) return false
return when (targetModule.moduleData) {
this.moduleData,
in moduleData.friendDependencies,
in moduleData.dependsOnDependencies -> true
else -> false
}
} }
override val platform: TargetPlatform override val platform: TargetPlatform
get() = session.moduleData.platform get() = moduleData.platform
override fun getPackage(fqName: FqName): PackageViewDescriptor { override fun getPackage(fqName: FqName): PackageViewDescriptor {
val symbolProvider = session.symbolProvider val symbolProvider = session.symbolProvider
if (symbolProvider.getPackage(fqName) != null) { if (symbolProvider.getPackage(fqName) != null) {
return FirPackageViewDescriptor(fqName, this) return FirPackageViewDescriptor(fqName, this)
} }
TODO("Missing package reporting") error("Module $moduleData doesn't contain package $fqName")
} }
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> { override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
TODO("not implemented") shouldNotBeCalled()
} }
override var allDependencyModules: List<ModuleDescriptor> = emptyList() override var allDependencyModules: List<ModuleDescriptor> = emptyList()
override val expectedByModules: List<ModuleDescriptor> override val expectedByModules: List<ModuleDescriptor>
get() = TODO("not implemented") get() = shouldNotBeCalled()
override val allExpectedByModules: Set<ModuleDescriptor> override val allExpectedByModules: Set<ModuleDescriptor>
get() = TODO("not implemented") get() = shouldNotBeCalled()
override fun <T> getCapability(capability: ModuleCapability<T>): T? { override fun <T> getCapability(capability: ModuleCapability<T>): T? {
return null return null
@@ -62,14 +82,14 @@ class FirModuleDescriptor(
} }
override fun getName(): Name { override fun getName(): Name {
return session.moduleData.name return moduleData.name
} }
override val stableName: Name override val stableName: Name
get() = name get() = name
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) { override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
TODO("not implemented") shouldNotBeCalled()
} }
override val annotations: Annotations override val annotations: Annotations
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: WASM // IGNORE_BACKEND: WASM
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61384
// WITH_STDLIB // WITH_STDLIB
// MODULE: lib1 // MODULE: lib1
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: WASM // IGNORE_BACKEND: WASM
// WITH_STDLIB // WITH_STDLIB
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61384
// MODULE: lib1 // MODULE: lib1
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61384
// WITH_STDLIB // WITH_STDLIB
// MODULE: lib // MODULE: lib
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61384
// WITH_STDLIB // WITH_STDLIB
// MODULE: lib // MODULE: lib
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: WASM // IGNORE_BACKEND: WASM
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61384
// MODULE: lib // MODULE: lib
// FILE: l.kt // FILE: l.kt