diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java index c763668d197..5888511ff8c 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java @@ -524,6 +524,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt"); } + @TestMetadata("safeCall.kt") + public void testSafeCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/safeCall.kt"); + } + @TestMetadata("SafeCallInvoke.kt") public void testSafeCallInvoke() throws Exception { runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index fe2b4d61db0..4aae14c1333 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.resolve.calls import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE @@ -86,7 +87,8 @@ class DiagnosticReporterByTrackingStrategy( override fun onCallReceiver(callReceiver: SimpleKotlinCallArgument, diagnostic: KotlinCallDiagnostic) { when (diagnostic.javaClass) { UnsafeCallError::class.java -> { - val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isForImplicitInvoke ?: false + val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isForImplicitInvoke + ?: callReceiver.receiver.receiverValue.type.isExtensionFunctionType tracingStrategy.unsafeCall(trace, callReceiver.receiver.receiverValue.type, implicitInvokeCheck) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 7b2f4c353a1..0aee6b6e18b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -540,10 +540,12 @@ class PSICallResolver( resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) } astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) + val isForImplicitInvoke = oldCall is CallTransformer.CallForImplicitInvoke + return PSIKotlinCallImpl( kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, dispatchReceiverForInvoke, name, resolvedTypeArguments, resolvedArgumentsInParenthesis, astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, - context.dataFlowInfoForArguments + context.dataFlowInfoForArguments, isForImplicitInvoke ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt index 5695315f0f7..f6cc0b5d621 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt @@ -65,7 +65,8 @@ class PSIKotlinCallImpl( override val externalArgument: KotlinCallArgument?, override val startingDataFlowInfo: DataFlowInfo, override val resultDataFlowInfo: DataFlowInfo, - override val dataFlowInfoForArguments: DataFlowInfoForArguments + override val dataFlowInfoForArguments: DataFlowInfoForArguments, + override val isForImplicitInvoke: Boolean ) : PSIKotlinCall() class PSIKotlinCallForVariable( @@ -86,6 +87,8 @@ class PSIKotlinCallForVariable( override val psiCall: Call = CallTransformer.stripCallArguments(baseCall.psiCall).let { if (explicitReceiver == null) CallTransformer.stripReceiver(it) else it } + + override val isForImplicitInvoke: Boolean get() = false } class PSIKotlinCallForInvoke( @@ -105,6 +108,7 @@ class PSIKotlinCallForInvoke( override val dataFlowInfoForArguments: DataFlowInfoForArguments get() = baseCall.dataFlowInfoForArguments override val psiCall: Call override val tracingStrategy: TracingStrategy + override val isForImplicitInvoke: Boolean = true init { val variableReceiver = dispatchReceiverForInvokeExtension ?: explicitReceiver diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt index 1e558ed9157..268887969ec 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt @@ -24,6 +24,8 @@ interface KotlinCall : ResolutionAtom { val argumentsInParenthesis: List val externalArgument: KotlinCallArgument? + + val isForImplicitInvoke: Boolean } private fun SimpleKotlinCallArgument.checkReceiverInvariants() { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index 78b5e13e4ac..69d38c1282f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -76,7 +76,9 @@ class SimpleCandidateFactory( fromResolution: ReceiverValueWithSmartCastInfo? ): SimpleKotlinCallArgument? = explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe - fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this + fromResolution?.let { + ReceiverExpressionKotlinCallArgument(it, isSafeCall = false, isForImplicitInvoke = kotlinCall.isForImplicitInvoke) + } // todo smartcast implicit this private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver @@ -94,7 +96,9 @@ class SimpleCandidateFactory( val explicitReceiverKind = if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER - val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) } + val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { + ReceiverExpressionKotlinCallArgument(it, isSafeCall) + } return createCandidate( givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null, listOf(), givenCandidate.knownTypeParametersResultingSubstitutor diff --git a/compiler/testData/diagnostics/tests/safeCall.kt b/compiler/testData/diagnostics/tests/safeCall.kt new file mode 100644 index 00000000000..66185463af1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/safeCall.kt @@ -0,0 +1,15 @@ +// !WITH_NEW_INFERENCE + +fun f(s: String, action: (String.() -> Unit)?) { + s.foo().bar().action() +} + +fun String.foo() = "" + +fun String.bar() = "" + +// -------------------------------------------------------- + +val functions: Map Any> = TODO() + +fun run(name: String) = functions[name]() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/safeCall.txt b/compiler/testData/diagnostics/tests/safeCall.txt new file mode 100644 index 00000000000..8990361e70c --- /dev/null +++ b/compiler/testData/diagnostics/tests/safeCall.txt @@ -0,0 +1,7 @@ +package + +public val functions: kotlin.collections.Map kotlin.Any> +public fun f(/*0*/ s: kotlin.String, /*1*/ action: (kotlin.String.() -> kotlin.Unit)?): kotlin.Unit +public fun run(/*0*/ name: kotlin.String): kotlin.Any +public fun kotlin.String.bar(): kotlin.String +public fun kotlin.String.foo(): kotlin.String diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9a81f826c76..9bc42c1c969 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -526,6 +526,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt"); } + @TestMetadata("safeCall.kt") + public void testSafeCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/safeCall.kt"); + } + @TestMetadata("SafeCallInvoke.kt") public void testSafeCallInvoke() throws Exception { runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 0c1aed657c1..faef7d7e17c 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -526,6 +526,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt"); } + @TestMetadata("safeCall.kt") + public void testSafeCall() throws Exception { + runTest("compiler/testData/diagnostics/tests/safeCall.kt"); + } + @TestMetadata("SafeCallInvoke.kt") public void testSafeCallInvoke() throws Exception { runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt");