JVM: Mark suspend lambda receiver as used if callable reference

accesses it.
 #KT-44131 Fixed
This commit is contained in:
Ilmir Usmanov
2021-01-21 10:55:15 +01:00
parent de00f72fa3
commit 704366e531
9 changed files with 87 additions and 22 deletions
@@ -8562,6 +8562,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/fromJava.kt");
}
@Test
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@Test
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
@@ -864,7 +864,9 @@ class ControlFlowInformationProvider private constructor(
}
private fun markImplicitReceiverOfSuspendLambda(instruction: Instruction) {
if (instruction !is MagicInstruction || instruction.kind != MagicKind.IMPLICIT_RECEIVER) return
if (instruction !is MagicInstruction ||
(instruction.kind != MagicKind.IMPLICIT_RECEIVER && instruction.kind != MagicKind.UNBOUND_CALLABLE_REFERENCE)
) return
fun CallableDescriptor?.markIfNeeded() {
if (this is AnonymousFunctionDescriptor && isSuspend) {
@@ -872,31 +874,36 @@ class ControlFlowInformationProvider private constructor(
}
}
if (instruction.element is KtDestructuringDeclarationEntry || instruction.element is KtCallExpression) {
val visited = mutableSetOf<Instruction>()
fun dfs(insn: Instruction) {
if (!visited.add(insn)) return
if (insn is CallInstruction && insn.element == instruction.element) {
for ((_, receiver) in insn.receiverValues) {
(receiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
when (val element = instruction.element) {
is KtDestructuringDeclarationEntry, is KtCallExpression -> {
val visited = mutableSetOf<Instruction>()
fun dfs(insn: Instruction) {
if (!visited.add(insn)) return
if (insn is CallInstruction && insn.element == element) {
for ((_, receiver) in insn.receiverValues) {
(receiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
}
}
for (next in insn.nextInstructions) {
dfs(next)
}
}
for (next in insn.nextInstructions) {
dfs(next)
}
}
instruction.next?.let { dfs(it) }
} else if (instruction.element is KtNameReferenceExpression || instruction.element is KtBinaryExpression ||
instruction.element is KtUnaryExpression
) {
val call = instruction.element.getResolvedCall(trace.bindingContext)
if (call is VariableAsFunctionResolvedCall) {
(call.variableCall.dispatchReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
(call.variableCall.extensionReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
instruction.next?.let { dfs(it) }
}
is KtNameReferenceExpression, is KtBinaryExpression, is KtUnaryExpression -> {
val call = element.getResolvedCall(trace.bindingContext)
if (call is VariableAsFunctionResolvedCall) {
(call.variableCall.dispatchReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
(call.variableCall.extensionReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
}
(call?.dispatchReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
(call?.extensionReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
}
is KtCallableReferenceExpression -> {
val resolvedCall = element.callableReference.getResolvedCall(trace.bindingContext)
(resolvedCall?.dispatchReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
}
(call?.dispatchReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
(call?.extensionReceiver as? ExtensionReceiver)?.declarationDescriptor?.apply { markIfNeeded() }
}
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
import kotlin.coroutines.*
fun box(): String = a { (::write)() }
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {})
}
fun a(a: suspend Writer.() -> String): String {
var res = ""
builder { res = Writer().a() }
return res
}
class Writer {
fun write(): String = "OK"
}
@@ -8562,6 +8562,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/fromJava.kt");
}
@Test
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@Test
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
@@ -8562,6 +8562,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/fromJava.kt");
}
@Test
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@Test
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
@@ -7461,6 +7461,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/fromJava.kt");
}
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/longArgs.kt");
@@ -6196,6 +6196,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/bigArity.kt");
}
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/longArgs.kt");
@@ -6196,6 +6196,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/bigArity.kt");
}
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/longArgs.kt");
@@ -6196,6 +6196,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/bigArity.kt");
}
@TestMetadata("lambdaParameterUsed.kt")
public void testLambdaParameterUsed() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/lambdaParameterUsed.kt");
}
@TestMetadata("longArgs.kt")
public void testLongArgs() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/callableReference/longArgs.kt");