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 {
TYPEOF,
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);
}
@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")
public void testCastToGenericType() throws Exception {
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.intellij.openapi.util.text.StringUtil;
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.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
@@ -399,13 +401,23 @@ public final class Namer {
return invokeFunctionAndSetTypeCheckMetadata("orNull", callable, TypeCheck.OR_NULL);
}
@NotNull
public JsExpression isAny() {
return invokeFunctionAndSetTypeCheckMetadata("isAny", null, TypeCheck.IS_ANY);
}
@NotNull
private JsExpression invokeFunctionAndSetTypeCheckMetadata(
@NotNull String functionName,
@NotNull JsExpression argument,
@Nullable JsExpression argument,
@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.setSideEffects(invocation, false);
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt;
import org.jetbrains.kotlin.js.patterns.NamePredicate;
@@ -116,6 +117,8 @@ public final class PatternTranslator extends AbstractTranslator {
@NotNull
private JsExpression doGetIsTypeCheckCallable(@NotNull KotlinType type) {
if (KotlinBuiltIns.isAnyOrNullableAny(type)) return namer().isAny();
JsExpression builtinCheck = getIsTypeCheckCallableForBuiltin(type);
if (builtinCheck != null) return builtinCheck;
@@ -68,7 +68,7 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
val calleeArgument = callee?.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)
if (replacement != null) {
@@ -80,7 +80,16 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
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
if (callee.typeCheck == TypeCheck.TYPEOF) {
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)
if (callee.typeCheck == TypeCheck.OR_NULL) {
if (calleeArgument is JsInvocation && calleeArgument.typeCheck == TypeCheck.OR_NULL) {
return JsInvocation(calleeArgument, argument)
if (calleeArgument is JsInvocation) {
if (calleeArgument.typeCheck == TypeCheck.OR_NULL) return JsInvocation(calleeArgument, argument)
if (calleeArgument.typeCheck == TypeCheck.IS_ANY) return 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) {
};