Support checks for annotation RestrictSuspension.

This commit is contained in:
Stanislav Erokhin
2016-12-15 14:52:57 +03:00
parent d1a3c4c48b
commit b88c8ea2e7
16 changed files with 571 additions and 0 deletions
@@ -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);
@@ -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();
@@ -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))
}
@@ -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()
}
}
}
@@ -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
}
@@ -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()
}
}
}
@@ -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
}
@@ -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<!>()
}
}
}
@@ -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
}
@@ -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<!>()
}
}
}
@@ -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
}
@@ -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<!>()
}
}
@@ -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)