JS: refactor generation of property callable references
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.callUtil
|
|||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -200,6 +201,15 @@ fun KtExpression.getFunctionResolvedCallWithAssert(context: BindingContext): Res
|
|||||||
return resolvedCall as ResolvedCall<out FunctionDescriptor>
|
return resolvedCall as ResolvedCall<out FunctionDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KtExpression.getPropertyResolvedCallWithAssert(context: BindingContext): ResolvedCall<out PropertyDescriptor> {
|
||||||
|
val resolvedCall = getResolvedCallWithAssert(context)
|
||||||
|
assert(resolvedCall.resultingDescriptor is PropertyDescriptor) {
|
||||||
|
"ResolvedCall for this expression must be ResolvedCall<? extends PropertyDescriptor>: ${this.getTextWithLocation()}"
|
||||||
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return resolvedCall as ResolvedCall<out PropertyDescriptor>
|
||||||
|
}
|
||||||
|
|
||||||
fun KtExpression.getType(context: BindingContext): KotlinType? {
|
fun KtExpression.getType(context: BindingContext): KotlinType? {
|
||||||
val type = context.getType(this)
|
val type = context.getType(this)
|
||||||
if (type != null) return type
|
if (type != null) return type
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// Enable when callable references to builtin members are supported.
|
|
||||||
// IGNORE_BACKEND: JS
|
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val f = "kotlin"::length
|
val f = "kotlin"::length
|
||||||
val result = f.get()
|
val result = f.get()
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
|
||||||
// IGNORE_BACKEND: JS
|
|
||||||
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun box(): String =
|
fun box(): String =
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.naming
|
package org.jetbrains.kotlin.js.naming
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||||
@@ -171,10 +172,9 @@ class NameSuggestion {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
parts += getSuggestedName(current)
|
parts += getSuggestedName(current)
|
||||||
var last = current
|
val last = current
|
||||||
current = current.containingDeclaration!!
|
current = current.containingDeclaration!!
|
||||||
if (last is ConstructorDescriptor && !last.isPrimary) {
|
if (last is ConstructorDescriptor && !last.isPrimary) {
|
||||||
last = current
|
|
||||||
parts[parts.lastIndex] = getSuggestedName(current) + "_init"
|
parts[parts.lastIndex] = getSuggestedName(current) + "_init"
|
||||||
current = current.containingDeclaration!!
|
current = current.containingDeclaration!!
|
||||||
}
|
}
|
||||||
@@ -232,6 +232,19 @@ class NameSuggestion {
|
|||||||
"kotlin.CharSequence.get" -> return NameAndStability("charAt", true)
|
"kotlin.CharSequence.get" -> return NameAndStability("charAt", true)
|
||||||
"kotlin.Any.equals" -> return NameAndStability("equals", true)
|
"kotlin.Any.equals" -> return NameAndStability("equals", true)
|
||||||
}
|
}
|
||||||
|
val container = overriddenDescriptor.containingDeclaration
|
||||||
|
if (container is ClassDescriptor && ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(container.defaultType)) {
|
||||||
|
val name = overriddenDescriptor.name.asString()
|
||||||
|
when (name) {
|
||||||
|
"get",
|
||||||
|
"set" -> return NameAndStability(name, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (overriddenDescriptor is PropertyDescriptor) {
|
||||||
|
when (overriddenDescriptor.fqNameUnsafe.asString()) {
|
||||||
|
"kotlin.reflect.KCallable.name" -> return NameAndStability("callableName", true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mangleRegularNameIfNecessary(baseName, overriddenDescriptor)
|
return mangleRegularNameIfNecessary(baseName, overriddenDescriptor)
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ abstract class FunctionContext(
|
|||||||
val qualifier = callQualifier.transitiveStaticRef
|
val qualifier = callQualifier.transitiveStaticRef
|
||||||
return when (qualifier) {
|
return when (qualifier) {
|
||||||
is JsInvocation -> {
|
is JsInvocation -> {
|
||||||
lookUpStaticFunction(getSimpleName(qualifier)!!)?.let { if (isFunctionCreator(it)) it else null }
|
getSimpleName(qualifier)?.let { simpleName ->
|
||||||
|
lookUpStaticFunction(simpleName)?.let { if (isFunctionCreator(it)) it else null }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is JsNameRef -> lookUpStaticFunction(qualifier.name)
|
is JsNameRef -> lookUpStaticFunction(qualifier.name)
|
||||||
is JsFunction -> qualifier
|
is JsFunction -> qualifier
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ internal fun arrayIterator(array: dynamic): MutableIterator<dynamic> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsName("PropertyMetadata")
|
@JsName("PropertyMetadata")
|
||||||
internal class PropertyMetadata(val name: String)
|
internal class PropertyMetadata(@JsName("callableName") val name: String)
|
||||||
|
|
||||||
@JsName("noWhenBranchMatched")
|
@JsName("noWhenBranchMatched")
|
||||||
internal fun noWhenBranchMatched(): Nothing = throw NoWhenBranchMatchedException()
|
internal fun noWhenBranchMatched(): Nothing = throw NoWhenBranchMatchedException()
|
||||||
@@ -53,44 +53,22 @@ Kotlin.getCallableRefForConstructor = function (klass) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Kotlin.getCallableRefForTopLevelProperty = function(getter, setter, name) {
|
Kotlin.getCallableRefZeroArg = function(name, getter, setter) {
|
||||||
var getFun = Function("getter", "return function " + name + "() { return getter(); }")(getter, setter);
|
getter.get = getter;
|
||||||
return getPropertyRefClass(getFun, "get", setter, "set_za3rmp$", propertyRefClassMetadataCache.zeroArg);
|
getter.set = setter;
|
||||||
|
getter.callableName = name;
|
||||||
|
return getPropertyRefClass(getter, setter, propertyRefClassMetadataCache.zeroArg);
|
||||||
};
|
};
|
||||||
|
|
||||||
Kotlin.getCallableRefForMemberProperty = function(name, isVar) {
|
Kotlin.getCallableRefOneArg = function(name, getter, setter) {
|
||||||
var getFun = Function("return function " + name + "(receiver) { return receiver['" + name + "']; }")();
|
getter.get = getter;
|
||||||
var setFun = isVar ? function(receiver, value) { receiver[name] = value; } : null;
|
getter.set = setter;
|
||||||
return getPropertyRefClass(getFun, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
getter.callableName = name;
|
||||||
|
return getPropertyRefClass(getter, setter, propertyRefClassMetadataCache.oneArg);
|
||||||
};
|
};
|
||||||
|
|
||||||
Kotlin.getBoundCallableRefForMemberProperty = function(receiver, name, isVar) {
|
function getPropertyRefClass(obj, setter, cache) {
|
||||||
var getFun = Function("receiver", "return function " + name + "() { return receiver['" + name + "']; }")(receiver);
|
obj.$metadata$ = getPropertyRefMetadata(typeof setter === "function" ? cache.mutable : cache.immutable);
|
||||||
var setFun = isVar ? function(value) { receiver[name] = value; } : null;
|
|
||||||
return getPropertyRefClass(getFun, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg);
|
|
||||||
};
|
|
||||||
|
|
||||||
Kotlin.getCallableRefForExtensionProperty = function(name, getFun, setFun) {
|
|
||||||
var getFunWrapper = Function("getFun", "return function " + name + "(receiver, extensionReceiver) { return getFun(receiver, extensionReceiver) }")(getFun);
|
|
||||||
return getPropertyRefClass(getFunWrapper, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
|
|
||||||
};
|
|
||||||
|
|
||||||
Kotlin.getBoundCallableRefForExtensionProperty = function(receiver, name, getFun, setFun) {
|
|
||||||
var getFunWrapper = Function("receiver", "getFun", "return function " + name + "(extensionReceiver) { return getFun(receiver, extensionReceiver) }")(receiver, getFun);
|
|
||||||
if (setFun) {
|
|
||||||
setFun = setFun.bind(null, receiver);
|
|
||||||
}
|
|
||||||
return getPropertyRefClass(getFunWrapper, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg);
|
|
||||||
};
|
|
||||||
|
|
||||||
function getPropertyRefClass(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;
|
obj.constructor = obj;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-21
@@ -1937,13 +1937,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("simpleProperty.kt")
|
@TestMetadata("simpleProperty.kt")
|
||||||
public void testSimpleProperty() throws Exception {
|
public void testSimpleProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
|
@TestMetadata("compiler/testData/codegen/box/callableReference/bound/equals")
|
||||||
@@ -2606,13 +2600,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("listOfStringsMapLength.kt")
|
@TestMetadata("listOfStringsMapLength.kt")
|
||||||
public void testListOfStringsMapLength() throws Exception {
|
public void testListOfStringsMapLength() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("localClassVar.kt")
|
@TestMetadata("localClassVar.kt")
|
||||||
@@ -2636,13 +2624,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("privateSetterOutsideClass.kt")
|
@TestMetadata("privateSetterOutsideClass.kt")
|
||||||
public void testPrivateSetterOutsideClass() throws Exception {
|
public void testPrivateSetterOutsideClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("simpleExtension.kt")
|
@TestMetadata("simpleExtension.kt")
|
||||||
|
|||||||
@@ -82,11 +82,6 @@ public final class Namer {
|
|||||||
private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction";
|
private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction";
|
||||||
private static final String BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForLocalExtensionFunction";
|
private static final String BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForLocalExtensionFunction";
|
||||||
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
|
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
|
||||||
private static final String CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty";
|
|
||||||
private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
|
|
||||||
private static final String BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY = "getBoundCallableRefForMemberProperty";
|
|
||||||
private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
|
|
||||||
private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getBoundCallableRefForExtensionProperty";
|
|
||||||
|
|
||||||
private static final String DELEGATE = "$delegate";
|
private static final String DELEGATE = "$delegate";
|
||||||
|
|
||||||
@@ -213,15 +208,9 @@ public final class Namer {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final JsName callableRefForConstructorName;
|
private final JsName callableRefForConstructorName;
|
||||||
@NotNull
|
@NotNull
|
||||||
private final JsName callableRefForTopLevelProperty;
|
public static final String PROPERTY_CALLABLE_REF_ZERO_ARG = "getCallableRefZeroArg";
|
||||||
@NotNull
|
@NotNull
|
||||||
private final JsName callableRefForMemberProperty;
|
public static final String PROPERTY_CALLABLE_REF_ONE_ARG = "getCallableRefOneArg";
|
||||||
@NotNull
|
|
||||||
private final JsName boundCallableRefForMemberProperty;
|
|
||||||
@NotNull
|
|
||||||
private final JsName callableRefForExtensionProperty;
|
|
||||||
@NotNull
|
|
||||||
private final JsName boundCallableRefForExtensionProperty;
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final JsExpression callGetProperty;
|
private final JsExpression callGetProperty;
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -241,11 +230,6 @@ public final class Namer {
|
|||||||
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||||
boundCallableRefForExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
boundCallableRefForExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||||
callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
|
callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
|
||||||
callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
|
|
||||||
callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
|
|
||||||
boundCallableRefForMemberProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY);
|
|
||||||
callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
|
|
||||||
boundCallableRefForExtensionProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY);
|
|
||||||
|
|
||||||
isTypeName = kotlinScope.declareName("isType");
|
isTypeName = kotlinScope.declareName("isType");
|
||||||
}
|
}
|
||||||
@@ -286,31 +270,6 @@ public final class Namer {
|
|||||||
return kotlin(callableRefForConstructorName);
|
return kotlin(callableRefForConstructorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JsExpression callableRefForTopLevelPropertyReference() {
|
|
||||||
return kotlin(callableRefForTopLevelProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JsExpression callableRefForMemberPropertyReference() {
|
|
||||||
return kotlin(callableRefForMemberProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JsExpression boundCallableRefForMemberPropertyReference() {
|
|
||||||
return kotlin(boundCallableRefForMemberProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JsExpression callableRefForExtensionPropertyReference() {
|
|
||||||
return kotlin(callableRefForExtensionProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JsExpression boundCallableRefForExtensionPropertyReference() {
|
|
||||||
return kotlin(boundCallableRefForExtensionProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression throwNPEFunctionRef() {
|
public static JsExpression throwNPEFunctionRef() {
|
||||||
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
|
||||||
|
|||||||
@@ -227,6 +227,11 @@ public class TranslationContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ClassDescriptor getClassDescriptor() {
|
||||||
|
return classDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public BindingContext bindingContext() {
|
public BindingContext bindingContext() {
|
||||||
return staticContext.getBindingContext();
|
return staticContext.getBindingContext();
|
||||||
|
|||||||
+87
-113
@@ -20,15 +20,20 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
|
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
|
||||||
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
import org.jetbrains.kotlin.js.translate.utils.*
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getPropertyResolvedCallWithAssert
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object CallableReferenceTranslator {
|
object CallableReferenceTranslator {
|
||||||
|
|
||||||
@@ -93,17 +98,87 @@ object CallableReferenceTranslator {
|
|||||||
expression: KtCallableReferenceExpression,
|
expression: KtCallableReferenceExpression,
|
||||||
receiver: JsExpression?
|
receiver: JsExpression?
|
||||||
): JsExpression {
|
): JsExpression {
|
||||||
return when {
|
val call = expression.callableReference.getPropertyResolvedCallWithAssert(context.bindingContext())
|
||||||
// TODO Support for callable reference to builtin properties
|
|
||||||
KotlinBuiltIns.isBuiltIn(descriptor) ->
|
val getter = translateForPropertyAccessor(call, descriptor, context, receiver, false) { context, call, _, receiverParam ->
|
||||||
reportNotSupported(context, expression)
|
CallTranslator.translateGet(context, call, receiverParam)
|
||||||
isExtension(descriptor) ->
|
|
||||||
translateForExtensionProperty(descriptor, context, receiver)
|
|
||||||
isMember(descriptor) ->
|
|
||||||
translateForMemberProperty(descriptor, context, receiver)
|
|
||||||
else ->
|
|
||||||
translateForTopLevelProperty(descriptor, context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val setter = if (isSetterVisible(descriptor, context)) {
|
||||||
|
translateForPropertyAccessor(call, descriptor, context, receiver, true, CallTranslator::translateSet)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapPropertyCallableRef(context, receiver, descriptor, descriptor.name.identifier, getter, setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSetterVisible(descriptor: PropertyDescriptor, context: TranslationContext): Boolean {
|
||||||
|
val setter = descriptor.setter ?: return false
|
||||||
|
if (setter.visibility != Visibilities.PRIVATE) return true
|
||||||
|
val classDescriptor = context.classDescriptor ?: return false
|
||||||
|
return classDescriptor == descriptor.containingDeclaration
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateForPropertyAccessor(
|
||||||
|
call: ResolvedCall<out PropertyDescriptor>,
|
||||||
|
descriptor: PropertyDescriptor,
|
||||||
|
context: TranslationContext,
|
||||||
|
receiver: JsExpression?,
|
||||||
|
isSetter: Boolean,
|
||||||
|
translator: (TranslationContext, ResolvedCall<out PropertyDescriptor>, JsExpression, JsExpression?) -> JsExpression
|
||||||
|
): JsExpression {
|
||||||
|
val accessorFunction = JsFunction(context.scope(), JsBlock(), "")
|
||||||
|
val accessorContext = context.innerBlock(accessorFunction.body)
|
||||||
|
val receiverParam = if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null) {
|
||||||
|
val name = accessorFunction.scope.declareTemporaryName(Namer.getReceiverParameterName())
|
||||||
|
accessorFunction.parameters += JsParameter(name)
|
||||||
|
name.makeRef()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val valueParam = if (isSetter) {
|
||||||
|
val name = accessorFunction.scope.declareTemporaryName("value")
|
||||||
|
accessorFunction.parameters += JsParameter(name)
|
||||||
|
name.makeRef()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JsLiteral.NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
val accessorResult = translator(accessorContext, call, valueParam, receiverParam)
|
||||||
|
accessorFunction.body.statements += if (isSetter) accessorResult.makeStmt() else JsReturn(accessorResult)
|
||||||
|
return if (receiver != null) {
|
||||||
|
JsInvocation(JsNameRef("bind", accessorFunction), JsLiteral.NULL, receiver)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
accessorFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wrapPropertyCallableRef(
|
||||||
|
context: TranslationContext,
|
||||||
|
receiver: JsExpression?,
|
||||||
|
descriptor: PropertyDescriptor,
|
||||||
|
name: String,
|
||||||
|
getter: JsExpression,
|
||||||
|
setter: JsExpression?
|
||||||
|
): JsExpression {
|
||||||
|
var argCount = if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null) 1 else 0
|
||||||
|
if (receiver != null) {
|
||||||
|
argCount--
|
||||||
|
}
|
||||||
|
val nameLiteral = context.program().getStringLiteral(name)
|
||||||
|
val invokeName = if (argCount == 0) Namer.PROPERTY_CALLABLE_REF_ZERO_ARG else Namer.PROPERTY_CALLABLE_REF_ONE_ARG
|
||||||
|
val invokeFun = JsNameRef(invokeName, Namer.kotlinObject())
|
||||||
|
val invocation = JsInvocation(invokeFun, nameLiteral, getter)
|
||||||
|
if (setter != null) {
|
||||||
|
invocation.arguments += setter
|
||||||
|
}
|
||||||
|
return invocation
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isConstructor(descriptor: CallableDescriptor) = descriptor is ConstructorDescriptor
|
private fun isConstructor(descriptor: CallableDescriptor) = descriptor is ConstructorDescriptor
|
||||||
@@ -112,107 +187,6 @@ object CallableReferenceTranslator {
|
|||||||
|
|
||||||
private fun isMember(descriptor: CallableDescriptor) = JsDescriptorUtils.getContainingDeclaration(descriptor) is ClassDescriptor
|
private fun isMember(descriptor: CallableDescriptor) = JsDescriptorUtils.getContainingDeclaration(descriptor) is ClassDescriptor
|
||||||
|
|
||||||
private fun isVar(descriptor: PropertyDescriptor) = if (descriptor.isVar) JsLiteral.TRUE else JsLiteral.FALSE
|
|
||||||
|
|
||||||
private fun translateForTopLevelProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
|
||||||
val packageDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor)
|
|
||||||
assert(packageDescriptor is PackageFragmentDescriptor) { "Expected PackageFragmentDescriptor: $packageDescriptor" }
|
|
||||||
|
|
||||||
val jsPropertyName = context.getNameForDescriptor(descriptor)
|
|
||||||
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
|
|
||||||
|
|
||||||
val getter = createTopLevelGetterFunction(descriptor, context)
|
|
||||||
val setter = if (descriptor.isVar) createTopLevelSetterFunction(descriptor, context) else JsLiteral.NULL
|
|
||||||
|
|
||||||
return JsInvocation(context.namer().callableRefForTopLevelPropertyReference(), getter, setter, jsPropertyNameAsString)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createTopLevelGetterFunction(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
|
||||||
val getter = descriptor.getter!!
|
|
||||||
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && context.isFromCurrentModule(descriptor)) {
|
|
||||||
return context.getInnerReference(getter)
|
|
||||||
}
|
|
||||||
|
|
||||||
val expression = if (TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
|
||||||
JsInvocation(ReferenceTranslator.translateAsValueReference(getter, context))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ReferenceTranslator.translateAsValueReference(descriptor, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
val function = context.createRootScopedFunction(getter)
|
|
||||||
function.body.statements += JsReturn(expression)
|
|
||||||
|
|
||||||
return function
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createTopLevelSetterFunction(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
|
|
||||||
val setter = descriptor.setter!!
|
|
||||||
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && context.isFromCurrentModule(descriptor)) {
|
|
||||||
return context.getInnerReference(setter)
|
|
||||||
}
|
|
||||||
|
|
||||||
val function = context.createRootScopedFunction(setter)
|
|
||||||
val valueParam = function.scope.declareTemporaryName("value")
|
|
||||||
function.parameters += JsParameter(valueParam)
|
|
||||||
|
|
||||||
val expression = if (TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
|
||||||
JsInvocation(ReferenceTranslator.translateAsValueReference(setter, context), valueParam.makeRef())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsAstUtils.assignment(ReferenceTranslator.translateAsValueReference(descriptor, context), valueParam.makeRef())
|
|
||||||
}
|
|
||||||
|
|
||||||
function.body.statements += expression.makeStmt()
|
|
||||||
|
|
||||||
return function
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateForMemberProperty(
|
|
||||||
descriptor: PropertyDescriptor,
|
|
||||||
context: TranslationContext,
|
|
||||||
receiver: JsExpression?
|
|
||||||
): JsExpression {
|
|
||||||
val jsPropertyName = context.getNameForDescriptor(descriptor)
|
|
||||||
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
|
|
||||||
if (receiver == null) {
|
|
||||||
return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return JsInvocation(context.namer().boundCallableRefForMemberPropertyReference(), receiver, jsPropertyNameAsString,
|
|
||||||
isVar(descriptor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateForExtensionProperty(
|
|
||||||
descriptor: PropertyDescriptor,
|
|
||||||
context: TranslationContext,
|
|
||||||
receiver: JsExpression?
|
|
||||||
): JsExpression {
|
|
||||||
val jsGetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.getter!!, context)
|
|
||||||
val propertyName = descriptor.name
|
|
||||||
val jsPropertyNameAsString = context.program().getStringLiteral(propertyName.asString())
|
|
||||||
val argumentList = ArrayList<JsExpression>(4)
|
|
||||||
if (receiver != null) {
|
|
||||||
argumentList.add(receiver)
|
|
||||||
}
|
|
||||||
argumentList.add(jsPropertyNameAsString)
|
|
||||||
argumentList.add(jsGetterNameRef)
|
|
||||||
if (descriptor.isVar) {
|
|
||||||
val jsSetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.setter!!, context)
|
|
||||||
argumentList.add(jsSetterNameRef)
|
|
||||||
}
|
|
||||||
return if (AnnotationsUtils.isNativeObject(descriptor)) {
|
|
||||||
translateForMemberProperty(descriptor, context, receiver)
|
|
||||||
}
|
|
||||||
else if (receiver == null) {
|
|
||||||
JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsInvocation(context.namer().boundCallableRefForExtensionPropertyReference(), argumentList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
|
||||||
val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context)
|
val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context)
|
||||||
return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)
|
return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)
|
||||||
|
|||||||
Reference in New Issue
Block a user