diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 3ee1e1c915a..b80e1fc4022 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isLocalMember import org.jetbrains.kotlin.fir.analysis.getChild import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors -import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.diagnostics.* import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression @@ -301,6 +300,8 @@ private fun mapInapplicableCandidateError( is MultipleContextReceiversApplicableForExtensionReceivers -> FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.createOn(qualifiedAccessSource ?: source) + is NoReceiverAllowed -> FirErrors.NO_RECEIVER_ALLOWED.createOn(qualifiedAccessSource ?: source) + is NoApplicableValueForContextReceiver -> FirErrors.NO_CONTEXT_RECEIVER.createOn( qualifiedAccessSource ?: source, diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilder.kt index 928b2c2d05b..a0f9f030220 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilder.kt @@ -1074,6 +1074,7 @@ abstract class AbstractRawFirBuilder(val baseSession: FirSession, val context arguments.add(receiver) arguments.addAll(firSelector.arguments) } + isCallWithExplicitReceiver = true calleeReference = firSelector.calleeReference } } else { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 61fd9c34200..1c3ee2a6bb4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -76,6 +76,18 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() { object CheckExtensionReceiver : ResolutionStage() { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { + val callSite = callInfo.callSite + + if (callSite is FirImplicitInvokeCall) { + val isInvokeFromExtensionFunctionType = candidate.isInvokeFromExtensionFunctionType + val isImplicitInvokeCallWithExplicitReceiver = callSite.isCallWithExplicitReceiver + + // We do allow automatic conversion in the other direction, though + if (!isInvokeFromExtensionFunctionType && isImplicitInvokeCallWithExplicitReceiver) { + sink.reportDiagnostic(NoReceiverAllowed) + } + } + val expectedReceiverType = candidate.getExpectedReceiverType() ?: return val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type) @@ -506,10 +518,7 @@ internal object CheckArguments : CheckerStage() { candidate.symbol.lazyResolveToPhase(FirResolvePhase.STATUS) val argumentMapping = candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!") - - val isInvokeFromExtensionFunctionType = candidate.explicitReceiverKind == DISPATCH_RECEIVER - && candidate.dispatchReceiver?.resolvedType?.isExtensionFunctionType == true - && (candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE + val isInvokeFromExtensionFunctionType = candidate.isInvokeFromExtensionFunctionType for ((index, argument) in callInfo.arguments.withIndex()) { candidate.resolveArgument( @@ -543,6 +552,11 @@ internal object CheckArguments : CheckerStage() { } } +private val Candidate.isInvokeFromExtensionFunctionType: Boolean + get() = explicitReceiverKind == DISPATCH_RECEIVER + && dispatchReceiver?.resolvedType?.isExtensionFunctionType == true + && (symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE + internal fun Candidate.shouldHaveLowPriorityDueToSAM(bodyResolveComponents: BodyResolveComponents): Boolean { if (!usesSAM || isJavaApplicableCandidate()) return false return argumentMapping!!.values.any { diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 7e4e9d36dd4..25d58dc7edb 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -142,6 +142,8 @@ class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnos class MultipleContextReceiversApplicableForExtensionReceivers : ResolutionDiagnostic(INAPPLICABLE) +object NoReceiverAllowed : ResolutionDiagnostic(INAPPLICABLE) + class NoApplicableValueForContextReceiver( val expectedContextReceiverType: ConeKotlinType ) : ResolutionDiagnostic(INAPPLICABLE) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirImplicitInvokeCall.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirImplicitInvokeCall.kt index da97ff58bdc..c301d8633c5 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirImplicitInvokeCall.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirImplicitInvokeCall.kt @@ -36,6 +36,7 @@ abstract class FirImplicitInvokeCall : FirFunctionCall() { abstract override val argumentList: FirArgumentList abstract override val calleeReference: FirNamedReference abstract override val origin: FirFunctionCallOrigin + abstract val isCallWithExplicitReceiver: Boolean override fun accept(visitor: FirVisitor, data: D): R = visitor.visitImplicitInvokeCall(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirImplicitInvokeCallBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirImplicitInvokeCallBuilder.kt index 5206e8d634a..878d79bf2b0 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirImplicitInvokeCallBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirImplicitInvokeCallBuilder.kt @@ -35,6 +35,7 @@ open class FirImplicitInvokeCallBuilder : FirAbstractFunctionCallBuilder, FirAnn override val nonFatalDiagnostics: MutableList = mutableListOf() override var argumentList: FirArgumentList = FirEmptyArgumentList override lateinit var calleeReference: FirNamedReference + open var isCallWithExplicitReceiver: Boolean = false override fun build(): FirImplicitInvokeCall { return FirImplicitInvokeCallImpl( @@ -49,6 +50,7 @@ open class FirImplicitInvokeCallBuilder : FirAbstractFunctionCallBuilder, FirAnn nonFatalDiagnostics.toMutableOrEmpty(), argumentList, calleeReference, + isCallWithExplicitReceiver, ) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirImplicitInvokeCallImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirImplicitInvokeCallImpl.kt index 4fbb7a410a6..2ab8043a73f 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirImplicitInvokeCallImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirImplicitInvokeCallImpl.kt @@ -38,6 +38,7 @@ internal class FirImplicitInvokeCallImpl( override var nonFatalDiagnostics: MutableOrEmptyList, override var argumentList: FirArgumentList, override var calleeReference: FirNamedReference, + override val isCallWithExplicitReceiver: Boolean, ) : FirImplicitInvokeCall() { override val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Operator diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt index 5710879fcc6..5a877daf439 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt @@ -227,7 +227,10 @@ object BuilderConfigurator : AbstractFirBuilderConfigurator(FirT } } builder(integerLiteralOperatorCall, config = configurationForFunctionCallBuilder) - builder(implicitInvokeCall, config = configurationForFunctionCallBuilder) + builder(implicitInvokeCall) { + configurationForFunctionCallBuilder() + defaultFalse("isCallWithExplicitReceiver") + } builder(getClassCall) { parents += callBuilder diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index a5789fbc7c5..ecacdcff907 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -408,6 +408,10 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild shouldBeAnInterface() } + implicitInvokeCall.configure { + +booleanField("isCallWithExplicitReceiver") + } + constructor.configure { +annotations +symbol("FirConstructorSymbol") diff --git a/compiler/testData/diagnostics/tests/expressionsInQaSelectorsCornerCases.fir.kt b/compiler/testData/diagnostics/tests/expressionsInQaSelectorsCornerCases.fir.kt index e0a3353309a..3ebfd1d02e7 100644 --- a/compiler/testData/diagnostics/tests/expressionsInQaSelectorsCornerCases.fir.kt +++ b/compiler/testData/diagnostics/tests/expressionsInQaSelectorsCornerCases.fir.kt @@ -30,5 +30,5 @@ fun rain() { 5.(::x)().inv() - 5.(Int::x)().inv() + 5.(Int::x)().inv() } diff --git a/compiler/testData/diagnostics/tests/expressionsInQaSelectorsReceiverConversion.fir.kt b/compiler/testData/diagnostics/tests/expressionsInQaSelectorsReceiverConversion.fir.kt index ec751e6aef8..4a03b5be38f 100644 --- a/compiler/testData/diagnostics/tests/expressionsInQaSelectorsReceiverConversion.fir.kt +++ b/compiler/testData/diagnostics/tests/expressionsInQaSelectorsReceiverConversion.fir.kt @@ -1,5 +1,5 @@ // ISSUE: KT-64891 fun test(f: (Int) -> Int) { - 2.(f)() + 2.(f)() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt index 7b5de563481..799c132e137 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt @@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) { fun test2(f: (Int) -> Int) { 1.f(2) - 2.(f)(2) + 2.(f)(2) }