Skip to content

Commit e56d735

Browse files
Alexey AndreevAlexey Andreev
authored andcommitted
JS: refactor how last argument to suspend call is substituted
1 parent 050a1e7 commit e56d735

File tree

9 files changed

+48
-29
lines changed

9 files changed

+48
-29
lines changed

compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// WITH_RUNTIME
22
// WITH_REFLECT
3+
// TARGET_BACKEND: JVM
34
class Controller {
45
fun withValue(v: String, x: Continuation<String>) {
56
x.resume(v)

js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2015 JetBrains s.r.o.
2+
* Copyright 2010-2016 JetBrains s.r.o.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.js.descriptorUtils
1919
import com.intellij.openapi.util.text.StringUtil
2020
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
2121
import org.jetbrains.kotlin.descriptors.ClassDescriptor
22+
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
2223
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
24+
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
2325
import org.jetbrains.kotlin.name.Name
2426
import org.jetbrains.kotlin.resolve.DescriptorUtils
2527
import org.jetbrains.kotlin.types.KotlinType
@@ -50,3 +52,6 @@ fun KotlinType.getJetTypeFqName(printTypeArguments: Boolean): String {
5052
}
5153

5254
fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConstructor != null
55+
56+
val DeclarationDescriptor.isCoroutineLambda: Boolean
57+
get() = this is AnonymousFunctionDescriptor && isCoroutine

js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,6 @@ class CoroutineBodyTransformer(val program: JsProgram, val scope: JsScope, val t
507507
}
508508

509509
private fun handleSuspend(invocation: JsInvocation): JsExpression {
510-
invocation.arguments += JsLiteral.THIS
511510
val nextBlock = CoroutineBlock()
512511
currentStatements += state(nextBlock)
513512
currentStatements += JsReturn(invocation)

js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.jetbrains.kotlin.js.translate.callTranslator
1818

1919
import com.google.dart.compiler.backend.js.ast.JsExpression
20-
import com.google.dart.compiler.backend.js.ast.JsFunction
2120
import com.google.dart.compiler.backend.js.ast.JsInvocation
2221
import com.google.dart.compiler.backend.js.ast.metadata.isSuspend
2322
import org.jetbrains.kotlin.descriptors.CallableDescriptor

js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.jetbrains.annotations.NotNull;
2323
import org.jetbrains.annotations.Nullable;
2424
import org.jetbrains.kotlin.descriptors.*;
25-
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
2625
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
2726
import org.jetbrains.kotlin.js.config.JsConfig;
2827
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
@@ -37,6 +36,7 @@
3736

3837
import java.util.*;
3938

39+
import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.isCoroutineLambda;
4040
import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
4141
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
4242

@@ -358,14 +358,10 @@ public JsExpression getDispatchReceiver(@NotNull ReceiverParameterDescriptor des
358358
if (alias != null) {
359359
return alias;
360360
}
361-
if (descriptor.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
362-
AnonymousFunctionDescriptor function = (AnonymousFunctionDescriptor) descriptor.getContainingDeclaration();
363-
if (function.isCoroutine()) {
364-
assert function.getExtensionReceiverParameter() != null;
365-
JsNameRef result = new JsNameRef("$$controller$$", JsLiteral.THIS);
366-
MetadataProperties.setCoroutineController(result, true);
367-
return result;
368-
}
361+
if (isCoroutineLambda(descriptor.getContainingDeclaration())) {
362+
JsNameRef result = new JsNameRef("$$controller$$", JsLiteral.THIS);
363+
MetadataProperties.setCoroutineController(result, true);
364+
return result;
369365
}
370366

371367
if (DescriptorUtils.isObject(descriptor.getContainingDeclaration())) {
@@ -513,6 +509,9 @@ public JsExpression getArgumentForClosureConstructor(@NotNull DeclarationDescrip
513509
if (descriptor instanceof ReceiverParameterDescriptor) {
514510
return getDispatchReceiver((ReceiverParameterDescriptor) descriptor);
515511
}
512+
if (isCoroutineLambda(descriptor)) {
513+
return JsLiteral.THIS;
514+
}
516515
return getNameForDescriptor(descriptor).makeRef();
517516
}
518517

js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
package org.jetbrains.kotlin.js.translate.context
1818

19-
import org.jetbrains.kotlin.descriptors.*
2019
import com.google.dart.compiler.backend.js.ast.JsName
2120
import com.google.dart.compiler.backend.js.ast.JsScope
21+
import org.jetbrains.kotlin.descriptors.*
22+
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
2223
import org.jetbrains.kotlin.js.naming.NameSuggestion
2324
import org.jetbrains.kotlin.resolve.DescriptorUtils
2425
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
@@ -48,8 +49,13 @@ class UsageTracker(
4849

4950
// local named function
5051
if (descriptor is FunctionDescriptor && descriptor.visibility == Visibilities.LOCAL) {
51-
assert(!descriptor.getName().isSpecial) { "Function with special name can not be captured, descriptor: $descriptor" }
52-
captureIfNeed(descriptor)
52+
if (descriptor.isCoroutineLambda) {
53+
captureIfNeed(descriptor)
54+
}
55+
else {
56+
assert(!descriptor.getName().isSpecial) { "Function with special name can not be captured, descriptor: $descriptor" }
57+
captureIfNeed(descriptor)
58+
}
5359
}
5460
// local variable
5561
else if (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) {
@@ -65,14 +71,15 @@ class UsageTracker(
6571
}
6672

6773
private fun captureIfNeed(descriptor: DeclarationDescriptor?) {
68-
6974
if (descriptor == null || isCaptured(descriptor) || !isInLocalDeclaration() ||
7075
isAncestor(containingDescriptor, descriptor, /* strict = */ true) ||
7176
isReceiverAncestor(descriptor) || isSingletonReceiver(descriptor)
7277
) {
7378
return
7479
}
7580

81+
if (descriptor.isCoroutineLambda && descriptor == containingDescriptor) return
82+
7683
parent?.captureIfNeed(descriptor)
7784

7885
captured[descriptor] = descriptor.getJsNameForCapturedDescriptor()
@@ -164,9 +171,9 @@ class UsageTracker(
164171
}
165172

166173
private fun DeclarationDescriptor.getJsNameForCapturedDescriptor(): JsName {
167-
val suggestedName = when (this) {
168-
is ReceiverParameterDescriptor -> getNameForCapturedReceiver()
169-
is TypeParameterDescriptor -> Namer.isInstanceSuggestedName(this)
174+
val suggestedName = when {
175+
this is ReceiverParameterDescriptor -> getNameForCapturedReceiver()
176+
this is TypeParameterDescriptor -> Namer.isInstanceSuggestedName(this)
170177

171178
// Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes
172179
else -> {

js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.js.translate.expression
1919
import com.google.dart.compiler.backend.js.ast.*
2020
import com.google.dart.compiler.backend.js.ast.metadata.*
2121
import org.jetbrains.kotlin.descriptors.*
22+
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
2223
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
24+
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
2325
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
2426
import org.jetbrains.kotlin.js.translate.context.TranslationContext
2527
import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
@@ -75,11 +77,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
7577
lambdaCreator.isLocal = true
7678
lambdaCreator.coroutineType = continuationType
7779
lambdaCreator.controllerType = controllerType
78-
if (!isRecursive) {
80+
if (!isRecursive || descriptor.isCoroutineLambda) {
7981
lambda.name = null
8082
}
8183
lambdaCreator.name.staticRef = lambdaCreator
82-
return lambdaCreator.withCapturedParameters(descriptor, functionContext, invokingContext)
84+
return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext),
85+
invokingContext)
8386
}
8487

8588
lambda.isLocal = true
@@ -101,6 +104,10 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
101104
}
102105
}
103106

107+
private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext {
108+
return if (isCoroutineLambda) context.innerContextWithDescriptorsAliased(mapOf(this to JsLiteral.THIS)) else context
109+
}
110+
104111
fun JsFunction.withCapturedParameters(
105112
descriptor: CallableMemberDescriptor,
106113
context: TranslationContext,
@@ -116,7 +123,7 @@ fun JsFunction.withCapturedParameters(
116123
val tracker = context.usageTracker()!!
117124

118125
for ((capturedDescriptor, name) in tracker.capturedDescriptorToJsName) {
119-
if (capturedDescriptor == tracker.containingDescriptor) continue
126+
if (capturedDescriptor == tracker.containingDescriptor && !capturedDescriptor.isCoroutineLambda) continue
120127

121128
val capturedRef = invokingContext.getArgumentForClosureConstructor(capturedDescriptor)
122129
var additionalArgs = listOf(capturedRef)

js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.psi.KtLambdaExpression
3939
import org.jetbrains.kotlin.psi.KtPsiUtil
4040
import org.jetbrains.kotlin.psi.ValueArgument
4141
import org.jetbrains.kotlin.resolve.calls.model.*
42+
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
4243
import org.jetbrains.kotlin.types.KotlinType
4344
import java.util.*
4445

@@ -75,9 +76,6 @@ class CallArgumentTranslator private constructor(
7576

7677
private fun translate(): ArgumentsInfo {
7778
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
78-
if (valueParameters.isEmpty()) {
79-
return ArgumentsInfo(listOf<JsExpression>(), false, null)
80-
}
8179
var hasSpreadOperator = false
8280
var cachedReceiver: TemporaryConstVariable? = null
8381

@@ -159,10 +157,15 @@ class CallArgumentTranslator private constructor(
159157
}
160158

161159
val callableDescriptor = resolvedCall.resultingDescriptor
162-
if (callableDescriptor !is FunctionDescriptor || !callableDescriptor.isSuspend) {
163-
removeLastUndefinedArguments(result)
160+
if (callableDescriptor is FunctionDescriptor && callableDescriptor.isSuspend &&
161+
callableDescriptor.initialSignatureDescriptor != null
162+
) {
163+
val coroutineDescriptor = resolvedCall.getImplicitReceiverValue()!!.declarationDescriptor
164+
result.add(context().getAliasForDescriptor(coroutineDescriptor) ?: JsLiteral.THIS)
164165
}
165166

167+
removeLastUndefinedArguments(result)
168+
166169
return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver)
167170
}
168171

js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.jetbrains.annotations.Nullable;
2424
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
2525
import org.jetbrains.kotlin.descriptors.*;
26-
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
2726
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
2827
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
2928
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
@@ -330,7 +329,7 @@ else if (KotlinBuiltIns.isUnit(returnType)) {
330329

331330
ImplicitReceiver receiver = (ImplicitReceiver) returnCall.getDispatchReceiver();
332331
assert receiver != null;
333-
AnonymousFunctionDescriptor lambdaDescriptor = (AnonymousFunctionDescriptor) receiver.getDeclarationDescriptor();
332+
FunctionDescriptor lambdaDescriptor = (FunctionDescriptor) receiver.getDeclarationDescriptor();
334333
ReceiverParameterDescriptor receiverParameter = lambdaDescriptor.getExtensionReceiverParameter();
335334
assert receiverParameter != null;
336335
JsExpression jsReceiver = returnContext.getDispatchReceiver(receiverParameter);

0 commit comments

Comments
 (0)