JS: bound callable references (KT-13573).

This commit is contained in:
Anton Bannykh
2016-11-22 16:44:10 +03:00
parent dc1e3ae441
commit 159df7964a
28 changed files with 474 additions and 121 deletions
@@ -1,6 +1,3 @@
// TODO investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
class A {
companion object {
fun ok() = "OK"
@@ -1,6 +1,4 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
enum class E {
A, B;
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
inline fun foo(x: () -> String) = x()
fun String.id() = this
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
inline fun go(f: () -> String) = f()
fun String.id(): String = this
@@ -1,8 +1,5 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// Enable when callable references to builtin members is supported
// IGNORE_BACKEND: JS
// See KT-12995
fun box(): String {
var state = 0
val name = (state++)::toString.name
@@ -1,6 +1,5 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// Enable when callable references to builtin members is supported
// IGNORE_BACKEND: JS
fun <T> get(t: T): () -> String {
return t::toString
}
@@ -0,0 +1,51 @@
class A(var v: Int) {
fun f(x: Int) = x * v
}
fun A.g(x: Int) = x * f(x);
var A.w: Int
get() = 1000 * v
set(c: Int) {
v = c + 10
}
object F {
var u = 0
}
fun box(): String {
val a = A(5)
val av = a::v
if (av() != 5) return "fail1: ${av()}"
if (av.get() != 5) return "fail2: ${av.get()}"
av.set(7)
if (a.v != 7) return "fail3: ${a.v}"
val af = a::f
if (af(10) != 70) return "fail4: ${af(10)}"
val ag = a::g
if (ag(10) != 700) return "fail5: ${ag(10)}"
val aw = a::w
if (aw() != 7000) return "fail6: ${aw()}"
if (aw.get() != 7000) return "fail7: ${aw.get()}"
aw.set(5)
if (a.v != 15) return "fail8: ${a.v}"
val fu = F::u
if (fu() != 0) return "fail9: ${fu()}"
if (fu.get() != 0) return "fail10: ${fu.get()}"
fu.set(8)
if (F.u != 8) return "fail11: ${F.u}"
val x = 100
fun A.lf() = v * x;
val alf = a::lf
if (alf() != 1500) return "fail9: ${alf()}"
return "OK"
}
@@ -1,8 +1,3 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// See https://youtrack.jetbrains.com/issue/KT-14939
val String?.ok: String
get() = "OK"
@@ -1,6 +1,3 @@
// TODO investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
object Singleton {
fun ok() = "OK"
}
@@ -1,6 +1,5 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// Enable when callable references to builtin members is supported
// IGNORE_BACKEND: JS
fun box(): String {
val f = "KOTLIN"::get
return "${f(1)}${f(0)}"
@@ -1,4 +1,4 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// Enable when callable references to builtin members are supported.
// IGNORE_BACKEND: JS
fun box(): String {
@@ -1,6 +1,4 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: A.java
@@ -1,3 +1,5 @@
// Enable when callable references to builtin members is supported
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1,3 +1,5 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1,3 +1,5 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1,3 +1,5 @@
// Enable when callable references to builtin members and using lambdas as extension lambdas (KT-13312) is supported
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1,3 +1,5 @@
// Enable when callable references to builtin members and using lambdas as extension lambdas (KT-13312) is supported
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1,3 +1,5 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt
package test
@@ -1525,6 +1525,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("multiCase.kt")
public void testMultiCase() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
doTest(fileName);
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
@@ -1525,6 +1525,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("multiCase.kt")
public void testMultiCase() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
doTest(fileName);
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
@@ -1200,13 +1200,17 @@ fun main(args: Array<String>) {
model("codegen/boxInline/nonLocalReturns/", targetBackend = TargetBackend.JS)
}
testClass<AbstractPropertyAccessorsInlineTests>() {
testClass<AbstractPropertyAccessorsInlineTests> {
model("codegen/boxInline/property/", targetBackend = TargetBackend.JS)
}
testClass<AbstractNoInlineTests>() {
testClass<AbstractNoInlineTests> {
model("codegen/boxInline/noInline/", targetBackend = TargetBackend.JS)
}
testClass<AbstractCallableReferenceInlineTests> {
model("codegen/boxInline/callableReference/", targetBackend = TargetBackend.JS)
}
}
}
@@ -0,0 +1,197 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.test.semantics;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/boxInline/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class CallableReferenceInlineTestsGenerated extends AbstractCallableReferenceInlineTests {
public void testAllFilesPresentInCallableReference() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/callableReference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("classLevel.kt")
public void testClassLevel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("classLevel2.kt")
public void testClassLevel2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel2.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/constructor.kt");
doTest(fileName);
}
@TestMetadata("intrinsic.kt")
public void testIntrinsic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/intrinsic.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("propertyIntrinsic.kt")
public void testPropertyIntrinsic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/propertyIntrinsic.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("propertyReference.kt")
public void testPropertyReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/propertyReference.kt");
doTest(fileName);
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevel.kt");
doTest(fileName);
}
@TestMetadata("topLevelExtension.kt")
public void testTopLevelExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelExtension.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("topLevelProperty.kt")
public void testTopLevelProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelProperty.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/callableReference/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Bound extends AbstractCallableReferenceInlineTests {
public void testAllFilesPresentInBound() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("classProperty.kt")
public void testClassProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/classProperty.kt");
doTest(fileName);
}
@TestMetadata("expression.kt")
public void testExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
doTest(fileName);
}
@TestMetadata("extensionReceiver.kt")
public void testExtensionReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/extensionReceiver.kt");
doTest(fileName);
}
@TestMetadata("filter.kt")
public void testFilter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/filter.kt");
doTest(fileName);
}
@TestMetadata("intrinsic.kt")
public void testIntrinsic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("map.kt")
public void testMap() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/map.kt");
doTest(fileName);
}
@TestMetadata("objectProperty.kt")
public void testObjectProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/objectProperty.kt");
doTest(fileName);
}
@TestMetadata("propertyImportedFromObject.kt")
public void testPropertyImportedFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/propertyImportedFromObject.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/simple.kt");
doTest(fileName);
}
@TestMetadata("topLevelExtensionProperty.kt")
public void testTopLevelExtensionProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/topLevelExtensionProperty.kt");
doTest(fileName);
}
}
}
@@ -1877,13 +1877,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("companionObjectReceiver.kt")
public void testCompanionObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
@@ -1922,28 +1916,22 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("multiCase.kt")
public void testMultiCase() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/multiCase.kt");
doTest(fileName);
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/nullReceiver.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("objectReceiver.kt")
public void testObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("primitiveReceiver.kt")
@@ -1976,18 +1964,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("syntheticExtensionOnLHS.kt")
public void testSyntheticExtensionOnLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/syntheticExtensionOnLHS.kt");
try {
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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2056,25 +2032,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/inline/simple.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("simpleVal.kt")
public void testSimpleVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/inline/simpleVal.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
}
}
@@ -33,6 +33,8 @@ abstract class AbstractPropertyAccessorsInlineTests : BorrowedInlineTest("proper
abstract class AbstractNoInlineTests : BorrowedInlineTest("noInline/")
abstract class AbstractCallableReferenceInlineTests : BorrowedInlineTest("callableReference/")
abstract class AbstractBoxJsTest() : BasicBoxTest(
BasicBoxTest.TEST_DATA_DIR_PATH + "box/",
BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/"
@@ -77,12 +77,17 @@ public final class Namer {
public static final String OUTER_FIELD_NAME = "$outer";
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
private static final String BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getBoundCallableRefForMemberFunction";
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForExtensionFunction";
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 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";
@@ -191,18 +196,28 @@ public final class Namer {
@NotNull
private final JsName callableRefForMemberFunctionName;
@NotNull
private final JsName boundCallableRefForMemberFunctionName;
@NotNull
private final JsName callableRefForExtensionFunctionName;
@NotNull
private final JsName boundCallableRefForExtensionFunctionName;
@NotNull
private final JsName callableRefForLocalExtensionFunctionName;
@NotNull
private final JsName boundCallableRefForLocalExtensionFunctionName;
@NotNull
private final JsName callableRefForConstructorName;
@NotNull
private final JsName callableRefForTopLevelProperty;
@NotNull
private final JsName callableRefForMemberProperty;
@NotNull
private final JsName boundCallableRefForMemberProperty;
@NotNull
private final JsName callableRefForExtensionProperty;
@NotNull
private final JsName boundCallableRefForExtensionProperty;
@NotNull
private final JsExpression callGetProperty;
@NotNull
private final JsExpression callSetProperty;
@@ -217,12 +232,17 @@ public final class Namer {
callSetProperty = kotlin("callSetter");
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
boundCallableRefForMemberFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
boundCallableRefForExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
callableRefForLocalExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME);
boundCallableRefForLocalExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_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");
}
@@ -243,16 +263,31 @@ public final class Namer {
return kotlin(callableRefForMemberFunctionName);
}
@NotNull
public JsExpression boundCallableRefForMemberFunctionReference() {
return kotlin(boundCallableRefForMemberFunctionName);
}
@NotNull
public JsExpression callableRefForExtensionFunctionReference() {
return kotlin(callableRefForExtensionFunctionName);
}
@NotNull
public JsExpression boundCallableRefForExtensionFunctionReference() {
return kotlin(boundCallableRefForExtensionFunctionName);
}
@NotNull
public JsExpression callableRefForLocalExtensionFunctionReference() {
return kotlin(callableRefForLocalExtensionFunctionName);
}
@NotNull
public JsExpression boundCallableRefForLocalExtensionFunctionReference() {
return kotlin(boundCallableRefForLocalExtensionFunctionName);
}
@NotNull
public JsExpression callableRefForConstructorReference() {
return kotlin(callableRefForConstructorName);
@@ -268,11 +303,21 @@ public final class Namer {
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
public static JsExpression throwNPEFunctionRef() {
return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject());
@@ -21,20 +21,41 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.*
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import java.util.*
object CallableReferenceTranslator {
fun translate(expression: KtCallableReferenceExpression, context: TranslationContext): JsExpression {
val descriptor = BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), expression.callableReference)
val receiver = expression.receiverExpression?.let { r ->
if (context.bindingContext().get(BindingContext.DOUBLE_COLON_LHS, r) is DoubleColonLHS.Expression) {
val block = JsBlock()
val e = Translation.translateAsExpression(r, context, block)
if (!block.isEmpty) {
context.addStatementsToCurrentBlockFrom(block)
}
e
}
else {
null
}
} ?: (descriptor as? PropertyImportedFromObject)?.let {
ReferenceTranslator.translateAsValueReference(it.containingObject, context)
}
return when (descriptor) {
is PropertyDescriptor ->
translateForProperty(descriptor, context, expression)
translateForProperty(descriptor, context, expression, receiver)
is FunctionDescriptor ->
translateForFunction(descriptor, context, expression)
translateForFunction(descriptor, context, expression, receiver)
else ->
throw IllegalArgumentException("Expected property or function: $descriptor, expression=${expression.text}")
}
@@ -45,31 +66,41 @@ object CallableReferenceTranslator {
return JsLiteral.NULL
}
private fun translateForFunction(descriptor: FunctionDescriptor, context: TranslationContext, expression: KtCallableReferenceExpression): JsExpression {
private fun translateForFunction(
descriptor: FunctionDescriptor,
context: TranslationContext,
expression: KtCallableReferenceExpression,
receiver: JsExpression?
): JsExpression {
return when {
// TODO Support for callable reference to builtin functions and members
// TODO Support for callable reference to builtin functions and members
KotlinBuiltIns.isBuiltIn(descriptor) ->
reportNotSupported(context, expression)
isConstructor(descriptor) ->
translateForConstructor(descriptor, context)
isExtension(descriptor) ->
translateForExtensionFunction(descriptor, context)
translateForExtensionFunction(descriptor, context, receiver)
isMember(descriptor) ->
translateForMemberFunction(descriptor, context)
translateForMemberFunction(descriptor, context, receiver)
else ->
ReferenceTranslator.translateAsValueReference(descriptor, context)
}
}
private fun translateForProperty(descriptor: PropertyDescriptor, context: TranslationContext, expression: KtCallableReferenceExpression): JsExpression {
private fun translateForProperty(
descriptor: PropertyDescriptor,
context: TranslationContext,
expression: KtCallableReferenceExpression,
receiver: JsExpression?
): JsExpression {
return when {
// TODO Support for callable reference to builtin properties
// TODO Support for callable reference to builtin properties
KotlinBuiltIns.isBuiltIn(descriptor) ->
reportNotSupported(context, expression)
isExtension(descriptor) ->
translateForExtensionProperty(descriptor, context)
translateForExtensionProperty(descriptor, context, receiver)
isMember(descriptor) ->
translateForMemberProperty(descriptor, context)
translateForMemberProperty(descriptor, context, receiver)
else ->
translateForTopLevelProperty(descriptor, context)
}
@@ -137,27 +168,49 @@ object CallableReferenceTranslator {
return function
}
private fun translateForMemberProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
private fun translateForMemberProperty(
descriptor: PropertyDescriptor,
context: TranslationContext,
receiver: JsExpression?
): JsExpression {
val jsPropertyName = context.getNameForDescriptor(descriptor)
val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString())
return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor))
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): JsExpression {
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>(3)
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)
else
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 {
@@ -165,39 +218,44 @@ object CallableReferenceTranslator {
return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)
}
private fun translateForExtensionFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
val receiverParameterDescriptor = descriptor.extensionReceiverParameter ?:
error("receiverParameter for extension should not be null")
private fun translateForExtensionFunction(descriptor: FunctionDescriptor,
context: TranslationContext,
receiver: JsExpression?
): JsExpression {
val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context)
if (descriptor.visibility == Visibilities.LOCAL) {
return JsInvocation(context.namer().callableRefForLocalExtensionFunctionReference(), jsFunctionRef)
if (receiver == null) {
return JsInvocation(context.namer().callableRefForLocalExtensionFunctionReference(), jsFunctionRef)
}
else {
return JsInvocation(context.namer().boundCallableRefForLocalExtensionFunctionReference(), receiver, jsFunctionRef)
}
}
else if (AnnotationsUtils.isNativeObject(descriptor)) {
val jetType = receiverParameterDescriptor.type
val receiverClassDescriptor = DescriptorUtils.getClassDescriptorForType(jetType)
return translateAsMemberFunctionReference(descriptor, receiverClassDescriptor, context)
return translateForMemberFunction(descriptor, context, receiver)
}
else {
return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef)
if (receiver == null) {
return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef)
}
else {
return JsInvocation(context.namer().boundCallableRefForExtensionFunctionReference(), receiver, jsFunctionRef)
}
}
}
private fun translateForMemberFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
val classDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor) as? ClassDescriptor ?:
throw IllegalArgumentException("Expected ClassDescriptor: $descriptor")
return translateAsMemberFunctionReference(descriptor, classDescriptor, context)
}
private fun translateAsMemberFunctionReference(
private fun translateForMemberFunction(
descriptor: CallableDescriptor,
classDescriptor: ClassDescriptor,
context: TranslationContext
context: TranslationContext,
receiver: JsExpression?
): JsExpression {
val jsClassNameRef = ReferenceTranslator.translateAsTypeReference(classDescriptor, context)
val funName = context.getNameForDescriptor(descriptor)
val funNameAsString = context.program().getStringLiteral(funName.toString())
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), jsClassNameRef, funNameAsString)
if (receiver == null) {
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), funNameAsString)
}
else {
return JsInvocation(context.namer().boundCallableRefForMemberFunctionReference(), receiver, funNameAsString)
}
}
}
+35 -1
View File
@@ -142,7 +142,7 @@
}
// TODO Store callable references for members in class
Kotlin.getCallableRefForMemberFunction = function (klass, memberName) {
Kotlin.getCallableRefForMemberFunction = function (memberName) {
return function () {
var args = [].slice.call(arguments);
var instance = args.shift();
@@ -150,6 +150,12 @@
};
};
Kotlin.getBoundCallableRefForMemberFunction = function (receiver, memberName) {
return function () {
return receiver[memberName].apply(receiver, arguments);
};
};
// TODO Store callable references for extension functions in class
// extFun expected receiver as the first argument
Kotlin.getCallableRefForExtensionFunction = function (extFun) {
@@ -158,6 +164,14 @@
};
};
Kotlin.getBoundCallableRefForExtensionFunction = function (receiver, extFun) {
return function () {
var args = [].slice.call(arguments);
args.unshift(receiver);
return extFun.apply(null, args);
};
};
Kotlin.getCallableRefForLocalExtensionFunction = function (extFun) {
return function () {
var args = [].slice.call(arguments);
@@ -166,6 +180,12 @@
};
};
Kotlin.getBoundCallableRefForLocalExtensionFunction = function (receiver, extFun) {
return function () {
return extFun.apply(receiver, arguments);
};
};
Kotlin.getCallableRefForConstructor = function (klass) {
return function () {
var obj = Object.create(klass.prototype);
@@ -185,11 +205,25 @@
return getPropertyRefClass(getFun, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg);
};
Kotlin.getBoundCallableRefForMemberProperty = function(receiver, name, isVar) {
var getFun = Function("receiver", "return function " + name + "() { return receiver['" + name + "']; }")(receiver);
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";
+2 -2
View File
@@ -2,10 +2,10 @@
<html>
<head>
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
<script type="application/javascript" src="out/box/native/eval_v5.js"></script>
<script type="application/javascript" src="out/codegen/boxInline/callableReference/bound/topLevelExtensionProperty_v5.js"></script>
<script type="application/javascript">
console.log(JS_TESTS.foo.box());
console.log(JS_TESTS.box());
</script>
</head>
<body>