[JS IR BE] Support external enum classes

* add lowering pass
 * fix EQEQ operator
This commit is contained in:
Roman Artemev
2018-10-19 16:46:18 +03:00
committed by romanart
parent eed22b0485
commit 3bea3eca2b
5 changed files with 67 additions and 11 deletions
@@ -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<IrEnumEntrySymbol, IrSimpleFunctionSymbol>()
val enumEntryToGetInstanceFunction = mutableMapOf<IrEnumEntrySymbol, () -> IrExpression>()
val coroutineGetContext: IrFunctionSymbol
get() {
@@ -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)
@@ -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) }
}
}
@@ -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<IrEnumEntry>().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
}
}
}
}
@@ -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<IrSimpleFunction>()
.filter { it.isEqualsInheritedFromAny() && !it.isFakeOverriddenFromAny() }