KT-12417: add support of RTTI against K(Mutable)Property* types
This commit is contained in:
@@ -120,6 +120,15 @@ class ReflectionTypes(module: ModuleDescriptor) {
|
||||
fun isCallableType(type: KotlinType): Boolean =
|
||||
type.isFunctionTypeOrSubtype || isKCallableType(type)
|
||||
|
||||
@JvmStatic fun isFunctionalKPropertyType(type: KotlinType): Boolean {
|
||||
val descriptor = type.constructor.declarationDescriptor ?: return false
|
||||
val segments = DescriptorUtils.getFqName(descriptor).pathSegments()
|
||||
return segments.size == 3 && segments.subList(0, 2) == KOTLIN_REFLECT_FQ_NAME.pathSegments() &&
|
||||
segments.last().let { it.isProperty("KProperty") || it.isProperty("KMutableProperty") }
|
||||
}
|
||||
|
||||
private fun Name.isProperty(baseName: String) = asString().startsWith(baseName) && asString() != baseName
|
||||
|
||||
private fun isKCallableType(type: KotlinType): Boolean =
|
||||
hasFqName(type.constructor, KotlinBuiltIns.FQ_NAMES.kCallable) ||
|
||||
type.constructor.supertypes.any { isKCallableType(it) }
|
||||
|
||||
@@ -35,6 +35,18 @@ public class CastTestGenerated extends AbstractCastTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/expression/cast/cases"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("castExtensionToKMutableProperty.kt")
|
||||
public void testCastExtensionToKMutableProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castExtensionToKMutableProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castExtensionToKProperty1.kt")
|
||||
public void testCastExtensionToKProperty1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castExtensionToKProperty1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToAny.kt")
|
||||
public void testCastToAny() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToAny.kt");
|
||||
@@ -71,6 +83,30 @@ public class CastTestGenerated extends AbstractCastTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToKMutableProperty0.kt")
|
||||
public void testCastToKMutableProperty0() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToKMutableProperty0.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToKMutableProperty1.kt")
|
||||
public void testCastToKMutableProperty1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToKMutableProperty1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToKProperty0.kt")
|
||||
public void testCastToKProperty0() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToKProperty0.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToKProperty1.kt")
|
||||
public void testCastToKProperty1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToKProperty1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("castToNotNull.kt")
|
||||
public void testCastToNotNull() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNull.kt");
|
||||
@@ -89,6 +125,12 @@ public class CastTestGenerated extends AbstractCastTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveToClass.kt")
|
||||
public void testPrimitiveToClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/primitiveToClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedToNotNull.kt")
|
||||
public void testReifiedToNotNull() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/reifiedToNotNull.kt");
|
||||
|
||||
+10
-8
@@ -17,7 +17,10 @@
|
||||
package org.jetbrains.kotlin.js.translate.callTranslator
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
@@ -161,14 +164,13 @@ object NativeSetterCallCase : AnnotatedAsNativeXCallCase(PredefinedAnnotation.NA
|
||||
object InvokeIntrinsic : FunctionCallCase() {
|
||||
fun canApply(callInfo: FunctionCallInfo): Boolean {
|
||||
val callableDescriptor = callInfo.callableDescriptor
|
||||
if (callableDescriptor.name != OperatorNameConventions.INVOKE)
|
||||
return false
|
||||
val isExtension = callableDescriptor.extensionReceiverParameter != null
|
||||
val parameterCount = callableDescriptor.valueParameters.size + (if (isExtension) 1 else 0)
|
||||
val funDeclaration = callableDescriptor.containingDeclaration
|
||||
if (callableDescriptor is FunctionInvokeDescriptor) return true
|
||||
|
||||
if (!isExtension && funDeclaration == callInfo.context.reflectionTypes.getKFunction(parameterCount))
|
||||
return true
|
||||
// Otherwise, it can be extension lambda
|
||||
if (callableDescriptor.name != OperatorNameConventions.INVOKE || callableDescriptor.extensionReceiverParameter == null)
|
||||
return false
|
||||
val parameterCount = callableDescriptor.valueParameters.size + 1
|
||||
val funDeclaration = callableDescriptor.containingDeclaration
|
||||
|
||||
return funDeclaration == callableDescriptor.builtIns.getFunction(parameterCount)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||
@@ -328,6 +329,7 @@ class ClassTranslator private constructor(
|
||||
|
||||
private fun getSupertypesNameReferences(): List<JsExpression> {
|
||||
val supertypes = getSupertypesWithoutFakes(descriptor)
|
||||
.filter { it.constructor.declarationDescriptor !is FunctionClassDescriptor }
|
||||
if (supertypes.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
+5
-1
@@ -22,6 +22,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
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.builtins.ReflectionTypesKt;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
@@ -181,7 +183,9 @@ public final class PatternTranslator extends AbstractTranslator {
|
||||
private JsExpression getIsTypeCheckCallableForBuiltin(@NotNull KotlinType type) {
|
||||
if (isAnyOrNullableAny(type)) return namer().isAny();
|
||||
|
||||
if (isFunctionTypeOrSubtype(type)) return namer().isTypeOf(program().getStringLiteral("function"));
|
||||
if (isFunctionTypeOrSubtype(type) && !ReflectionTypes.isFunctionalKPropertyType(type)) {
|
||||
return namer().isTypeOf(program().getStringLiteral("function"));
|
||||
}
|
||||
|
||||
if (isArray(type)) return Namer.IS_ARRAY_FUN_REF;
|
||||
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
|
||||
class A
|
||||
|
||||
var A.x: Int
|
||||
get() = 23
|
||||
set(value) { }
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (A::x as Any) is KProperty1<*, *>)
|
||||
assertEquals(true, (A::x as Any) is KMutableProperty1<*, *>)
|
||||
assertEquals(23, ((A::x as Any) as KProperty1<A, Any>)(A()))
|
||||
assertEquals(23, ((A::x as Any) as KMutableProperty1<A, Any>)(A()))
|
||||
assertEquals(false, (23 as Any) is KMutableProperty1<*, *>)
|
||||
assertEquals(false, ({ A().x } as Any) is KMutableProperty1<*, *>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class A
|
||||
|
||||
val A.x: Int
|
||||
get() = 23
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (A::x as Any) is KProperty1<*, *>)
|
||||
assertEquals(23, ((A::x as Any) as KProperty1<A, Any>)(A()))
|
||||
assertEquals(false, (23 as Any) is KProperty1<*, *>)
|
||||
assertEquals(false, ({ A().x } as Any) is KProperty1<*, *>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
var x = 23
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (::x as Any) is KProperty0<*>)
|
||||
assertEquals(true, (::x as Any) is KMutableProperty0<*>)
|
||||
assertEquals(23, ((::x as Any) as KProperty0<Any>)())
|
||||
assertEquals(23, ((::x as Any) as KMutableProperty0<Any>)())
|
||||
assertEquals(false, (23 as Any) is KMutableProperty0<*>)
|
||||
assertEquals(false, ({ x } as Any) is KMutableProperty0<*>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
|
||||
class A {
|
||||
var x = 23
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (A::x as Any) is KProperty1<*, *>)
|
||||
assertEquals(true, (A::x as Any) is KMutableProperty1<*, *>)
|
||||
assertEquals(23, ((A::x as Any) as KProperty1<A, Any>)(A()))
|
||||
assertEquals(23, ((A::x as Any) as KMutableProperty1<A, Any>)(A()))
|
||||
assertEquals(false, (23 as Any) is KProperty1<*, *>)
|
||||
assertEquals(false, (23 as Any) is KMutableProperty1<*, *>)
|
||||
assertEquals(false, ({ A().x } as Any) is KMutableProperty1<*, *>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
val x = 23
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (::x as Any) is KProperty0<*>)
|
||||
assertEquals(23, ((::x as Any) as KProperty0<Any>)())
|
||||
assertEquals(false, (23 as Any) is KProperty0<*>)
|
||||
assertEquals(false, ({ x } as Any) is KProperty0<*>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class A {
|
||||
val x = 23
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(true, (A::x as Any) is KProperty1<*, *>)
|
||||
assertEquals(23, ((A::x as Any) as KProperty1<A, Any>)(A()))
|
||||
assertEquals(false, (23 as Any) is KProperty1<*, *>)
|
||||
assertEquals(false, ({ A().x } as Any) is KProperty1<*, *>)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
interface A
|
||||
|
||||
class B
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(false, (23 as Any) is A)
|
||||
assertEquals(false, (23 as Any) is B)
|
||||
assertEquals(false, (23L as Any) is A)
|
||||
assertEquals(false, (23L as Any) is B)
|
||||
assertEquals(false, ("qwe" as Any) is A)
|
||||
assertEquals(false, ("qwe" as Any) is B)
|
||||
assertEquals(false, ({ 23 } as Any) is A)
|
||||
assertEquals(false, ({ 23 } as Any) is B)
|
||||
assertEquals(false, (true as Any) is A)
|
||||
assertEquals(false, (true as Any) is B)
|
||||
return "OK"
|
||||
}
|
||||
+64
-27
@@ -348,11 +348,11 @@ var Kotlin = {};
|
||||
klass.$metadata$.properties[propertyName].set.call(thisObject, value);
|
||||
};
|
||||
|
||||
function isInheritanceFromTrait(objConstructor, trait) {
|
||||
if (isNativeClass(objConstructor) || objConstructor.$metadata$.classIndex < trait.$metadata$.classIndex) {
|
||||
function isInheritanceFromTrait(metadata, trait) {
|
||||
if (metadata == null || metadata.classIndex < trait.$metadata$.classIndex) {
|
||||
return false;
|
||||
}
|
||||
var baseClasses = objConstructor.$metadata$.baseClasses;
|
||||
var baseClasses = metadata.baseClasses;
|
||||
var i;
|
||||
for (i = 0; i < baseClasses.length; i++) {
|
||||
if (baseClasses[i] === trait) {
|
||||
@@ -360,7 +360,7 @@ var Kotlin = {};
|
||||
}
|
||||
}
|
||||
for (i = 0; i < baseClasses.length; i++) {
|
||||
if (isInheritanceFromTrait(baseClasses[i], trait)) {
|
||||
if (isInheritanceFromTrait(baseClasses[i].$metadata$, trait)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -368,7 +368,7 @@ var Kotlin = {};
|
||||
}
|
||||
|
||||
Kotlin.isType = function (object, klass) {
|
||||
if (object == null || klass == null) {
|
||||
if (object == null || klass == null || (typeof object !== 'object' && typeof object !== 'function')) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
@@ -379,7 +379,8 @@ var Kotlin = {};
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return isInheritanceFromTrait(object.constructor, klass);
|
||||
var metadata = "$metadata$" in object ? object.$metadata$ : object.constructor.$metadata$;
|
||||
return isInheritanceFromTrait(metadata, klass);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -418,34 +419,70 @@ var Kotlin = {};
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForTopLevelProperty = function(packageName, name, isVar) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get = function() { return packageName[name]; };
|
||||
if (isVar) {
|
||||
obj.set_za3rmp$ = function(value) { packageName[name] = value; };
|
||||
}
|
||||
return obj;
|
||||
var getFun = function() { return packageName[name]; };
|
||||
var setFun = isVar ? function(value) { packageName[name] = value; } : null;
|
||||
return getPropertyRefClass(name, getFun, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.zeroArg);
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForMemberProperty = function(name, isVar) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get_za3rmp$ = function(receiver) { return receiver[name]; };
|
||||
if (isVar) {
|
||||
obj.set_wn2jw4$ = function(receiver, value) { receiver[name] = value; };
|
||||
}
|
||||
return obj;
|
||||
var getFun = function(receiver) { return receiver[name]; };
|
||||
var setFun = isVar ? function(receiver, value) { receiver[name] = value; } : null;
|
||||
return getPropertyRefClass(name, getFun, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
Kotlin.getCallableRefForExtensionProperty = function(name, getFun, setFun) {
|
||||
var obj = {};
|
||||
obj.name = name;
|
||||
obj.get_za3rmp$ = getFun;
|
||||
if (typeof setFun === "function") {
|
||||
obj.set_wn2jw4$ = setFun;
|
||||
}
|
||||
return obj;
|
||||
var getFunWrapper = function(receiver, extensionReceiver) { return getFun(receiver, extensionReceiver) };
|
||||
return getPropertyRefClass(name, getFunWrapper, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
||||
};
|
||||
|
||||
function getPropertyRefClass(name, getFun, getName, setFun, setName, cache) {
|
||||
var obj = getFun;
|
||||
var isMutable = typeof setFun === "function";
|
||||
obj.$metadata$ = getPropertyRefMetadata(isMutable ? cache.mutable : cache.immutable);
|
||||
obj[getName] = getFun;
|
||||
if (isMutable) {
|
||||
obj[setName] = setFun;
|
||||
}
|
||||
obj.constructor = obj;
|
||||
Object.defineProperty(obj, "name", { get : function() { return name; } });
|
||||
return obj;
|
||||
}
|
||||
|
||||
var propertyRefClassMetadataCache = {
|
||||
zeroArg: {
|
||||
mutable: { value: null, implementedInterface: function () {
|
||||
return Kotlin.modules['stdlib'].kotlin.reflect.KMutableProperty0 }
|
||||
},
|
||||
immutable: { value: null, implementedInterface: function () {
|
||||
return Kotlin.modules['stdlib'].kotlin.reflect.KProperty0 }
|
||||
}
|
||||
},
|
||||
oneArg: {
|
||||
mutable: { value: null, implementedInterface: function () {
|
||||
return Kotlin.modules['stdlib'].kotlin.reflect.KMutableProperty1 }
|
||||
},
|
||||
immutable: { value: null, implementedInterface: function () {
|
||||
return Kotlin.modules['stdlib'].kotlin.reflect.KProperty1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getPropertyRefMetadata(cache) {
|
||||
if (cache.value === null) {
|
||||
cache.value = {
|
||||
baseClasses: [cache.implementedInterface()],
|
||||
baseClass: null,
|
||||
classIndex: Kotlin.newClassIndex(),
|
||||
functions: {},
|
||||
properties: {},
|
||||
types: {},
|
||||
staticMembers: {}
|
||||
};
|
||||
}
|
||||
return cache.value;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////// packages & modules //////////////////////////////
|
||||
|
||||
Kotlin.modules = {};
|
||||
|
||||
Reference in New Issue
Block a user