[FIR2IR] Introduce staged transformation (first step)

Now FE IR -> BE IR transformation is performed in multiple stages
controller by Fir2IrConverter. Stages are
 * files & classes registration
 * supertypes & type parameters handling
 * functions & properties signature generation
 * body generation

After each step we have guarantee (with exception of local classes &
type inference combination, and external symbols) that required symbols
(class/function/property/variable/type parameter)
are already bound to real declarations and have correct parents.

This commit also fixes incorrect parents for local classes
This commit is contained in:
Mikhail Glukhikh
2020-03-11 15:35:14 +03:00
parent a9f7ff254b
commit 20c4a7b244
95 changed files with 436 additions and 394 deletions
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiCompiledElement
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirConstExpression
@@ -216,3 +217,6 @@ internal fun FirReference.statementOrigin(): IrStatementOrigin? {
else -> null else -> null
} }
} }
fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? =
declarations.filterIsInstance<FirConstructor>().firstOrNull()?.takeIf { it.isPrimary }
@@ -17,8 +17,6 @@ class Fir2IrCallableCache {
private val variableCache = mutableMapOf<FirVariable<*>, IrVariable>() private val variableCache = mutableMapOf<FirVariable<*>, IrVariable>()
private val localClassCache = mutableMapOf<FirClass<*>, IrClass>()
private val localFunctionCache = mutableMapOf<FirFunction<*>, IrSimpleFunction>() private val localFunctionCache = mutableMapOf<FirFunction<*>, IrSimpleFunction>()
fun getParameter(parameter: FirValueParameter): IrValueParameter? = parameterCache[parameter] fun getParameter(parameter: FirValueParameter): IrValueParameter? = parameterCache[parameter]
@@ -33,13 +31,6 @@ class Fir2IrCallableCache {
variableCache[firVariable] = irVariable variableCache[firVariable] = irVariable
} }
fun getLocalClass(localClass: FirClass<*>): IrClass? = localClassCache[localClass]
fun putLocalClass(localClass: FirClass<*>, irClass: IrClass) {
require(localClass !is FirRegularClass || localClass.visibility == Visibilities.LOCAL)
localClassCache[localClass] = irClass
}
fun getLocalFunction(localFunction: FirFunction<*>): IrSimpleFunction? = localFunctionCache[localFunction] fun getLocalFunction(localFunction: FirFunction<*>): IrSimpleFunction? = localFunctionCache[localFunction]
fun putLocalFunction(localFunction: FirFunction<*>, irFunction: IrSimpleFunction) { fun putLocalFunction(localFunction: FirFunction<*>, irFunction: IrSimpleFunction) {
@@ -50,7 +41,6 @@ class Fir2IrCallableCache {
fun clear() { fun clear() {
parameterCache.clear() parameterCache.clear()
variableCache.clear() variableCache.clear()
localClassCache.clear()
localFunctionCache.clear() localFunctionCache.clear()
} }
} }
@@ -20,6 +20,8 @@ class Fir2IrConversionScope {
return parent return parent
} }
fun parentFromStack(): IrDeclarationParent = parentStack.last()
fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T { fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T {
declaration.parent = parentStack.last() declaration.parent = parentStack.last()
return declaration return declaration
@@ -7,58 +7,207 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.PsiSourceManager
object Fir2IrConverter { class Fir2IrConverter(
private val moduleDescriptor: FirModuleDescriptor,
private val sourceManager: PsiSourceManager,
private val declarationStorage: Fir2IrDeclarationStorage
) {
fun createModuleFragment( fun processLocalClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent) {
session: FirSession, val irClass = registerClassAndNestedClasses(regularClass, parent)
firFiles: List<FirFile>, processClassAndNestedClassHeaders(regularClass)
languageVersionSettings: LanguageVersionSettings, processClassMembers(regularClass, irClass)
fakeOverrideMode: FakeOverrideMode = FakeOverrideMode.NORMAL,
signaturer: IdSignatureComposer
): Fir2IrResult {
val moduleDescriptor = FirModuleDescriptor(session)
val symbolTable = SymbolTable(signaturer)
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator = TypeTranslator(symbolTable, languageVersionSettings, moduleDescriptor.builtIns)
constantValueGenerator.typeTranslator = typeTranslator
typeTranslator.constantValueGenerator = constantValueGenerator
val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, signaturer, symbolTable)
val sourceManager = PsiSourceManager()
val fir2irVisitor = Fir2IrVisitor(session, moduleDescriptor, symbolTable, sourceManager, builtIns, fakeOverrideMode)
val irFiles = mutableListOf<IrFile>()
for (firFile in firFiles) {
fir2irVisitor.registerFile(firFile)
}
for (firFile in firFiles) {
val irFile = firFile.accept(fir2irVisitor, null) as IrFile
val fileEntry = sourceManager.getOrCreateFileEntry(firFile.psi as KtFile)
sourceManager.putFileEntry(irFile, fileEntry)
irFiles += irFile
}
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, irFiles)
generateUnboundSymbolsAsDependencies(irModuleFragment, symbolTable, builtIns)
return Fir2IrResult(irModuleFragment, symbolTable, sourceManager)
} }
private fun generateUnboundSymbolsAsDependencies( fun processRegisteredLocalClassAndNestedClasses(regularClass: FirRegularClass, irClass: IrClass) {
irModule: IrModuleFragment, regularClass.declarations.forEach {
symbolTable: SymbolTable, if (it is FirRegularClass) {
builtIns: IrBuiltIns registerClassAndNestedClasses(it, irClass)
) { }
// TODO: provide StubGeneratorExtensions for correct lazy stub IR generation on JVM }
ExternalDependenciesGenerator(symbolTable, generateTypicalIrProviderList(irModule.descriptor, builtIns, symbolTable)) processClassAndNestedClassHeaders(regularClass)
.generateUnboundSymbolsAsDependencies() processClassMembers(regularClass, irClass)
}
fun registerFileAndClasses(file: FirFile) {
val irFile = IrFileImpl(
sourceManager.getOrCreateFileEntry(file.psi as KtFile),
moduleDescriptor.getPackage(file.packageFqName).fragments.first()
)
declarationStorage.registerFile(file, irFile)
file.declarations.forEach {
if (it is FirRegularClass) {
registerClassAndNestedClasses(it, irFile)
}
}
}
fun processClassHeaders(file: FirFile) {
file.declarations.forEach {
if (it is FirRegularClass) {
processClassAndNestedClassHeaders(it)
}
}
}
fun processFileAndClassMembers(file: FirFile) {
val irFile = declarationStorage.getIrFile(file)
for (declaration in file.declarations) {
val irDeclaration = processMemberDeclaration(declaration, irFile) ?: continue
irFile.declarations += irDeclaration
}
}
fun processAnonymousObjectMembers(
anonymousObject: FirAnonymousObject,
irClass: IrClass = declarationStorage.getCachedIrClass(anonymousObject)!!
): IrClass {
anonymousObject.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
}
for (declaration in anonymousObject.declarations) {
if (declaration is FirRegularClass) {
registerClassAndNestedClasses(declaration, irClass)
processClassAndNestedClassHeaders(declaration)
}
val irDeclaration = processMemberDeclaration(declaration, irClass) ?: continue
irClass.declarations += irDeclaration
}
return irClass
}
private fun processClassMembers(
regularClass: FirRegularClass,
irClass: IrClass = declarationStorage.getCachedIrClass(regularClass)!!
): IrClass {
regularClass.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
}
for (declaration in regularClass.declarations) {
val irDeclaration = processMemberDeclaration(declaration, irClass) ?: continue
irClass.declarations += irDeclaration
}
return irClass
}
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
val irClass = declarationStorage.registerIrClass(regularClass, parent)
regularClass.declarations.forEach {
if (it is FirRegularClass) {
registerClassAndNestedClasses(it, irClass)
}
}
return irClass
}
private fun processClassAndNestedClassHeaders(regularClass: FirRegularClass) {
declarationStorage.processClassHeader(regularClass)
regularClass.declarations.forEach {
if (it is FirRegularClass) {
processClassAndNestedClassHeaders(it)
}
}
}
private fun processMemberDeclaration(declaration: FirDeclaration, parent: IrDeclarationParent): IrDeclaration? {
return when (declaration) {
is FirRegularClass -> {
processClassMembers(declaration)
}
is FirSimpleFunction -> {
declarationStorage.createIrFunction(declaration, parent)
}
is FirProperty -> {
declarationStorage.createIrProperty(declaration, parent)
}
is FirConstructor -> if (!declaration.isPrimary) {
declarationStorage.createIrConstructor(declaration, parent as IrClass)
} else {
null
}
is FirEnumEntry -> {
declarationStorage.createIrEnumEntry(declaration, parent as IrClass)
}
is FirAnonymousInitializer -> {
declarationStorage.createIrAnonymousInitializer(declaration, parent as IrClass)
}
is FirTypeAlias -> {
// DO NOTHING
null
}
else -> {
throw AssertionError("Unexpected member: ${declaration::class}")
}
}
}
companion object {
fun createModuleFragment(
session: FirSession,
firFiles: List<FirFile>,
languageVersionSettings: LanguageVersionSettings,
fakeOverrideMode: FakeOverrideMode = FakeOverrideMode.NORMAL,
signaturer: IdSignatureComposer
): Fir2IrResult {
val moduleDescriptor = FirModuleDescriptor(session)
val symbolTable = SymbolTable(signaturer)
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator = TypeTranslator(symbolTable, languageVersionSettings, moduleDescriptor.builtIns)
constantValueGenerator.typeTranslator = typeTranslator
typeTranslator.constantValueGenerator = constantValueGenerator
val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, signaturer, symbolTable)
val sourceManager = PsiSourceManager()
val declarationStorage = Fir2IrDeclarationStorage(session, symbolTable, moduleDescriptor)
val typeConverter = Fir2IrTypeConverter(session, declarationStorage, builtIns)
declarationStorage.typeConverter = typeConverter
typeConverter.initBuiltinTypes()
val irFiles = mutableListOf<IrFile>()
val converter = Fir2IrConverter(moduleDescriptor, sourceManager, declarationStorage)
for (firFile in firFiles) {
converter.registerFileAndClasses(firFile)
}
for (firFile in firFiles) {
converter.processClassHeaders(firFile)
}
for (firFile in firFiles) {
converter.processFileAndClassMembers(firFile)
}
val fir2irVisitor = Fir2IrVisitor(
session, symbolTable, declarationStorage, converter, typeConverter, builtIns, fakeOverrideMode
)
for (firFile in firFiles) {
val irFile = firFile.accept(fir2irVisitor, null) as IrFile
val fileEntry = sourceManager.getOrCreateFileEntry(firFile.psi as KtFile)
sourceManager.putFileEntry(irFile, fileEntry)
irFiles += irFile
}
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, irFiles)
generateUnboundSymbolsAsDependencies(irModuleFragment, symbolTable, builtIns)
return Fir2IrResult(irModuleFragment, symbolTable, sourceManager)
}
private fun generateUnboundSymbolsAsDependencies(
irModule: IrModuleFragment,
symbolTable: SymbolTable,
builtIns: IrBuiltIns
) {
// TODO: provide StubGeneratorExtensions for correct lazy stub IR generation on JVM
ExternalDependenciesGenerator(symbolTable, generateTypicalIrProviderList(irModule.descriptor, builtIns, symbolTable))
.generateUnboundSymbolsAsDependencies()
}
} }
} }
@@ -66,6 +66,8 @@ class Fir2IrDeclarationStorage(
private val constructorCache = mutableMapOf<FirConstructor, IrConstructor>() private val constructorCache = mutableMapOf<FirConstructor, IrConstructor>()
private val initializerCache = mutableMapOf<FirAnonymousInitializer, IrAnonymousInitializer>()
private val propertyCache = mutableMapOf<FirProperty, IrProperty>() private val propertyCache = mutableMapOf<FirProperty, IrProperty>()
private val fieldCache = mutableMapOf<FirField, IrField>() private val fieldCache = mutableMapOf<FirField, IrField>()
@@ -98,7 +100,8 @@ class Fir2IrDeclarationStorage(
fun leaveScope(descriptor: DeclarationDescriptor) { fun leaveScope(descriptor: DeclarationDescriptor) {
if (descriptor is WrappedSimpleFunctionDescriptor || if (descriptor is WrappedSimpleFunctionDescriptor ||
descriptor is WrappedClassConstructorDescriptor || descriptor is WrappedClassConstructorDescriptor ||
descriptor is WrappedPropertyDescriptor descriptor is WrappedPropertyDescriptor ||
descriptor is WrappedEnumEntryDescriptor
) { ) {
localStorage.leaveCallable() localStorage.leaveCallable()
} }
@@ -189,14 +192,18 @@ class Fir2IrDeclarationStorage(
irClass.declarations += when (declaration) { irClass.declarations += when (declaration) {
is FirSimpleFunction -> { is FirSimpleFunction -> {
processedNames += declaration.name processedNames += declaration.name
getIrFunction(declaration, irClass) createIrFunction(declaration, irClass)
} }
is FirProperty -> { is FirProperty -> {
processedNames += declaration.name processedNames += declaration.name
getIrProperty(declaration, irClass) createIrProperty(declaration, irClass)
}
is FirConstructor -> {
createIrConstructor(declaration, irClass)
}
is FirRegularClass -> {
createIrClass(declaration, irClass)
} }
is FirConstructor -> getIrConstructor(declaration, irClass)
is FirRegularClass -> getIrClass(declaration, exactlySourceClass = false)
else -> continue else -> continue
} }
} }
@@ -210,14 +217,14 @@ class Fir2IrDeclarationStorage(
if (functionSymbol is FirNamedFunctionSymbol) { if (functionSymbol is FirNamedFunctionSymbol) {
val fakeOverrideSymbol = val fakeOverrideSymbol =
FirClassSubstitutionScope.createFakeOverrideFunction(session, functionSymbol.fir, functionSymbol) FirClassSubstitutionScope.createFakeOverrideFunction(session, functionSymbol.fir, functionSymbol)
irClass.declarations += getIrFunction(fakeOverrideSymbol.fir, irClass) irClass.declarations += createIrFunction(fakeOverrideSymbol.fir, irClass)
} }
} }
scope.processPropertiesByName(name) { propertySymbol -> scope.processPropertiesByName(name) { propertySymbol ->
if (propertySymbol is FirPropertySymbol) { if (propertySymbol is FirPropertySymbol) {
val fakeOverrideSymbol = val fakeOverrideSymbol =
FirClassSubstitutionScope.createFakeOverrideProperty(session, propertySymbol.fir, propertySymbol) FirClassSubstitutionScope.createFakeOverrideProperty(session, propertySymbol.fir, propertySymbol)
irClass.declarations += getIrProperty(fakeOverrideSymbol.fir, irClass) irClass.declarations += createIrProperty(fakeOverrideSymbol.fir, irClass)
} }
} }
} }
@@ -228,7 +235,7 @@ class Fir2IrDeclarationStorage(
} }
} }
private fun getCachedIrClass(klass: FirClass<*>): IrClass? { fun getCachedIrClass(klass: FirClass<*>): IrClass? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.LOCAL) { return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.LOCAL) {
localStorage.getLocalClass(klass) localStorage.getLocalClass(klass)
} else { } else {
@@ -250,24 +257,39 @@ class Fir2IrDeclarationStorage(
} }
} }
private fun createIrClass(klass: FirClass<*>, exactlySourceClass: Boolean = false): IrClass { private fun createIrClass(klass: FirClass<*>, parent: IrDeclarationParent? = null): IrClass {
// NB: klass can be either FirRegularClass or FirAnonymousObject // NB: klass can be either FirRegularClass or FirAnonymousObject
if (klass is FirAnonymousObject) { if (klass is FirAnonymousObject) {
return createIrAnonymousObject(klass) return createIrAnonymousObject(klass, irParent = parent)
} }
val regularClass = klass as FirRegularClass val regularClass = klass as FirRegularClass
val descriptor = WrappedClassDescriptor()
val origin = val origin =
if (exactlySourceClass || firProvider.getFirClassifierContainerFileIfAny(klass.symbol) != null) IrDeclarationOrigin.DEFINED if (firProvider.getFirClassifierContainerFileIfAny(klass.symbol) != null) IrDeclarationOrigin.DEFINED
else IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
val irClass = registerIrClass(regularClass, parent, origin)
processClassHeader(regularClass, irClass)
return irClass
}
fun processClassHeader(regularClass: FirRegularClass, irClass: IrClass = getCachedIrClass(regularClass)!!): IrClass {
irClass.declareSupertypesAndTypeParameters(regularClass)
irClass.setThisReceiver()
return irClass
}
fun registerIrClass(
regularClass: FirRegularClass,
parent: IrDeclarationParent? = null,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrClass {
val descriptor = WrappedClassDescriptor()
val visibility = regularClass.visibility val visibility = regularClass.visibility
val modality = if (regularClass.classKind == ClassKind.ENUM_CLASS) { val modality = if (regularClass.classKind == ClassKind.ENUM_CLASS) {
regularClass.enumClassModality() regularClass.enumClassModality()
} else { } else {
regularClass.modality ?: Modality.FINAL regularClass.modality ?: Modality.FINAL
} }
val irClass = klass.convertWithOffsets { startOffset, endOffset -> val irClass = regularClass.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol -> irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol ->
IrClassImpl( IrClassImpl(
startOffset, startOffset,
@@ -275,7 +297,7 @@ class Fir2IrDeclarationStorage(
origin, origin,
symbol, symbol,
regularClass.name, regularClass.name,
klass.classKind, regularClass.classKind,
visibility, visibility,
modality, modality,
isCompanion = regularClass.isCompanion, isCompanion = regularClass.isCompanion,
@@ -290,25 +312,22 @@ class Fir2IrDeclarationStorage(
} }
} }
} }
if (regularClass.visibility == Visibilities.LOCAL) { if (parent != null) {
localStorage.putLocalClass(klass, irClass) irClass.parent = parent
} else { }
classCache[klass] = irClass if (regularClass.visibility == Visibilities.LOCAL) {
localStorage.putLocalClass(regularClass, irClass)
} else {
classCache[regularClass] = irClass
} }
irClass.declareSupertypesAndTypeParameters(klass)
irClass.setThisReceiver()
return irClass return irClass
} }
fun getIrClass(klass: FirClass<*>, exactlySourceClass: Boolean = true): IrClass { fun createIrAnonymousObject(
return getCachedIrClass(klass) ?: createIrClass(klass, exactlySourceClass)
}
private fun createIrAnonymousObject(
anonymousObject: FirAnonymousObject, anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.LOCAL, visibility: Visibility = Visibilities.LOCAL,
name: Name = Name.special("<no name provided>"), name: Name = Name.special("<no name provided>"),
irParent: IrClass? = null irParent: IrDeclarationParent? = null
): IrClass { ): IrClass {
val descriptor = WrappedClassDescriptor() val descriptor = WrappedClassDescriptor()
val origin = IrDeclarationOrigin.DEFINED val origin = IrDeclarationOrigin.DEFINED
@@ -335,18 +354,9 @@ class Fir2IrDeclarationStorage(
return result return result
} }
fun getIrAnonymousObject( private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.LOCAL,
name: Name = Name.special("<no name provided>"),
irParent: IrClass? = null
): IrClass {
localStorage.getLocalClass(anonymousObject)?.let { return it } localStorage.getLocalClass(anonymousObject)?.let { return it }
return createIrAnonymousObject(anonymousObject, visibility, name, irParent) return createIrAnonymousObject(anonymousObject, Visibilities.PRIVATE, name, irParent)
}
private fun getIrEnumEntryClass(enumEntry: FirEnumEntry, anonymousObject: FirAnonymousObject, irParent: IrClass?): IrClass {
return getIrAnonymousObject(anonymousObject, Visibilities.PRIVATE, enumEntry.name, irParent)
} }
private fun getIrTypeParameter( private fun getIrTypeParameter(
@@ -487,7 +497,7 @@ class Fir2IrDeclarationStorage(
declareDefaultSetterParameter(type) declareDefaultSetterParameter(type)
} else if (function != null) { } else if (function != null) {
valueParameters = function.valueParameters.mapIndexed { index, valueParameter -> valueParameters = function.valueParameters.mapIndexed { index, valueParameter ->
createAndSaveIrParameter( createIrParameter(
valueParameter, index, valueParameter, index,
useStubForDefaultValueStub = function !is FirConstructor || containingClass?.name != Name.identifier("Enum"), useStubForDefaultValueStub = function !is FirConstructor || containingClass?.name != Name.identifier("Enum"),
typeContext typeContext
@@ -535,16 +545,18 @@ class Fir2IrDeclarationStorage(
return this return this
} }
fun <T : IrFunction> T.enterLocalScope(function: FirFunction<*>): T { fun <T : IrFunction> T.putParametersInScope(function: FirFunction<*>): T {
enterScope(descriptor)
for ((firParameter, irParameter) in function.valueParameters.zip(valueParameters)) { for ((firParameter, irParameter) in function.valueParameters.zip(valueParameters)) {
irSymbolTable.introduceValueParameter(irParameter)
localStorage.putParameter(firParameter, irParameter) localStorage.putParameter(firParameter, irParameter)
} }
return this return this
} }
private fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? { fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) {
localStorage.putLocalClass(enumEntry.initializer as FirAnonymousObject, correspondingClass)
}
fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? {
return if (function !is FirSimpleFunction || function.visibility == Visibilities.LOCAL) { return if (function !is FirSimpleFunction || function.visibility == Visibilities.LOCAL) {
localStorage.getLocalFunction(function) localStorage.getLocalFunction(function)
} else { } else {
@@ -552,10 +564,9 @@ class Fir2IrDeclarationStorage(
} }
} }
private fun createIrFunction( fun createIrFunction(
function: FirFunction<*>, function: FirFunction<*>,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
shouldLeaveScope: Boolean = true,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrSimpleFunction { ): IrSimpleFunction {
val simpleFunction = function as? FirSimpleFunction val simpleFunction = function as? FirSimpleFunction
@@ -591,9 +602,7 @@ class Fir2IrDeclarationStorage(
result result
}.bindAndDeclareParameters(function, descriptor, irParent, isStatic = simpleFunction?.isStatic == true) }.bindAndDeclareParameters(function, descriptor, irParent, isStatic = simpleFunction?.isStatic == true)
if (shouldLeaveScope) { leaveScope(created.descriptor)
leaveScope(created.descriptor)
}
if (visibility == Visibilities.LOCAL) { if (visibility == Visibilities.LOCAL) {
localStorage.putLocalFunction(function, created) localStorage.putLocalFunction(function, created)
return created return created
@@ -607,33 +616,32 @@ class Fir2IrDeclarationStorage(
return created return created
} }
fun getIrFunction( fun getCachedIrAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer): IrAnonymousInitializer? =
function: FirFunction<*>, initializerCache[anonymousInitializer]
irParent: IrDeclarationParent?,
shouldLeaveScope: Boolean = true, fun createIrAnonymousInitializer(
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED anonymousInitializer: FirAnonymousInitializer,
): IrSimpleFunction { irParent: IrClass
return getCachedIrFunction(function)?.apply { ): IrAnonymousInitializer {
if (!shouldLeaveScope) enterLocalScope(function) return anonymousInitializer.convertWithOffsets { startOffset, endOffset ->
} ?: createIrFunction(function, irParent, shouldLeaveScope, origin) irSymbolTable.declareAnonymousInitializer(startOffset, endOffset, IrDeclarationOrigin.DEFINED, irParent.descriptor).apply {
this.parent = irParent
initializerCache[anonymousInitializer] = this
}
}
} }
private fun getCachedIrConstructor( fun getCachedIrConstructor(constructor: FirConstructor): IrConstructor? = constructorCache[constructor]
constructor: FirConstructor
): IrConstructor? {
return constructorCache[constructor]
}
private fun createIrConstructor( fun createIrConstructor(
constructor: FirConstructor, constructor: FirConstructor,
irParent: IrDeclarationParent, irParent: IrClass,
shouldLeaveScope: Boolean = true,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrConstructor { ): IrConstructor {
val descriptor = WrappedClassConstructorDescriptor() val descriptor = WrappedClassConstructorDescriptor()
val isPrimary = constructor.isPrimary val isPrimary = constructor.isPrimary
val visibility = when { val visibility = when (irParent.modality) {
irParent is IrClass && irParent.modality == Modality.SEALED -> Visibilities.PRIVATE Modality.SEALED -> Visibilities.PRIVATE
else -> constructor.visibility else -> constructor.visibility
} }
val created = constructor.convertWithOffsets { startOffset, endOffset -> val created = constructor.convertWithOffsets { startOffset, endOffset ->
@@ -646,9 +654,7 @@ class Fir2IrDeclarationStorage(
).apply { ).apply {
enterScope(descriptor) enterScope(descriptor)
}.bindAndDeclareParameters(constructor, descriptor, irParent, isStatic = true).apply { }.bindAndDeclareParameters(constructor, descriptor, irParent, isStatic = true).apply {
if (shouldLeaveScope) { leaveScope(descriptor)
leaveScope(descriptor)
}
} }
} }
} }
@@ -656,18 +662,6 @@ class Fir2IrDeclarationStorage(
return created return created
} }
fun getIrConstructor(
constructor: FirConstructor,
irParent: IrDeclarationParent,
shouldLeaveScope: Boolean = true
): IrConstructor {
val cached = getCachedIrConstructor(constructor)
if (cached != null) {
return if (shouldLeaveScope) cached else cached.enterLocalScope(constructor)
}
return createIrConstructor(constructor, irParent, shouldLeaveScope)
}
private fun createIrPropertyAccessor( private fun createIrPropertyAccessor(
propertyAccessor: FirPropertyAccessor?, propertyAccessor: FirPropertyAccessor?,
property: FirProperty, property: FirProperty,
@@ -725,49 +719,48 @@ class Fir2IrDeclarationStorage(
} }
} }
fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry]
fun getIrEnumEntry( fun createIrEnumEntry(
enumEntry: FirEnumEntry, enumEntry: FirEnumEntry,
irParent: IrClass? = null, irParent: IrClass?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrEnumEntry { ): IrEnumEntry {
return enumEntryCache.getOrPut(enumEntry) { return enumEntry.convertWithOffsets { startOffset, endOffset ->
enumEntry.convertWithOffsets { startOffset, endOffset -> val desc = WrappedEnumEntryDescriptor()
val desc = WrappedEnumEntryDescriptor() enterScope(desc)
enterScope(desc) val result = irSymbolTable.declareEnumEntry(startOffset, endOffset, origin, desc) { symbol ->
val result = irSymbolTable.declareEnumEntry(startOffset, endOffset, origin, desc) { symbol -> IrEnumEntryImpl(
IrEnumEntryImpl( startOffset, endOffset, origin, symbol, enumEntry.name
startOffset, endOffset, origin, symbol, enumEntry.name ).apply {
).apply { desc.bind(this)
desc.bind(this) val irType = enumEntry.returnTypeRef.toIrType()
val irType = enumEntry.returnTypeRef.toIrType() if (irParent != null) {
if (irParent != null) { this.parent = irParent
this.parent = irParent }
} val initializer = enumEntry.initializer
val initializer = enumEntry.initializer if (initializer != null) {
if (initializer != null) { initializer as FirAnonymousObject
initializer as FirAnonymousObject val klass = getIrAnonymousObjectForEnumEntry(initializer, enumEntry.name, irParent)
val klass = getIrEnumEntryClass(enumEntry, initializer, irParent)
this.correspondingClass = klass this.correspondingClass = klass
} else if (irParent != null) { } else if (irParent != null) {
this.initializerExpression = IrExpressionBodyImpl( this.initializerExpression = IrExpressionBodyImpl(
IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol) IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol)
) )
}
} }
} }
leaveScope(desc)
result
} }
leaveScope(desc)
enumEntryCache[enumEntry] = result
result
} }
} }
private fun createIrProperty( fun createIrProperty(
property: FirProperty, property: FirProperty,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED, origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
shouldLeaveScope: Boolean = true
): IrProperty { ): IrProperty {
val containerSource = property.containerSource val containerSource = property.containerSource
val descriptor = containerSource?.let { WrappedPropertyDescriptorWithContainerSource(it) } ?: WrappedPropertyDescriptor() val descriptor = containerSource?.let { WrappedPropertyDescriptorWithContainerSource(it) } ?: WrappedPropertyDescriptor()
@@ -818,29 +811,13 @@ class Fir2IrDeclarationStorage(
} }
} }
} }
if (shouldLeaveScope) { leaveScope(descriptor)
leaveScope(descriptor)
}
propertyCache[property] = result propertyCache[property] = result
result result
} }
} }
fun getIrProperty( fun getCachedIrProperty(property: FirProperty): IrProperty? = propertyCache[property]
property: FirProperty,
irParent: IrDeclarationParent?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
shouldLeaveScope: Boolean = true
): IrProperty {
val cached = propertyCache[property]
if (cached != null) {
if (!shouldLeaveScope) {
enterScope(cached.descriptor)
}
return cached
}
return createIrProperty(property, irParent, origin, shouldLeaveScope)
}
private fun createIrField(field: FirField): IrField { private fun createIrField(field: FirField): IrField {
val descriptor = WrappedFieldDescriptor() val descriptor = WrappedFieldDescriptor()
@@ -866,7 +843,7 @@ class Fir2IrDeclarationStorage(
} }
} }
private fun createAndSaveIrParameter( private fun createIrParameter(
valueParameter: FirValueParameter, valueParameter: FirValueParameter,
index: Int = -1, index: Int = -1,
useStubForDefaultValueStub: Boolean = true, useStubForDefaultValueStub: Boolean = true,
@@ -929,7 +906,7 @@ class Fir2IrDeclarationStorage(
} }
} }
fun createAndSaveIrVariable(variable: FirVariable<*>, givenOrigin: IrDeclarationOrigin? = null): IrVariable { fun createIrVariable(variable: FirVariable<*>, irParent: IrDeclarationParent, givenOrigin: IrDeclarationOrigin? = null): IrVariable {
val type = variable.returnTypeRef.toIrType() val type = variable.returnTypeRef.toIrType()
// Some temporary variables are produced in RawFirBuilder, but we consistently use special names for them. // Some temporary variables are produced in RawFirBuilder, but we consistently use special names for them.
val origin = when { val origin = when {
@@ -944,6 +921,7 @@ class Fir2IrDeclarationStorage(
variable.name, type, variable.isVar, isConst = false, isLateinit = false variable.name, type, variable.isVar, isConst = false, isLateinit = false
) )
} }
irVariable.parent = irParent
localStorage.putVariable(variable, irVariable) localStorage.putVariable(variable, irVariable)
return irVariable return irVariable
} }
@@ -961,6 +939,7 @@ class Fir2IrDeclarationStorage(
fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol {
val firClass = firClassSymbol.fir val firClass = firClassSymbol.fir
getCachedIrClass(firClass)?.let { return irSymbolTable.referenceClass(it.descriptor) } getCachedIrClass(firClass)?.let { return irSymbolTable.referenceClass(it.descriptor) }
// TODO: remove all this code and change to unbound symbol creation
val irClass = createIrClass(firClass) val irClass = createIrClass(firClass)
if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.LOCAL) { if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.LOCAL) {
return irSymbolTable.referenceClass(irClass.descriptor) return irSymbolTable.referenceClass(irClass.descriptor)
@@ -982,10 +961,22 @@ class Fir2IrDeclarationStorage(
firTypeParameterSymbol: FirTypeParameterSymbol, firTypeParameterSymbol: FirTypeParameterSymbol,
typeContext: ConversionTypeContext typeContext: ConversionTypeContext
): IrTypeParameterSymbol { ): IrTypeParameterSymbol {
// TODO: use cached type parameter here
val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext) val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext)
return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor) return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor)
} }
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol {
val firConstructor = firConstructorSymbol.fir
getCachedIrConstructor(firConstructor)?.let { return irSymbolTable.referenceConstructor(it.descriptor) }
val irParent = findIrParent(firConstructor) as IrClass
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
val irDeclaration = createIrConstructor(firConstructor, irParent, origin = parentOrigin).apply {
setAndModifyParent(irParent)
}
return irSymbolTable.referenceConstructor(irDeclaration.descriptor)
}
fun getIrFunctionSymbol(firFunctionSymbol: FirFunctionSymbol<*>): IrFunctionSymbol { fun getIrFunctionSymbol(firFunctionSymbol: FirFunctionSymbol<*>): IrFunctionSymbol {
return when (val firDeclaration = firFunctionSymbol.fir) { return when (val firDeclaration = firFunctionSymbol.fir) {
is FirSimpleFunction, is FirAnonymousFunction -> { is FirSimpleFunction, is FirAnonymousFunction -> {
@@ -998,13 +989,7 @@ class Fir2IrDeclarationStorage(
irSymbolTable.referenceSimpleFunction(irDeclaration.descriptor) irSymbolTable.referenceSimpleFunction(irDeclaration.descriptor)
} }
is FirConstructor -> { is FirConstructor -> {
getCachedIrConstructor(firDeclaration)?.let { return irSymbolTable.referenceConstructor(it.descriptor) } getIrConstructorSymbol(firDeclaration.symbol)
val irParent = findIrParent(firDeclaration)!!
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
val irDeclaration = createIrConstructor(firDeclaration, irParent, origin = parentOrigin).apply {
setAndModifyParent(irParent)
}
irSymbolTable.referenceConstructor(irDeclaration.descriptor)
} }
else -> throw AssertionError("Should not be here: ${firDeclaration::class.java}: ${firDeclaration.render()}") else -> throw AssertionError("Should not be here: ${firDeclaration::class.java}: ${firDeclaration.render()}")
} }
@@ -1058,10 +1043,11 @@ class Fir2IrDeclarationStorage(
fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol {
return when (val firDeclaration = firVariableSymbol.fir) { return when (val firDeclaration = firVariableSymbol.fir) {
is FirEnumEntry -> { is FirEnumEntry -> {
getCachedIrEnumEntry(firDeclaration)?.let { return irSymbolTable.referenceEnumEntry(it.descriptor) }
val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol) val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol)
val parentClassSymbol = firVariableSymbol.callableId.classId?.let { firSymbolProvider.getClassLikeSymbolByFqName(it) } val parentClassSymbol = firVariableSymbol.callableId.classId?.let { firSymbolProvider.getClassLikeSymbolByFqName(it) }
val irParentClass = (parentClassSymbol?.fir as? FirClass<*>)?.let { getIrClass(it) } val irParentClass = (parentClassSymbol?.fir as? FirClass<*>)?.let { getCachedIrClass(it) }
val irEnumEntry = getIrEnumEntry( val irEnumEntry = createIrEnumEntry(
firDeclaration, firDeclaration,
irParent = irParentClass, irParent = irParentClass,
origin = if (containingFile == null) IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else IrDeclarationOrigin.DEFINED origin = if (containingFile == null) IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else IrDeclarationOrigin.DEFINED
@@ -43,9 +43,7 @@ class Fir2IrFakeOverrideGenerator(
firOverriddenSymbol: FirPropertySymbol firOverriddenSymbol: FirPropertySymbol
): IrProperty { ): IrProperty {
val firOverriddenProperty = firOverriddenSymbol.fir val firOverriddenProperty = firOverriddenSymbol.fir
val overriddenProperty = declarationStorage.getIrProperty( val overriddenProperty = declarationStorage.getCachedIrProperty(firOverriddenProperty)!!
firOverriddenProperty, declarationStorage.findIrParent(firOverriddenProperty)
)
getter?.apply { getter?.apply {
overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) } overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) }
} }
@@ -71,7 +69,7 @@ class Fir2IrFakeOverrideGenerator(
if (functionSymbol.isFakeOverride) { if (functionSymbol.isFakeOverride) {
// Substitution case // Substitution case
val baseSymbol = functionSymbol.deepestOverriddenSymbol() as FirNamedFunctionSymbol val baseSymbol = functionSymbol.deepestOverriddenSymbol() as FirNamedFunctionSymbol
val irFunction = declarationStorage.getIrFunction( val irFunction = declarationStorage.createIrFunction(
// TODO: parents for functions and properties should be consistent // TODO: parents for functions and properties should be consistent
originalFunction, declarationStorage.findIrParent(baseSymbol.fir), origin = origin originalFunction, declarationStorage.findIrParent(baseSymbol.fir), origin = origin
) )
@@ -89,7 +87,7 @@ class Fir2IrFakeOverrideGenerator(
) )
val fakeOverrideFunction = fakeOverrideSymbol.fir val fakeOverrideFunction = fakeOverrideSymbol.fir
val irFunction = declarationStorage.getIrFunction( val irFunction = declarationStorage.createIrFunction(
fakeOverrideFunction, declarationStorage.findIrParent(originalFunction), origin = origin fakeOverrideFunction, declarationStorage.findIrParent(originalFunction), origin = origin
) )
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(functionSymbol) as IrSimpleFunctionSymbol val overriddenSymbol = declarationStorage.getIrFunctionSymbol(functionSymbol) as IrSimpleFunctionSymbol
@@ -106,7 +104,7 @@ class Fir2IrFakeOverrideGenerator(
if (propertySymbol.isFakeOverride) { if (propertySymbol.isFakeOverride) {
// Substitution case // Substitution case
val baseSymbol = propertySymbol.deepestOverriddenSymbol() as FirPropertySymbol val baseSymbol = propertySymbol.deepestOverriddenSymbol() as FirPropertySymbol
val irProperty = declarationStorage.getIrProperty( val irProperty = declarationStorage.createIrProperty(
originalProperty, irParent = this, origin = origin originalProperty, irParent = this, origin = origin
) )
declarations += irProperty.withProperty { declarations += irProperty.withProperty {
@@ -119,7 +117,7 @@ class Fir2IrFakeOverrideGenerator(
) )
val fakeOverrideProperty = fakeOverrideSymbol.fir val fakeOverrideProperty = fakeOverrideSymbol.fir
val irProperty = declarationStorage.getIrProperty( val irProperty = declarationStorage.createIrProperty(
fakeOverrideProperty, irParent = this, origin = origin fakeOverrideProperty, irParent = this, origin = origin
) )
declarations += irProperty.withProperty { declarations += irProperty.withProperty {
@@ -18,6 +18,8 @@ class Fir2IrLocalStorage {
private val cacheStack = mutableListOf<Fir2IrCallableCache>() private val cacheStack = mutableListOf<Fir2IrCallableCache>()
private val localClassCache = mutableMapOf<FirClass<*>, IrClass>()
fun enterCallable() { fun enterCallable() {
cacheStack += Fir2IrCallableCache() cacheStack += Fir2IrCallableCache()
} }
@@ -44,11 +46,7 @@ class Fir2IrLocalStorage {
} }
fun getLocalClass(localClass: FirClass<*>): IrClass? { fun getLocalClass(localClass: FirClass<*>): IrClass? {
for (cache in cacheStack.asReversed()) { return localClassCache[localClass]
val local = cache.getLocalClass(localClass)
if (local != null) return local
}
return null
} }
fun getLocalFunction(localFunction: FirFunction<*>): IrSimpleFunction? { fun getLocalFunction(localFunction: FirFunction<*>): IrSimpleFunction? {
@@ -68,7 +66,7 @@ class Fir2IrLocalStorage {
} }
fun putLocalClass(firClass: FirClass<*>, irClass: IrClass) { fun putLocalClass(firClass: FirClass<*>, irClass: IrClass) {
cacheStack.last().putLocalClass(firClass, irClass) localClassCache[firClass] = irClass
} }
fun putLocalFunction(firFunction: FirFunction<*>, irFunction: IrSimpleFunction) { fun putLocalFunction(firFunction: FirFunction<*>, irFunction: IrSimpleFunction) {
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -44,14 +42,14 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import java.util.* import java.util.*
class Fir2IrVisitor( class Fir2IrVisitor(
private val session: FirSession, private val session: FirSession,
private val moduleDescriptor: FirModuleDescriptor,
private val symbolTable: SymbolTable, private val symbolTable: SymbolTable,
private val sourceManager: PsiSourceManager, private val declarationStorage: Fir2IrDeclarationStorage,
private val converter: Fir2IrConverter,
private val typeConverter: Fir2IrTypeConverter,
override val irBuiltIns: IrBuiltIns, override val irBuiltIns: IrBuiltIns,
fakeOverrideMode: FakeOverrideMode fakeOverrideMode: FakeOverrideMode
) : FirDefaultVisitor<IrElement, Any?>(), IrGeneratorContextInterface { ) : FirDefaultVisitor<IrElement, Any?>(), IrGeneratorContextInterface {
@@ -63,40 +61,24 @@ class Fir2IrVisitor(
private val integerApproximator = IntegerLiteralTypeApproximationTransformer(session.firSymbolProvider, session.inferenceContext) private val integerApproximator = IntegerLiteralTypeApproximationTransformer(session.firSymbolProvider, session.inferenceContext)
private val declarationStorage = Fir2IrDeclarationStorage(session, symbolTable, moduleDescriptor) private val conversionScope = Fir2IrConversionScope()
private val typeConverter = Fir2IrTypeConverter(session, declarationStorage, irBuiltIns).also { private val fakeOverrideGenerator = Fir2IrFakeOverrideGenerator(session, declarationStorage, conversionScope, fakeOverrideMode)
declarationStorage.typeConverter = it
it.initBuiltinTypes()
}
private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() } private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() }
private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() } private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() }
private val conversionScope = Fir2IrConversionScope()
private fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration) private fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration)
private val fakeOverrideGenerator = Fir2IrFakeOverrideGenerator(session, declarationStorage, conversionScope, fakeOverrideMode)
override fun visitElement(element: FirElement, data: Any?): IrElement { override fun visitElement(element: FirElement, data: Any?): IrElement {
TODO("Should not be here: ${element.render()}") TODO("Should not be here: ${element.render()}")
} }
fun registerFile(file: FirFile) {
val irFile = IrFileImpl(
sourceManager.getOrCreateFileEntry(file.psi as KtFile),
moduleDescriptor.getPackage(file.packageFqName).fragments.first()
)
declarationStorage.registerFile(file, irFile)
}
override fun visitFile(file: FirFile, data: Any?): IrFile { override fun visitFile(file: FirFile, data: Any?): IrFile {
return conversionScope.withParent(declarationStorage.getIrFile(file)) { return conversionScope.withParent(declarationStorage.getIrFile(file)) {
file.declarations.forEach { file.declarations.forEach {
val irDeclaration = it.toIrDeclaration() ?: return@forEach it.toIrDeclaration()
declarations += irDeclaration
} }
annotations = file.annotations.mapNotNull { annotations = file.annotations.mapNotNull {
@@ -110,9 +92,14 @@ class Fir2IrVisitor(
return accept(this@Fir2IrVisitor, null) as IrDeclaration return accept(this@Fir2IrVisitor, null) as IrDeclaration
} }
// ==================================================================================
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Any?): IrElement { override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Any?): IrElement {
val irEnumEntry = declarationStorage.getIrEnumEntry(enumEntry, irParent = conversionScope.lastClass()) val irEnumEntry = declarationStorage.getCachedIrEnumEntry(enumEntry)!!
val correspondingClass = irEnumEntry.correspondingClass ?: return irEnumEntry val correspondingClass = irEnumEntry.correspondingClass ?: return irEnumEntry
declarationStorage.enterScope(irEnumEntry.descriptor)
declarationStorage.putEnumEntryClassInScope(enumEntry, correspondingClass)
converter.processAnonymousObjectMembers(enumEntry.initializer as FirAnonymousObject, correspondingClass)
conversionScope.withParent(correspondingClass) { conversionScope.withParent(correspondingClass) {
setClassContent(enumEntry.initializer as FirAnonymousObject) setClassContent(enumEntry.initializer as FirAnonymousObject)
irEnumEntry.initializerExpression = IrExpressionBodyImpl( irEnumEntry.initializerExpression = IrExpressionBodyImpl(
@@ -122,25 +109,27 @@ class Fir2IrVisitor(
) )
) )
} }
declarationStorage.leaveScope(irEnumEntry.descriptor)
return irEnumEntry return irEnumEntry
} }
private fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? =
declarations.filterIsInstance<FirConstructor>().firstOrNull()?.takeIf { it.isPrimary }
private fun IrClass.setClassContent(klass: FirClass<*>) { private fun IrClass.setClassContent(klass: FirClass<*>) {
declarationStorage.enterScope(descriptor) declarationStorage.enterScope(descriptor)
conversionScope.withClass(this) { conversionScope.withClass(this) {
val primaryConstructor = klass.getPrimaryConstructorIfAny() val primaryConstructor = klass.getPrimaryConstructorIfAny()
val irPrimaryConstructor = primaryConstructor?.accept(this@Fir2IrVisitor, null) as IrConstructor? val irPrimaryConstructor = primaryConstructor?.let { declarationStorage.getCachedIrConstructor(it)!! }
if (irPrimaryConstructor != null) { if (irPrimaryConstructor != null) {
declarations += irPrimaryConstructor with(declarationStorage) {
enterScope(irPrimaryConstructor.descriptor)
irPrimaryConstructor.valueParameters.forEach { symbolTable.introduceValueParameter(it) }
irPrimaryConstructor.putParametersInScope(primaryConstructor)
irPrimaryConstructor.setFunctionContent(irPrimaryConstructor.descriptor, primaryConstructor)
}
} }
val processedCallableNames = mutableListOf<Name>() val processedCallableNames = mutableListOf<Name>()
klass.declarations.forEach { klass.declarations.forEach {
if (it !is FirConstructor || !it.isPrimary) { if (it !is FirConstructor || !it.isPrimary) {
val irDeclaration = it.toIrDeclaration() ?: return@forEach it.toIrDeclaration() ?: return@forEach
declarations += irDeclaration
when (it) { when (it) {
is FirSimpleFunction -> processedCallableNames += it.name is FirSimpleFunction -> processedCallableNames += it.name
is FirProperty -> processedCallableNames += it.name is FirProperty -> processedCallableNames += it.name
@@ -159,16 +148,64 @@ class Fir2IrVisitor(
} }
override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement { override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement {
return conversionScope.withParent( if (regularClass.visibility == Visibilities.LOCAL) {
applyParentFromStackTo(declarationStorage.getIrClass(regularClass)) val irParent = conversionScope.parentFromStack()
) { val irClass = declarationStorage.getCachedIrClass(regularClass)?.apply { this.parent = irParent }
if (irClass != null) {
converter.processRegisteredLocalClassAndNestedClasses(regularClass, irClass)
return conversionScope.withParent(irClass) {
setClassContent(regularClass)
}
}
converter.processLocalClassAndNestedClasses(regularClass, irParent)
}
val irClass = declarationStorage.getCachedIrClass(regularClass)!!
return conversionScope.withParent(irClass) {
setClassContent(regularClass) setClassContent(regularClass)
} }
} }
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): IrElement {
val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that anonymous object is already cached
val irAnonymousObject = declarationStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent }
?: declarationStorage.createIrAnonymousObject(anonymousObject, irParent = irParent)
converter.processAnonymousObjectMembers(anonymousObject, irAnonymousObject)
conversionScope.withParent(irAnonymousObject) {
setClassContent(anonymousObject)
}
val anonymousClassType = irAnonymousObject.thisReceiver!!.type
return anonymousObject.convertWithOffsets { startOffset, endOffset ->
IrBlockImpl(
startOffset, endOffset, anonymousClassType, IrStatementOrigin.OBJECT_LITERAL,
listOf(
irAnonymousObject,
IrConstructorCallImpl.fromSymbolOwner(
startOffset,
endOffset,
anonymousClassType,
irAnonymousObject.constructors.first().symbol,
irAnonymousObject.typeParameters.size,
origin = IrStatementOrigin.OBJECT_LITERAL
)
)
)
}
}
// ==================================================================================
private fun <T : IrFunction> T.setFunctionContent(descriptor: FunctionDescriptor, firFunction: FirFunction<*>?): T { private fun <T : IrFunction> T.setFunctionContent(descriptor: FunctionDescriptor, firFunction: FirFunction<*>?): T {
conversionScope.withParent(this) { conversionScope.withParent(this) {
if (firFunction != null) { if (firFunction != null) {
if (this !is IrConstructor || !this.isPrimary) {
// Scope for primary constructor should be entered before class declaration processing
with(declarationStorage) {
enterScope(descriptor)
valueParameters.forEach { symbolTable.introduceValueParameter(it) }
putParametersInScope(firFunction)
}
}
for ((valueParameter, firValueParameter) in valueParameters.zip(firFunction.valueParameters)) { for ((valueParameter, firValueParameter) in valueParameters.zip(firFunction.valueParameters)) {
valueParameter.setDefaultValue(firValueParameter) valueParameter.setDefaultValue(firValueParameter)
} }
@@ -208,27 +245,18 @@ class Fir2IrVisitor(
} }
override fun visitConstructor(constructor: FirConstructor, data: Any?): IrElement { override fun visitConstructor(constructor: FirConstructor, data: Any?): IrElement {
val irConstructor = declarationStorage.getIrConstructor( val irConstructor = declarationStorage.getCachedIrConstructor(constructor)!!
constructor, irParent = conversionScope.lastClass()!!, shouldLeaveScope = false
)
return conversionScope.withFunction(irConstructor) { return conversionScope.withFunction(irConstructor) {
setFunctionContent(irConstructor.descriptor, constructor) setFunctionContent(irConstructor.descriptor, constructor)
} }
} }
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Any?): IrElement { override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Any?): IrElement {
val origin = IrDeclarationOrigin.DEFINED val irAnonymousInitializer = declarationStorage.getCachedIrAnonymousInitializer(anonymousInitializer)!!
val parent = conversionScope.lastClass()!! declarationStorage.enterScope(irAnonymousInitializer.descriptor)
return anonymousInitializer.convertWithOffsets { startOffset, endOffset -> irAnonymousInitializer.body = anonymousInitializer.body!!.convertToIrBlockBody()
symbolTable.declareAnonymousInitializer( declarationStorage.leaveScope(irAnonymousInitializer.descriptor)
startOffset, endOffset, origin, parent.descriptor return irAnonymousInitializer
).apply {
this.parent = parent
declarationStorage.enterScope(descriptor)
body = anonymousInitializer.body!!.convertToIrBlockBody()
declarationStorage.leaveScope(descriptor)
}
}
} }
private fun FirDelegatedConstructorCall.toIrDelegatingConstructorCall(): IrCallWithIndexedArgumentsBase? { private fun FirDelegatedConstructorCall.toIrDelegatingConstructorCall(): IrCallWithIndexedArgumentsBase? {
@@ -265,9 +293,12 @@ class Fir2IrVisitor(
} }
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement { override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement {
val irFunction = declarationStorage.getIrFunction( val irFunction = if (simpleFunction.visibility == Visibilities.LOCAL) {
simpleFunction, irParent = conversionScope.parent(), shouldLeaveScope = false val irParent = conversionScope.parent()
) declarationStorage.createIrFunction(simpleFunction, irParent)
} else {
declarationStorage.getCachedIrFunction(simpleFunction)!!
}
return conversionScope.withFunction(irFunction) { return conversionScope.withFunction(irFunction) {
setFunctionContent(irFunction.descriptor, simpleFunction) setFunctionContent(irFunction.descriptor, simpleFunction)
} }
@@ -275,7 +306,7 @@ class Fir2IrVisitor(
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): IrElement { override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): IrElement {
return anonymousFunction.convertWithOffsets { startOffset, endOffset -> return anonymousFunction.convertWithOffsets { startOffset, endOffset ->
val irFunction = declarationStorage.getIrFunction(anonymousFunction, conversionScope.parent(), shouldLeaveScope = false) val irFunction = declarationStorage.createIrFunction(anonymousFunction, conversionScope.parent())
conversionScope.withFunction(irFunction) { conversionScope.withFunction(irFunction) {
setFunctionContent(irFunction.descriptor, anonymousFunction) setFunctionContent(irFunction.descriptor, anonymousFunction)
} }
@@ -299,14 +330,13 @@ class Fir2IrVisitor(
val isNextVariable = initializer is FirFunctionCall && val isNextVariable = initializer is FirFunctionCall &&
initializer.resolvedNamedFunctionSymbol()?.callableId?.isIteratorNext() == true && initializer.resolvedNamedFunctionSymbol()?.callableId?.isIteratorNext() == true &&
variable.source.psi?.parent is KtForExpression variable.source.psi?.parent is KtForExpression
val irVariable = declarationStorage.createAndSaveIrVariable( val irVariable = declarationStorage.createIrVariable(
variable, if (isNextVariable) IrDeclarationOrigin.FOR_LOOP_VARIABLE else null variable, conversionScope.parentFromStack(), if (isNextVariable) IrDeclarationOrigin.FOR_LOOP_VARIABLE else null
) )
return applyParentFromStackTo(irVariable).apply { if (initializer != null) {
if (initializer != null) { irVariable.initializer = initializer.toIrExpression()
this.initializer = initializer.toIrExpression()
}
} }
return irVariable
} }
private fun IrProperty.createBackingField( private fun IrProperty.createBackingField(
@@ -373,14 +403,15 @@ class Fir2IrVisitor(
annotations = property.annotations.mapNotNull { annotations = property.annotations.mapNotNull {
it.accept(this@Fir2IrVisitor, null) as? IrConstructorCall it.accept(this@Fir2IrVisitor, null) as? IrConstructorCall
} }
declarationStorage.leaveScope(descriptor)
return this return this
} }
override fun visitProperty(property: FirProperty, data: Any?): IrElement { override fun visitProperty(property: FirProperty, data: Any?): IrElement {
if (property.isLocal) return visitLocalVariable(property) if (property.isLocal) return visitLocalVariable(property)
val irProperty = declarationStorage.getIrProperty(property, irParent = conversionScope.parent(), shouldLeaveScope = false) val irProperty = declarationStorage.getCachedIrProperty(property)!!
return conversionScope.withProperty(irProperty) { setPropertyContent(irProperty.descriptor, property) } return conversionScope.withProperty(irProperty) {
setPropertyContent(irProperty.descriptor, property)
}
} }
private fun IrFieldAccessExpression.setReceiver(declaration: IrDeclaration): IrFieldAccessExpression { private fun IrFieldAccessExpression.setReceiver(declaration: IrDeclaration): IrFieldAccessExpression {
@@ -400,11 +431,6 @@ class Fir2IrVisitor(
isDefault: Boolean isDefault: Boolean
) { ) {
conversionScope.withFunction(this) { conversionScope.withFunction(this) {
if (propertyAccessor != null) {
with(declarationStorage) { this@setPropertyAccessorContent.enterLocalScope(propertyAccessor) }
} else {
declarationStorage.enterScope(descriptor)
}
applyParentFromStackTo(this) applyParentFromStackTo(this)
setFunctionContent(descriptor, propertyAccessor) setFunctionContent(descriptor, propertyAccessor)
if (isDefault) { if (isDefault) {
@@ -518,14 +544,12 @@ class Fir2IrVisitor(
val irClass = symbol.owner val irClass = symbol.owner
val fir = firSymbol?.fir as? FirClass<*> val fir = firSymbol?.fir as? FirClass<*>
val irConstructor = fir?.getPrimaryConstructorIfAny()?.let { firConstructor -> val irConstructor = fir?.getPrimaryConstructorIfAny()?.let { firConstructor ->
declarationStorage.getIrConstructor(firConstructor, irParent = irClass) declarationStorage.getIrConstructorSymbol(firConstructor.symbol)
}?.apply {
this.parent = irClass
} }
if (irConstructor == null) { if (irConstructor == null) {
IrErrorCallExpressionImpl(startOffset, endOffset, type, "No annotation constructor found: ${irClass.name}") IrErrorCallExpressionImpl(startOffset, endOffset, type, "No annotation constructor found: ${irClass.name}")
} else { } else {
IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, irConstructor.symbol) IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, irConstructor)
} }
} }
@@ -623,7 +647,7 @@ class Fir2IrVisitor(
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
} }
firClass?.convertWithOffsets { startOffset, endOffset -> firClass?.convertWithOffsets { startOffset, endOffset ->
val irClass = declarationStorage.getIrClass(firClass) val irClass = declarationStorage.getCachedIrClass(firClass)!!
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol) IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
} }
} }
@@ -691,7 +715,7 @@ class Fir2IrVisitor(
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
} }
if (firObject != null) { if (firObject != null) {
val irObject = declarationStorage.getIrClass(firObject) val irObject = declarationStorage.getCachedIrClass(firObject)!!
if (irObject != conversionScope.lastClass()) { if (irObject != conversionScope.lastClass()) {
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset -> return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
IrGetObjectValueImpl(startOffset, endOffset, irObject.defaultType, irObject.symbol) IrGetObjectValueImpl(startOffset, endOffset, irObject.defaultType, irObject.symbol)
@@ -827,30 +851,6 @@ class Fir2IrVisitor(
} }
} }
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): IrElement {
val anonymousClass = declarationStorage.getIrAnonymousObject(anonymousObject)
conversionScope.withParent(applyParentFromStackTo(anonymousClass)) {
setClassContent(anonymousObject)
}
val anonymousClassType = anonymousClass.thisReceiver!!.type
return anonymousObject.convertWithOffsets { startOffset, endOffset ->
IrBlockImpl(
startOffset, endOffset, anonymousClassType, IrStatementOrigin.OBJECT_LITERAL,
listOf(
anonymousClass,
IrConstructorCallImpl.fromSymbolOwner(
startOffset,
endOffset,
anonymousClassType,
anonymousClass.constructors.first().symbol,
anonymousClass.typeParameters.size,
origin = IrStatementOrigin.OBJECT_LITERAL
)
)
)
}
}
// ================================================================================== // ==================================================================================
private fun FirStatement.toIrStatement(): IrStatement? { private fun FirStatement.toIrStatement(): IrStatement? {
@@ -1082,8 +1082,8 @@ class Fir2IrVisitor(
override fun visitCatch(catch: FirCatch, data: Any?): IrElement { override fun visitCatch(catch: FirCatch, data: Any?): IrElement {
return catch.convertWithOffsets { startOffset, endOffset -> return catch.convertWithOffsets { startOffset, endOffset ->
val catchParameter = declarationStorage.createAndSaveIrVariable(catch.parameter) val catchParameter = declarationStorage.createIrVariable(catch.parameter, conversionScope.parentFromStack())
IrCatchImpl(startOffset, endOffset, applyParentFromStackTo(catchParameter)).apply { IrCatchImpl(startOffset, endOffset, catchParameter).apply {
result = catch.block.convertToIrExpressionOrBlock() result = catch.block.convertToIrExpressionOrBlock()
} }
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// TODO: muted automatically, investigate should it be ran for JS or not // TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS, NATIVE // IGNORE_BACKEND: JS, NATIVE
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var result = "Fail" var result = "Fail"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS, JS_IR // IGNORE_BACKEND: JS, JS_IR
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A class A
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
class A class A
fun A.foo() = "OK" fun A.foo() = "OK"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun Int.is42With(that: Int) = this + 2 * that == 42 fun Int.is42With(that: Int) = this + 2 * that == 42
return if ((Int::is42With)(16, 13)) "OK" else "Fail" return if ((Int::is42With)(16, 13)) "OK" else "Fail"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A class A
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo(): String { fun foo(): String {
fun bar() = "OK" fun bar() = "OK"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(until: Int): String { fun foo(until: Int): String {
fun bar(x: Int): String = fun bar(x: Int): String =
if (x == until) "OK" else bar(x + 1) if (x == until) "OK" else bar(x + 1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo() = "OK" fun foo() = "OK"
return (::foo)() return (::foo)()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
val result = "OK" val result = "OK"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo(s: String) = s fun foo(s: String) = s
return (::foo)("OK") return (::foo)("OK")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
var state = 23 var state = 23
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// TODO: muted automatically, investigate should it be ran for JS or not // TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS, NATIVE // IGNORE_BACKEND: JS, NATIVE
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package example2 package example2
fun box() = Context.OsType.OK.toString() fun box() = Context.OsType.OK.toString()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun String.f(x: String): String { fun String.f(x: String): String {
fun String.g() = { this@f + this@g }() fun String.g() = { this@f + this@g }()
return x.g() return x.g()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class Base(val fn: () -> String) open class Base(val fn: () -> String)
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class Z(val s: Int) { open class Z(val s: Int) {
open fun a() {} open fun a() {}
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() : String { fun box() : String {
fun <T> local(s : T) : T { fun <T> local(s : T) : T {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun rec(n : Int) { fun rec(n : Int) {
fun x(m : Int) { fun x(m : Int) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun rec(n : Int) { fun rec(n : Int) {
fun x(m : Int, k : Int) { fun x(m : Int, k : Int) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo(x: Int) { fun foo(x: Int) {
fun bar(y: Int) { fun bar(y: Int) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo(x: Int, s: String): String { fun foo(x: Int, s: String): String {
fun bar(y: Int) { fun bar(y: Int) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
//KT-3276 //KT-3276
fun box(): String { fun box(): String {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() : String { fun box() : String {
fun <T> foo(t:() -> T) : T = t() fun <T> foo(t:() -> T) : T = t()
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
val x = "OK" val x = "OK"
fun bar(y: String = x): String = y fun bar(y: String = x): String = y
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
val o = "O" val o = "O"
fun ok() = o + "K" fun ok() = o + "K"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun local():Int { fun local():Int {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun local():Int { fun local():Int {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() : String { fun box() : String {
fun <T> local(s : T) : T { fun <T> local(s : T) : T {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(s: String): String { fun foo(s: String): String {
fun bar(count: Int): String = fun bar(count: Int): String =
if (count == 0) s else bar(count - 1) if (count == 0) s else bar(count - 1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS, JS_IR // IGNORE_BACKEND: JS, JS_IR
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
fun test() { fun test() {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package test package test
fun box() = MyEnum.E1.f() + MyEnum.E2.f() fun box() = MyEnum.E1.f() + MyEnum.E2.f()
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() = if(Context.operatingSystemType == Context.Companion.OsType.OTHER) "OK" else "fail" fun box() = if(Context.operatingSystemType == Context.Companion.OsType.OTHER) "OK" else "fail"
public class Context public class Context
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
enum class X { enum class X {
B { B {
val value2 = "K" val value2 = "K"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
fun box(): String { fun box(): String {
val sb = StringBuilder() val sb = StringBuilder()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun String.foo() : String { fun String.foo() : String {
fun Int.bar() : String { fun Int.bar() : String {
fun Long.baz() : String { fun Long.baz() : String {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun rmrf(i: Int) { fun rmrf(i: Int) {
if (i > 0) rmrf(i - 1) if (i > 0) rmrf(i - 1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun <T, V : T> f(x: V): V { fun <T, V : T> f(x: V): V {
fun g(y: V) = y fun g(y: V) = y
return g(x) return g(x)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun outer() { fun outer() {
fun inner(i: Int) { fun inner(i: Int) {
if (i > 0){ if (i > 0){
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun <T> foo(t: T) = t fun <T> foo(t: T) = t
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() : String { fun box() : String {
fun local(i: Int = 1) : Int { fun local(i: Int = 1) : Int {
return i return i
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class C() { class C() {
fun box(): Int { fun box(): Int {
fun local(i: Int = 1): Int { fun local(i: Int = 1): Int {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(f: (Int?) -> Int): Int { fun foo(f: (Int?) -> Int): Int {
return f(0) return f(0)
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
infix fun Int.foo(a: Int): Int = a + 2 infix fun Int.foo(a: Int): Int = a + 2
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun String.f() = this fun String.f() = this
val vf: String.() -> String = { this } val vf: String.() -> String = { this }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class T(val value: Int) { class T(val value: Int) {
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class It(val id: String) class It(val id: String)
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var s = "" var s = ""
var foo = "O" var foo = "O"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun test(b: Boolean): String { fun test(b: Boolean): String {
if (b) { if (b) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
fun foo(x: String) = x fun foo(x: String) = x
fun foo() = foo("K") fun foo() = foo("K")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var s = "" var s = ""
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var s = "" var s = ""
var foo = "K" var foo = "K"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var s = "" var s = ""
var foo = "K" var foo = "K"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var s = "" var s = ""
var foo = "O" var foo = "O"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(): String { fun foo(): String {
fun bar(x: String, y: String = x): String { fun bar(x: String, y: String = x): String {
return y return y
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class Holder<T: Any>(val v: T) class Holder<T: Any>(val v: T)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(x: String): String { fun foo(x: String): String {
fun bar(y: String) = x + y fun bar(y: String) = x + y
return bar("K") return bar("K")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun <X : Any> foo(x: X): String { fun <X : Any> foo(x: X): String {
fun <Y : Any> bar(y: Y) = fun <Y : Any> bar(y: Y) =
x.toString() + y.toString() x.toString() + y.toString()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun foo(x: String): String { fun foo(x: String): String {
fun bar(y: String): String { fun bar(y: String): String {
fun qux(z: String): String = fun qux(z: String): String =
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun String.foo(): String { fun String.foo(): String {
fun bar(y: String) = this + y fun bar(y: String) = this + y
return bar("K") return bar("K")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var result = "" var result = ""
fun add(s: String) { fun add(s: String) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
data class A(val a: Int, val b: Int) data class A(val a: Int, val b: Int)
fun box() : String fun box() : String
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class C(val s: String) { open class C(val s: String) {
fun test(): String { fun test(): String {
return s return s
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var x = "" var x = ""
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var x = "" var x = ""
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A { class A {
operator fun component1() = 1 operator fun component1() = 1
operator fun component2() = 2 operator fun component2() = 2
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperVisibilityForCompanionObjectInstanceField // !LANGUAGE: +ProperVisibilityForCompanionObjectInstanceField
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: fromAnonymousObjectInNestedClass.kt // FILE: fromAnonymousObjectInNestedClass.kt
import outer.* import outer.*
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperVisibilityForCompanionObjectInstanceField // !LANGUAGE: +ProperVisibilityForCompanionObjectInstanceField
// IGNORE_BACKEND_FIR: JVM_IR
class Outer { class Outer {
private companion object { private companion object {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
var boo = "OK" var boo = "OK"
var foo = object { var foo = object {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package p package p
private class C(val y: Int) { private class C(val y: Int) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A(open val v: String) open class A(open val v: String)
fun A.a(newv: String) = object: A("fail") { fun A.a(newv: String) = object: A("fail") {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
operator fun Int?.inc() = (this ?: 0) + 1 operator fun Int?.inc() = (this ?: 0) + 1
var counter: Int? = null var counter: Int? = null
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_JDK6 // SKIP_JDK6
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
private class One { private class One {
val a1 = arrayOf( val a1 = arrayOf(
object { val fy = "text"} object { val fy = "text"}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class Foo { class Foo {
fun bar(): String { fun bar(): String {
fun <T> foo(t:() -> T) : T = t() fun <T> foo(t:() -> T) : T = t()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -108,7 +108,7 @@ FILE fqName:<root> fileName:/partialSam.kt
BLOCK_BODY BLOCK_BODY
CALL 'public final fun runConversion (f1: <root>.Fn<kotlin.String, kotlin.Int>, f2: <root>.Fn<kotlin.Int, kotlin.String>): kotlin.Int declared in <root>.J' type=kotlin.Int origin=null CALL 'public final fun runConversion (f1: <root>.Fn<kotlin.String, kotlin.Int>, f2: <root>.Fn<kotlin.Int, kotlin.String>): kotlin.Int declared in <root>.J' type=kotlin.Int origin=null
$this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null $this: GET_VAR 'j: <root>.J declared in <root>.test' type=<root>.J origin=null
f1: CALL 'public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>' type=<uninitialized parent>.<no name provided> origin=GET_PROPERTY f1: CALL 'public final fun <get-fsi> (): <root>.fsi.<no name provided> declared in <root>' type=<root>.fsi.<no name provided> origin=GET_PROPERTY
f2: FUN_EXPR type=kotlin.Function3<kotlin.String, kotlin.Int, kotlin.Int, kotlin.String> origin=LAMBDA f2: FUN_EXPR type=kotlin.Function3<kotlin.String, kotlin.Int, kotlin.Int, kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (s:kotlin.String, i:kotlin.Int, ti:kotlin.Int) returnType:kotlin.String FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (s:kotlin.String, i:kotlin.Int, ti:kotlin.Int) returnType:kotlin.String
VALUE_PARAMETER name:s index:0 type:kotlin.String VALUE_PARAMETER name:s index:0 type:kotlin.String
@@ -127,4 +127,4 @@ FILE fqName:<root> fileName:/partialSam.kt
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (s: kotlin.String, i: kotlin.Int, ts: kotlin.String): kotlin.Int declared in <root>.test' RETURN type=kotlin.Nothing from='local final fun <anonymous> (s: kotlin.String, i: kotlin.Int, ts: kotlin.String): kotlin.Int declared in <root>.test'
CONST Int type=kotlin.Int value=1 CONST Int type=kotlin.Int value=1
f2: CALL 'public final fun <get-fis> (): <root>.fis.<no name provided> declared in <root>' type=<uninitialized parent>.<no name provided> origin=GET_PROPERTY f2: CALL 'public final fun <get-fis> (): <root>.fis.<no name provided> declared in <root>' type=<root>.fis.<no name provided> origin=GET_PROPERTY
+1 -1
View File
@@ -11,4 +11,4 @@ FILE fqName:<root> fileName:/localFunction.kt
CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.outer.local' type=kotlin.Int origin=null $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.outer.local' type=kotlin.Int origin=null
GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.outer.local' type=kotlin.Int origin=null GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.outer.local' type=kotlin.Int origin=null
CALL 'local final fun local (): kotlin.Unit declared in <local>' type=kotlin.Unit origin=null CALL 'local final fun local (): kotlin.Unit declared in <root>.outer' type=kotlin.Unit origin=null