diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index fc5b964e53d..21300f472c9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -124,6 +124,13 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC PrimitiveType.DOUBLE to getInternalFunction("isLongArray") ) + + // Enum + + val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic") + val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic") + + // Other: val jsObjectCreate = defineObjectCreateIntrinsic() // Object.create 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 e3fe25548c1..99f7e739f50 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 @@ -102,7 +102,6 @@ private fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) } private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependencies: List) { -<<<<<<< HEAD moduleFragment.files.forEach(UnitMaterializationLowering(this)::lower) moduleFragment.files.forEach(EnumClassLowering(this)::runOnFilePostfix) moduleFragment.files.forEach(EnumUsageLowering(this)::lower) 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 9da2fa7d1c6..d7d08cc7e3b 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 @@ -148,12 +148,9 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } private fun List.toArrayLiteral(arrayType: IrType, elementType: IrType): IrExpression { - val startOffset = firstOrNull()?.startOffset ?: UNDEFINED_OFFSET - val endOffset = lastOrNull()?.endOffset ?: UNDEFINED_OFFSET + val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this) - val irVararg = IrVarargImpl(startOffset, endOffset, arrayType, elementType, this) - - return IrCallImpl(startOffset, endOffset, arrayType, context.intrinsics.arrayLiteral).apply { + return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply { putValueArgument(0, irVararg) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/CallsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/CallsLowering.kt index e00b30e4bcc..95c4bc607e9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/CallsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/CallsLowering.kt @@ -23,7 +23,8 @@ class CallsLowering(val context: JsIrBackendContext) : FileLoweringPass { EqualityAndComparisonCallsTransformer(context), PrimitiveContainerMemberCallTransformer(context), MethodsOfAnyCallsTransformer(context), - ReflectionCallsTransformer(context) + ReflectionCallsTransformer(context), + EnumIntrinsicsTransformer(context) ) override fun lower(irFile: IrFile) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt new file mode 100644 index 00000000000..312c1de788a --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt @@ -0,0 +1,50 @@ +/* + * 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.calls + +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.ir.irCall +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.isStatic +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.types.getClass +import org.jetbrains.kotlin.ir.types.isString +import org.jetbrains.kotlin.ir.util.findDeclaration +import org.jetbrains.kotlin.ir.util.isEnumClass +import org.jetbrains.kotlin.name.Name + + +class EnumIntrinsicsTransformer(private val context: JsIrBackendContext) : CallsTransformer { + private fun transformEnumTopLevelIntrinsic( + call: IrCall, + staticMethodPredicate: (IrSimpleFunction) -> Boolean + ): IrExpression { + val enum = call.getTypeArgument(0)?.getClass() ?: return call + if (!enum.isEnumClass) return call + val staticMethod = enum.findDeclaration(staticMethodPredicate) + if (staticMethod == null || !staticMethod.isStatic) + throw IllegalStateException("Enum class should have static method for ${call.symbol.owner.name}") + + return irCall(call, staticMethod.symbol) + } + + private fun transformEnumValueOfIntrinsic(call: IrCall) = transformEnumTopLevelIntrinsic(call) { + it.name == Name.identifier("valueOf") && + it.valueParameters.count() == 1 && + it.valueParameters[0].type.isString() + } + + private fun transformEnumValuesIntrinsic(call: IrCall) = transformEnumTopLevelIntrinsic(call) { + it.name == Name.identifier("values") && it.valueParameters.count() == 0 + } + + override fun transformCall(call: IrCall) = when (call.symbol) { + context.intrinsics.enumValueOfIntrinsic -> transformEnumValueOfIntrinsic(call) + context.intrinsics.enumValuesIntrinsic -> transformEnumValuesIntrinsic(call) + else -> call + } +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt index 7b6f3897d70..03ad060a371 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.js.backend.ast.* @@ -79,7 +80,8 @@ fun translateCallArguments(expression: IrMemberAccessExpression, context: JsGene } else arguments } -val IrFunction.isStatic: Boolean get() = this.dispatchReceiverParameter == null +val IrFunction.isStatic: Boolean + get() = parent is IrClass && dispatchReceiverParameter == null fun JsStatement.asBlock() = this as? JsBlock ?: JsBlock(this) 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 9723a654e6c..b14dd91d987 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,6 +6,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.isStatic import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -176,7 +177,7 @@ class SimpleNameGenerator : NameGenerator { } is IrSimpleFunction -> { - if (declaration.dispatchReceiverParameter == null && declaration.parent is IrClass) { + if (declaration.isStatic) { nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context)) nameBuilder.append('.') } diff --git a/compiler/testData/codegen/box/reflection/methodsFromAny/functionEqualsHashCode.kt b/compiler/testData/codegen/box/reflection/methodsFromAny/functionEqualsHashCode.kt index 72b169fe9fb..cb3c7288eec 100644 --- a/compiler/testData/codegen/box/reflection/methodsFromAny/functionEqualsHashCode.kt +++ b/compiler/testData/codegen/box/reflection/methodsFromAny/functionEqualsHashCode.kt @@ -1,4 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE // WITH_REFLECT diff --git a/compiler/testData/codegen/box/reflection/methodsFromAny/propertyEqualsHashCode.kt b/compiler/testData/codegen/box/reflection/methodsFromAny/propertyEqualsHashCode.kt index 82dc465e532..d2e332c3b24 100644 --- a/compiler/testData/codegen/box/reflection/methodsFromAny/propertyEqualsHashCode.kt +++ b/compiler/testData/codegen/box/reflection/methodsFromAny/propertyEqualsHashCode.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE // WITH_REFLECT diff --git a/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt b/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt index e6343fe779f..b2fd2b389c6 100644 --- a/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt +++ b/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // CHECK_CASES_COUNT: function=crash count=2 // CHECK_IF_COUNT: function=crash count=1 diff --git a/compiler/testData/codegen/boxInline/enum/kt10569.kt b/compiler/testData/codegen/boxInline/enum/kt10569.kt index 3218943f26e..2ffd30c8ad8 100644 --- a/compiler/testData/codegen/boxInline/enum/kt10569.kt +++ b/compiler/testData/codegen/boxInline/enum/kt10569.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/kt18254.kt b/compiler/testData/codegen/boxInline/enum/kt18254.kt index 3d6b2ed7727..eb5cf04573c 100644 --- a/compiler/testData/codegen/boxInline/enum/kt18254.kt +++ b/compiler/testData/codegen/boxInline/enum/kt18254.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valueOf.kt b/compiler/testData/codegen/boxInline/enum/valueOf.kt index 1fd2236cd41..5a9f2420163 100644 --- a/compiler/testData/codegen/boxInline/enum/valueOf.kt +++ b/compiler/testData/codegen/boxInline/enum/valueOf.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valueOfCapturedType.kt b/compiler/testData/codegen/boxInline/enum/valueOfCapturedType.kt index 2ebb48efcc1..14bc52fb041 100644 --- a/compiler/testData/codegen/boxInline/enum/valueOfCapturedType.kt +++ b/compiler/testData/codegen/boxInline/enum/valueOfCapturedType.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valueOfChain.kt b/compiler/testData/codegen/boxInline/enum/valueOfChain.kt index 2527674dfea..15d240b28c5 100644 --- a/compiler/testData/codegen/boxInline/enum/valueOfChain.kt +++ b/compiler/testData/codegen/boxInline/enum/valueOfChain.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valueOfChainCapturedType.kt b/compiler/testData/codegen/boxInline/enum/valueOfChainCapturedType.kt index 2e364e642c0..77892c6d74d 100644 --- a/compiler/testData/codegen/boxInline/enum/valueOfChainCapturedType.kt +++ b/compiler/testData/codegen/boxInline/enum/valueOfChainCapturedType.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valueOfNonReified.kt b/compiler/testData/codegen/boxInline/enum/valueOfNonReified.kt index 5c4213867d6..761813faec2 100644 --- a/compiler/testData/codegen/boxInline/enum/valueOfNonReified.kt +++ b/compiler/testData/codegen/boxInline/enum/valueOfNonReified.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/values.kt b/compiler/testData/codegen/boxInline/enum/values.kt index 220abfcb66d..b0f397f5a1a 100644 --- a/compiler/testData/codegen/boxInline/enum/values.kt +++ b/compiler/testData/codegen/boxInline/enum/values.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valuesAsArray.kt b/compiler/testData/codegen/boxInline/enum/valuesAsArray.kt index 28598cabefa..027b228d6be 100644 --- a/compiler/testData/codegen/boxInline/enum/valuesAsArray.kt +++ b/compiler/testData/codegen/boxInline/enum/valuesAsArray.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valuesCapturedType.kt b/compiler/testData/codegen/boxInline/enum/valuesCapturedType.kt index 867a9809838..a4abc639f8d 100644 --- a/compiler/testData/codegen/boxInline/enum/valuesCapturedType.kt +++ b/compiler/testData/codegen/boxInline/enum/valuesCapturedType.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valuesChain.kt b/compiler/testData/codegen/boxInline/enum/valuesChain.kt index 639938d196b..2207e07e806 100644 --- a/compiler/testData/codegen/boxInline/enum/valuesChain.kt +++ b/compiler/testData/codegen/boxInline/enum/valuesChain.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valuesChainCapturedType.kt b/compiler/testData/codegen/boxInline/enum/valuesChainCapturedType.kt index 56057eab22f..ba145eb8676 100644 --- a/compiler/testData/codegen/boxInline/enum/valuesChainCapturedType.kt +++ b/compiler/testData/codegen/boxInline/enum/valuesChainCapturedType.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/enum/valuesNonReified.kt b/compiler/testData/codegen/boxInline/enum/valuesNonReified.kt index 267f88a1081..fee857c2c3c 100644 --- a/compiler/testData/codegen/boxInline/enum/valuesNonReified.kt +++ b/compiler/testData/codegen/boxInline/enum/valuesNonReified.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // FILE: 1.kt // WITH_RUNTIME package test diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 73f38903083..64bf388125c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -1584,6 +1584,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/enum/simpleEnum.kt"); } + @TestMetadata("standardFunctions.kt") + public void testStandardFunctions() throws Exception { + runTest("js/js.translator/testData/box/enum/standardFunctions.kt"); + } + @TestMetadata("standardMethods.kt") public void testStandardMethods() throws Exception { runTest("js/js.translator/testData/box/enum/standardMethods.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index b85956c86e7..c6bec58bdfa 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -1584,6 +1584,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/enum/simpleEnum.kt"); } + @TestMetadata("standardFunctions.kt") + public void testStandardFunctions() throws Exception { + runTest("js/js.translator/testData/box/enum/standardFunctions.kt"); + } + @TestMetadata("standardMethods.kt") public void testStandardMethods() throws Exception { runTest("js/js.translator/testData/box/enum/standardMethods.kt"); diff --git a/js/js.translator/testData/box/enum/standardFunctions.kt b/js/js.translator/testData/box/enum/standardFunctions.kt new file mode 100644 index 00000000000..9bf6f290229 --- /dev/null +++ b/js/js.translator/testData/box/enum/standardFunctions.kt @@ -0,0 +1,18 @@ +// EXPECTED_REACHABLE_NODES: 1555 +package foo + +enum class EmptyEnum + +enum class A { + a() { + }, + b(), + c +} + +fun box(): String { + if (enumValues().size != 0) return "enumValues().size != 0" + if (enumValues().asList() != listOf(A.a, A.b, A.c)) return "Wrong enumValues(): " + enumValues().toString() + if (enumValueOf("b") != A.b) return "enumValueOf('b') != A.b" + return "OK" +} \ No newline at end of file diff --git a/libraries/stdlib/js/irRuntime/Enum.kt b/libraries/stdlib/js/irRuntime/Enum.kt index 1160f711da3..a4255f598b1 100644 --- a/libraries/stdlib/js/irRuntime/Enum.kt +++ b/libraries/stdlib/js/irRuntime/Enum.kt @@ -5,7 +5,9 @@ package kotlin -public class Enum>(val name: String, val ordinal: Int) : Comparable { +import kotlin.js.* + +abstract class Enum>(val name: String, val ordinal: Int) : Comparable { override fun compareTo(other: E) = ordinal.compareTo(other.ordinal) @@ -16,4 +18,14 @@ public class Enum>(val name: String, val ordinal: Int) : Comparable< override fun toString() = name companion object -} \ No newline at end of file +} + +// Use non-inline calls to enumValuesIntrinsic and enumValueOfIntrinsic calls in order +// for compiler to replace them with method calls of concrete enum classes after inlining. +// TODO: Figure out better solution (Inline hacks? Dynamic calls to stable mangled names?) + +@SinceKotlin("1.1") +public inline fun > enumValues(): Array = enumValuesIntrinsic() + +@SinceKotlin("1.1") +public inline fun > enumValueOf(name: String): T = enumValueOfIntrinsic(name) diff --git a/libraries/stdlib/js/irRuntime/kotlinJsHacks.kt b/libraries/stdlib/js/irRuntime/kotlinJsHacks.kt new file mode 100644 index 00000000000..9da861928fb --- /dev/null +++ b/libraries/stdlib/js/irRuntime/kotlinJsHacks.kt @@ -0,0 +1,14 @@ +/* + * 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 kotlin.js + +@PublishedApi +internal fun > enumValuesIntrinsic(): Array = + throw IllegalStateException("Should be replaced by compiler") + +@PublishedApi +internal fun > enumValueOfIntrinsic(name: String): T = + throw IllegalStateException("Should be replaced by compiler")