FIR: introduce ILLEGAL_SUSPEND_FUNCTION_CALL & PROPERTY_ACCESS diagnostics
This commit is contained in:
committed by
teamcityserver
parent
e4992176c1
commit
8f1d07084b
+9
@@ -1182,6 +1182,15 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
|
|
||||||
val OPERATOR_RENAMED_ON_IMPORT by error<KtImportDirective>(PositioningStrategy.IMPORT_LAST_NAME)
|
val OPERATOR_RENAMED_ON_IMPORT by error<KtImportDirective>(PositioningStrategy.IMPORT_LAST_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val SUSPEND by object : DiagnosticGroup("Suspend errors") {
|
||||||
|
val ILLEGAL_SUSPEND_FUNCTION_CALL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||||
|
parameter<Symbol>("suspendCallable")
|
||||||
|
}
|
||||||
|
val ILLEGAL_SUSPEND_PROPERTY_ACCESS by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||||
|
parameter<Symbol>("suspendCallable")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
||||||
|
|||||||
@@ -607,4 +607,8 @@ object FirErrors {
|
|||||||
val CONFLICTING_IMPORT by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
val CONFLICTING_IMPORT by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||||
val OPERATOR_RENAMED_ON_IMPORT by error0<KtImportDirective>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
val OPERATOR_RENAMED_ON_IMPORT by error0<KtImportDirective>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||||
|
|
||||||
|
// Suspend errors
|
||||||
|
val ILLEGAL_SUSPEND_FUNCTION_CALL by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
|
val ILLEGAL_SUSPEND_PROPERTY_ACCESS by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -41,7 +41,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
FirSealedClassConstructorCallChecker,
|
FirSealedClassConstructorCallChecker,
|
||||||
FirUninitializedEnumChecker,
|
FirUninitializedEnumChecker,
|
||||||
FirFunInterfaceConstructorReferenceChecker,
|
FirFunInterfaceConstructorReferenceChecker,
|
||||||
FirReifiedChecker
|
FirReifiedChecker,
|
||||||
|
FirSuspendCallChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_20_FQ_NAME
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_30_FQ_NAME
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_3_FQ_NAME
|
||||||
|
|
||||||
|
object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||||
|
private val SUSPEND_PROPERTIES_FQ_NAMES = setOf(
|
||||||
|
COROUTINE_CONTEXT_1_2_20_FQ_NAME, COROUTINE_CONTEXT_1_2_30_FQ_NAME, COROUTINE_CONTEXT_1_3_FQ_NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
@OptIn(SymbolInternals::class)
|
||||||
|
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
|
||||||
|
if (reference is FirResolvedCallableReference) return
|
||||||
|
val symbol = reference.resolvedSymbol as? FirCallableSymbol ?: return
|
||||||
|
symbol.ensureResolved(FirResolvePhase.STATUS)
|
||||||
|
val fir = symbol.fir as? FirMemberDeclaration ?: return
|
||||||
|
when (fir) {
|
||||||
|
is FirSimpleFunction -> if (!fir.isSuspend) return
|
||||||
|
is FirProperty -> if (symbol.callableId.asSingleFqName() !in SUSPEND_PROPERTIES_FQ_NAMES) return
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
val enclosingSuspendFunction = findEnclosingSuspendFunction(context)
|
||||||
|
if (enclosingSuspendFunction == null) {
|
||||||
|
when (fir) {
|
||||||
|
is FirSimpleFunction -> reporter.reportOn(expression.source, FirErrors.ILLEGAL_SUSPEND_FUNCTION_CALL, symbol, context)
|
||||||
|
is FirProperty -> reporter.reportOn(expression.source, FirErrors.ILLEGAL_SUSPEND_PROPERTY_ACCESS, symbol, context)
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findEnclosingSuspendFunction(context: CheckerContext): FirFunction? {
|
||||||
|
return context.containingDeclarations.lastOrNull {
|
||||||
|
when (it) {
|
||||||
|
is FirAnonymousFunction -> it.typeRef.coneType.isSuspendFunctionType(context.session)
|
||||||
|
is FirSimpleFunction -> it.isSuspend
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
} as? FirFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -191,6 +191,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SELECTOR
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SELECTOR
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SUSPEND_FUNCTION_CALL
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SUSPEND_PROPERTY_ACCESS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
|
||||||
@@ -1477,6 +1479,18 @@ class FirDefaultErrorMessages {
|
|||||||
)
|
)
|
||||||
map.put(OPERATOR_RENAMED_ON_IMPORT, "Operator renamed to a different operator on import")
|
map.put(OPERATOR_RENAMED_ON_IMPORT, "Operator renamed to a different operator on import")
|
||||||
|
|
||||||
|
// Suspend
|
||||||
|
map.put(
|
||||||
|
ILLEGAL_SUSPEND_FUNCTION_CALL,
|
||||||
|
"Suspend function ''{0}'' should be called only from a coroutine or another suspend function",
|
||||||
|
SYMBOL
|
||||||
|
)
|
||||||
|
map.put(
|
||||||
|
ILLEGAL_SUSPEND_PROPERTY_ACCESS,
|
||||||
|
"Suspend property ''{0}'' should be accessed only from a coroutine or suspend function",
|
||||||
|
SYMBOL
|
||||||
|
)
|
||||||
|
|
||||||
// Extended checkers group
|
// Extended checkers group
|
||||||
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
||||||
map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier")
|
map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier")
|
||||||
|
|||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
// !LANGUAGE: +Coroutines
|
|
||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
import kotlin.reflect.KSuspendFunction0
|
|
||||||
|
|
||||||
fun test(c: KSuspendFunction0<Unit>) {
|
|
||||||
c()
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +Coroutines
|
// !LANGUAGE: +Coroutines
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
|
|||||||
Vendored
-19
@@ -1,19 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
fun foo(x: () -> Int) {}
|
|
||||||
fun foo(x: suspend () -> Int) {}
|
|
||||||
|
|
||||||
fun usualCall(): Int = 42
|
|
||||||
suspend fun suspendCall(): Int = 42
|
|
||||||
|
|
||||||
// it's important to have ambiguity in these cases to introduce overload resolution by suspend modifier in future
|
|
||||||
fun test1() {
|
|
||||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> { usualCall() }
|
|
||||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> { suspendCall() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// candidate without suspend conversions is more specific
|
|
||||||
fun test2(f: () -> Int, g: suspend () -> Int) {
|
|
||||||
foo(f)
|
|
||||||
foo(g)
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
fun foo(x: () -> Int) {}
|
fun foo(x: () -> Int) {}
|
||||||
|
|||||||
compiler/testData/diagnostics/testsWithStdLib/builderInference/inferCoroutineTypeInOldVersion.fir.kt
Vendored
-29
@@ -1,29 +0,0 @@
|
|||||||
// !LANGUAGE: +UnrestrictedBuilderInference
|
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
class Builder<T> {
|
|
||||||
suspend fun add(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> build(g: suspend Builder<S>.() -> Unit): List<S> = TODO()
|
|
||||||
fun <S> wrongBuild(g: Builder<S>.() -> Unit): List<S> = TODO()
|
|
||||||
|
|
||||||
fun <S> Builder<S>.extensionAdd(s: S) {}
|
|
||||||
|
|
||||||
suspend fun <S> Builder<S>.safeExtensionAdd(s: S) {}
|
|
||||||
|
|
||||||
val member = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>build<!> {
|
|
||||||
add(42)
|
|
||||||
}
|
|
||||||
|
|
||||||
val memberWithoutAnn = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>wrongBuild<!> {
|
|
||||||
add(42)
|
|
||||||
}
|
|
||||||
|
|
||||||
val extension = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>build<!> {
|
|
||||||
extensionAdd("foo")
|
|
||||||
}
|
|
||||||
|
|
||||||
val safeExtension = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>build<!> {
|
|
||||||
safeExtensionAdd("foo")
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +UnrestrictedBuilderInference
|
// !LANGUAGE: +UnrestrictedBuilderInference
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
|||||||
-53
@@ -1,53 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
// SKIP_TXT
|
|
||||||
|
|
||||||
import kotlin.coroutines.*
|
|
||||||
|
|
||||||
fun ordinal() {
|
|
||||||
kotlin.coroutines.coroutineContext
|
|
||||||
coroutineContext
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun named() {
|
|
||||||
kotlin.coroutines.coroutineContext
|
|
||||||
coroutineContext
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
val coroutineContextNew = kotlin.coroutines.coroutineContext
|
|
||||||
val context = coroutineContext
|
|
||||||
}
|
|
||||||
|
|
||||||
class Controller {
|
|
||||||
fun ordinal() {
|
|
||||||
kotlin.coroutines.coroutineContext
|
|
||||||
coroutineContext
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun named() {
|
|
||||||
kotlin.coroutines.coroutineContext
|
|
||||||
coroutineContext
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun severalArgs(s: String, a: Any) {
|
|
||||||
kotlin.coroutines.coroutineContext
|
|
||||||
coroutineContext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun builder(c: () -> CoroutineContext) = {}
|
|
||||||
fun builderSuspend(c: suspend () -> CoroutineContext) = {}
|
|
||||||
|
|
||||||
fun builderSeveralArgs(c: (Int, Int, Int) -> CoroutineContext) = {}
|
|
||||||
fun builderSuspendSeveralArgs(c: suspend (Int, Int, Int) -> CoroutineContext) = {}
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
builder { kotlin.coroutines.coroutineContext }
|
|
||||||
builder { coroutineContext }
|
|
||||||
builderSuspend { kotlin.coroutines.coroutineContext }
|
|
||||||
builderSuspend { coroutineContext }
|
|
||||||
builderSeveralArgs { _, _, _ -> kotlin.coroutines.coroutineContext }
|
|
||||||
builderSeveralArgs { _, _, _ -> coroutineContext }
|
|
||||||
builderSuspendSeveralArgs { _, _, _ -> kotlin.coroutines.coroutineContext }
|
|
||||||
builderSuspendSeveralArgs { _, _, _ -> coroutineContext }
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|
||||||
|
|||||||
-22
@@ -1,22 +0,0 @@
|
|||||||
import Host.bar
|
|
||||||
|
|
||||||
object Host {
|
|
||||||
suspend fun bar() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun foo() {}
|
|
||||||
|
|
||||||
fun noSuspend() {
|
|
||||||
foo()
|
|
||||||
bar()
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
init {
|
|
||||||
foo()
|
|
||||||
bar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val x = foo()
|
|
||||||
val y = bar()
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
import Host.bar
|
import Host.bar
|
||||||
|
|
||||||
object Host {
|
object Host {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fun bar(d: Delegate): String {
|
fun bar(d: Delegate): String {
|
||||||
val x: String by d
|
val x: String by <!ILLEGAL_SUSPEND_FUNCTION_CALL!>d<!>
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
|
||||||
// !LANGUAGE: +NewInference
|
|
||||||
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
|
||||||
|
|
||||||
interface In<in E> {
|
|
||||||
fun send(element: E)
|
|
||||||
}
|
|
||||||
|
|
||||||
class InImpl<E> : In<E> {
|
|
||||||
override fun send(element: E) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalTypeInference::class)
|
|
||||||
public fun <T> builder(@BuilderInference block: In<T>.() -> Unit) {
|
|
||||||
InImpl<T>().block()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun yield() {}
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
builder {
|
|
||||||
send(run {
|
|
||||||
yield() // No error but `yield` is not inside "suspension" context actually
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -28,6 +28,6 @@ suspend fun calculate() = "OK"
|
|||||||
|
|
||||||
fun box() {
|
fun box() {
|
||||||
test {
|
test {
|
||||||
calculate()
|
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>calculate<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ interface SuspendRunnable {
|
|||||||
// suspend calls possible inside lambda matching to the parameter
|
// suspend calls possible inside lambda matching to the parameter
|
||||||
|
|
||||||
inline fun test(crossinline c: suspend () -> Unit) {
|
inline fun test(crossinline c: suspend () -> Unit) {
|
||||||
c()
|
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
|
||||||
val o = object : SuspendRunnable {
|
val o = object : SuspendRunnable {
|
||||||
override suspend fun run() {
|
override suspend fun run() {
|
||||||
c()
|
c()
|
||||||
|
|||||||
+1
-1
@@ -27,6 +27,6 @@ suspend fun calculate() = "OK"
|
|||||||
|
|
||||||
fun box() {
|
fun box() {
|
||||||
test {
|
test {
|
||||||
calculate()
|
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>calculate<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
|
||||||
// SKIP_TXT
|
|
||||||
// WITH_COROUTINES
|
|
||||||
import kotlin.coroutines.*
|
|
||||||
import kotlin.coroutines.intrinsics.*
|
|
||||||
import helpers.*
|
|
||||||
|
|
||||||
interface SuspendRunnable {
|
|
||||||
suspend fun run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function is NOT suspend
|
|
||||||
// parameter is noinline
|
|
||||||
// parameter is suspend
|
|
||||||
// Block is NOT allowed to be called inside the body of owner inline function
|
|
||||||
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
|
|
||||||
// It is possible to call startCoroutine on the parameter
|
|
||||||
// suspend calls possible inside lambda matching to the parameter
|
|
||||||
|
|
||||||
inline fun test(noinline c: suspend () -> Unit) {
|
|
||||||
c()
|
|
||||||
val o = object : SuspendRunnable {
|
|
||||||
override suspend fun run() {
|
|
||||||
c()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val l: suspend () -> Unit = { c() }
|
|
||||||
c.startCoroutine(EmptyContinuation)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun calculate() = "OK"
|
|
||||||
|
|
||||||
fun box() {
|
|
||||||
test {
|
|
||||||
calculate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ interface SuspendRunnable {
|
|||||||
// suspend calls possible inside lambda matching to the parameter
|
// suspend calls possible inside lambda matching to the parameter
|
||||||
|
|
||||||
inline fun test(c: suspend () -> Unit) {
|
inline fun test(c: suspend () -> Unit) {
|
||||||
c()
|
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
|
||||||
val o = object: SuspendRunnable {
|
val o = object: SuspendRunnable {
|
||||||
override suspend fun run() {
|
override suspend fun run() {
|
||||||
c()
|
c()
|
||||||
|
|||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
suspend fun foo1(q: suspend () -> Unit) = q()
|
|
||||||
suspend fun foo2(x: suspend (Int) -> String) = x(1)
|
|
||||||
|
|
||||||
|
|
||||||
suspend fun foo3(y: suspend String.(Int) -> Double) = "".y(1)
|
|
||||||
suspend fun String.foo4(y: suspend String.(Int) -> Double) = "".y(1)
|
|
||||||
|
|
||||||
fun noSuspend(x: suspend (Int) -> String) {
|
|
||||||
x(1)
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
suspend fun foo1(q: suspend () -> Unit) = q()
|
suspend fun foo1(q: suspend () -> Unit) = q()
|
||||||
suspend fun foo2(x: suspend (Int) -> String) = x(1)
|
suspend fun foo2(x: suspend (Int) -> String) = x(1)
|
||||||
|
|
||||||
|
|||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
fun test1(sfn: suspend () -> Unit) = sfn()
|
|
||||||
fun test2(sfn: suspend () -> Unit) = sfn.invoke()
|
|
||||||
+1
@@ -1,2 +1,3 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
fun test1(sfn: suspend () -> Unit) = <!ILLEGAL_SUSPEND_FUNCTION_CALL!>sfn<!>()
|
fun test1(sfn: suspend () -> Unit) = <!ILLEGAL_SUSPEND_FUNCTION_CALL!>sfn<!>()
|
||||||
fun test2(sfn: suspend () -> Unit) = sfn.<!ILLEGAL_SUSPEND_FUNCTION_CALL!>invoke<!>()
|
fun test2(sfn: suspend () -> Unit) = sfn.<!ILLEGAL_SUSPEND_FUNCTION_CALL!>invoke<!>()
|
||||||
|
|||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
val test1: (suspend () -> Unit)? = null
|
|
||||||
val test2: <!WRONG_MODIFIER_TARGET!>suspend<!> (() -> Unit)? = null
|
|
||||||
val test3: <!WRONG_MODIFIER_TARGET!>suspend<!> ( (() -> Unit)? ) = null
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
test1?.invoke()
|
|
||||||
test2?.invoke()
|
|
||||||
test3?.invoke()
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
val test1: (suspend () -> Unit)? = null
|
val test1: (suspend () -> Unit)? = null
|
||||||
val test2: <!WRONG_MODIFIER_TARGET!>suspend<!> (() -> Unit)? = null
|
val test2: <!WRONG_MODIFIER_TARGET!>suspend<!> (() -> Unit)? = null
|
||||||
val test3: <!WRONG_MODIFIER_TARGET!>suspend<!> ( (() -> Unit)? ) = null
|
val test3: <!WRONG_MODIFIER_TARGET!>suspend<!> ( (() -> Unit)? ) = null
|
||||||
|
|||||||
+14
@@ -3142,6 +3142,20 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.ILLEGAL_SUSPEND_FUNCTION_CALL) { firDiagnostic ->
|
||||||
|
IllegalSuspendFunctionCallImpl(
|
||||||
|
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir),
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(FirErrors.ILLEGAL_SUSPEND_PROPERTY_ACCESS) { firDiagnostic ->
|
||||||
|
IllegalSuspendPropertyAccessImpl(
|
||||||
|
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir),
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic ->
|
add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic ->
|
||||||
ConflictingJvmDeclarationsImpl(
|
ConflictingJvmDeclarationsImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
|||||||
+10
@@ -2197,6 +2197,16 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = OperatorRenamedOnImport::class
|
override val diagnosticClass get() = OperatorRenamedOnImport::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class IllegalSuspendFunctionCall : KtFirDiagnostic<PsiElement>() {
|
||||||
|
override val diagnosticClass get() = IllegalSuspendFunctionCall::class
|
||||||
|
abstract val suspendCallable: KtSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class IllegalSuspendPropertyAccess : KtFirDiagnostic<PsiElement>() {
|
||||||
|
override val diagnosticClass get() = IllegalSuspendPropertyAccess::class
|
||||||
|
abstract val suspendCallable: KtSymbol
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() {
|
abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = ConflictingJvmDeclarations::class
|
override val diagnosticClass get() = ConflictingJvmDeclarations::class
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -3545,6 +3545,22 @@ internal class OperatorRenamedOnImportImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class IllegalSuspendFunctionCallImpl(
|
||||||
|
override val suspendCallable: KtSymbol,
|
||||||
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.IllegalSuspendFunctionCall(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class IllegalSuspendPropertyAccessImpl(
|
||||||
|
override val suspendCallable: KtSymbol,
|
||||||
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.IllegalSuspendPropertyAccess(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ConflictingJvmDeclarationsImpl(
|
internal class ConflictingJvmDeclarationsImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user