[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:
committed by
Space Team
parent
eb11901d43
commit
9b786d35f8
+2
-1
@@ -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.checkers.declaration.isLocalMember
|
||||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||||
import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors
|
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.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
@@ -301,6 +300,8 @@ private fun mapInapplicableCandidateError(
|
|||||||
is MultipleContextReceiversApplicableForExtensionReceivers ->
|
is MultipleContextReceiversApplicableForExtensionReceivers ->
|
||||||
FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.createOn(qualifiedAccessSource ?: source)
|
FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.createOn(qualifiedAccessSource ?: source)
|
||||||
|
|
||||||
|
is NoReceiverAllowed -> FirErrors.NO_RECEIVER_ALLOWED.createOn(qualifiedAccessSource ?: source)
|
||||||
|
|
||||||
is NoApplicableValueForContextReceiver ->
|
is NoApplicableValueForContextReceiver ->
|
||||||
FirErrors.NO_CONTEXT_RECEIVER.createOn(
|
FirErrors.NO_CONTEXT_RECEIVER.createOn(
|
||||||
qualifiedAccessSource ?: source,
|
qualifiedAccessSource ?: source,
|
||||||
|
|||||||
+1
@@ -1074,6 +1074,7 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
|
|||||||
arguments.add(receiver)
|
arguments.add(receiver)
|
||||||
arguments.addAll(firSelector.arguments)
|
arguments.addAll(firSelector.arguments)
|
||||||
}
|
}
|
||||||
|
isCallWithExplicitReceiver = true
|
||||||
calleeReference = firSelector.calleeReference
|
calleeReference = firSelector.calleeReference
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+18
-4
@@ -76,6 +76,18 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
|||||||
|
|
||||||
object CheckExtensionReceiver : ResolutionStage() {
|
object CheckExtensionReceiver : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
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 expectedReceiverType = candidate.getExpectedReceiverType() ?: return
|
||||||
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
|
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
|
||||||
|
|
||||||
@@ -506,10 +518,7 @@ internal object CheckArguments : CheckerStage() {
|
|||||||
candidate.symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
candidate.symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||||
val argumentMapping =
|
val argumentMapping =
|
||||||
candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!")
|
candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!")
|
||||||
|
val isInvokeFromExtensionFunctionType = candidate.isInvokeFromExtensionFunctionType
|
||||||
val isInvokeFromExtensionFunctionType = candidate.explicitReceiverKind == DISPATCH_RECEIVER
|
|
||||||
&& candidate.dispatchReceiver?.resolvedType?.isExtensionFunctionType == true
|
|
||||||
&& (candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE
|
|
||||||
|
|
||||||
for ((index, argument) in callInfo.arguments.withIndex()) {
|
for ((index, argument) in callInfo.arguments.withIndex()) {
|
||||||
candidate.resolveArgument(
|
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 {
|
internal fun Candidate.shouldHaveLowPriorityDueToSAM(bodyResolveComponents: BodyResolveComponents): Boolean {
|
||||||
if (!usesSAM || isJavaApplicableCandidate()) return false
|
if (!usesSAM || isJavaApplicableCandidate()) return false
|
||||||
return argumentMapping!!.values.any {
|
return argumentMapping!!.values.any {
|
||||||
|
|||||||
+2
@@ -142,6 +142,8 @@ class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnos
|
|||||||
|
|
||||||
class MultipleContextReceiversApplicableForExtensionReceivers : ResolutionDiagnostic(INAPPLICABLE)
|
class MultipleContextReceiversApplicableForExtensionReceivers : ResolutionDiagnostic(INAPPLICABLE)
|
||||||
|
|
||||||
|
object NoReceiverAllowed : ResolutionDiagnostic(INAPPLICABLE)
|
||||||
|
|
||||||
class NoApplicableValueForContextReceiver(
|
class NoApplicableValueForContextReceiver(
|
||||||
val expectedContextReceiverType: ConeKotlinType
|
val expectedContextReceiverType: ConeKotlinType
|
||||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ abstract class FirImplicitInvokeCall : FirFunctionCall() {
|
|||||||
abstract override val argumentList: FirArgumentList
|
abstract override val argumentList: FirArgumentList
|
||||||
abstract override val calleeReference: FirNamedReference
|
abstract override val calleeReference: FirNamedReference
|
||||||
abstract override val origin: FirFunctionCallOrigin
|
abstract override val origin: FirFunctionCallOrigin
|
||||||
|
abstract val isCallWithExplicitReceiver: Boolean
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||||
visitor.visitImplicitInvokeCall(this, data)
|
visitor.visitImplicitInvokeCall(this, data)
|
||||||
|
|||||||
+2
@@ -35,6 +35,7 @@ open class FirImplicitInvokeCallBuilder : FirAbstractFunctionCallBuilder, FirAnn
|
|||||||
override val nonFatalDiagnostics: MutableList<ConeDiagnostic> = mutableListOf()
|
override val nonFatalDiagnostics: MutableList<ConeDiagnostic> = mutableListOf()
|
||||||
override var argumentList: FirArgumentList = FirEmptyArgumentList
|
override var argumentList: FirArgumentList = FirEmptyArgumentList
|
||||||
override lateinit var calleeReference: FirNamedReference
|
override lateinit var calleeReference: FirNamedReference
|
||||||
|
open var isCallWithExplicitReceiver: Boolean = false
|
||||||
|
|
||||||
override fun build(): FirImplicitInvokeCall {
|
override fun build(): FirImplicitInvokeCall {
|
||||||
return FirImplicitInvokeCallImpl(
|
return FirImplicitInvokeCallImpl(
|
||||||
@@ -49,6 +50,7 @@ open class FirImplicitInvokeCallBuilder : FirAbstractFunctionCallBuilder, FirAnn
|
|||||||
nonFatalDiagnostics.toMutableOrEmpty(),
|
nonFatalDiagnostics.toMutableOrEmpty(),
|
||||||
argumentList,
|
argumentList,
|
||||||
calleeReference,
|
calleeReference,
|
||||||
|
isCallWithExplicitReceiver,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -38,6 +38,7 @@ internal class FirImplicitInvokeCallImpl(
|
|||||||
override var nonFatalDiagnostics: MutableOrEmptyList<ConeDiagnostic>,
|
override var nonFatalDiagnostics: MutableOrEmptyList<ConeDiagnostic>,
|
||||||
override var argumentList: FirArgumentList,
|
override var argumentList: FirArgumentList,
|
||||||
override var calleeReference: FirNamedReference,
|
override var calleeReference: FirNamedReference,
|
||||||
|
override val isCallWithExplicitReceiver: Boolean,
|
||||||
) : FirImplicitInvokeCall() {
|
) : FirImplicitInvokeCall() {
|
||||||
override val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Operator
|
override val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Operator
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -227,7 +227,10 @@ object BuilderConfigurator : AbstractFirBuilderConfigurator<FirTreeBuilder>(FirT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder(integerLiteralOperatorCall, config = configurationForFunctionCallBuilder)
|
builder(integerLiteralOperatorCall, config = configurationForFunctionCallBuilder)
|
||||||
builder(implicitInvokeCall, config = configurationForFunctionCallBuilder)
|
builder(implicitInvokeCall) {
|
||||||
|
configurationForFunctionCallBuilder()
|
||||||
|
defaultFalse("isCallWithExplicitReceiver")
|
||||||
|
}
|
||||||
|
|
||||||
builder(getClassCall) {
|
builder(getClassCall) {
|
||||||
parents += callBuilder
|
parents += callBuilder
|
||||||
|
|||||||
+4
@@ -408,6 +408,10 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
|||||||
shouldBeAnInterface()
|
shouldBeAnInterface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicitInvokeCall.configure {
|
||||||
|
+booleanField("isCallWithExplicitReceiver")
|
||||||
|
}
|
||||||
|
|
||||||
constructor.configure {
|
constructor.configure {
|
||||||
+annotations
|
+annotations
|
||||||
+symbol("FirConstructorSymbol")
|
+symbol("FirConstructorSymbol")
|
||||||
|
|||||||
+1
-1
@@ -30,5 +30,5 @@ fun rain() {
|
|||||||
|
|
||||||
5.(<!UNRESOLVED_REFERENCE!>::<!UNRESOLVED_REFERENCE!>x<!><!>)().inv()
|
5.(<!UNRESOLVED_REFERENCE!>::<!UNRESOLVED_REFERENCE!>x<!><!>)().inv()
|
||||||
|
|
||||||
5.(Int::x)().inv()
|
<!NO_RECEIVER_ALLOWED!>5.(Int::x)()<!>.inv()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// ISSUE: KT-64891
|
// ISSUE: KT-64891
|
||||||
|
|
||||||
fun test(f: (Int) -> Int) {
|
fun test(f: (Int) -> Int) {
|
||||||
2.(f)()
|
<!NO_RECEIVER_ALLOWED!>2.(f)()<!>
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) {
|
|||||||
fun test2(f: (Int) -> Int) {
|
fun test2(f: (Int) -> Int) {
|
||||||
1.<!UNRESOLVED_REFERENCE!>f<!>(2)
|
1.<!UNRESOLVED_REFERENCE!>f<!>(2)
|
||||||
|
|
||||||
2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)
|
<!NO_RECEIVER_ALLOWED!>2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)<!>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user