[JS IR BE] Add basic support for external declarations

This commit is contained in:
Zalim Bashorov
2018-07-24 01:56:52 +03:00
parent 3c0d0d2ab4
commit 4a7ecaa908
6 changed files with 67 additions and 13 deletions
@@ -59,8 +59,8 @@ object JsIrBuilder {
fun buildSetVariable(symbol: IrVariableSymbol, value: IrExpression, type: IrType) =
IrSetVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, value, SYNTHESIZED_STATEMENT)
fun buildGetField(symbol: IrFieldSymbol, receiver: IrExpression?, superQualifierSymbol: IrClassSymbol? = null) =
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, symbol.owner.type, receiver, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildGetField(symbol: IrFieldSymbol, receiver: IrExpression?, superQualifierSymbol: IrClassSymbol? = null, type: IrType? = null) =
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, type ?: symbol.owner.type, receiver, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildSetField(symbol: IrFieldSymbol, receiver: IrExpression?, value: IrExpression, type: IrType, superQualifierSymbol: IrClassSymbol? = null) =
IrSetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, receiver, value, type, SYNTHESIZED_STATEMENT, superQualifierSymbol)
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNullable
@@ -64,6 +65,9 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
// Pass these parameters to delegating constructor calls
lowerEnumConstructorsBody()
// The first step creates a new `IrConstructor` with new `IrValueParameter`s so references to old `IrValueParameter`s must be replaced with new ones.
fixReferencesToConstructorParameters()
// Create instance variable for each enum entry initialized with `null`
val entryInstances = createEnumEntryInstanceVariables()
@@ -95,6 +99,29 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns
}
private fun fixReferencesToConstructorParameters() {
val fromOldToNewParameter = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
loweredEnumConstructors.forEach { (oldCtorSymbol, newCtor) ->
val oldParameters = oldCtorSymbol.owner.valueParameters
val newParameters = newCtor.valueParameters
oldParameters.forEach { old ->
fromOldToNewParameter[old.symbol] = newParameters.single { it.name == old.name }
}
}
irClass.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
fromOldToNewParameter[expression.symbol]?.let {
return builder.irGet(it)
}
return super.visitGetValue(expression)
}
})
}
private fun createEnumValueOfBody(): IrBody {
val valueOfFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUEOF)
val nameParameter = valueOfFun.valueParameters[0]
@@ -9,12 +9,10 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.utils.isNullable
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOfClass
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.ConversionNames
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
import org.jetbrains.kotlin.ir.backend.js.utils.isFakeOverriddenFromAny
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -23,6 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.isNullConst
@@ -262,6 +261,22 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
if (call is IrCall) {
val symbol = call.symbol
if (symbol.isEffectivelyExternal()) {
when (call.origin) {
IrStatementOrigin.GET_PROPERTY -> {
val fieldSymbol = IrFieldSymbolImpl((symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty)
return JsIrBuilder.buildGetField(fieldSymbol, call.dispatchReceiver, type = call.type)
}
// assignment to a property
IrStatementOrigin.EQ -> {
val fieldSymbol = IrFieldSymbolImpl((symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty)
return JsIrBuilder.buildSetField(fieldSymbol, call.dispatchReceiver, call.getValueArgument(0)!!, call.type)
}
}
}
symbolToTransformer[symbol]?.let {
return it(call)
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.isEffectivelyExternal
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -84,7 +85,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
if (!irClass.isInterface) {
declaration.resolveFakeOverride()?.let {
val implClassDesc = it.descriptor.containingDeclaration as ClassDescriptor
if (!KotlinBuiltIns.isAny(implClassDesc)) {
if (!KotlinBuiltIns.isAny(implClassDesc) && !it.isEffectivelyExternal()) {
val implMethodName = context.getNameForSymbol(it.symbol)
val implClassName = context.getNameForSymbol(IrClassSymbolImpl(implClassDesc))
@@ -164,7 +165,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
JsArrayLiteral(
irClass.superTypes.mapNotNull {
val symbol = it.classifierOrFail
if (symbol.isInterface) JsNameRef(context.getNameForSymbol(symbol)) else null
// TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal
if (symbol.isInterface && !symbol.isEffectivelyExternal()) JsNameRef(context.getNameForSymbol(symbol)) else null
}
)
)
@@ -6,13 +6,13 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -30,6 +30,16 @@ class SimpleNameGenerator : NameGenerator {
private fun getNameForDescriptor(descriptor: DeclarationDescriptor, context: JsGenerationContext): JsName =
nameCache.getOrPut(descriptor) {
var nameDeclarator: (String) -> JsName = context.currentScope::declareName
if (descriptor is MemberDescriptor && descriptor.isEffectivelyExternal()) {
val descriptorForName = when (descriptor) {
is ConstructorDescriptor -> descriptor.constructedClass
is PropertyAccessorDescriptor -> descriptor.correspondingProperty
else -> descriptor
}
return@getOrPut nameDeclarator(descriptorForName.name.asString())
}
val nameBuilder = StringBuilder()
when (descriptor) {
is ReceiverParameterDescriptor -> {
@@ -42,10 +52,7 @@ class SimpleNameGenerator : NameGenerator {
is ValueParameterDescriptor -> {
val declaredName = descriptor.name.asString()
nameBuilder.append(declaredName)
if (declaredName.startsWith("\$")) {
nameBuilder.append('_')
nameBuilder.append(descriptor.index)
}
nameDeclarator = context.currentScope::declareFreshName
}
is PropertyDescriptor -> {
nameBuilder.append(descriptor.name.identifier)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.types.KotlinType
@@ -50,3 +51,5 @@ fun CallableMemberDescriptor.isFakeOverriddenFromAny(): Boolean {
}
fun IrDeclaration.isEffectivelyExternal() = descriptor.isEffectivelyExternal()
fun IrSymbol.isEffectivelyExternal() = descriptor.isEffectivelyExternal()