[FIR] Resolve operator calls to operator functions only

This commit is contained in:
Andrey Zinovyev
2021-05-17 11:46:04 +03:00
committed by TeamCityServer
parent b1c8669b43
commit e021e25d6c
10 changed files with 19 additions and 97 deletions
@@ -143,6 +143,8 @@ private fun mapInapplicableCandidateError(
is UnsafeCall -> mapUnsafeCallError(diagnostic.candidate, rootCause, source, qualifiedAccessSource) is UnsafeCall -> mapUnsafeCallError(diagnostic.candidate, rootCause, source, qualifiedAccessSource)
is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(rootCause.argument.source ?: source) is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(rootCause.argument.source ?: source)
is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.on(source, rootCause.function) is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.on(source, rootCause.function)
is OperatorCallOfNonOperatorFunction ->
FirErrors.OPERATOR_MODIFIER_REQUIRED.on(source, rootCause.function, rootCause.function.fir.name.asString())
else -> null else -> null
} }
}.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) } }.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) }
@@ -1889,7 +1889,7 @@ open class RawFirBuilder(
} }
explicitReceiver = leftArgument explicitReceiver = leftArgument
argumentList = buildUnaryArgumentList(rightArgument) argumentList = buildUnaryArgumentList(rightArgument)
origin = if (conventionCallName != null) FirFunctionCallOrigin.REGULAR else FirFunctionCallOrigin.INFIX origin = if (conventionCallName != null) FirFunctionCallOrigin.OPERATOR else FirFunctionCallOrigin.INFIX
} }
} else { } else {
val firOperation = operationToken.toFirOperation() val firOperation = operationToken.toFirOperation()
@@ -39,7 +39,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
CheckDispatchReceiver, CheckDispatchReceiver,
CheckExtensionReceiver, CheckExtensionReceiver,
CheckArguments, CheckArguments,
CheckInfixCall, CheckCallModifiers,
EagerResolveOfCallableReferences, EagerResolveOfCallableReferences,
CheckLowPriorityInOverloadResolution, CheckLowPriorityInOverloadResolution,
PostponedVariablesInitializerResolutionStage PostponedVariablesInitializerResolutionStage
@@ -104,4 +104,5 @@ class ManyLambdaExpressionArguments(
val argument: FirExpression val argument: FirExpression
) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) ) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR)
class InfixCallOfNonInfixFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER) class InfixCallOfNonInfixFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER)
class OperatorCallOfNonOperatorFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER)
@@ -267,14 +267,15 @@ internal object PostponedVariablesInitializerResolutionStage : ResolutionStage()
} }
} }
internal object CheckInfixCall : CheckerStage() { internal object CheckCallModifiers : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (callInfo.callSite is FirFunctionCall) { if (callInfo.callSite is FirFunctionCall) {
if (callInfo.callSite.origin == FirFunctionCallOrigin.INFIX) { val functionSymbol = candidate.symbol as? FirNamedFunctionSymbol ?: return
val functionSymbol = candidate.symbol as? FirNamedFunctionSymbol ?: return when {
if (!functionSymbol.fir.isInfix) { callInfo.callSite.origin == FirFunctionCallOrigin.INFIX && !functionSymbol.fir.isInfix ->
sink.reportDiagnostic(InfixCallOfNonInfixFunction(functionSymbol)) sink.reportDiagnostic(InfixCallOfNonInfixFunction(functionSymbol))
} callInfo.callSite.origin == FirFunctionCallOrigin.OPERATOR && !functionSymbol.fir.isOperator ->
sink.reportDiagnostic(OperatorCallOfNonOperatorFunction(functionSymbol))
} }
} }
} }
+5 -5
View File
@@ -49,9 +49,9 @@ fun test() {
a == b a == b
c != d c != d
Example() + Example() Example() <!OPERATOR_MODIFIER_REQUIRED!>+<!> Example()
a + b a <!OPERATOR_MODIFIER_REQUIRED!>+<!> b
a - b a - b
a[1] a[1]
a["str"] a["str"]
@@ -67,10 +67,10 @@ fun test() {
c += d c += d
c -= d c -= d
a..b a<!OPERATOR_MODIFIER_REQUIRED!>..<!>b
c..d c..d
Example()..Example() Example()<!OPERATOR_MODIFIER_REQUIRED!>..<!>Example()
Example2()..Example2() Example2()..Example2()
a < b a < b
@@ -109,7 +109,7 @@ class Anc2 : Anc()
fun test2() { fun test2() {
Anc() + Anc() Anc() + Anc()
Anc() - Anc() Anc() <!OPERATOR_MODIFIER_REQUIRED!>-<!> Anc()
Anc2() + Anc2() Anc2() + Anc2()
} }
@@ -1,39 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class Example
fun Example.plus(other: Example) = 0
operator infix fun Example.minus(other: Example) = 0
operator infix fun Example.times(other: Example) = 0
fun Example.div(other: Example) = 0
fun a() {
with (Example()) {
operator infix fun Example.plus(other: Example) = ""
fun Example.minus(other: Example) = ""
operator infix fun Example.times(other: Example) = ""
fun Example.div(other: Example) = ""
with (Example()) {
val a = Example()
val b = Example()
consumeString(a + b)
consumeInt(<!ARGUMENT_TYPE_MISMATCH!>a - b<!>)
consumeString(a plus b)
consumeInt(a minus b)
a * b
a / b
a times b
a <!INFIX_MODIFIER_REQUIRED!>div<!> b
}
}
}
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER // !DIAGNOSTICS: -UNUSED_PARAMETER
class Example class Example
@@ -1,45 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER
class Example {
operator infix fun plus(other: Example) = 0
fun minus(other: Example) = 0
operator infix fun times(other: Example) = 0
fun div(other: Example) = 0
}
fun Example.plus(other: Example) = ""
operator infix fun Example.minus(other: Example) = ""
operator infix fun Example.times(other: Example) = ""
fun Example.div(other: Example) = ""
fun a() {
val a = Example()
val b = Example()
a + b
a - b
a * b
a / b
a plus b
a minus b
a times b
a <!INFIX_MODIFIER_REQUIRED!>div<!> b
with (Example()) {
consumeInt(this + a)
consumeString(<!ARGUMENT_TYPE_MISMATCH!>this - b<!>)
consumeInt(this * a)
consumeInt(this / b)
consumeInt(this plus a)
consumeString(this minus b)
consumeInt(this times a)
consumeInt(this <!INFIX_MODIFIER_REQUIRED!>div<!> b)
}
}
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER // !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER
class Example { class Example {