Add diagnostics tests. Forbid callable reference to coroutineContext
#KT-16908: Fixed
This commit is contained in:
@@ -982,11 +982,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
ClosureCodegen coroutineCodegen = CoroutineCodegenForLambda.create(this, descriptor, declaration, cv);
|
||||
ClosureContext closureContext = descriptor.isSuspend() ? this.context.intoCoroutineClosure(
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
descriptor,
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
state.getBindingContext()
|
||||
),
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, state),
|
||||
descriptor, this, state.getTypeMapper()
|
||||
) : this.context.intoClosure(descriptor, this, typeMapper);
|
||||
ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
|
||||
|
||||
@@ -178,8 +178,7 @@ public class FunctionCodegen {
|
||||
@NotNull FunctionGenerationStrategy strategy
|
||||
) {
|
||||
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(descriptor)) {
|
||||
generateMethod(origin, CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, state.getLanguageVersionSettings()
|
||||
.supportsFeature(LanguageFeature.ReleaseCoroutines), bindingContext), strategy);
|
||||
generateMethod(origin, CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, state), strategy);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -675,8 +674,7 @@ public class FunctionCodegen {
|
||||
if (functionDescriptor instanceof AnonymousFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||
functionDescriptor = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
functionDescriptor,
|
||||
parentCodegen.state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
typeMapper.getBindingContext()
|
||||
parentCodegen.state
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+10
-24
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
@@ -42,6 +31,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.addFakeContinuationMarker;
|
||||
|
||||
/*
|
||||
* Notice the difference between two function descriptors in this class.
|
||||
* - [referencedFunction] is the function declaration which is referenced by the "::" expression. This is a real function present in code.
|
||||
@@ -78,19 +69,14 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
|
||||
) {
|
||||
super(state);
|
||||
this.resolvedCall = resolvedCall;
|
||||
if (resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor &&
|
||||
((FunctionDescriptor) resolvedCall.getResultingDescriptor()).isSuspend()) {
|
||||
this.referencedFunction = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor(),
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
state.getBindingContext());
|
||||
this.functionDescriptor = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
functionDescriptor,
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
state.getBindingContext());
|
||||
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||
if (resultingDescriptor instanceof FunctionDescriptor && ((FunctionDescriptor) resultingDescriptor).isSuspend()) {
|
||||
this.referencedFunction =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView((FunctionDescriptor) resultingDescriptor, state);
|
||||
this.functionDescriptor = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(functionDescriptor, state);
|
||||
}
|
||||
else {
|
||||
this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
|
||||
this.referencedFunction = (FunctionDescriptor) resultingDescriptor;
|
||||
this.functionDescriptor = functionDescriptor;
|
||||
}
|
||||
this.receiverType = receiverType;
|
||||
|
||||
+41
-48
@@ -407,20 +407,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
if (callableDescriptor instanceof SimpleFunctionDescriptor) {
|
||||
SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) callableDescriptor;
|
||||
if (functionDescriptor.isSuspend()){
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
functionDescriptor,
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
/*bindingContext*/ null
|
||||
);
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
|
||||
closure.setSuspend(true);
|
||||
createAndRecordSuspendFunctionView(closure, functionDescriptor, /* isSuspendLambda */ false, /* isDropSuspend */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,6 +418,33 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
super.visitCallableReferenceExpression(expression);
|
||||
}
|
||||
|
||||
private SimpleFunctionDescriptor createAndRecordSuspendFunctionView(
|
||||
MutableClosure closure,
|
||||
SimpleFunctionDescriptor functionDescriptor,
|
||||
boolean isSuspendLambda,
|
||||
boolean isDropSuspend
|
||||
) {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
functionDescriptor,
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
this.bindingContext,
|
||||
isDropSuspend
|
||||
);
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
|
||||
closure.setSuspend(true);
|
||||
if (isSuspendLambda) {
|
||||
closure.setSuspendLambda();
|
||||
}
|
||||
return jvmSuspendFunctionView;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MutableClosure recordClosure(@NotNull ClassDescriptor classDescriptor, @NotNull String name) {
|
||||
return CodegenBinding.recordClosure(bindingTrace, classDescriptor, getProperEnclosingClass(), Type.getObjectType(name));
|
||||
@@ -557,11 +571,18 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
|
||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend() &&
|
||||
!functionDescriptor.getVisibility().equals(Visibilities.LOCAL)) {
|
||||
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName();
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, name, functionDescriptor);
|
||||
MutableClosure closure = recordClosure(classDescriptor, name);
|
||||
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
(SimpleFunctionDescriptor) functionDescriptor,
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
|
||||
);
|
||||
createAndRecordSuspendFunctionView(closure, (SimpleFunctionDescriptor) functionDescriptor,
|
||||
/* isSuspendLambda*/ false, /* isDropSuspend */ false);
|
||||
|
||||
// This is a very subtle place (hack).
|
||||
// When generating bytecode of some suspend function, we replace the original descriptor
|
||||
@@ -577,21 +598,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
);
|
||||
}
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName();
|
||||
ClassDescriptor classDescriptor =
|
||||
recordClassForFunction(function, functionDescriptor, name, functionDescriptor);
|
||||
MutableClosure closure = recordClosure(classDescriptor, name);
|
||||
closure.setSuspend(true);
|
||||
functionsStack.push(functionDescriptor);
|
||||
|
||||
super.visitNamedFunction(function);
|
||||
@@ -620,21 +626,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
nameStack.push(name);
|
||||
|
||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
(SimpleFunctionDescriptor) functionDescriptor,
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
/*bindingContext*/ null,
|
||||
/*dropSuspend*/ true
|
||||
);
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
closure.setSuspend(true);
|
||||
closure.setSuspendLambda();
|
||||
createAndRecordSuspendFunctionView(closure, (SimpleFunctionDescriptor) functionDescriptor,
|
||||
/* isSuspendLambda */ true, /* isDropSuspend */ true);
|
||||
}
|
||||
|
||||
functionsStack.push(functionDescriptor);
|
||||
|
||||
@@ -338,11 +338,7 @@ class CoroutineCodegenForLambda private constructor(
|
||||
expressionCodegen,
|
||||
declaration,
|
||||
expressionCodegen.context.intoCoroutineClosure(
|
||||
getOrCreateJvmSuspendFunctionView(
|
||||
originalSuspendLambdaDescriptor,
|
||||
expressionCodegen.state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
expressionCodegen.state.bindingContext
|
||||
),
|
||||
getOrCreateJvmSuspendFunctionView(originalSuspendLambdaDescriptor, expressionCodegen.state),
|
||||
originalSuspendLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||
),
|
||||
classBuilder,
|
||||
|
||||
@@ -201,6 +201,12 @@ fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
|
||||
return this.isSuspend && this.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) == null
|
||||
}
|
||||
|
||||
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, state: GenerationState): D = getOrCreateJvmSuspendFunctionView(
|
||||
function,
|
||||
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||
state.bindingContext
|
||||
)
|
||||
|
||||
// Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`,
|
||||
// and return type Any?
|
||||
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.ClosureCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
|
||||
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
@@ -214,12 +216,34 @@ class MethodInliner(
|
||||
return
|
||||
}
|
||||
|
||||
// in case of inlining suspend lambda reference as ordinary parameter of inline function:
|
||||
// suspend fun foo (...) ...
|
||||
// inline fun inlineMe(c: (...) -> ...) ...
|
||||
// builder {
|
||||
// inlineMe(::foo)
|
||||
// }
|
||||
// we should create additional parameter for continuation.
|
||||
var coroutineDesc = desc
|
||||
if (info.invokeMethodDescriptor.isSuspend) {
|
||||
val coroutineInvokeMethodDescriptor = getOrCreateJvmSuspendFunctionView(
|
||||
info.invokeMethodDescriptor,
|
||||
inliningContext.state
|
||||
)
|
||||
val coroutineInvokeDesc = typeMapper.mapAsmMethod(coroutineInvokeMethodDescriptor).descriptor
|
||||
// And here we expect invoke(...Ljava/lang/Object;) be replaced with invoke(...Lkotlin/coroutines/Continuation;)
|
||||
// if this does not happen, insert fake continuation, since we could not have one yet.
|
||||
val argumentTypes = Type.getArgumentTypes(desc)
|
||||
if (Type.getArgumentTypes(coroutineInvokeDesc).size != argumentTypes.size) {
|
||||
addFakeContinuationMarker(this)
|
||||
coroutineDesc = Type.getMethodDescriptor(Type.getReturnType(desc), *argumentTypes, AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
}
|
||||
val valueParameters =
|
||||
listOfNotNull(info.invokeMethodDescriptor.extensionReceiverParameter) + info.invokeMethodDescriptor.valueParameters
|
||||
|
||||
val valueParamShift = Math.max(nextLocalIndex, markerShift)//NB: don't inline cause it changes
|
||||
putStackValuesIntoLocalsForLambdaOnInvoke(
|
||||
listOf(*info.invokeMethod.argumentTypes), valueParameters, valueParamShift, this, desc
|
||||
listOf(*info.invokeMethod.argumentTypes), valueParameters, valueParamShift, this, coroutineDesc
|
||||
)
|
||||
|
||||
if (invokeCall.lambdaInfo.invokeMethodDescriptor.valueParameters.isEmpty()) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
||||
@@ -1024,8 +1025,8 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
private static boolean isSuspendFunctionReference(FunctionDescriptor descriptor) {
|
||||
return descriptor.getSource() instanceof KotlinSourceElement &&
|
||||
((KotlinSourceElement) descriptor.getSource()).getPsi() instanceof KtCallableReferenceExpression &&
|
||||
return descriptor instanceof SimpleFunctionDescriptor &&
|
||||
descriptor.getName().isSpecial() &&
|
||||
CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor) != null &&
|
||||
CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor).isSuspend();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user