diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt index 612a33965cf..d1fa1c08699 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt @@ -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) 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 e281f8d2977..911d44e1b8e 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 @@ -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() + + 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] diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt index 929b5958ed7..70bb41239ff 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt @@ -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) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 2d489dbd261..0de33ed220b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -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 } ) ) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt index af03757577c..4eadec8a0ca 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt index aea1e6816d3..709937d0879 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt @@ -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()