From 3bea3eca2b855be223dbfe22489304da8be719ed Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Fri, 19 Oct 2018 16:46:18 +0300 Subject: [PATCH] [JS IR BE] Support external enum classes * add lowering pass * fix EQEQ operator --- .../ir/backend/js/JsIrBackendContext.kt | 4 +- .../kotlin/ir/backend/js/compiler.kt | 1 + .../ir/backend/js/lower/EnumClassLowering.kt | 16 +++--- .../backend/js/lower/ExternalEnumLowering.kt | 56 +++++++++++++++++++ .../EqualityAndComparisonCallsTransformer.kt | 1 + 5 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 099536e068b..66685a918a7 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol @@ -34,7 +35,6 @@ import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.getPropertyDeclaration import org.jetbrains.kotlin.ir.util.kotlinPackageFqn -import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -110,7 +110,7 @@ class JsIrBackendContext( private val coroutinePackage = module.getPackage(COROUTINE_PACKAGE_FQNAME) private val coroutineIntrinsicsPackage = module.getPackage(COROUTINE_INTRINSICS_PACKAGE_FQNAME) - val enumEntryToGetInstanceFunction = mutableMapOf() + val enumEntryToGetInstanceFunction = mutableMapOf IrExpression>() val coroutineGetContext: IrFunctionSymbol get() { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index bce360c6380..70a254bb9d4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -73,6 +73,7 @@ fun compile( moduleFragment.files.forEach { irFile -> extension.generate(irFile, context, psi2IrContext.bindingContext) } } + ExternalEnumLowering(context).runOnFilesPostfix(moduleFragment) MoveExternalDeclarationsToSeparatePlace().lower(moduleFragment) ExpectDeclarationsRemoving(context).lower(moduleFragment) CoroutineIntrinsicLowering(context).lower(moduleFragment) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 9ff7e7d60ba..5fb76d9655b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -35,7 +35,7 @@ class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(object : IrElementTransformerVoid() { override fun visitGetEnumValue(expression: IrGetEnumValue) = - JsIrBuilder.buildCall(context.enumEntryToGetInstanceFunction[expression.symbol]!!) + context.enumEntryToGetInstanceFunction[expression.symbol]!!.invoke() }) } } @@ -49,7 +49,7 @@ class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerL } else { EnumClassTransformer(context, declaration).transform() } - } else + } else listOf(declaration) } } @@ -137,9 +137,9 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: irWhen( irClass.defaultType, enumEntries.map { - val getInstance = entryInstanceToFunction[it.symbol]!! irBranch( - irEquals(irString(it.name.identifier), irGet(nameParameter)), irCall(getInstance) + irEquals(irString(it.name.identifier), irGet(nameParameter)), + entryInstanceToFunction[it.symbol]!!.invoke() ) } + irElseBranch(irCall(throwISESymbol)) ) @@ -163,10 +163,8 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: return context.createIrBuilder(valuesFun.symbol).run { irBlockBody { +irReturn( - enumEntries.map { - val function = entryInstanceToFunction[it.symbol]!! - irCall(function) - }.toArrayLiteral(valuesFun.returnType, irClass.defaultType) + enumEntries.map { entryInstanceToFunction[it.symbol]!!.invoke() } + .toArrayLiteral(valuesFun.returnType, irClass.defaultType) ) } } @@ -246,7 +244,7 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: +irCall(initEntryInstancesFun) +irReturn(irGet(entryInstances[index])) }.apply { - context.enumEntryToGetInstanceFunction[enumEntry.symbol] = this@apply.symbol + context.enumEntryToGetInstanceFunction[enumEntry.symbol] = { JsIrBuilder.buildCall(this@apply.symbol) } } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt new file mode 100644 index 00000000000..069c45b4687 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ExternalEnumLowering.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrEnumEntry +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.isEnumClass + +// TODO: Shouldn't it be lazy pass? +class ExternalEnumLowering(val context: JsIrBackendContext) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + if (!irClass.isExternal) return + if (!irClass.isEnumClass) return + + irClass.declarations.filterIsInstance().forEach { + val enumField = createFieldForEntry(it, irClass) + context.enumEntryToGetInstanceFunction[it.symbol] = { + JsIrBuilder.buildGetField(enumField.symbol, classAsReceiver(irClass), null, irClass.defaultType) + } + } + } + + private fun classAsReceiver(irClass: IrClass): IrExpression { + val intrinsic = context.intrinsics.jsClass + return JsIrBuilder.buildCall(intrinsic, context.irBuiltIns.anyType, listOf(irClass.defaultType)) + } + + + private fun createFieldForEntry(entry: IrEnumEntry, irClass: IrClass): IrField { + val descriptor = WrappedPropertyDescriptor() + val symbol = IrFieldSymbolImpl(descriptor) + return entry.run { + IrFieldImpl(startOffset, endOffset, origin, symbol, name, irClass.defaultType, Visibilities.DEFAULT_VISIBILITY, false, true, true ).also { f -> + descriptor.bind(f) + f.parent = irClass + irClass.declarations += f + + } + } + } + + +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EqualityAndComparisonCallsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EqualityAndComparisonCallsTransformer.kt index 88c05127b8d..3c1405a698d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EqualityAndComparisonCallsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EqualityAndComparisonCallsTransformer.kt @@ -142,6 +142,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls private fun IrType.findEqualsMethod(): IrSimpleFunction? { val klass = getClass() ?: return null + if (klass.isEnumClass && klass.isExternal) return null return klass.declarations .filterIsInstance() .filter { it.isEqualsInheritedFromAny() && !it.isFakeOverriddenFromAny() }