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:
+2
-1
@@ -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);
|
||||
|
||||
+5
-12
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user