diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 3b2ceb718f1..83128c28ef8 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -18662,6 +18662,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/resolve/invoke/KT-4372.kt"); } + @TestMetadata("kt30695.kt") + public void testKt30695() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt"); + } + + @TestMetadata("kt30695_2.kt") + public void testKt30695_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt"); + } + @TestMetadata("kt3772.kt") public void testKt3772() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt3772.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 be386182c64..69e005ab4c4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -104,9 +104,14 @@ class DiagnosticReporterByTrackingStrategy( override fun onCallReceiver(callReceiver: SimpleKotlinCallArgument, diagnostic: KotlinCallDiagnostic) { when (diagnostic.javaClass) { UnsafeCallError::class.java -> { - val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isForImplicitInvoke - ?: callReceiver.receiver.receiverValue.type.isExtensionFunctionType - tracingStrategy.unsafeCall(trace, callReceiver.receiver.receiverValue.type, implicitInvokeCheck) + val unsafeCallErrorDiagnostic = diagnostic.cast() + val isForImplicitInvoke = when (callReceiver) { + is ReceiverExpressionKotlinCallArgument -> callReceiver.isForImplicitInvoke + else -> unsafeCallErrorDiagnostic.isForImplicitInvoke + || callReceiver.receiver.receiverValue.type.isExtensionFunctionType + } + + tracingStrategy.unsafeCall(trace, callReceiver.receiver.receiverValue.type, isForImplicitInvoke) } SuperAsExtensionReceiver::class.java -> { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index 14a760d49e3..e3e0f446623 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -35,11 +35,11 @@ fun resolveKtPrimitive( argument: KotlinCallArgument, expectedType: UnwrappedType?, diagnosticsHolder: KotlinDiagnosticsHolder, - isReceiver: Boolean, - convertedType: UnwrappedType? + receiverInfo: ReceiverInfo, + convertedType: UnwrappedType?, ): ResolvedAtom = when (argument) { is SimpleKotlinCallArgument -> - checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver, convertedType) + checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo, convertedType) is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType, diagnosticsHolder) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index e4e3586e267..234ef057e50 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -132,7 +132,7 @@ class PostponedArgumentsAnalyzer( val subResolvedKtPrimitives = returnArgumentsInfo.nonErrorArguments.map { resolveKtPrimitive( - c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false, convertedType = null + c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, ReceiverInfo.notReceiver, convertedType = null ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index c547211fe73..95a12b63553 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -288,7 +288,7 @@ internal object CheckExplicitReceiverKindConsistency : ResolutionPart() { private fun KotlinResolutionCandidate.resolveKotlinArgument( argument: KotlinCallArgument, candidateParameter: ParameterDescriptor?, - isReceiver: Boolean + receiverInfo: ReceiverInfo ) { val expectedType = candidateParameter?.let { prepareExpectedType(argument, candidateParameter) } val convertedArgument = if (expectedType != null && shouldRunConversionForConstants(expectedType)) { @@ -306,7 +306,7 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument( argument, expectedType, this, - isReceiver, + receiverInfo, convertedArgument?.unknownIntegerType?.unwrap() ) ) @@ -327,6 +327,30 @@ private fun KotlinResolutionCandidate.shouldRunConversionForConstants(expectedTy return false } +internal enum class ImplicitInvokeCheckStatus { + NO_INVOKE, INVOKE_ON_NOT_NULL_VARIABLE, UNSAFE_INVOKE_REPORTED +} + +private fun KotlinResolutionCandidate.checkUnsafeImplicitInvokeAfterSafeCall(argument: SimpleKotlinCallArgument): ImplicitInvokeCheckStatus { + val variableForInvoke = variableCandidateIfInvoke ?: return ImplicitInvokeCheckStatus.NO_INVOKE + + val receiverArgument = with(variableForInvoke.resolvedCall) { + when (explicitReceiverKind) { + DISPATCH_RECEIVER -> dispatchReceiverArgument + EXTENSION_RECEIVER, + BOTH_RECEIVERS -> extensionReceiverArgument + NO_EXPLICIT_RECEIVER -> return ImplicitInvokeCheckStatus.INVOKE_ON_NOT_NULL_VARIABLE + } + } ?: error("Receiver kind does not match receiver argument") + + if (receiverArgument.receiver.stableType.isNullable()) { + addDiagnostic(UnsafeCallError(argument, isForImplicitInvoke = true)) + return ImplicitInvokeCheckStatus.UNSAFE_INVOKE_REPORTED + } + + return ImplicitInvokeCheckStatus.INVOKE_ON_NOT_NULL_VARIABLE +} + private fun KotlinResolutionCandidate.prepareExpectedType( argument: KotlinCallArgument, candidateParameter: ParameterDescriptor @@ -388,21 +412,40 @@ private fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion( internal object CheckReceivers : ResolutionPart() { private fun KotlinResolutionCandidate.checkReceiver( receiverArgument: SimpleKotlinCallArgument?, - receiverParameter: ReceiverParameterDescriptor? + receiverParameter: ReceiverParameterDescriptor?, + shouldCheckImplicitInvoke: Boolean, ) { if ((receiverArgument == null) != (receiverParameter == null)) { error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor") } if (receiverArgument == null || receiverParameter == null) return - resolveKotlinArgument(receiverArgument, receiverParameter, isReceiver = true) + val implicitInvokeState = if (shouldCheckImplicitInvoke) { + checkUnsafeImplicitInvokeAfterSafeCall(receiverArgument) + } else ImplicitInvokeCheckStatus.NO_INVOKE + + val receiverInfo = ReceiverInfo( + isReceiver = true, + shouldReportUnsafeCall = implicitInvokeState != ImplicitInvokeCheckStatus.UNSAFE_INVOKE_REPORTED, + reportUnsafeCallAsUnsafeImplicitInvoke = implicitInvokeState == ImplicitInvokeCheckStatus.INVOKE_ON_NOT_NULL_VARIABLE + ) + + resolveKotlinArgument(receiverArgument, receiverParameter, receiverInfo) } override fun KotlinResolutionCandidate.process(workIndex: Int) { if (workIndex == 0) { - checkReceiver(resolvedCall.dispatchReceiverArgument, candidateDescriptor.dispatchReceiverParameter) + checkReceiver( + resolvedCall.dispatchReceiverArgument, + candidateDescriptor.dispatchReceiverParameter, + shouldCheckImplicitInvoke = true, + ) } else { - checkReceiver(resolvedCall.extensionReceiverArgument, candidateDescriptor.extensionReceiverParameter) + checkReceiver( + resolvedCall.extensionReceiverArgument, + candidateDescriptor.extensionReceiverParameter, + shouldCheckImplicitInvoke = false, // reproduce old inference behaviour + ) } } @@ -412,7 +455,7 @@ internal object CheckReceivers : ResolutionPart() { internal object CheckArgumentsInParenthesis : ResolutionPart() { override fun KotlinResolutionCandidate.process(workIndex: Int) { val argument = kotlinCall.argumentsInParenthesis[workIndex] - resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false) + resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], ReceiverInfo.notReceiver) } override fun KotlinResolutionCandidate.workCount() = kotlinCall.argumentsInParenthesis.size @@ -422,7 +465,7 @@ internal object CheckExternalArgument : ResolutionPart() { override fun KotlinResolutionCandidate.process(workIndex: Int) { val argument = kotlinCall.externalArgument ?: return - resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false) + resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], ReceiverInfo.notReceiver) } } @@ -485,14 +528,14 @@ internal object ErrorDescriptorResolutionPart : ResolutionPart() { resolvedCall.argumentToCandidateParameter = emptyMap() kotlinCall.explicitReceiver?.safeAs()?.let { - resolveKotlinArgument(it, null, isReceiver = true) + resolveKotlinArgument(it, null, ReceiverInfo.notReceiver) } for (argument in kotlinCall.argumentsInParenthesis) { - resolveKotlinArgument(argument, null, isReceiver = true) + resolveKotlinArgument(argument, null, ReceiverInfo.notReceiver) } kotlinCall.externalArgument?.let { - resolveKotlinArgument(it, null, isReceiver = true) + resolveKotlinArgument(it, null, ReceiverInfo.notReceiver) } } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt index 6807301c81c..0152510cb05 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt @@ -31,17 +31,30 @@ import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.supertypes +class ReceiverInfo( + val isReceiver: Boolean, + val shouldReportUnsafeCall: Boolean, // should not report if unsafe implicit invoke has been reported already + val reportUnsafeCallAsUnsafeImplicitInvoke: Boolean, +) { + init { + assert(!reportUnsafeCallAsUnsafeImplicitInvoke || shouldReportUnsafeCall) { "Inconsistent receiver info" } + } + + companion object { + val notReceiver = ReceiverInfo(isReceiver = false, shouldReportUnsafeCall = true, reportUnsafeCallAsUnsafeImplicitInvoke = false) + } +} fun checkSimpleArgument( csBuilder: ConstraintSystemBuilder, argument: SimpleKotlinCallArgument, expectedType: UnwrappedType?, diagnosticsHolder: KotlinDiagnosticsHolder, - isReceiver: Boolean, + receiverInfo: ReceiverInfo, convertedType: UnwrappedType? ): ResolvedAtom = when (argument) { - is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver, convertedType) - is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) + is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo.isReceiver, convertedType) + is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo) else -> unexpectedArgument(argument) } @@ -164,14 +177,14 @@ private fun checkSubCallArgument( subCallArgument: SubKotlinCallArgument, expectedType: UnwrappedType?, diagnosticsHolder: KotlinDiagnosticsHolder, - isReceiver: Boolean + receiverInfo: ReceiverInfo, ): ResolvedAtom { val subCallResult = subCallArgument.callResult if (expectedType == null) return subCallResult val expectedNullableType = expectedType.makeNullableAsSpecified(true) - val position = if (isReceiver) ReceiverConstraintPosition(subCallArgument) else ArgumentConstraintPosition(subCallArgument) + val position = if (receiverInfo.isReceiver) ReceiverConstraintPosition(subCallArgument) else ArgumentConstraintPosition(subCallArgument) // subArgument cannot has stable smartcast // return type can contains fixed type variables @@ -183,10 +196,15 @@ private fun checkSubCallArgument( return subCallResult } - if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) && - csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position) + if (receiverInfo.isReceiver + && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) + && csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position) ) { - diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument)) + if (receiverInfo.shouldReportUnsafeCall) { + diagnosticsHolder.addDiagnostic( + UnsafeCallError(subCallArgument, isForImplicitInvoke = receiverInfo.reportUnsafeCallAsUnsafeImplicitInvoke) + ) + } return subCallResult } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index d458fa8dbcf..da1bbce5da5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -169,7 +169,10 @@ class UnstableSmartCastDiagnosticError( targetType: UnwrappedType, ) : UnstableSmartCast(argument, targetType, RESOLVED_WITH_ERROR) -class UnsafeCallError(val receiver: SimpleKotlinCallArgument) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) { +class UnsafeCallError( + val receiver: SimpleKotlinCallArgument, + val isForImplicitInvoke: Boolean = false +) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) = reporter.onCallReceiver(receiver, this) } diff --git a/compiler/testData/diagnostics/tests/SafeCallInvoke.fir.kt b/compiler/testData/diagnostics/tests/SafeCallInvoke.fir.kt index b5366e9679c..bc4d474faf8 100644 --- a/compiler/testData/diagnostics/tests/SafeCallInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/SafeCallInvoke.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE class Rule(val apply:() -> Unit) fun bar() {} diff --git a/compiler/testData/diagnostics/tests/SafeCallInvoke.kt b/compiler/testData/diagnostics/tests/SafeCallInvoke.kt index 1aaeaffe446..e374ecbdf72 100644 --- a/compiler/testData/diagnostics/tests/SafeCallInvoke.kt +++ b/compiler/testData/diagnostics/tests/SafeCallInvoke.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE class Rule(val apply:() -> Unit) fun bar() {} @@ -14,7 +13,7 @@ fun foo() { rule?.apply?.invoke() // this should be an error - rule?.apply() + rule?.apply() // these both also ok (with smart cast / unnecessary safe call) if (rule != null) { diff --git a/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt b/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt index dba11ad9cc2..216d32c9541 100644 --- a/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE //KT-1875 Safe call should be binded with receiver or this object (but not with both by default) package kt1875 diff --git a/compiler/testData/diagnostics/tests/extensions/kt1875.kt b/compiler/testData/diagnostics/tests/extensions/kt1875.kt index 05c21438a17..107e9706daf 100644 --- a/compiler/testData/diagnostics/tests/extensions/kt1875.kt +++ b/compiler/testData/diagnostics/tests/extensions/kt1875.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE //KT-1875 Safe call should be binded with receiver or this object (but not with both by default) package kt1875 @@ -10,13 +9,13 @@ interface T { } fun test(t: T) { - t.f(1) //unsafe call error + t.f(1) //unsafe call error t.f?.invoke(1) } fun test1(t: T?) { t.f(1) // todo resolve f as value and report UNSAFE_CALL - t?.f(1) + t?.f(1) t.f?.invoke(1) t?.f?.invoke(1) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.fir.kt b/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.fir.kt index b6286cdd509..1a95bf72e24 100644 --- a/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE fun Unit)?> foo(x: E, y: T) { if (x != null) { y(x) diff --git a/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt b/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt index 5b5fcac8443..2944a0a2b31 100644 --- a/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt +++ b/compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt @@ -1,7 +1,6 @@ -// !WITH_NEW_INFERENCE fun Unit)?> foo(x: E, y: T) { if (x != null) { - y(x) + y(x) } if (y != null) { diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.fir.kt index cd541506a09..5556634de6d 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.fir.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // FILE: J.java import org.jetbrains.annotations.*; diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.kt index f7ba81e509c..a1c251fae35 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // FILE: J.java import org.jetbrains.annotations.*; @@ -19,6 +18,6 @@ public class J { fun test() { J.staticNN() - J.staticN() + J.staticN() J.staticJ() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt index 3a5a8a49df6..3639d81d5f5 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE class A(val x: (String.() -> Unit)?) fun test(a: A) { diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.kt b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.kt index 12dc450e4da..619c7f51c2a 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE class A(val x: (String.() -> Unit)?) fun test(a: A) { diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.fir.kt new file mode 100644 index 00000000000..f93087f55d8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.fir.kt @@ -0,0 +1,18 @@ +class A { + val lambda: () -> Unit = TODO() + val memberInvoke: B = TODO() + val extensionInvoke: C = TODO() +} + +class B { + operator fun invoke() {} +} + +class C +operator fun C.invoke() {} + +fun test(a: A?) { + a?.lambda() + a?.memberInvoke() + a?.extensionInvoke() +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt new file mode 100644 index 00000000000..61fdcb5d65a --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt @@ -0,0 +1,18 @@ +class A { + val lambda: () -> Unit = TODO() + val memberInvoke: B = TODO() + val extensionInvoke: C = TODO() +} + +class B { + operator fun invoke() {} +} + +class C +operator fun C.invoke() {} + +fun test(a: A?) { + a?.lambda() + a?.memberInvoke() + a?.extensionInvoke() +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.txt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.txt new file mode 100644 index 00000000000..1399dfe15dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695.txt @@ -0,0 +1,29 @@ +package + +public fun test(/*0*/ a: A?): kotlin.Unit +public operator fun C.invoke(): kotlin.Unit + +public final class A { + public constructor A() + public final val extensionInvoke: C + public final val lambda: () -> kotlin.Unit + public final val memberInvoke: B + 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 B { + public constructor B() + 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 operator fun invoke(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C { + public constructor C() + 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 +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt new file mode 100644 index 00000000000..574de7f7751 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt @@ -0,0 +1,25 @@ +class MemberInvokeOwner { + operator fun invoke() {} +} + +class Cls { + fun testImplicitReceiver() { + nullableExtensionProperty() + } +} + +val Cls.nullableExtensionProperty: MemberInvokeOwner? + get() = null + +val Cls.extensionProperty: MemberInvokeOwner + get() = TODO() + +fun testNullableReceiver(nullable: Cls?) { + nullable?.extensionProperty() + nullable.extensionProperty() +} + +fun testNotNullableReceiver(notNullable: Cls) { + notNullable.nullableExtensionProperty() + notNullable?.extensionProperty() +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt new file mode 100644 index 00000000000..eb9e9bccb54 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt @@ -0,0 +1,25 @@ +class MemberInvokeOwner { + operator fun invoke() {} +} + +class Cls { + fun testImplicitReceiver() { + nullableExtensionProperty() + } +} + +val Cls.nullableExtensionProperty: MemberInvokeOwner? + get() = null + +val Cls.extensionProperty: MemberInvokeOwner + get() = TODO() + +fun testNullableReceiver(nullable: Cls?) { + nullable?.extensionProperty() + nullable.extensionProperty() +} + +fun testNotNullableReceiver(notNullable: Cls) { + notNullable.nullableExtensionProperty() + notNullable?.extensionProperty() +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.txt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.txt new file mode 100644 index 00000000000..2827f06c42f --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.txt @@ -0,0 +1,22 @@ +package + +public val Cls.extensionProperty: MemberInvokeOwner +public val Cls.nullableExtensionProperty: MemberInvokeOwner? +public fun testNotNullableReceiver(/*0*/ notNullable: Cls): kotlin.Unit +public fun testNullableReceiver(/*0*/ nullable: Cls?): kotlin.Unit + +public final class Cls { + public constructor Cls() + 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 fun testImplicitReceiver(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class MemberInvokeOwner { + public constructor MemberInvokeOwner() + 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 operator fun invoke(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.fir.kt index 4e93259c46b..c374fd5a0f6 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // !LANGUAGE: -SafeCastCheckBoundSmartCasts -BooleanElvisBoundSmartCasts // A set of examples for // "If the result of a safe call is not null, understand that its receiver is not null" diff --git a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.kt b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.kt index c2baa0e49d3..ed6868f1789 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeAccessReceiverNotNull.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE // !LANGUAGE: -SafeCastCheckBoundSmartCasts -BooleanElvisBoundSmartCasts // A set of examples for // "If the result of a safe call is not null, understand that its receiver is not null" @@ -130,7 +129,7 @@ class Invokable(val x: String) { class InvokableProperty(val i: Invokable) fun checkInvokable(ip: InvokableProperty?) { - if (ip?.i() == "Hello") { + if (ip?.i() == "Hello") { ip.hashCode() } } \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.kt index 51581791a85..ef346755b04 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.kt @@ -370,23 +370,23 @@ fun case_21() { // TESTCASE NUMBER: 22 fun case_22(a: (() -> Unit)?) { if (a != null !is Boolean) { - a() - a().equals(null) - a().propT - a().propAny - a().propNullableT - a().propNullableAny - a().funT() - a().funAny() - a().funNullableT() - a().funNullableAny() + a() + a().equals(null) + a().propT + a().propAny + a().propNullableT + a().propNullableAny + a().funT() + a().funAny() + a().funNullableT() + a().funNullableAny() } } // TESTCASE NUMBER: 23 fun case_23(a: ((Float) -> Int?)?, b: Float?) { if (a != null !is Boolean && b !== null is Boolean) { - val x = a(b) + val x = a(b) if (x != null) { x x.equals(null) @@ -405,8 +405,8 @@ fun case_23(a: ((Float) -> Int?)?, b: Float?) { // TESTCASE NUMBER: 24 fun case_24(a: ((() -> Unit) -> Unit)?, b: (() -> Unit)?) = if (a !== null is Boolean && b !== null !is Boolean) { - a( kotlin.Unit)?"), TYPE_MISMATCH!>b) - a(b) + a( kotlin.Unit)?"), TYPE_MISMATCH!>b) + a(b) kotlin.Unit)?")!>b.equals(null) kotlin.Unit)?")!>b.propT kotlin.Unit)?")!>b.propAny @@ -429,7 +429,7 @@ fun case_25(b: Boolean) { val y = if (b) x else null if (y !== null === true) { - val z = .?")!>y() + val z = .?")!>y() if (z != null !== false) { .?")!>z.a diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.kt index cc3f0abe5a6..0ef38ee85f4 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.kt @@ -76,7 +76,7 @@ fun case_3(b: Boolean) { val y = if (b) x else null if (false || false || false || false || y !== null) { - val z = .?")!>y() + val z = .?")!>y() case_3..?)?")!>y.equals(null) case_3..?)?")!>y.propT case_3..?)?")!>y.propAny @@ -283,7 +283,7 @@ fun case_11(b: Boolean) { val y = if (b) x else null if (y === null && true) else { - val z = .?")!>y() + val z = .?")!>y() case_11..?)?")!>y.equals(null) case_11..?)?")!>y.propT case_11..?)?")!>y.propAny diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.kt index 127c106a50c..4a237f61f72 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.kt @@ -583,7 +583,7 @@ fun case_29(x: Boolean) { val y = if (x) z else null if (false || false || false || false || y !== v) { - val t = .?")!>y() + val t = .?")!>y() if (z !== t || false) { .?")!>t.a diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 3c199c9b547..cb68a01c195 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18674,6 +18674,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/resolve/invoke/KT-4372.kt"); } + @TestMetadata("kt30695.kt") + public void testKt30695() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt"); + } + + @TestMetadata("kt30695_2.kt") + public void testKt30695_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt"); + } + @TestMetadata("kt3772.kt") public void testKt3772() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt3772.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index ebddbb0e1a4..f82e64c9b03 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -18664,6 +18664,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/resolve/invoke/KT-4372.kt"); } + @TestMetadata("kt30695.kt") + public void testKt30695() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695.kt"); + } + + @TestMetadata("kt30695_2.kt") + public void testKt30695_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.kt"); + } + @TestMetadata("kt3772.kt") public void testKt3772() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/invoke/kt3772.kt");