Add custom applicability checks for suspend/coroutine modifiers
This commit is contained in:
@@ -18,14 +18,17 @@ package org.jetbrains.kotlin.coroutines
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||||
import org.jetbrains.kotlin.types.expressions.FakeCallKind
|
import org.jetbrains.kotlin.types.expressions.FakeCallKind
|
||||||
@@ -77,10 +80,13 @@ fun FakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(
|
|||||||
|
|
||||||
val resolutionResults = resolveFakeCall(
|
val resolutionResults = resolveFakeCall(
|
||||||
context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value,
|
context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value,
|
||||||
Name.identifier("handleResult"), callElement, callElement, FakeCallKind.OTHER,
|
OperatorNameConventions.COROUTINE_HANDLE_RESULT, callElement, callElement, FakeCallKind.OTHER,
|
||||||
listOf(firstArgument, continuation))
|
listOf(firstArgument, continuation))
|
||||||
|
|
||||||
if (resolutionResults.isSuccess) {
|
if (resolutionResults.isSuccess) {
|
||||||
context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall)
|
context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KotlinType.isValidContinuation() =
|
||||||
|
(constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.toUnsafe()
|
||||||
|
|||||||
@@ -622,6 +622,8 @@ public interface Errors {
|
|||||||
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> OPERATOR_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> OPERATOR_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
|
||||||
DiagnosticFactory2<KtOperationReferenceExpression, FunctionDescriptor, String> INFIX_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<KtOperationReferenceExpression, FunctionDescriptor, String> INFIX_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
|
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> INAPPLICABLE_MODIFIER = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
// Labels
|
// Labels
|
||||||
|
|
||||||
DiagnosticFactory0<KtSimpleNameExpression> LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING);
|
DiagnosticFactory0<KtSimpleNameExpression> LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING);
|
||||||
|
|||||||
+2
@@ -383,6 +383,8 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(OPERATOR_MODIFIER_REQUIRED, "''operator'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
|
MAP.put(OPERATOR_MODIFIER_REQUIRED, "''operator'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
|
||||||
MAP.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
|
MAP.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
|
||||||
|
|
||||||
|
MAP.put(INAPPLICABLE_MODIFIER, "''{0}'' modifier is inapplicable. The reason is that {1}", TO_STRING, STRING);
|
||||||
|
|
||||||
MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY,
|
MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY,
|
||||||
"Returns are not allowed for functions with expression body. Use block body in '{...}'");
|
"Returns are not allowed for functions with expression body. Use block body in '{...}'");
|
||||||
MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')");
|
MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')");
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ object ModifierCheckerCore {
|
|||||||
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||||
COROUTINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
COROUTINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||||
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
||||||
SUSPEND_KEYWORD to EnumSet.of(FUNCTION),
|
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION),
|
||||||
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER),
|
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||||
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
||||||
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||||
|
import org.jetbrains.kotlin.coroutines.isValidContinuation
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||||
|
import org.jetbrains.kotlin.psi.KtFunction
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
import org.jetbrains.kotlin.utils.sure
|
||||||
|
|
||||||
|
object SuspendModifierChecker : DeclarationChecker {
|
||||||
|
override fun check(
|
||||||
|
declaration: KtDeclaration,
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
diagnosticHolder: DiagnosticSink,
|
||||||
|
bindingContext: BindingContext
|
||||||
|
) {
|
||||||
|
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
|
||||||
|
if (!functionDescriptor.isSuspend) return
|
||||||
|
|
||||||
|
val suspendModifierElement = declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD).sure { "${declaration.text}" }
|
||||||
|
fun report(message: String) {
|
||||||
|
diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(suspendModifierElement, KtTokens.SUSPEND_KEYWORD, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionDescriptor.isInline) {
|
||||||
|
report("inline suspend functions are not supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val isValidContinuation = functionDescriptor.valueParameters.lastOrNull()?.type?.isValidContinuation() ?: false
|
||||||
|
if (!isValidContinuation) {
|
||||||
|
report("last parameter of suspend function should have a type of Continuation<T>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CoroutineModifierChecker : DeclarationChecker {
|
||||||
|
override fun check(
|
||||||
|
declaration: KtDeclaration,
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
diagnosticHolder: DiagnosticSink,
|
||||||
|
bindingContext: BindingContext
|
||||||
|
) {
|
||||||
|
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
|
||||||
|
if (declaration !is KtDeclarationWithBody) return
|
||||||
|
val location = KotlinLookupLocation(declaration)
|
||||||
|
|
||||||
|
for ((parameterDescriptor, parameterDeclaration) in functionDescriptor.valueParameters.zip(declaration.valueParameters)) {
|
||||||
|
if (!parameterDescriptor.isCoroutine) continue
|
||||||
|
val coroutineModifier = parameterDeclaration.modifierList?.getModifier(KtTokens.COROUTINE_KEYWORD) ?: continue
|
||||||
|
|
||||||
|
fun report(message: String) {
|
||||||
|
diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(coroutineModifier, KtTokens.COROUTINE_KEYWORD, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parameterDescriptor.type.isExtensionFunctionType) {
|
||||||
|
report("parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val returnType = getReturnTypeFromFunctionType(parameterDescriptor.type)
|
||||||
|
|
||||||
|
if (returnType.isMarkedNullable || !returnType.isValidContinuation() || !returnType.arguments.single().type.isUnit()) {
|
||||||
|
report("parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionDescriptor.isInline && !parameterDescriptor.isNoinline) {
|
||||||
|
report("coroutine parameter of inline function should be marked as 'noinline'")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val controller = getReceiverTypeFromFunctionType(parameterDescriptor.type)!!
|
||||||
|
|
||||||
|
val handleResultFunctions =
|
||||||
|
controller.memberScope
|
||||||
|
.getContributedFunctions(OperatorNameConventions.COROUTINE_HANDLE_RESULT, location)
|
||||||
|
.filter { it.isOperator }
|
||||||
|
|
||||||
|
if (handleResultFunctions.size > 1) {
|
||||||
|
report("only one operator handleResult should be declared for controller, but ${handleResultFunctions.size} found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,7 +63,9 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
|||||||
UnderscoreChecker,
|
UnderscoreChecker,
|
||||||
InlineParameterChecker,
|
InlineParameterChecker,
|
||||||
OperatorModifierChecker(),
|
OperatorModifierChecker(),
|
||||||
InfixModifierChecker())
|
InfixModifierChecker(),
|
||||||
|
SuspendModifierChecker,
|
||||||
|
CoroutineModifierChecker)
|
||||||
|
|
||||||
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
|
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
|
||||||
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
|
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
||||||
|
class Controller
|
||||||
|
|
||||||
|
class A(coroutine c: Controller.() -> Continuation<Unit>, y: Int) {
|
||||||
|
var x: String = ""
|
||||||
|
set(<!INAPPLICABLE_MODIFIER!>coroutine<!> x) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(coroutine c: Controller.() -> Continuation<Unit>) : this(c, 1)
|
||||||
|
constructor(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Nothing>, y: String) : <!NONE_APPLICABLE!>this<!>(c, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun valid(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noFunctionType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noExtensionFunction(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: (Controller) -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nullableReturnType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Unit>?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun wrongReturnType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Collection<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notUnitContinuation(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun inlineBuilder(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun inlineBuilderNoInlineCoroutine(coroutine noinline c: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public inline fun inlineBuilder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public inline fun inlineBuilderNoInlineCoroutine(/*0*/ noinline coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public fun noExtensionFunction(/*0*/ coroutine c: (Controller) -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public fun noFunctionType(/*0*/ coroutine c: kotlin.Unit): kotlin.Unit
|
||||||
|
public fun notUnitContinuation(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
|
||||||
|
public fun nullableReturnType(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>?): kotlin.Unit
|
||||||
|
public fun valid(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public fun wrongReturnType(/*0*/ coroutine c: Controller.() -> kotlin.collections.Collection<kotlin.Unit>): kotlin.Unit
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Nothing>, /*1*/ y: kotlin.String)
|
||||||
|
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>)
|
||||||
|
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ y: kotlin.Int)
|
||||||
|
public final var x: kotlin.String
|
||||||
|
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 Controller {
|
||||||
|
public constructor Controller()
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ fun emptyBuilder(coroutine c: EmptyController.() -> Continuation<Unit>) = 1
|
|||||||
fun <T> manyArgumentsBuilder(
|
fun <T> manyArgumentsBuilder(
|
||||||
coroutine c1: UnitController.() -> Continuation<Unit>,
|
coroutine c1: UnitController.() -> Continuation<Unit>,
|
||||||
coroutine c2: GenericController<T>.() -> Continuation<Unit>,
|
coroutine c2: GenericController<T>.() -> Continuation<Unit>,
|
||||||
coroutine c3: IntController.() -> Continuation<Int>
|
coroutine c3: IntController.() -> Continuation<Unit>
|
||||||
):T = null!!
|
):T = null!!
|
||||||
|
|
||||||
fun severalParamsInLambda(coroutine c: UnitController.(String, Int) -> Continuation<Unit>) {}
|
fun severalParamsInLambda(coroutine c: UnitController.(String, Int) -> Continuation<Unit>) {}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public fun builder(/*0*/ coroutine c: IntController.() -> kotlin.coroutines.Cont
|
|||||||
public fun emptyBuilder(/*0*/ coroutine c: EmptyController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
|
public fun emptyBuilder(/*0*/ coroutine c: EmptyController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
|
||||||
public fun foo(): kotlin.Unit
|
public fun foo(): kotlin.Unit
|
||||||
public fun </*0*/ T> genericBuilder(/*0*/ coroutine c: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>): T
|
public fun </*0*/ T> genericBuilder(/*0*/ coroutine c: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>): T
|
||||||
public fun </*0*/ T> manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ coroutine c2: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation<kotlin.Int>): T
|
public fun </*0*/ T> manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ coroutine c2: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): T
|
||||||
public fun severalParamsInLambda(/*0*/ coroutine c: UnitController.(kotlin.String, kotlin.Int) -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
public fun severalParamsInLambda(/*0*/ coroutine c: UnitController.(kotlin.String, kotlin.Int) -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
public fun unitBuilder(/*0*/ coroutine c: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
|
public fun unitBuilder(/*0*/ coroutine c: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
interface A {
|
||||||
|
operator fun handleResult(x: Int, y: Continuation<Nothing>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
operator fun handleResult(x: String, y: Continuation<Nothing>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C : A, B {
|
||||||
|
// multiple handleResults
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder1(coroutine c: A.() -> Continuation<Unit>) {}
|
||||||
|
fun builder2(coroutine c: B.() -> Continuation<Unit>) {}
|
||||||
|
fun builder3(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: C.() -> Continuation<Unit>) {}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun builder1(/*0*/ coroutine c: A.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public fun builder2(/*0*/ coroutine c: B.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
public fun builder3(/*0*/ coroutine c: C.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||||
|
|
||||||
|
public interface A {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open operator fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface B {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open operator fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class C : A, B {
|
||||||
|
public constructor C()
|
||||||
|
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||||
|
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
||||||
|
<!WRONG_MODIFIER_TARGET!>suspend<!> fun notMember(x: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
suspend fun valid(x: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline <!INAPPLICABLE_MODIFIER!>suspend<!> fun inlineFun(x: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<!INAPPLICABLE_MODIFIER!>suspend<!> fun noParams() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<!INAPPLICABLE_MODIFIER!>suspend<!> fun wrongParam(x: Collection<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<!INAPPLICABLE_MODIFIER!>suspend<!> fun starProjection(vararg x: Continuation<Any>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public suspend fun notMember(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
|
||||||
|
|
||||||
|
public final class Controller {
|
||||||
|
public constructor Controller()
|
||||||
|
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 inline suspend fun inlineFun(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
|
||||||
|
public final suspend fun noParams(): kotlin.Unit
|
||||||
|
public final suspend fun starProjection(/*0*/ vararg x: kotlin.coroutines.Continuation<kotlin.Any> /*kotlin.Array<out kotlin.coroutines.Continuation<kotlin.Any>>*/): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
public final suspend fun valid(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
|
||||||
|
public final suspend fun wrongParam(/*0*/ x: kotlin.collections.Collection<kotlin.Int>): kotlin.Unit
|
||||||
|
}
|
||||||
@@ -3867,6 +3867,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("coroutineApplicability.kt")
|
||||||
|
public void testCoroutineApplicability() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
||||||
public void testIrrelevantSuspendDeclarations() throws Exception {
|
public void testIrrelevantSuspendDeclarations() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt");
|
||||||
@@ -3879,12 +3885,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("manyHandleResults.kt")
|
||||||
|
public void testManyHandleResults() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonLocalSuspension.kt")
|
@TestMetadata("nonLocalSuspension.kt")
|
||||||
public void testNonLocalSuspension() throws Exception {
|
public void testNonLocalSuspension() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspendApplicability.kt")
|
||||||
|
public void testSuspendApplicability() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("suspendFunctions.kt")
|
@TestMetadata("suspendFunctions.kt")
|
||||||
public void testSuspendFunctions() throws Exception {
|
public void testSuspendFunctions() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt");
|
||||||
|
|||||||
@@ -34,5 +34,4 @@ class B {
|
|||||||
// EXIST: external
|
// EXIST: external
|
||||||
// EXIST: annotation class
|
// EXIST: annotation class
|
||||||
// EXIST: const
|
// EXIST: const
|
||||||
// EXIST: suspend
|
|
||||||
// NOTHING_ELSE
|
// NOTHING_ELSE
|
||||||
|
|||||||
@@ -38,5 +38,4 @@ var a : Int
|
|||||||
// EXIST: external
|
// EXIST: external
|
||||||
// EXIST: annotation class
|
// EXIST: annotation class
|
||||||
// EXIST: const
|
// EXIST: const
|
||||||
// EXIST: suspend
|
|
||||||
// NOTHING_ELSE
|
// NOTHING_ELSE
|
||||||
|
|||||||
@@ -25,5 +25,4 @@ package Test
|
|||||||
// EXIST: external
|
// EXIST: external
|
||||||
// EXIST: annotation class
|
// EXIST: annotation class
|
||||||
// EXIST: const
|
// EXIST: const
|
||||||
// EXIST: suspend
|
|
||||||
// NOTHING_ELSE
|
// NOTHING_ELSE
|
||||||
|
|||||||
@@ -24,5 +24,4 @@
|
|||||||
// EXIST: external
|
// EXIST: external
|
||||||
// EXIST: annotation class
|
// EXIST: annotation class
|
||||||
// EXIST: const
|
// EXIST: const
|
||||||
// EXIST: suspend
|
|
||||||
// NOTHING_ELSE
|
// NOTHING_ELSE
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
||||||
|
class Controller
|
||||||
|
|
||||||
|
fun valid(<info descr="null">coroutine</info> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noFunctionType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noExtensionFunction(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: (Controller) -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nullableReturnType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun wrongReturnType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Collection<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notUnitContinuation(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<info descr="null">inline</info> fun inlineBuilder(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that coroutine parameter of inline function should be marked as 'noinline'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<warning descr="[NOTHING_TO_INLINE] Expected performance impact of inlining 'public inline fun inlineBuilderNoInlineCoroutine(noinline coroutine c: Controller.() -> Continuation<Unit>): Unit defined in root package' can be insignificant. Inlining works best for functions with lambda parameters"><info descr="null">inline</info></warning> fun inlineBuilderNoInline<TYPO descr="Typo: In word 'Coroutine'">Coroutine</TYPO>(<info descr="null">coroutine</info> <info descr="null">noinline</info> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
||||||
|
<error descr="[WRONG_MODIFIER_TARGET] Modifier 'suspend' is not applicable to 'top level function'"><info descr="null">suspend</info></error> fun notMember(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
<info descr="null">suspend</info> fun valid(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<warning descr="[NOTHING_TO_INLINE] Expected performance impact of inlining 'public final inline suspend fun inlineFun(x: Continuation<Int>): Unit defined in Controller' can be insignificant. Inlining works best for functions with lambda parameters"><info descr="null">inline</info></warning> <error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that inline suspend functions are not supported"><info descr="null">suspend</info></error> fun inlineFun(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that last parameter of suspend function should have a type of Continuation<T>"><info descr="null">suspend</info></error> fun noParams() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that last parameter of suspend function should have a type of Continuation<T>"><info descr="null">suspend</info></error> fun wrongParam(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Collection<Int>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<info descr="null">suspend</info> fun starProjection(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<*>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -874,6 +874,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
|||||||
doTestWithInfos(fileName);
|
doTestWithInfos(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("coroutineApplicability.kt")
|
||||||
|
public void testCoroutineApplicability() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/coroutineApplicability.kt");
|
||||||
|
doTestWithInfos(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("PropertiesWithBackingFields.kt")
|
@TestMetadata("PropertiesWithBackingFields.kt")
|
||||||
public void testPropertiesWithBackingFields() throws Exception {
|
public void testPropertiesWithBackingFields() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt");
|
||||||
@@ -910,6 +916,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
|||||||
doTestWithInfos(fileName);
|
doTestWithInfos(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspendApplicability.kt")
|
||||||
|
public void testSuspendApplicability() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/suspendApplicability.kt");
|
||||||
|
doTestWithInfos(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Typos.kt")
|
@TestMetadata("Typos.kt")
|
||||||
public void testTypos() throws Exception {
|
public void testTypos() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/Typos.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/Typos.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user