JS: support enumValues<E>() and enumValueOf<E>("name") intrinsics.

This commit is contained in:
Anton Bannykh
2016-12-05 16:43:12 +03:00
parent c31f91c28a
commit addd24955b
6 changed files with 183 additions and 22 deletions
@@ -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<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> {
model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS)
}
testClass<AbstractEnumValuesInlineTests> {
model("codegen/boxInline/enum/", targetBackend = TargetBackend.JS)
}
}
}
@@ -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);
}
}
@@ -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/"
@@ -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 }
}
}
@@ -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<? 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() {
@NotNull
@Override
public JsExpression apply(
@NotNull CallInfo callInfo, @NotNull List<JsExpression> arguments, @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);
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<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
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 {