[FIR] Fix NO_RECEIVER_ALLOWED

If we do create an implicit invoke call, and
then put the receiver into the argument list,
we should mark it.
This commit is contained in:
Nikolay Lunyak
2024-01-22 12:34:39 +02:00
committed by Space Team
parent eb11901d43
commit 9b786d35f8
12 changed files with 38 additions and 9 deletions
@@ -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,
@@ -1074,6 +1074,7 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
arguments.add(receiver)
arguments.addAll(firSelector.arguments)
}
isCallWithExplicitReceiver = true
calleeReference = firSelector.calleeReference
}
} else {
@@ -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 {
@@ -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)
@@ -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 <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitImplicitInvokeCall(this, data)
@@ -35,6 +35,7 @@ open class FirImplicitInvokeCallBuilder : FirAbstractFunctionCallBuilder, FirAnn
override val nonFatalDiagnostics: MutableList<ConeDiagnostic> = 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,
)
}
@@ -38,6 +38,7 @@ internal class FirImplicitInvokeCallImpl(
override var nonFatalDiagnostics: MutableOrEmptyList<ConeDiagnostic>,
override var argumentList: FirArgumentList,
override var calleeReference: FirNamedReference,
override val isCallWithExplicitReceiver: Boolean,
) : FirImplicitInvokeCall() {
override val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Operator
@@ -227,7 +227,10 @@ object BuilderConfigurator : AbstractFirBuilderConfigurator<FirTreeBuilder>(FirT
}
}
builder(integerLiteralOperatorCall, config = configurationForFunctionCallBuilder)
builder(implicitInvokeCall, config = configurationForFunctionCallBuilder)
builder(implicitInvokeCall) {
configurationForFunctionCallBuilder()
defaultFalse("isCallWithExplicitReceiver")
}
builder(getClassCall) {
parents += callBuilder
@@ -408,6 +408,10 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
shouldBeAnInterface()
}
implicitInvokeCall.configure {
+booleanField("isCallWithExplicitReceiver")
}
constructor.configure {
+annotations
+symbol("FirConstructorSymbol")
@@ -30,5 +30,5 @@ fun rain() {
5.(<!UNRESOLVED_REFERENCE!>::<!UNRESOLVED_REFERENCE!>x<!><!>)().inv()
5.(Int::x)().inv()
<!NO_RECEIVER_ALLOWED!>5.(Int::x)()<!>.inv()
}
@@ -1,5 +1,5 @@
// ISSUE: KT-64891
fun test(f: (Int) -> Int) {
2.(f)()
<!NO_RECEIVER_ALLOWED!>2.(f)()<!>
}
@@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) {
fun test2(f: (Int) -> Int) {
1.<!UNRESOLVED_REFERENCE!>f<!>(2)
2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)
<!NO_RECEIVER_ALLOWED!>2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)<!>
}