Support explicit this receiver (this.foo()) for RestrictSuspension function call.

This commit is contained in:
Stanislav Erokhin
2016-12-15 16:17:32 +03:00
parent 8e3fd0efc3
commit c5aeaae8e6
3 changed files with 45 additions and 16 deletions
@@ -28,12 +28,14 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.hasRestrictSuspensionAnnotation import org.jetbrains.kotlin.resolve.descriptorUtil.hasRestrictSuspensionAnnotation
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
@@ -65,7 +67,7 @@ object CoroutineSuspendCallChecker : CallChecker {
// Here we only record enclosing function mapping (for backends purposes) // Here we only record enclosing function mapping (for backends purposes)
context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction) context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction)
checkRestrictSuspension(enclosingSuspendFunction.extensionReceiverParameter, resolvedCall, reportOn, context) checkRestrictSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
} }
closestSuspensionLambdaDescriptor != null -> { closestSuspensionLambdaDescriptor != null -> {
val callElement = resolvedCall.call.callElement as KtExpression val callElement = resolvedCall.call.callElement as KtExpression
@@ -78,7 +80,7 @@ object CoroutineSuspendCallChecker : CallChecker {
BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.call, closestSuspensionLambdaDescriptor BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.call, closestSuspensionLambdaDescriptor
) )
checkRestrictSuspension(closestSuspensionLambdaDescriptor.extensionReceiverParameter, resolvedCall, reportOn, context) checkRestrictSuspension(closestSuspensionLambdaDescriptor, resolvedCall, reportOn, context)
} }
else -> { else -> {
context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn)) context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn))
@@ -109,20 +111,28 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia
} }
private fun checkRestrictSuspension( private fun checkRestrictSuspension(
enclosingSuspendReceiver: ReceiverParameterDescriptor?, enclosingCallableDescriptor: CallableDescriptor,
resolvedCall: ResolvedCall<*>, resolvedCall: ResolvedCall<*>,
reportOn: PsiElement, reportOn: PsiElement,
context: CallCheckerContext context: CallCheckerContext
) { ) {
if (enclosingSuspendReceiver == null) return val enclosingSuspendReceiverValue = enclosingCallableDescriptor.extensionReceiverParameter?.value ?: return
val enclosingSuspendReceiverValue = enclosingSuspendReceiver.value
fun ReceiverValue.isRestrictSuspensionReceiver() = (type.supertypes() + type).any { fun ReceiverValue.isRestrictSuspensionReceiver() = (type.supertypes() + type).any {
it.constructor.declarationDescriptor?.hasRestrictSuspensionAnnotation() == true it.constructor.declarationDescriptor?.hasRestrictSuspensionAnnotation() == true
} }
// todo explicit this and implicit this is not equals now infix fun ReceiverValue.sameInstance(other: ReceiverValue?): Boolean {
infix fun ReceiverValue.sameInstance(other: ReceiverValue?) = this === other if (other == null) return false
if (this === other) return true
val referenceExpression = ((other as? ExpressionReceiver)?.expression as? KtThisExpression)?.instanceReference
val referenceTarget = referenceExpression?.let {
context.trace.get(BindingContext.REFERENCE_TARGET, referenceExpression)
}
return this === (referenceTarget as? CallableDescriptor)?.extensionReceiverParameter?.value
}
if (!enclosingSuspendReceiverValue.isRestrictSuspensionReceiver()) return if (!enclosingSuspendReceiverValue.isRestrictSuspensionReceiver()) return
@@ -14,22 +14,40 @@ fun test() {
member() member()
extension() extension()
// todo this.member()
this.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>() this.extension()
this.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
val foo = this val foo = this
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>() foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>() foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
// todo this@l.member()
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>() this@l.extension()
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
with(1) { with(1) {
// todo this@l.member()
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>() this@l.extension()
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
} }
} }
}
suspend fun RestrictedController.l() {
member()
extension()
this.member()
this.extension()
val foo = this
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
this@l.member()
this@l.extension()
with(1) {
this@l.member()
this@l.extension()
}
} }
@@ -3,6 +3,7 @@ package
public fun generate(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit public fun generate(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
public fun test(): kotlin.Unit public fun test(): kotlin.Unit
public suspend fun RestrictedController.extension(): kotlin.Unit public suspend fun RestrictedController.extension(): kotlin.Unit
public suspend fun RestrictedController.l(): kotlin.Unit
@kotlin.coroutines.RestrictSuspension public final class RestrictedController { @kotlin.coroutines.RestrictSuspension public final class RestrictedController {
public constructor RestrictedController() public constructor RestrictedController()