JS: extension lambdas translated same as local lambdas (KT-13312 fixed)

This commit is contained in:
Anton Bannykh
2017-01-16 16:24:06 +03:00
parent 5021be351d
commit 07bb7ef4d3
32 changed files with 123 additions and 183 deletions
@@ -0,0 +1,23 @@
fun test1(f: (Int) -> Int) = f(1)
fun test2(f: Int.() -> Int) = 2.f()
class A(val foo: Int.() -> Int)
fun box(): String {
val a: (Int) -> Int = { it }
val b: Int.() -> Int = { this }
if (test1(a) != 1) return "fail 1a"
if (test1(b) != 1) return "fail 1b"
if (test2(a) != 2) return "fail 2a"
if (test2(b) != 2) return "fail 2b"
val x = A({ this })
if (x.foo(3) != 3) return "fail 3"
if (with(x) { foo(4) } != 4) return "fail 4"
if (with(x) { 5.foo() } != 5) return "fail 5"
return "OK"
}
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun test(cl: Int.() -> Int):Int = 11.cl() fun test(cl: Int.() -> Int):Int = 11.cl()
class Foo { class Foo {
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun box(): String { fun box(): String {
val f = fun (s: String): String = s val f = fun (s: String): String = s
val g = f as String.() -> String val g = f as String.() -> String
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
class It(val id: String) class It(val id: String)
fun box(): String { fun box(): String {
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun box(): String { fun box(): String {
operator fun Int?.inc() = (this ?: 0) + 1 operator fun Int?.inc() = (this ?: 0) + 1
var counter: Int? = null var counter: Int? = null
@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT // WITH_REFLECT
fun doStuff(fn: String.() -> String) = "ok".fn() fun doStuff(fn: String.() -> String) = "ok".fn()
@@ -1,5 +1,3 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1,5 +1,3 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1,5 +1,3 @@
// Enable when using lambdas as extension lambdas is supported (KT-13312)
// IGNORE_BACKEND: JS
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -0,0 +1,13 @@
@kotlin.Metadata
public final class A {
private final @org.jetbrains.annotations.NotNull field foo: kotlin.jvm.functions.Function1
public method <init>(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
public final @org.jetbrains.annotations.NotNull method getFoo(): kotlin.jvm.functions.Function1
}
@kotlin.Metadata
public final class Kt13312Kt {
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method test1(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): int
public final static method test2(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): int
}
@@ -7142,6 +7142,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt13312.kt")
public void testKt13312() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt13312.kt");
doTest(fileName);
}
@TestMetadata("kt1776.kt") @TestMetadata("kt1776.kt")
public void testKt1776() throws Exception { public void testKt1776() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt");
@@ -7142,6 +7142,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt13312.kt")
public void testKt13312() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt13312.kt");
doTest(fileName);
}
@TestMetadata("kt1776.kt") @TestMetadata("kt1776.kt")
public void testKt1776() throws Exception { public void testKt1776() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt");
@@ -7142,6 +7142,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt13312.kt")
public void testKt13312() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt13312.kt");
doTest(fileName);
}
@TestMetadata("kt1776.kt") @TestMetadata("kt1776.kt")
public void testKt1776() throws Exception { public void testKt1776() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt");
@@ -23,8 +23,8 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.IdentitySet import org.jetbrains.kotlin.js.inline.util.IdentitySet
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.inline.util.rewriters.ContinueReplacingVisitor import org.jetbrains.kotlin.js.inline.util.rewriters.ContinueReplacingVisitor
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.* import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.* import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.*
@@ -288,8 +288,8 @@ internal class ExpressionDecomposer private constructor(
private fun Callable.process() { private fun Callable.process() {
qualifier = accept(qualifier) qualifier = accept(qualifier)
val matchedIndices = arguments.indicesOfExtractable var matchedIndices = arguments.indicesOfExtractable
if (!matchedIndices.hasNext()) return if (matchedIndices.isEmpty()) return
if (qualifier in containsNodeWithSideEffect) { if (qualifier in containsNodeWithSideEffect) {
val callee = qualifier as? JsNameRef val callee = qualifier as? JsNameRef
@@ -307,20 +307,27 @@ internal class ExpressionDecomposer private constructor(
else { else {
if (receiver != null && applyBindIfNecessary) { if (receiver != null && applyBindIfNecessary) {
val receiverTmp = receiver.extractToTemporary() val receiverTmp = receiver.extractToTemporary()
qualifier = JsAstUtils.invokeBind(receiverTmp, pureFqn(callee.ident, receiverTmp)) val fqn = JsNameRef(callee.ident, receiverTmp).apply {
synthetic = true
callee.name?.let { sideEffects = it.sideEffects }
}
qualifier = fqn.extractToTemporary()
qualifier = Namer.getFunctionCallRef(qualifier)
arguments.add(0, receiverTmp)
matchedIndices = matchedIndices.map { it + 1 }
}
else {
qualifier = qualifier.extractToTemporary()
} }
qualifier = qualifier.extractToTemporary()
} }
} }
processByIndices(arguments, matchedIndices) processByIndices(arguments, matchedIndices)
} }
private fun processByIndices(elements: MutableList<JsExpression>, matchedIndices: Iterator<Int>) { private fun processByIndices(elements: MutableList<JsExpression>, matchedIndices: List<Int>) {
var prev = 0 var prev = 0
while (matchedIndices.hasNext()) { for (curr in matchedIndices) {
val curr = matchedIndices.next()
for (i in prev..curr-1) { for (i in prev..curr-1) {
val arg = elements[i] val arg = elements[i]
if (arg !in containsNodeWithSideEffect) continue if (arg !in containsNodeWithSideEffect) continue
@@ -374,8 +381,8 @@ internal class ExpressionDecomposer private constructor(
} }
} }
private val List<JsNode>.indicesOfExtractable: Iterator<Int> private val List<JsNode>.indicesOfExtractable: List<Int>
get() = indices.filter { get(it) in containsExtractable }.iterator() get() = indices.filter { get(it) in containsExtractable }
} }
/** /**
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.js.inline.clean.removeDefaultInitializers
import org.jetbrains.kotlin.js.inline.context.InliningContext import org.jetbrains.kotlin.js.inline.context.InliningContext
import org.jetbrains.kotlin.js.inline.util.* import org.jetbrains.kotlin.js.inline.util.*
import org.jetbrains.kotlin.js.inline.util.rewriters.ReturnReplacingVisitor import org.jetbrains.kotlin.js.inline.util.rewriters.ReturnReplacingVisitor
import org.jetbrains.kotlin.js.translate.context.Namer
class FunctionInlineMutator class FunctionInlineMutator
private constructor( private constructor(
@@ -77,7 +78,7 @@ private constructor(
return when (qualifier) { return when (qualifier) {
is JsInvocation -> qualifier is JsInvocation -> qualifier
is JsNameRef -> { is JsNameRef -> {
val callee = if (qualifier.ident == "call") qualifier.qualifier else (qualifier.name?.staticRef as? JsExpression) val callee = if (qualifier.ident == Namer.CALL_FUNCTION) qualifier.qualifier else (qualifier.name?.staticRef as? JsExpression)
callee?.let { getInnerCall(it) } callee?.let { getInnerCall(it) }
} }
else -> null else -> null
@@ -171,7 +171,6 @@ private fun JsFunction.markInlineArguments(descriptor: CallableDescriptor) {
val params = descriptor.valueParameters val params = descriptor.valueParameters
val paramsJs = parameters val paramsJs = parameters
val inlineFuns = IdentitySet<JsName>() val inlineFuns = IdentitySet<JsName>()
val inlineExtensionFuns = IdentitySet<JsName>()
val offset = if (descriptor.isExtension) 1 else 0 val offset = if (descriptor.isExtension) 1 else 0
for ((i, param) in params.withIndex()) { for ((i, param) in params.withIndex()) {
@@ -180,25 +179,21 @@ private fun JsFunction.markInlineArguments(descriptor: CallableDescriptor) {
val type = param.type val type = param.type
if (!type.isFunctionTypeOrSubtype) continue if (!type.isFunctionTypeOrSubtype) continue
val namesSet = if (type.isExtensionFunctionType) inlineExtensionFuns else inlineFuns inlineFuns.add(paramsJs[i + offset].name)
namesSet.add(paramsJs[i + offset].name)
} }
val visitor = object: JsVisitorWithContextImpl() { val visitor = object: JsVisitorWithContextImpl() {
override fun endVisit(x: JsInvocation, ctx: JsContext<*>) { override fun endVisit(x: JsInvocation, ctx: JsContext<*>) {
val qualifier: JsExpression? val qualifier: JsExpression?
val namesSet: Set<JsName>
if (isCallInvocation(x)) { if (isCallInvocation(x)) {
qualifier = (x.qualifier as? JsNameRef)?.qualifier qualifier = (x.qualifier as? JsNameRef)?.qualifier
namesSet = inlineExtensionFuns
} else { } else {
qualifier = x.qualifier qualifier = x.qualifier
namesSet = inlineFuns
} }
(qualifier as? JsNameRef)?.name?.let { name -> (qualifier as? JsNameRef)?.name?.let { name ->
if (name in namesSet) { if (name in inlineFuns) {
x.inlineStrategy = InlineStrategy.IN_PLACE x.inlineStrategy = InlineStrategy.IN_PLACE
} }
} }
@@ -18,14 +18,14 @@ package org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.JsFunction import org.jetbrains.kotlin.js.backend.ast.JsFunction
class FunctionPostProcessor(root: JsFunction) { class FunctionPostProcessor(val root: JsFunction) {
val optimizations = listOf( val optimizations = listOf(
//{ TemporaryAssignmentElimination(root.body).apply() }, //{ TemporaryAssignmentElimination(root.body).apply() },
{ RedundantLabelRemoval(root.body).apply() }, { RedundantLabelRemoval(root.body).apply() },
{ WhileConditionFolding(root.body).apply() }, { WhileConditionFolding(root.body).apply() },
{ DoWhileGuardElimination(root.body).apply() }, { DoWhileGuardElimination(root.body).apply() },
{ TemporaryVariableElimination(root).apply() }, { TemporaryVariableElimination(root).apply() },
{ RedundantBindElimination(root.body).apply() }, { RedundantCallElimination(root.body).apply() },
{ IfStatementReduction(root.body).apply() }, { IfStatementReduction(root.body).apply() },
{ DeadCodeElimination(root.body).apply() }, { DeadCodeElimination(root.body).apply() },
{ RedundantVariableDeclarationElimination(root.body).apply() }, { RedundantVariableDeclarationElimination(root.body).apply() },
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@ import org.jetbrains.kotlin.js.backend.ast.JsBlock
import org.jetbrains.kotlin.js.backend.ast.JsInvocation import org.jetbrains.kotlin.js.backend.ast.JsInvocation
import org.jetbrains.kotlin.js.backend.ast.JsNameRef import org.jetbrains.kotlin.js.backend.ast.JsNameRef
import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor
import org.jetbrains.kotlin.js.inline.util.getCallerQualifier
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
// TODO: this optimization is a little unfair. It tries to recognize pattern like this a.bind(b)(args) and // Replaces a.foo.call(a, b) with a.foo(b)
// replace it with b.a(args). However, we can't be completely sure that `a` is a Function. class RedundantCallElimination(private val root: JsBlock) {
// Using JS-independent AST should solve the issue (as well as many other issues).
class RedundantBindElimination(private val root: JsBlock) {
private var changed = false private var changed = false
fun apply(): Boolean { fun apply(): Boolean {
@@ -35,15 +35,18 @@ class RedundantBindElimination(private val root: JsBlock) {
} }
private fun tryEliminate(invocation: JsInvocation) { private fun tryEliminate(invocation: JsInvocation) {
val qualifier = invocation.qualifier as? JsInvocation ?: return if (!isCallInvocation(invocation)) return
val outerQualifier = qualifier.qualifier as? JsNameRef ?: return val qualifier = getCallerQualifier(invocation) as? JsNameRef ?: return
val name = outerQualifier.ident
if (name != "bind") return
val qualifierReplacement = outerQualifier.qualifier ?: return val receiver = qualifier.qualifier as? JsNameRef ?: return
invocation.qualifier = qualifierReplacement val firstArg = invocation.arguments.firstOrNull() as? JsNameRef ?: return
changed = true
if (receiver.qualifier == null && receiver.name != null && firstArg.qualifier == null && receiver.name == firstArg.name) {
invocation.arguments.removeAt(0)
invocation.qualifier = qualifier
changed = true
}
} }
}) })
+2 -2
View File
@@ -28,7 +28,7 @@ import kotlin.coroutines.intrinsics.*
public fun <R, T> (suspend R.() -> T).createCoroutine( public fun <R, T> (suspend R.() -> T).createCoroutine(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
): Continuation<Unit> = this.asDynamic().call(receiver, completion, true).facade ): Continuation<Unit> = this.asDynamic()(receiver, completion, true).facade
/** /**
* Starts coroutine with receiver type [R] and result type [T]. * Starts coroutine with receiver type [R] and result type [T].
@@ -40,7 +40,7 @@ public fun <R, T> (suspend R.() -> T).startCoroutine(
receiver: R, receiver: R,
completion: Continuation<T> completion: Continuation<T>
) { ) {
this.asDynamic().call(receiver, completion) this.asDynamic()(receiver, completion)
} }
/** /**
@@ -45,20 +45,6 @@ Kotlin.getBoundCallableRefForExtensionFunction = function (receiver, extFun) {
}; };
}; };
Kotlin.getCallableRefForLocalExtensionFunction = function (extFun) {
return function () {
var args = [].slice.call(arguments);
var instance = args.shift();
return extFun.apply(instance, args);
};
};
Kotlin.getBoundCallableRefForLocalExtensionFunction = function (receiver, extFun) {
return function () {
return extFun.apply(receiver, arguments);
};
};
Kotlin.getCallableRefForConstructor = function (klass) { Kotlin.getCallableRefForConstructor = function (klass) {
return function () { return function () {
var obj = Object.create(klass.prototype); var obj = Object.create(klass.prototype);
@@ -39,25 +39,13 @@ public class CallableReferenceInlineTestsGenerated extends AbstractCallableRefer
@TestMetadata("classLevel.kt") @TestMetadata("classLevel.kt")
public void testClassLevel() throws Exception { public void testClassLevel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel.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("classLevel2.kt") @TestMetadata("classLevel2.kt")
public void testClassLevel2() throws Exception { public void testClassLevel2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel2.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/classLevel2.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("constructor.kt") @TestMetadata("constructor.kt")
@@ -111,13 +99,7 @@ public class CallableReferenceInlineTestsGenerated extends AbstractCallableRefer
@TestMetadata("topLevelExtension.kt") @TestMetadata("topLevelExtension.kt")
public void testTopLevelExtension() throws Exception { public void testTopLevelExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelExtension.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/topLevelExtension.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("topLevelProperty.kt") @TestMetadata("topLevelProperty.kt")
@@ -8127,6 +8127,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt13312.kt")
public void testKt13312() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt13312.kt");
doTest(fileName);
}
@TestMetadata("kt1776.kt") @TestMetadata("kt1776.kt")
public void testKt1776() throws Exception { public void testKt1776() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt1776.kt");
@@ -8160,13 +8166,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("kt3646.kt") @TestMetadata("kt3646.kt")
public void testKt3646() throws Exception { public void testKt3646() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt3646.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionFunctions/kt3646.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("kt3969.kt") @TestMetadata("kt3969.kt")
@@ -8966,13 +8966,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("castFunctionToExtension.kt") @TestMetadata("castFunctionToExtension.kt")
public void testCastFunctionToExtension() throws Exception { public void testCastFunctionToExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/invoke/castFunctionToExtension.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/invoke/castFunctionToExtension.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("extensionInvokeOnExpr.kt") @TestMetadata("extensionInvokeOnExpr.kt")
@@ -9173,13 +9167,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("kt4989.kt") @TestMetadata("kt4989.kt")
public void testKt4989() throws Exception { public void testKt4989() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/kt4989.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/kt4989.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("localExtensionOnNullableParameter.kt") @TestMetadata("localExtensionOnNullableParameter.kt")
@@ -12657,13 +12645,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("kt4987.kt") @TestMetadata("kt4987.kt")
public void testKt4987() throws Exception { public void testKt4987() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/kt4987.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/operatorConventions/kt4987.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("nestedMaps.kt") @TestMetadata("nestedMaps.kt")
@@ -16607,13 +16589,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("functionFromStdlib.kt") @TestMetadata("functionFromStdlib.kt")
public void testFunctionFromStdlib() throws Exception { public void testFunctionFromStdlib() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.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("functionReferenceErasedToKFunction.kt") @TestMetadata("functionReferenceErasedToKFunction.kt")
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.js.translate.callTranslator package org.jetbrains.kotlin.js.translate.callTranslator
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.PredefinedAnnotation import org.jetbrains.kotlin.js.PredefinedAnnotation
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
@@ -101,20 +100,12 @@ object DefaultFunctionCallCase : FunctionCallCase() {
val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context) val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context)
val referenceToCall = return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(extensionReceiver!!))
if (callableDescriptor.visibility == Visibilities.LOCAL) {
Namer.getFunctionCallRef(functionRef)
}
else {
functionRef
}
return JsInvocation(referenceToCall, argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
override fun FunctionCallInfo.bothReceivers(): JsExpression { override fun FunctionCallInfo.bothReceivers(): JsExpression {
// TODO: think about crazy case: spreadOperator + native // TODO: think about crazy case: spreadOperator + native
val functionRef = JsNameRef(functionName, dispatchReceiver!!) val functionRef = JsAstUtils.pureFqn(functionName, dispatchReceiver!!)
return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(extensionReceiver!!)) return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
} }
@@ -170,14 +161,7 @@ object InvokeIntrinsic : FunctionCallCase() {
} }
override fun FunctionCallInfo.dispatchReceiver(): JsExpression { override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
val receiver = resolvedCall.dispatchReceiver!! return JsInvocation(dispatchReceiver!!, argumentsInfo.translateArguments)
val jsReceiver = if (receiver.type.isExtensionFunctionType) {
pureFqn(Namer.CALL_FUNCTION, dispatchReceiver)
}
else {
dispatchReceiver!!
}
return JsInvocation(jsReceiver, argumentsInfo.translateArguments)
} }
/** /**
@@ -194,7 +178,7 @@ object InvokeIntrinsic : FunctionCallCase() {
* extLambda.call(obj, some, args) * extLambda.call(obj, some, args)
*/ */
override fun FunctionCallInfo.bothReceivers(): JsExpression { override fun FunctionCallInfo.bothReceivers(): JsExpression {
return JsInvocation(Namer.getFunctionCallRef(dispatchReceiver!!), argumentsInfo.argsWithReceiver(extensionReceiver!!)) return JsInvocation(dispatchReceiver!!, argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
} }
@@ -130,7 +130,7 @@ object DefaultVariableAccessCase : VariableAccessCase() {
} }
override fun VariableAccessInfo.bothReceivers(): JsExpression { override fun VariableAccessInfo.bothReceivers(): JsExpression {
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!) val funRef = JsAstUtils.pureFqn(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!)
return JsInvocation(funRef, extensionReceiver!!, *additionalArguments.toTypedArray()) return JsInvocation(funRef, extensionReceiver!!, *additionalArguments.toTypedArray())
} }
} }
@@ -211,10 +211,6 @@ public final class Namer {
@NotNull @NotNull
private final JsName boundCallableRefForExtensionFunctionName; private final JsName boundCallableRefForExtensionFunctionName;
@NotNull @NotNull
private final JsName callableRefForLocalExtensionFunctionName;
@NotNull
private final JsName boundCallableRefForLocalExtensionFunctionName;
@NotNull
private final JsName callableRefForConstructorName; private final JsName callableRefForConstructorName;
@NotNull @NotNull
private final JsName callableRefForTopLevelProperty; private final JsName callableRefForTopLevelProperty;
@@ -244,8 +240,6 @@ public final class Namer {
boundCallableRefForMemberFunctionName = kotlinScope.declareName(BOUND_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); 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);
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); callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME);
callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY); callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY);
callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY); callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY);
@@ -287,16 +281,6 @@ public final class Namer {
return kotlin(boundCallableRefForExtensionFunctionName); return kotlin(boundCallableRefForExtensionFunctionName);
} }
@NotNull
public JsExpression callableRefForLocalExtensionFunctionReference() {
return kotlin(callableRefForLocalExtensionFunctionName);
}
@NotNull
public JsExpression boundCallableRefForLocalExtensionFunctionReference() {
return kotlin(boundCallableRefForLocalExtensionFunctionName);
}
@NotNull @NotNull
public JsExpression callableRefForConstructorReference() { public JsExpression callableRefForConstructorReference() {
return kotlin(callableRefForConstructorName); return kotlin(callableRefForConstructorName);
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.expression
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.js.backend.ast.JsExpression import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsFunction import org.jetbrains.kotlin.js.backend.ast.JsFunction
import org.jetbrains.kotlin.js.backend.ast.JsParameter import org.jetbrains.kotlin.js.backend.ast.JsParameter
@@ -77,7 +76,7 @@ private fun FunctionDescriptor.getCorrectTypeParameters() =
private val FunctionDescriptor.requiresExtensionReceiverParameter private val FunctionDescriptor.requiresExtensionReceiverParameter
get() = DescriptorUtils.isExtension(this) && visibility != Visibilities.LOCAL get() = DescriptorUtils.isExtension(this)
fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, function: JsFunction) { fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, function: JsFunction) {
val descriptor = BindingUtils.getFunctionDescriptor(bindingContext(), declaration) val descriptor = BindingUtils.getFunctionDescriptor(bindingContext(), declaration)
@@ -223,15 +223,7 @@ object CallableReferenceTranslator {
receiver: JsExpression? receiver: JsExpression?
): JsExpression { ): JsExpression {
val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context) val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context)
if (descriptor.visibility == Visibilities.LOCAL) { if (AnnotationsUtils.isNativeObject(descriptor)) {
if (receiver == null) {
return JsInvocation(context.namer().callableRefForLocalExtensionFunctionReference(), jsFunctionRef)
}
else {
return JsInvocation(context.namer().boundCallableRefForLocalExtensionFunctionReference(), receiver, jsFunctionRef)
}
}
else if (AnnotationsUtils.isNativeObject(descriptor)) {
return translateForMemberFunction(descriptor, context, receiver) return translateForMemberFunction(descriptor, context, receiver)
} }
else { else {
@@ -16,12 +16,12 @@
package org.jetbrains.kotlin.js.translate.reference; package org.jetbrains.kotlin.js.translate.reference;
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation;
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
import org.jetbrains.kotlin.js.backend.ast.JsNameRef;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation;
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
import org.jetbrains.kotlin.js.backend.ast.JsNameRef;
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
@@ -18,11 +18,9 @@
package org.jetbrains.kotlin.js.translate.utils package org.jetbrains.kotlin.js.translate.utils
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
import org.jetbrains.kotlin.js.backend.ast.metadata.psiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.inline.util.isCallInvocation import org.jetbrains.kotlin.js.inline.util.isCallInvocation
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
@@ -3,5 +3,5 @@ function A(v) {
} }
function nativeBox(b) { function nativeBox(b) {
return b.bar_asnz92$(new A("foo"), function(i, s) { return "" + this.v + s + i }) return b.bar_asnz92$(new A("foo"), function($reciever, i, s) { return "" + $reciever.v + s + i })
} }
@@ -3,5 +3,5 @@ function A(v) {
} }
function bar(a, extLambda) { function bar(a, extLambda) {
return extLambda.call(a, 4, "boo") return extLambda(a, 4, "boo")
} }
@@ -1,3 +1,3 @@
function bar(a, extLambda) { function bar(a, extLambda) {
return extLambda.call(a, 4, "boo") return extLambda(a, 4, "boo")
} }