JS: support enumValues<E>() and enumValueOf<E>("name") intrinsics.
This commit is contained in:
@@ -587,4 +587,17 @@ public class DescriptorUtils {
|
|||||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||||
return containingClass != null && isEffectivelyExternal(containingClass);
|
return containingClass != null && isEffectivelyExternal(containingClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static FunctionDescriptor getFunctionByName(@NotNull MemberScope scope, @NotNull Name name) {
|
||||||
|
Collection<DeclarationDescriptor> 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1258,6 +1258,10 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractCallableReferenceInlineTests> {
|
testClass<AbstractCallableReferenceInlineTests> {
|
||||||
model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS)
|
model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractEnumValuesInlineTests> {
|
||||||
|
model("codegen/boxInline/enum/", targetBackend = TargetBackend.JS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+110
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -35,6 +35,8 @@ abstract class AbstractNoInlineTests : BorrowedInlineTest("noInline/")
|
|||||||
|
|
||||||
abstract class AbstractCallableReferenceInlineTests : BorrowedInlineTest("callableReference/")
|
abstract class AbstractCallableReferenceInlineTests : BorrowedInlineTest("callableReference/")
|
||||||
|
|
||||||
|
abstract class AbstractEnumValuesInlineTests : BorrowedInlineTest("enum/")
|
||||||
|
|
||||||
abstract class AbstractBoxJsTest() : BasicBoxTest(
|
abstract class AbstractBoxJsTest() : BasicBoxTest(
|
||||||
BasicBoxTest.TEST_DATA_DIR_PATH + "box/",
|
BasicBoxTest.TEST_DATA_DIR_PATH + "box/",
|
||||||
BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/"
|
BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/"
|
||||||
|
|||||||
+2
-11
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
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.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
|
||||||
|
|
||||||
class EnumTranslator(
|
class EnumTranslator(
|
||||||
context: TranslationContext,
|
context: TranslationContext,
|
||||||
@@ -37,14 +35,14 @@ class EnumTranslator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateValuesFunction() {
|
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)) }
|
val values = entries.map { JsInvocation(JsAstUtils.pureFqn(context().getNameForObjectInstance(it), null)) }
|
||||||
function.body.statements += JsReturn(JsArrayLiteral(values))
|
function.body.statements += JsReturn(JsArrayLiteral(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateValueOfFunction() {
|
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")
|
val nameParam = function.scope.declareTemporaryName("name")
|
||||||
function.parameters += JsParameter(nameParam)
|
function.parameters += JsParameter(nameParam)
|
||||||
@@ -74,11 +72,4 @@ class EnumTranslator(
|
|||||||
|
|
||||||
return function
|
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 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+52
-11
@@ -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.JsExpression;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
|
||||||
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
|
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
|
||||||
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
import org.jetbrains.kotlin.js.patterns.NamePredicate;
|
||||||
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
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.KtExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
|
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtReferenceExpression;
|
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.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
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<? extends CallableDescriptor> resolvedCall = callInfo.getResolvedCall();
|
||||||
|
Map<TypeParameterDescriptor, KotlinType> 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() {
|
private static final FunctionIntrinsic JS_CLASS_FUN_INTRINSIC = new FunctionIntrinsic() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JsExpression apply(
|
public JsExpression apply(
|
||||||
@NotNull CallInfo callInfo, @NotNull List<JsExpression> arguments, @NotNull TranslationContext context
|
@NotNull CallInfo callInfo, @NotNull List<JsExpression> arguments, @NotNull TranslationContext context
|
||||||
) {
|
) {
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = callInfo.getResolvedCall();
|
return getReferenceToOnlyTypeParameter(callInfo, context);
|
||||||
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
|
|
||||||
|
|
||||||
assert typeArguments.size() == 1;
|
|
||||||
KotlinType type = typeArguments.values().iterator().next();
|
|
||||||
|
|
||||||
return UtilsKt.getReferenceToJsClass(type, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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<JsExpression> 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<JsExpression> 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
|
@NotNull
|
||||||
public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString");
|
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", "Json", "set"), ArrayFIF.SET_INTRINSIC);
|
||||||
|
|
||||||
add(pattern("kotlin.js", "jsClass"), JS_CLASS_FUN_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 {
|
private abstract static class NativeMapGetSet extends CallParametersAwareFunctionIntrinsic {
|
||||||
|
|||||||
Reference in New Issue
Block a user