diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index f1066e39366..4e24de63e74 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -587,4 +587,17 @@ public class DescriptorUtils { ClassDescriptor containingClass = getContainingClass(descriptor); return containingClass != null && isEffectivelyExternal(containingClass); } + + @NotNull + public static FunctionDescriptor getFunctionByName(@NotNull MemberScope scope, @NotNull Name name) { + Collection functions = scope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS, + MemberScope.Companion.getALL_NAME_FILTER()); + for (DeclarationDescriptor d : functions) { + if (d instanceof FunctionDescriptor && name.equals(d.getOriginal().getName())) { + return (FunctionDescriptor) d; + } + } + + throw new IllegalStateException("Function not found"); + } } diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 4ac66fc5c42..4597155aebf 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -1258,6 +1258,10 @@ fun main(args: Array) { testClass { model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS) } + + testClass { + model("codegen/boxInline/enum/", targetBackend = TargetBackend.JS) + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumValuesInlineTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumValuesInlineTestsGenerated.java new file mode 100644 index 00000000000..4056c11702e --- /dev/null +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EnumValuesInlineTestsGenerated.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.test.semantics; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/codegen/boxInline/enum") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class EnumValuesInlineTestsGenerated extends AbstractEnumValuesInlineTests { + public void testAllFilesPresentInEnum() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/enum"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("kt10569.kt") + public void testKt10569() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/kt10569.kt"); + doTest(fileName); + } + + @TestMetadata("valueOf.kt") + public void testValueOf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valueOf.kt"); + doTest(fileName); + } + + @TestMetadata("valueOfCapturedType.kt") + public void testValueOfCapturedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valueOfCapturedType.kt"); + doTest(fileName); + } + + @TestMetadata("valueOfChain.kt") + public void testValueOfChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valueOfChain.kt"); + doTest(fileName); + } + + @TestMetadata("valueOfChainCapturedType.kt") + public void testValueOfChainCapturedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valueOfChainCapturedType.kt"); + doTest(fileName); + } + + @TestMetadata("valueOfNonReified.kt") + public void testValueOfNonReified() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valueOfNonReified.kt"); + doTest(fileName); + } + + @TestMetadata("values.kt") + public void testValues() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/values.kt"); + doTest(fileName); + } + + @TestMetadata("valuesAsArray.kt") + public void testValuesAsArray() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valuesAsArray.kt"); + doTest(fileName); + } + + @TestMetadata("valuesCapturedType.kt") + public void testValuesCapturedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valuesCapturedType.kt"); + doTest(fileName); + } + + @TestMetadata("valuesChain.kt") + public void testValuesChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valuesChain.kt"); + doTest(fileName); + } + + @TestMetadata("valuesChainCapturedType.kt") + public void testValuesChainCapturedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valuesChainCapturedType.kt"); + doTest(fileName); + } + + @TestMetadata("valuesNonReified.kt") + public void testValuesNonReified() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enum/valuesNonReified.kt"); + doTest(fileName); + } +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt index 6a6c387797b..c90b0367553 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt @@ -35,6 +35,8 @@ abstract class AbstractNoInlineTests : BorrowedInlineTest("noInline/") abstract class AbstractCallableReferenceInlineTests : BorrowedInlineTest("callableReference/") +abstract class AbstractEnumValuesInlineTests : BorrowedInlineTest("enum/") + abstract class AbstractBoxJsTest() : BasicBoxTest( BasicBoxTest.TEST_DATA_DIR_PATH + "box/", BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/" diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt index ffb49d22a20..bdcd88ab1d9 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/EnumTranslator.kt @@ -22,9 +22,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter class EnumTranslator( context: TranslationContext, @@ -37,14 +35,14 @@ class EnumTranslator( } private fun generateValuesFunction() { - val function = createFunction(getEnumFunction(DescriptorUtils.ENUM_VALUES)) + val function = createFunction(DescriptorUtils.getFunctionByName(descriptor.staticScope, DescriptorUtils.ENUM_VALUES)) val values = entries.map { JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(it), null)) } function.body.statements += JsReturn(JsArrayLiteral(values)) } private fun generateValueOfFunction() { - val function = createFunction(getEnumFunction(DescriptorUtils.ENUM_VALUE_OF)) + val function = createFunction(DescriptorUtils.getFunctionByName(descriptor.staticScope, DescriptorUtils.ENUM_VALUE_OF)) val nameParam = function.scope.declareTemporaryName("name") function.parameters += JsParameter(nameParam) @@ -74,11 +72,4 @@ class EnumTranslator( return function } - - private fun getEnumFunction(name: Name): FunctionDescriptor { - val functions = descriptor.staticScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) - return functions - .mapNotNull { (it as? FunctionDescriptor)?.original } - .first { it.name == name } - } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java index 8d7b16bf6a7..ddf9d080094 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -18,12 +18,10 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsInvocation; +import com.google.dart.compiler.backend.js.ast.JsNameRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyDescriptor; -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.js.patterns.DescriptorPredicate; import org.jetbrains.kotlin.js.patterns.NamePredicate; import org.jetbrains.kotlin.js.resolve.JsPlatform; @@ -38,6 +36,7 @@ import org.jetbrains.kotlin.js.translate.utils.UtilsKt; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtQualifiedExpression; import org.jetbrains.kotlin.psi.KtReferenceExpression; +import org.jetbrains.kotlin.resolve.DescriptorFactory; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; @@ -140,19 +139,25 @@ public final class TopLevelFIF extends CompositeFIF { } }; + private static final JsExpression getReferenceToOnlyTypeParameter( + @NotNull CallInfo callInfo, @NotNull TranslationContext context + ) { + ResolvedCall resolvedCall = callInfo.getResolvedCall(); + Map typeArguments = resolvedCall.getTypeArguments(); + + assert typeArguments.size() == 1; + KotlinType type = typeArguments.values().iterator().next(); + + return UtilsKt.getReferenceToJsClass(type, context); + } + private static final FunctionIntrinsic JS_CLASS_FUN_INTRINSIC = new FunctionIntrinsic() { @NotNull @Override public JsExpression apply( @NotNull CallInfo callInfo, @NotNull List arguments, @NotNull TranslationContext context ) { - ResolvedCall resolvedCall = callInfo.getResolvedCall(); - Map typeArguments = resolvedCall.getTypeArguments(); - - assert typeArguments.size() == 1; - KotlinType type = typeArguments.values().iterator().next(); - - return UtilsKt.getReferenceToJsClass(type, context); + return getReferenceToOnlyTypeParameter(callInfo, context); } @NotNull @@ -164,6 +169,39 @@ public final class TopLevelFIF extends CompositeFIF { } }; + + private static final FunctionIntrinsic ENUM_VALUES_INTRINSIC = new CallParametersAwareFunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply( + @NotNull CallInfo callInfo, @NotNull List arguments, @NotNull TranslationContext context + ) { + JsExpression enumClassRef = getReferenceToOnlyTypeParameter(callInfo, context); + + FunctionDescriptor fd = DescriptorFactory.createEnumValuesMethod(context.getCurrentModule().getBuiltIns().getEnum()); + + return new JsInvocation(new JsNameRef(context.getNameForDescriptor(fd), enumClassRef)); + } + }; + + + private static final FunctionIntrinsic ENUM_VALUE_OF_INTRINSIC = new CallParametersAwareFunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply( + @NotNull CallInfo callInfo, @NotNull List arguments, @NotNull TranslationContext context + ) { + JsExpression arg = arguments.get(2); // The first two are reified parameters + + JsExpression enumClassRef = getReferenceToOnlyTypeParameter(callInfo, context); + + FunctionDescriptor fd = DescriptorFactory.createEnumValueOfMethod(context.getCurrentModule().getBuiltIns().getEnum()); + + return new JsInvocation(new JsNameRef(context.getNameForDescriptor(fd), enumClassRef), arg); + } + }; + + @NotNull public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString"); @@ -187,6 +225,9 @@ public final class TopLevelFIF extends CompositeFIF { add(pattern("kotlin.js", "Json", "set"), ArrayFIF.SET_INTRINSIC); add(pattern("kotlin.js", "jsClass"), JS_CLASS_FUN_INTRINSIC); + + add(pattern("kotlin", "enumValues"), ENUM_VALUES_INTRINSIC); + add(pattern("kotlin", "enumValueOf"), ENUM_VALUE_OF_INTRINSIC); } private abstract static class NativeMapGetSet extends CallParametersAwareFunctionIntrinsic {