JS/RTTI: fix cast to Any

This commit is contained in:
Alexey Tsvetkov
2015-06-16 22:13:42 +03:00
committed by Alexey Andreev
parent 2b3ebc7e9f
commit 38b0effe15
7 changed files with 58 additions and 7 deletions
@@ -62,5 +62,6 @@ var HasMetadata.sideEffects: Boolean by MetadataProperty(default = true)
enum class TypeCheck { enum class TypeCheck {
TYPEOF, TYPEOF,
INSTANCEOF, INSTANCEOF,
OR_NULL OR_NULL,
IS_ANY
} }
@@ -35,6 +35,12 @@ public class CastTestGenerated extends AbstractCastTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/expression/cast/cases"), Pattern.compile("^(.+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/expression/cast/cases"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("castToAny.kt")
public void testCastToAny() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToAny.kt");
doTest(fileName);
}
@TestMetadata("castToGenericType.kt") @TestMetadata("castToGenericType.kt")
public void testCastToGenericType() throws Exception { public void testCastToGenericType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToGenericType.kt"); String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToGenericType.kt");
@@ -22,6 +22,8 @@ import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck; import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
@@ -399,13 +401,23 @@ public final class Namer {
return invokeFunctionAndSetTypeCheckMetadata("orNull", callable, TypeCheck.OR_NULL); return invokeFunctionAndSetTypeCheckMetadata("orNull", callable, TypeCheck.OR_NULL);
} }
@NotNull
public JsExpression isAny() {
return invokeFunctionAndSetTypeCheckMetadata("isAny", null, TypeCheck.IS_ANY);
}
@NotNull @NotNull
private JsExpression invokeFunctionAndSetTypeCheckMetadata( private JsExpression invokeFunctionAndSetTypeCheckMetadata(
@NotNull String functionName, @NotNull String functionName,
@NotNull JsExpression argument, @Nullable JsExpression argument,
@NotNull TypeCheck metadata @NotNull TypeCheck metadata
) { ) {
JsInvocation invocation = new JsInvocation(kotlin(functionName), argument); JsInvocation invocation = new JsInvocation(kotlin(functionName));
if (argument != null) {
invocation.getArguments().add(argument);
}
MetadataProperties.setTypeCheck(invocation, metadata); MetadataProperties.setTypeCheck(invocation, metadata);
MetadataProperties.setSideEffects(invocation, false); MetadataProperties.setSideEffects(invocation, false);
return invocation; return invocation;
@@ -25,6 +25,7 @@ import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage; import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt; import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
import org.jetbrains.kotlin.js.patterns.NamePredicate; import org.jetbrains.kotlin.js.patterns.NamePredicate;
@@ -116,6 +117,8 @@ public final class PatternTranslator extends AbstractTranslator {
@NotNull @NotNull
private JsExpression doGetIsTypeCheckCallable(@NotNull KotlinType type) { private JsExpression doGetIsTypeCheckCallable(@NotNull KotlinType type) {
if (KotlinBuiltIns.isAnyOrNullableAny(type)) return namer().isAny();
JsExpression builtinCheck = getIsTypeCheckCallableForBuiltin(type); JsExpression builtinCheck = getIsTypeCheckCallableForBuiltin(type);
if (builtinCheck != null) return builtinCheck; if (builtinCheck != null) return builtinCheck;
@@ -68,7 +68,7 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
val calleeArgument = callee?.arguments?.firstOrNull() val calleeArgument = callee?.arguments?.firstOrNull()
val argument = x.arguments.firstOrNull() val argument = x.arguments.firstOrNull()
if (callee != null && calleeArgument != null && argument != null) { if (callee != null && argument != null) {
val replacement = getReplacement(callee, calleeArgument, argument) val replacement = getReplacement(callee, calleeArgument, argument)
if (replacement != null) { if (replacement != null) {
@@ -80,7 +80,16 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
return true return true
} }
private fun getReplacement(callee: JsInvocation, calleeArgument: JsExpression, argument: JsExpression): JsExpression? { private fun getReplacement(callee: JsInvocation, calleeArgument: JsExpression?, argument: JsExpression): JsExpression? {
if (calleeArgument == null) {
// Kotlin.isAny()(argument) -> argument != null
if (callee.typeCheck == TypeCheck.IS_ANY) {
return TranslationUtils.isNotNullCheck(argument)
}
return null
}
// Kotlin.isTypeOf(calleeArgument)(argument) -> typeOf argument === calleeArgument // Kotlin.isTypeOf(calleeArgument)(argument) -> typeOf argument === calleeArgument
if (callee.typeCheck == TypeCheck.TYPEOF) { if (callee.typeCheck == TypeCheck.TYPEOF) {
return typeOfIs(argument, calleeArgument as JsStringLiteral) return typeOfIs(argument, calleeArgument as JsStringLiteral)
@@ -93,8 +102,10 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
// Kotlin.orNull(calleeArgument)(argument) -> (tmp = argument) == null || calleeArgument(tmp) // Kotlin.orNull(calleeArgument)(argument) -> (tmp = argument) == null || calleeArgument(tmp)
if (callee.typeCheck == TypeCheck.OR_NULL) { if (callee.typeCheck == TypeCheck.OR_NULL) {
if (calleeArgument is JsInvocation && calleeArgument.typeCheck == TypeCheck.OR_NULL) { if (calleeArgument is JsInvocation) {
return JsInvocation(calleeArgument, argument) if (calleeArgument.typeCheck == TypeCheck.OR_NULL) return JsInvocation(calleeArgument, argument)
if (calleeArgument.typeCheck == TypeCheck.IS_ANY) return argument
} }
var nullCheckTarget = argument var nullCheckTarget = argument
@@ -0,0 +1,12 @@
package foo
fun box(): String {
val x = 0
val y = 1
val z = 2
val xs = arrayListOf(z, y, x)
xs.remove(x as Any)
assertEquals(listOf(z, y), xs)
return "OK"
}
+6
View File
@@ -555,6 +555,12 @@ var Kotlin = {};
} }
}; };
Kotlin.isAny = function () {
return function (object) {
return object != null;
}
};
Kotlin.kotlinModuleMetadata = function (abiVersion, moduleName, data) { Kotlin.kotlinModuleMetadata = function (abiVersion, moduleName, data) {
}; };