FIR: Fix false-positive ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL on invokeExtension calls
This commit is contained in:
committed by
TeamCityServer
parent
37b5237e97
commit
2e37ec6f0c
+6
@@ -35410,6 +35410,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("invokeExtension.kt")
|
||||||
|
public void testInvokeExtension() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/invokeExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("memberExtension.kt")
|
@TestMetadata("memberExtension.kt")
|
||||||
public void testMemberExtension() throws Exception {
|
public void testMemberExtension() throws Exception {
|
||||||
|
|||||||
+6
@@ -35410,6 +35410,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("invokeExtension.kt")
|
||||||
|
public void testInvokeExtension() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/invokeExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("memberExtension.kt")
|
@TestMetadata("memberExtension.kt")
|
||||||
public void testMemberExtension() throws Exception {
|
public void testMemberExtension() throws Exception {
|
||||||
|
|||||||
+6
@@ -35410,6 +35410,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("invokeExtension.kt")
|
||||||
|
public void testInvokeExtension() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/invokeExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("memberExtension.kt")
|
@TestMetadata("memberExtension.kt")
|
||||||
public void testMemberExtension() throws Exception {
|
public void testMemberExtension() throws Exception {
|
||||||
|
|||||||
+38
-8
@@ -23,16 +23,12 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
|||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|
||||||
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||||
@@ -144,11 +140,14 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
|||||||
context: CheckerContext
|
context: CheckerContext
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val session = context.session
|
val session = context.session
|
||||||
|
|
||||||
val enclosingSuspendFunctionDispatchReceiverOwnerSymbol =
|
val enclosingSuspendFunctionDispatchReceiverOwnerSymbol =
|
||||||
(enclosingSuspendFunction.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.toFirRegularClassSymbol(session)
|
(enclosingSuspendFunction.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.toFirRegularClassSymbol(session)
|
||||||
val enclosingSuspendFunctionExtensionReceiverOwnerSymbol = enclosingSuspendFunction.takeIf { it.receiverTypeRef != null }?.symbol
|
val enclosingSuspendFunctionExtensionReceiverOwnerSymbol = enclosingSuspendFunction.takeIf { it.receiverTypeRef != null }?.symbol
|
||||||
val dispatchReceiverExpression = expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }
|
|
||||||
val extensionReceiverExpression = expression.extensionReceiver.takeIf { it !is FirNoReceiverExpression }
|
val (dispatchReceiverExpression, extensionReceiverExpression, extensionReceiverParameterType) =
|
||||||
|
expression.computeReceiversInfo(session, calledDeclarationSymbol)
|
||||||
|
|
||||||
for (receiverExpression in listOfNotNull(dispatchReceiverExpression, extensionReceiverExpression)) {
|
for (receiverExpression in listOfNotNull(dispatchReceiverExpression, extensionReceiverExpression)) {
|
||||||
if (!receiverExpression.typeRef.coneType.isRestrictSuspensionReceiver(session)) continue
|
if (!receiverExpression.typeRef.coneType.isRestrictSuspensionReceiver(session)) continue
|
||||||
if (sameInstanceOfReceiver(receiverExpression, enclosingSuspendFunctionDispatchReceiverOwnerSymbol)) continue
|
if (sameInstanceOfReceiver(receiverExpression, enclosingSuspendFunctionDispatchReceiverOwnerSymbol)) continue
|
||||||
@@ -156,14 +155,17 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enclosingSuspendFunctionExtensionReceiverOwnerSymbol?.resolvedReceiverTypeRef?.coneType?.isRestrictSuspensionReceiver(session) != true) {
|
if (enclosingSuspendFunctionExtensionReceiverOwnerSymbol?.resolvedReceiverTypeRef?.coneType?.isRestrictSuspensionReceiver(session) != true) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sameInstanceOfReceiver(dispatchReceiverExpression, enclosingSuspendFunctionExtensionReceiverOwnerSymbol)) {
|
if (sameInstanceOfReceiver(dispatchReceiverExpression, enclosingSuspendFunctionExtensionReceiverOwnerSymbol)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sameInstanceOfReceiver(extensionReceiverExpression, enclosingSuspendFunctionExtensionReceiverOwnerSymbol)) {
|
if (sameInstanceOfReceiver(extensionReceiverExpression, enclosingSuspendFunctionExtensionReceiverOwnerSymbol)) {
|
||||||
if (calledDeclarationSymbol.resolvedReceiverTypeRef?.coneType?.isRestrictSuspensionReceiver(session) == true) {
|
if (extensionReceiverParameterType?.isRestrictSuspensionReceiver(session) == true) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,4 +198,32 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Triple<DispatchReceiverValue, ExtensionReceiverValue, ExtensionReceiverParameterType>
|
||||||
|
private fun FirQualifiedAccessExpression.computeReceiversInfo(
|
||||||
|
session: FirSession,
|
||||||
|
calledDeclarationSymbol: FirCallableSymbol<*>
|
||||||
|
): Triple<FirExpression?, FirExpression?, ConeKotlinType?> {
|
||||||
|
if (this is FirImplicitInvokeCall &&
|
||||||
|
dispatchReceiver.typeRef.coneTypeSafe<ConeKotlinType>()?.isSuspendFunctionType(session) == true
|
||||||
|
) {
|
||||||
|
val variableForInvoke = dispatchReceiver
|
||||||
|
val variableForInvokeType = variableForInvoke.typeRef.coneType
|
||||||
|
if (!variableForInvokeType.isExtensionFunctionType) return Triple(null, null, null)
|
||||||
|
|
||||||
|
// `a.foo()` is resolved to invokeExtension, so it's been desugared to `foo.invoke(a)`
|
||||||
|
// And we use the first argument (`a`) as an extension receiver
|
||||||
|
return Triple(
|
||||||
|
null,
|
||||||
|
argumentList.arguments.getOrNull(0),
|
||||||
|
variableForInvokeType.typeArguments.getOrNull(0) as? ConeKotlinType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Triple(
|
||||||
|
dispatchReceiver.takeIf { it !is FirNoReceiverExpression },
|
||||||
|
extensionReceiver.takeIf { it !is FirNoReceiverExpression },
|
||||||
|
calledDeclarationSymbol.resolvedReceiverTypeRef?.coneType,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// SKIP_TXT
|
||||||
|
import kotlin.coroutines.RestrictsSuspension
|
||||||
|
|
||||||
|
@RestrictsSuspension
|
||||||
|
interface Scope
|
||||||
|
|
||||||
|
suspend fun Scope.foo(
|
||||||
|
a1: suspend Scope.() -> Unit,
|
||||||
|
a2: suspend () -> Unit,
|
||||||
|
a3: suspend String.() -> Unit,
|
||||||
|
) {
|
||||||
|
a1()
|
||||||
|
this.a1()
|
||||||
|
<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>a2<!>()
|
||||||
|
|
||||||
|
"".<!ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL!>a3<!>()
|
||||||
|
}
|
||||||
Generated
+6
@@ -35506,6 +35506,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("invokeExtension.kt")
|
||||||
|
public void testInvokeExtension() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/invokeExtension.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("memberExtension.kt")
|
@TestMetadata("memberExtension.kt")
|
||||||
public void testMemberExtension() throws Exception {
|
public void testMemberExtension() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user