JS: refactor how last argument to suspend call is substituted
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
// TARGET_BACKEND: JVM
|
||||||
class Controller {
|
class Controller {
|
||||||
fun withValue(v: String, x: Continuation<String>) {
|
fun withValue(v: String, x: Continuation<String>) {
|
||||||
x.resume(v)
|
x.resume(v)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 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.
|
||||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.js.descriptorUtils
|
|||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -50,3 +52,6 @@ fun KotlinType.getJetTypeFqName(printTypeArguments: Boolean): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConstructor != null
|
fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConstructor != null
|
||||||
|
|
||||||
|
val DeclarationDescriptor.isCoroutineLambda: Boolean
|
||||||
|
get() = this is AnonymousFunctionDescriptor && isCoroutine
|
||||||
@@ -507,7 +507,6 @@ class CoroutineBodyTransformer(val program: JsProgram, val scope: JsScope, val t
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSuspend(invocation: JsInvocation): JsExpression {
|
private fun handleSuspend(invocation: JsInvocation): JsExpression {
|
||||||
invocation.arguments += JsLiteral.THIS
|
|
||||||
val nextBlock = CoroutineBlock()
|
val nextBlock = CoroutineBlock()
|
||||||
currentStatements += state(nextBlock)
|
currentStatements += state(nextBlock)
|
||||||
currentStatements += JsReturn(invocation)
|
currentStatements += JsReturn(invocation)
|
||||||
|
|||||||
-1
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.callTranslator
|
package org.jetbrains.kotlin.js.translate.callTranslator
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsExpression
|
import com.google.dart.compiler.backend.js.ast.JsExpression
|
||||||
import com.google.dart.compiler.backend.js.ast.JsFunction
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsInvocation
|
import com.google.dart.compiler.backend.js.ast.JsInvocation
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.isSuspend
|
import com.google.dart.compiler.backend.js.ast.metadata.isSuspend
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
|||||||
+8
-9
@@ -22,7 +22,6 @@ import com.intellij.psi.PsiElement;
|
|||||||
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.descriptors.impl.AnonymousFunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||||
@@ -37,6 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.isCoroutineLambda;
|
||||||
import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
|
import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
|
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
|
||||||
|
|
||||||
@@ -358,14 +358,10 @@ public class TranslationContext {
|
|||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
if (descriptor.getContainingDeclaration() instanceof AnonymousFunctionDescriptor) {
|
if (isCoroutineLambda(descriptor.getContainingDeclaration())) {
|
||||||
AnonymousFunctionDescriptor function = (AnonymousFunctionDescriptor) descriptor.getContainingDeclaration();
|
JsNameRef result = new JsNameRef("$$controller$$", JsLiteral.THIS);
|
||||||
if (function.isCoroutine()) {
|
MetadataProperties.setCoroutineController(result, true);
|
||||||
assert function.getExtensionReceiverParameter() != null;
|
return result;
|
||||||
JsNameRef result = new JsNameRef("$$controller$$", JsLiteral.THIS);
|
|
||||||
MetadataProperties.setCoroutineController(result, true);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DescriptorUtils.isObject(descriptor.getContainingDeclaration())) {
|
if (DescriptorUtils.isObject(descriptor.getContainingDeclaration())) {
|
||||||
@@ -513,6 +509,9 @@ public class TranslationContext {
|
|||||||
if (descriptor instanceof ReceiverParameterDescriptor) {
|
if (descriptor instanceof ReceiverParameterDescriptor) {
|
||||||
return getDispatchReceiver((ReceiverParameterDescriptor) descriptor);
|
return getDispatchReceiver((ReceiverParameterDescriptor) descriptor);
|
||||||
}
|
}
|
||||||
|
if (isCoroutineLambda(descriptor)) {
|
||||||
|
return JsLiteral.THIS;
|
||||||
|
}
|
||||||
return getNameForDescriptor(descriptor).makeRef();
|
return getNameForDescriptor(descriptor).makeRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.context
|
package org.jetbrains.kotlin.js.translate.context
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName
|
import com.google.dart.compiler.backend.js.ast.JsName
|
||||||
import com.google.dart.compiler.backend.js.ast.JsScope
|
import com.google.dart.compiler.backend.js.ast.JsScope
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
||||||
@@ -48,8 +49,13 @@ class UsageTracker(
|
|||||||
|
|
||||||
// local named function
|
// local named function
|
||||||
if (descriptor is FunctionDescriptor && descriptor.visibility == Visibilities.LOCAL) {
|
if (descriptor is FunctionDescriptor && descriptor.visibility == Visibilities.LOCAL) {
|
||||||
assert(!descriptor.getName().isSpecial) { "Function with special name can not be captured, descriptor: $descriptor" }
|
if (descriptor.isCoroutineLambda) {
|
||||||
captureIfNeed(descriptor)
|
captureIfNeed(descriptor)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(!descriptor.getName().isSpecial) { "Function with special name can not be captured, descriptor: $descriptor" }
|
||||||
|
captureIfNeed(descriptor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// local variable
|
// local variable
|
||||||
else if (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) {
|
else if (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) {
|
||||||
@@ -65,7 +71,6 @@ class UsageTracker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun captureIfNeed(descriptor: DeclarationDescriptor?) {
|
private fun captureIfNeed(descriptor: DeclarationDescriptor?) {
|
||||||
|
|
||||||
if (descriptor == null || isCaptured(descriptor) || !isInLocalDeclaration() ||
|
if (descriptor == null || isCaptured(descriptor) || !isInLocalDeclaration() ||
|
||||||
isAncestor(containingDescriptor, descriptor, /* strict = */ true) ||
|
isAncestor(containingDescriptor, descriptor, /* strict = */ true) ||
|
||||||
isReceiverAncestor(descriptor) || isSingletonReceiver(descriptor)
|
isReceiverAncestor(descriptor) || isSingletonReceiver(descriptor)
|
||||||
@@ -73,6 +78,8 @@ class UsageTracker(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (descriptor.isCoroutineLambda && descriptor == containingDescriptor) return
|
||||||
|
|
||||||
parent?.captureIfNeed(descriptor)
|
parent?.captureIfNeed(descriptor)
|
||||||
|
|
||||||
captured[descriptor] = descriptor.getJsNameForCapturedDescriptor()
|
captured[descriptor] = descriptor.getJsNameForCapturedDescriptor()
|
||||||
@@ -164,9 +171,9 @@ class UsageTracker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.getJsNameForCapturedDescriptor(): JsName {
|
private fun DeclarationDescriptor.getJsNameForCapturedDescriptor(): JsName {
|
||||||
val suggestedName = when (this) {
|
val suggestedName = when {
|
||||||
is ReceiverParameterDescriptor -> getNameForCapturedReceiver()
|
this is ReceiverParameterDescriptor -> getNameForCapturedReceiver()
|
||||||
is TypeParameterDescriptor -> Namer.isInstanceSuggestedName(this)
|
this is TypeParameterDescriptor -> Namer.isInstanceSuggestedName(this)
|
||||||
|
|
||||||
// Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes
|
// Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+10
-3
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.js.translate.expression
|
|||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.*
|
import com.google.dart.compiler.backend.js.ast.metadata.*
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
||||||
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
|
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
|
import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
|
||||||
@@ -75,11 +77,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
lambdaCreator.isLocal = true
|
lambdaCreator.isLocal = true
|
||||||
lambdaCreator.coroutineType = continuationType
|
lambdaCreator.coroutineType = continuationType
|
||||||
lambdaCreator.controllerType = controllerType
|
lambdaCreator.controllerType = controllerType
|
||||||
if (!isRecursive) {
|
if (!isRecursive || descriptor.isCoroutineLambda) {
|
||||||
lambda.name = null
|
lambda.name = null
|
||||||
}
|
}
|
||||||
lambdaCreator.name.staticRef = lambdaCreator
|
lambdaCreator.name.staticRef = lambdaCreator
|
||||||
return lambdaCreator.withCapturedParameters(descriptor, functionContext, invokingContext)
|
return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext),
|
||||||
|
invokingContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
lambda.isLocal = true
|
lambda.isLocal = true
|
||||||
@@ -101,6 +104,10 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext {
|
||||||
|
return if (isCoroutineLambda) context.innerContextWithDescriptorsAliased(mapOf(this to JsLiteral.THIS)) else context
|
||||||
|
}
|
||||||
|
|
||||||
fun JsFunction.withCapturedParameters(
|
fun JsFunction.withCapturedParameters(
|
||||||
descriptor: CallableMemberDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
context: TranslationContext,
|
context: TranslationContext,
|
||||||
@@ -116,7 +123,7 @@ fun JsFunction.withCapturedParameters(
|
|||||||
val tracker = context.usageTracker()!!
|
val tracker = context.usageTracker()!!
|
||||||
|
|
||||||
for ((capturedDescriptor, name) in tracker.capturedDescriptorToJsName) {
|
for ((capturedDescriptor, name) in tracker.capturedDescriptorToJsName) {
|
||||||
if (capturedDescriptor == tracker.containingDescriptor) continue
|
if (capturedDescriptor == tracker.containingDescriptor && !capturedDescriptor.isCoroutineLambda) continue
|
||||||
|
|
||||||
val capturedRef = invokingContext.getArgumentForClosureConstructor(capturedDescriptor)
|
val capturedRef = invokingContext.getArgumentForClosureConstructor(capturedDescriptor)
|
||||||
var additionalArgs = listOf(capturedRef)
|
var additionalArgs = listOf(capturedRef)
|
||||||
|
|||||||
+8
-5
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.psi.KtLambdaExpression
|
|||||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -75,9 +76,6 @@ class CallArgumentTranslator private constructor(
|
|||||||
|
|
||||||
private fun translate(): ArgumentsInfo {
|
private fun translate(): ArgumentsInfo {
|
||||||
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
|
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
|
||||||
if (valueParameters.isEmpty()) {
|
|
||||||
return ArgumentsInfo(listOf<JsExpression>(), false, null)
|
|
||||||
}
|
|
||||||
var hasSpreadOperator = false
|
var hasSpreadOperator = false
|
||||||
var cachedReceiver: TemporaryConstVariable? = null
|
var cachedReceiver: TemporaryConstVariable? = null
|
||||||
|
|
||||||
@@ -159,10 +157,15 @@ class CallArgumentTranslator private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val callableDescriptor = resolvedCall.resultingDescriptor
|
val callableDescriptor = resolvedCall.resultingDescriptor
|
||||||
if (callableDescriptor !is FunctionDescriptor || !callableDescriptor.isSuspend) {
|
if (callableDescriptor is FunctionDescriptor && callableDescriptor.isSuspend &&
|
||||||
removeLastUndefinedArguments(result)
|
callableDescriptor.initialSignatureDescriptor != null
|
||||||
|
) {
|
||||||
|
val coroutineDescriptor = resolvedCall.getImplicitReceiverValue()!!.declarationDescriptor
|
||||||
|
result.add(context().getAliasForDescriptor(coroutineDescriptor) ?: JsLiteral.THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeLastUndefinedArguments(result)
|
||||||
|
|
||||||
return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver)
|
return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
||||||
@@ -330,7 +329,7 @@ public final class TranslationUtils {
|
|||||||
|
|
||||||
ImplicitReceiver receiver = (ImplicitReceiver) returnCall.getDispatchReceiver();
|
ImplicitReceiver receiver = (ImplicitReceiver) returnCall.getDispatchReceiver();
|
||||||
assert receiver != null;
|
assert receiver != null;
|
||||||
AnonymousFunctionDescriptor lambdaDescriptor = (AnonymousFunctionDescriptor) receiver.getDeclarationDescriptor();
|
FunctionDescriptor lambdaDescriptor = (FunctionDescriptor) receiver.getDeclarationDescriptor();
|
||||||
ReceiverParameterDescriptor receiverParameter = lambdaDescriptor.getExtensionReceiverParameter();
|
ReceiverParameterDescriptor receiverParameter = lambdaDescriptor.getExtensionReceiverParameter();
|
||||||
assert receiverParameter != null;
|
assert receiverParameter != null;
|
||||||
JsExpression jsReceiver = returnContext.getDispatchReceiver(receiverParameter);
|
JsExpression jsReceiver = returnContext.getDispatchReceiver(receiverParameter);
|
||||||
|
|||||||
Reference in New Issue
Block a user