KT-7397: use reference comparison (===) when translating a is A, where A is an object. Use more sophisticated check for reified parameters.

This commit is contained in:
Alexey Andreev
2016-09-07 15:38:03 +03:00
parent 5d34f5fb75
commit 5534350fd6
8 changed files with 47 additions and 15 deletions
@@ -62,7 +62,8 @@ enum class TypeCheck {
INSTANCEOF,
OR_NULL,
IS_ANY,
AND_PREDICATE
AND_PREDICATE,
SAME_AS
}
enum class SideEffectKind {
@@ -59,6 +59,12 @@ public class RttiTestGenerated extends AbstractRttiTest {
doTest(fileName);
}
@TestMetadata("isReifiedObject.kt")
public void testIsReifiedObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/isReifiedObject.kt");
doTest(fileName);
}
@TestMetadata("isSameClass.kt")
public void testIsSameClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/rtti/cases/isSameClass.kt");
@@ -400,6 +400,11 @@ public final class Namer {
return invokeFunctionAndSetTypeCheckMetadata("isInstanceOf", type, TypeCheck.INSTANCEOF);
}
@NotNull
public JsExpression isInstanceOfObject(@NotNull JsExpression type) {
return invokeFunctionAndSetTypeCheckMetadata("isInstanceOf", type, TypeCheck.SAME_AS);
}
@NotNull
public JsExpression orNull(@NotNull JsExpression callable) {
return invokeFunctionAndSetTypeCheckMetadata("orNull", callable, TypeCheck.OR_NULL);
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.builtins.ReflectionTypes;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.patterns.NamePredicate;
import org.jetbrains.kotlin.js.patterns.typePredicates.TypePredicatesKt;
import org.jetbrains.kotlin.js.translate.context.Namer;
@@ -170,8 +167,10 @@ public final class PatternTranslator extends AbstractTranslator {
return result;
}
JsNameRef typeName = getClassNameReference(type);
return namer().isInstanceOf(typeName);
ClassDescriptor referencedClass = DescriptorUtils.getClassDescriptorForType(type);
JsNameRef typeName = context().getQualifiedReference(referencedClass);
return referencedClass.getKind() != ClassKind.OBJECT ? namer().isInstanceOf(typeName) : namer().isInstanceOfObject(typeName);
}
@Nullable
@@ -235,12 +234,6 @@ public final class PatternTranslator extends AbstractTranslator {
return alias;
}
@NotNull
private JsNameRef getClassNameReference(@NotNull KotlinType type) {
ClassDescriptor referencedClass = DescriptorUtils.getClassDescriptorForType(type);
return context().getQualifiedReference(referencedClass);
}
@NotNull
public JsExpression translateExpressionPattern(
@NotNull KotlinType type,
@@ -86,6 +86,12 @@ private class TypeCheckRewritingVisitor(private val context: TranslationContext)
if (calleeArguments.size == 1) context.namer().isInstanceOf(argument, calleeArguments[0]) else null
}
TypeCheck.SAME_AS -> {
// `Kotlin.isInstanceOf(calleeArgument)(argument)` -> `argument === calleeArgument`
// when it's known at compile time that `argument` represents an object type
if (calleeArguments.size == 1) JsAstUtils.equality(argument, calleeArguments[0]) else null
}
TypeCheck.OR_NULL -> {
// `Kotlin.orNull(calleeArgument)(argument)` -> `(tmp = argument) == null || calleeArgument(tmp)`
if (calleeArguments.size == 1) getReplacementForOrNull(argument, calleeArguments[0]) else null
+9
View File
@@ -381,6 +381,15 @@
return object instanceof klass;
}
var proto = Object.getPrototypeOf(klass);
var constructor = proto != null ? proto.constructor : null;
if (constructor != null && "$metadata$" in constructor) {
var metadata = constructor.$metadata$;
if (metadata.type === Kotlin.TYPE.OBJECT) {
return object === klass;
}
}
// In WebKit (JavaScriptCore) for some interfaces from DOM typeof returns "object", nevertheless they can be used in RHS of instanceof
if (isNativeClass(klass)) {
return object instanceof klass;
+1 -2
View File
@@ -5,8 +5,7 @@ object Obj
fun box(): String {
val r: Any = Obj
// TODO: fix KT-13465
// if (r !is Obj) return "r !is Obj"
if (r !is Obj) return "r !is Obj"
return "OK"
}
+13
View File
@@ -0,0 +1,13 @@
// NO_INLINE
package foo
object Obj
private inline fun <reified T> check(a: Any): String {
return if (a is T) "OK" else "fail"
}
fun box(): String {
var x: Any = Obj
return check<Obj>(x)
}