Support checks for annotation RestrictSuspension.
This commit is contained in:
@@ -884,6 +884,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<PsiElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> ILLEGAL_SUSPEND_FUNCTION_CALL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
|
||||
+1
@@ -884,6 +884,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(NON_LOCAL_RETURN_IN_DISABLED_INLINE, "Non-local returns are not allowed with inlining disabled");
|
||||
MAP.put(NON_LOCAL_SUSPENSION_POINT, "Suspension functions can be called only within coroutine body");
|
||||
MAP.put(ILLEGAL_SUSPEND_FUNCTION_CALL, "Suspend functions are only allowed to be called from a coroutine or another suspend function");
|
||||
MAP.put(ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL, "Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope");
|
||||
MAP.put(SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE, "Only tail calls are allowed to another suspension function, and these calls must be used as return values");
|
||||
|
||||
MAP.setImmutable();
|
||||
|
||||
+35
@@ -23,16 +23,20 @@ import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasRestrictSuspensionAnnotation
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -60,6 +64,8 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
// Tail calls checks happen during control flow analysis
|
||||
// Here we only record enclosing function mapping (for backends purposes)
|
||||
context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction)
|
||||
|
||||
checkRestrictSuspension(enclosingSuspendFunction.extensionReceiverParameter, resolvedCall, reportOn, context)
|
||||
}
|
||||
closestSuspensionLambdaDescriptor != null -> {
|
||||
val callElement = resolvedCall.call.callElement as KtExpression
|
||||
@@ -71,6 +77,8 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
context.trace.record(
|
||||
BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.call, closestSuspensionLambdaDescriptor
|
||||
)
|
||||
|
||||
checkRestrictSuspension(closestSuspensionLambdaDescriptor.extensionReceiverParameter, resolvedCall, reportOn, context)
|
||||
}
|
||||
else -> {
|
||||
context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn))
|
||||
@@ -98,4 +106,31 @@ private fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSetti
|
||||
else if (languageVersionSettings.supportsFeature(LanguageFeature.WarnOnCoroutines)) {
|
||||
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(reportOn, LanguageFeature.Coroutines))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkRestrictSuspension(
|
||||
enclosingSuspendReceiver: ReceiverParameterDescriptor?,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext
|
||||
) {
|
||||
if (enclosingSuspendReceiver == null) return
|
||||
val enclosingSuspendReceiverValue = enclosingSuspendReceiver.value
|
||||
|
||||
fun ReceiverValue.isRestrictSuspensionReceiver() = (type.supertypes() + type).any {
|
||||
it.constructor.declarationDescriptor?.hasRestrictSuspensionAnnotation() == true
|
||||
}
|
||||
|
||||
// todo explicit this and implicit this is not equals now
|
||||
infix fun ReceiverValue.sameInstance(other: ReceiverValue?) = this === other
|
||||
|
||||
if (!enclosingSuspendReceiverValue.isRestrictSuspensionReceiver()) return
|
||||
|
||||
// member of suspend receiver
|
||||
if (enclosingSuspendReceiverValue sameInstance resolvedCall.dispatchReceiver) return
|
||||
|
||||
if (enclosingSuspendReceiverValue sameInstance resolvedCall.extensionReceiver &&
|
||||
resolvedCall.candidateDescriptor.extensionReceiverParameter!!.value.isRestrictSuspensionReceiver()) return
|
||||
|
||||
context.trace.report(Errors.ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL.on(reportOn))
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE
|
||||
|
||||
interface SuperInterface {
|
||||
suspend fun superFun() {}
|
||||
suspend fun String.superExtFun() {}
|
||||
}
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension
|
||||
open class RestrictedController : SuperInterface {
|
||||
suspend fun memberFun() {}
|
||||
suspend fun String.memberExtFun() {}
|
||||
}
|
||||
|
||||
class SubClass : RestrictedController() {
|
||||
suspend fun subFun() {}
|
||||
suspend fun String.subExtFun() {}
|
||||
}
|
||||
|
||||
fun generate1(f: suspend SuperInterface.() -> Unit) {}
|
||||
fun generate2(f: suspend RestrictedController.() -> Unit) {}
|
||||
fun generate3(f: suspend SubClass.() -> Unit) {}
|
||||
|
||||
fun String.test() {
|
||||
generate1 {
|
||||
superFun()
|
||||
superExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
}
|
||||
}
|
||||
generate2 {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
}
|
||||
}
|
||||
generate3 {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
subFun()
|
||||
superExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
subFun()
|
||||
superExtFun()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun SuperInterface.fun1() {
|
||||
superFun()
|
||||
superExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
}
|
||||
}
|
||||
suspend fun RestrictedController.fun2() {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
}
|
||||
}
|
||||
suspend fun SubClass.fun3() {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
subFun()
|
||||
superExtFun()
|
||||
with("") {
|
||||
superFun()
|
||||
superExtFun()
|
||||
memberFun()
|
||||
memberExtFun()
|
||||
subFun()
|
||||
superExtFun()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package
|
||||
|
||||
public fun generate1(/*0*/ f: suspend SuperInterface.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate2(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate3(/*0*/ f: suspend SubClass.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun kotlin.String.test(): kotlin.Unit
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension public open class RestrictedController : SuperInterface {
|
||||
public constructor RestrictedController()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend fun memberFun(): kotlin.Unit
|
||||
public open suspend override /*1*/ /*fake_override*/ fun superFun(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
public final suspend fun kotlin.String.memberExtFun(): kotlin.Unit
|
||||
public open suspend override /*1*/ /*fake_override*/ fun kotlin.String.superExtFun(): kotlin.Unit
|
||||
}
|
||||
|
||||
public final class SubClass : RestrictedController {
|
||||
public constructor SubClass()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend override /*1*/ /*fake_override*/ fun memberFun(): kotlin.Unit
|
||||
public final suspend fun subFun(): kotlin.Unit
|
||||
public open suspend override /*1*/ /*fake_override*/ fun superFun(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
public final suspend override /*1*/ /*fake_override*/ fun kotlin.String.memberExtFun(): kotlin.Unit
|
||||
public final suspend fun kotlin.String.subExtFun(): kotlin.Unit
|
||||
public open suspend override /*1*/ /*fake_override*/ fun kotlin.String.superExtFun(): kotlin.Unit
|
||||
}
|
||||
|
||||
public interface SuperInterface {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open suspend fun superFun(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
public open suspend fun kotlin.String.superExtFun(): kotlin.Unit
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE
|
||||
|
||||
interface SuperInterface
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension
|
||||
open class RestrictedController : SuperInterface
|
||||
|
||||
class SubClass : RestrictedController()
|
||||
|
||||
suspend fun Any?.extAny() {}
|
||||
suspend fun SuperInterface.extSuper() {}
|
||||
suspend fun RestrictedController.ext() {}
|
||||
suspend fun SubClass.extSub() {}
|
||||
|
||||
class A {
|
||||
suspend fun Any?.memExtAny() {}
|
||||
suspend fun SuperInterface.memExtSuper() {}
|
||||
suspend fun RestrictedController.memExt() {}
|
||||
suspend fun SubClass.memExtSub() {}
|
||||
}
|
||||
|
||||
|
||||
fun generate1(f: suspend SuperInterface.() -> Unit) {}
|
||||
fun generate2(f: suspend RestrictedController.() -> Unit) {}
|
||||
fun generate3(f: suspend SubClass.() -> Unit) {}
|
||||
|
||||
fun A.test() {
|
||||
generate1 {
|
||||
extAny()
|
||||
memExtAny()
|
||||
extSuper()
|
||||
memExtSuper()
|
||||
with(A()) {
|
||||
extAny()
|
||||
memExtAny()
|
||||
extSuper()
|
||||
memExtSuper()
|
||||
}
|
||||
}
|
||||
generate2 {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
|
||||
ext()
|
||||
memExt()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
ext()
|
||||
memExt()
|
||||
}
|
||||
}
|
||||
generate3 {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
|
||||
ext()
|
||||
memExt()
|
||||
extSub()
|
||||
memExtSub()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
ext()
|
||||
memExt()
|
||||
extSub()
|
||||
memExtSub()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun SuperInterface.fun1() {
|
||||
extAny()
|
||||
memExtAny()
|
||||
extSuper()
|
||||
memExtSuper()
|
||||
with(A()) {
|
||||
extAny()
|
||||
memExtAny()
|
||||
extSuper()
|
||||
memExtSuper()
|
||||
}
|
||||
}
|
||||
suspend fun RestrictedController.fun2() {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
|
||||
ext()
|
||||
memExt()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
ext()
|
||||
memExt()
|
||||
}
|
||||
}
|
||||
suspend fun SubClass.fun3() {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
|
||||
ext()
|
||||
memExt()
|
||||
extSub()
|
||||
memExtSub()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtAny<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extSuper<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>memExtSuper<!>()
|
||||
ext()
|
||||
memExt()
|
||||
extSub()
|
||||
memExtSub()
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package
|
||||
|
||||
public fun generate1(/*0*/ f: suspend SuperInterface.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate2(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate3(/*0*/ f: suspend SubClass.() -> kotlin.Unit): kotlin.Unit
|
||||
public suspend fun RestrictedController.ext(): kotlin.Unit
|
||||
public suspend fun kotlin.Any?.extAny(): kotlin.Unit
|
||||
public suspend fun SubClass.extSub(): kotlin.Unit
|
||||
public suspend fun SuperInterface.extSuper(): kotlin.Unit
|
||||
public fun A.test(): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
public constructor A()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
public final suspend fun RestrictedController.memExt(): kotlin.Unit
|
||||
public final suspend fun kotlin.Any?.memExtAny(): kotlin.Unit
|
||||
public final suspend fun SubClass.memExtSub(): kotlin.Unit
|
||||
public final suspend fun SuperInterface.memExtSuper(): kotlin.Unit
|
||||
}
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension public open class RestrictedController : SuperInterface {
|
||||
public constructor RestrictedController()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class SubClass : RestrictedController {
|
||||
public constructor SubClass()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface SuperInterface {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE
|
||||
|
||||
interface SuperInterface
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension
|
||||
open class RestrictedController : SuperInterface
|
||||
|
||||
class SubClass : RestrictedController()
|
||||
|
||||
suspend fun topLevel() {}
|
||||
|
||||
class A {
|
||||
suspend fun member() {}
|
||||
}
|
||||
|
||||
fun generate1(f: suspend SuperInterface.() -> Unit) {}
|
||||
fun generate2(f: suspend RestrictedController.() -> Unit) {}
|
||||
fun generate3(f: suspend SubClass.() -> Unit) {}
|
||||
|
||||
fun A.test() {
|
||||
generate1 {
|
||||
topLevel()
|
||||
member()
|
||||
with(A()) {
|
||||
topLevel()
|
||||
member()
|
||||
}
|
||||
}
|
||||
generate2 {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
}
|
||||
}
|
||||
generate3 {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun SuperInterface.fun1() {
|
||||
topLevel()
|
||||
member()
|
||||
with(A()) {
|
||||
topLevel()
|
||||
member()
|
||||
}
|
||||
}
|
||||
suspend fun RestrictedController.fun2() {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
}
|
||||
}
|
||||
suspend fun SubClass.fun3() {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
with(A()) {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>topLevel<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package
|
||||
|
||||
public fun generate1(/*0*/ f: suspend SuperInterface.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate2(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun generate3(/*0*/ f: suspend SubClass.() -> kotlin.Unit): kotlin.Unit
|
||||
public suspend fun topLevel(): kotlin.Unit
|
||||
public fun A.test(): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
public constructor A()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend fun member(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension public open class RestrictedController : SuperInterface {
|
||||
public constructor RestrictedController()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class SubClass : RestrictedController {
|
||||
public constructor SubClass()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface SuperInterface {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension
|
||||
class RestrictedController {
|
||||
suspend fun member() {}
|
||||
}
|
||||
|
||||
suspend fun RestrictedController.extension() {}
|
||||
|
||||
fun generate(f: suspend RestrictedController.() -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
generate() l@ {
|
||||
member()
|
||||
extension()
|
||||
|
||||
// todo
|
||||
this.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
this.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
|
||||
|
||||
val foo = this
|
||||
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
foo.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
|
||||
|
||||
// todo
|
||||
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
|
||||
|
||||
with(1) {
|
||||
// todo
|
||||
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>member<!>()
|
||||
this@l.<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extension<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public fun generate(/*0*/ f: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
public suspend fun RestrictedController.extension(): kotlin.Unit
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension public final class RestrictedController {
|
||||
public constructor RestrictedController()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend fun member(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
@kotlin.coroutines.RestrictSuspension
|
||||
class RestrictedController
|
||||
|
||||
suspend fun Any?.extFun() {}
|
||||
suspend fun suspendFun() {}
|
||||
|
||||
fun generate(<!UNUSED_PARAMETER!>c<!>: suspend RestrictedController.() -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
generate {
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>extFun<!>()
|
||||
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>suspendFun<!>()
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public fun generate(/*0*/ c: suspend RestrictedController.() -> kotlin.Unit): kotlin.Unit
|
||||
public suspend fun suspendFun(): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
public suspend fun kotlin.Any?.extFun(): kotlin.Unit
|
||||
|
||||
@kotlin.coroutines.RestrictSuspension public final class RestrictedController {
|
||||
public constructor RestrictedController()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -4417,6 +4417,45 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class RestrictSuspension extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInRestrictSuspension() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/restrictSuspension"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("allMembersAllowed.kt")
|
||||
public void testAllMembersAllowed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension/allMembersAllowed.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensions.kt")
|
||||
public void testExtensions() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension/extensions.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("notRelatedFun.kt")
|
||||
public void testNotRelatedFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension/notRelatedFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sameInstance.kt")
|
||||
public void testSameInstance() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension/sameInstance.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleForbidden.kt")
|
||||
public void testSimpleForbidden() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/restrictSuspension/simpleForbidden.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionType")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -55,4 +55,6 @@ public val SUSPENDED: Any? = Any()
|
||||
* receiver only and are restricted from calling arbitrary suspension functions.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
public annotation class RestrictSuspension
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.resolve.descriptorUtil
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
@@ -31,6 +33,7 @@ val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME = FqName("kotlin.internal.LowPri
|
||||
private val HIDES_MEMBERS_ANNOTATION_FQ_NAME = FqName("kotlin.internal.HidesMembers")
|
||||
private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes")
|
||||
private val DYNAMIC_EXTENSION_FQ_NAME = FqName("kotlin.internal.DynamicExtension")
|
||||
private val RESTRICT_SUSPENSION_FQ_NAME = FqName("kotlin.coroutines.RestrictSuspension")
|
||||
|
||||
// @HidesMembers annotation only has effect for members with these names
|
||||
val HIDES_MEMBERS_NAME_LIST = setOf(Name.identifier("forEach"))
|
||||
@@ -48,6 +51,7 @@ fun CallableDescriptor.hasLowPriorityInOverloadResolution(): Boolean = annotatio
|
||||
|
||||
fun CallableDescriptor.hasHidesMembersAnnotation(): Boolean = annotations.hasAnnotation(HIDES_MEMBERS_ANNOTATION_FQ_NAME)
|
||||
fun CallableDescriptor.hasDynamicExtensionAnnotation(): Boolean = annotations.hasAnnotation(DYNAMIC_EXTENSION_FQ_NAME)
|
||||
fun ClassifierDescriptor.hasRestrictSuspensionAnnotation(): Boolean = annotations.hasAnnotation(RESTRICT_SUSPENSION_FQ_NAME)
|
||||
|
||||
fun TypeParameterDescriptor.hasOnlyInputTypesAnnotation(): Boolean = annotations.hasAnnotation(ONLY_INPUT_TYPES_FQ_NAME)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user