From fa3b3e7a9a0b61ae5e68752d9ed20cd3409a832f Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 20 Apr 2020 15:29:14 +0300 Subject: [PATCH] FIR: Fix false positive INAPPLICABLE_INFIX_MODIFIER --- .../resolve/diagnostics/infixFunctions.kt | 13 +++++++++++- .../resolve/diagnostics/infixFunctions.txt | 21 +++++++++++++++++++ .../resolve/fromBuilder/typeParameters.kt | 2 +- .../FirInfixFunctionDeclarationChecker.kt | 13 ++++++++++-- .../diagnostics/tests/AutoCreatedIt.fir.kt | 2 +- .../testData/diagnostics/tests/Infix.fir.kt | 4 ++-- .../tests/InfixModifierApplicability.fir.kt | 4 ++-- .../diagnostics/tests/OperatorChecks.fir.kt | 4 ++-- .../tests/functionLiterals/kt4529.fir.kt | 19 ----------------- .../tests/functionLiterals/kt4529.kt | 1 + ...t6541_extensionForExtensionFunction.fir.kt | 2 +- .../onlyLocalReturnLambdaBinaryExpr.fir.kt | 4 ++-- .../operatorInfix/MemberFunctions.fir.kt | 6 +++--- .../InfixCallNullability.fir.kt | 4 ++-- .../infixExtensionVsNonInfixMember.fir.kt | 4 ++-- .../tests/smartCasts/afterBinaryExpr.fir.kt | 4 ++-- 16 files changed, 65 insertions(+), 42 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/functionLiterals/kt4529.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt index 21e7601f977..7c01b92b317 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt @@ -10,4 +10,15 @@ infix class A infix typealias B = A -infix val x = 1 \ No newline at end of file +infix val x = 1 + +class C { + infix fun good(x: Int) {} + infix fun Int.goodAsWell(x: Int) {} + + infix fun Int.foo(x: Int, y: Int) {} + + infix fun Int.bar() {} + + infix fun baz(x: Int, y: Int) {} +} diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.txt index a77c9adeee3..bdf7ac587eb 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.txt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.txt @@ -16,3 +16,24 @@ FILE: infixFunctions.kt public final typealias B = R|A| public final val x: R|kotlin/Int| = Int(1) public get(): R|kotlin/Int| + public final class C : R|kotlin/Any| { + public constructor(): R|C| { + super() + } + + public final infix fun good(x: R|kotlin/Int|): R|kotlin/Unit| { + } + + public final infix fun R|kotlin/Int|.goodAsWell(x: R|kotlin/Int|): R|kotlin/Unit| { + } + + public final infix fun R|kotlin/Int|.foo(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Unit| { + } + + public final infix fun R|kotlin/Int|.bar(): R|kotlin/Unit| { + } + + public final infix fun baz(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Unit| { + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/fromBuilder/typeParameters.kt b/compiler/fir/analysis-tests/testData/resolve/fromBuilder/typeParameters.kt index 2dec3fea65a..e267b1ada73 100644 --- a/compiler/fir/analysis-tests/testData/resolve/fromBuilder/typeParameters.kt +++ b/compiler/fir/analysis-tests/testData/resolve/fromBuilder/typeParameters.kt @@ -1,7 +1,7 @@ interface List { operator fun get(index: Int): T - infix fun concat(other: List): List + infix fun concat(other: List): List } typealias StringList = List diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInfixFunctionDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInfixFunctionDeclarationChecker.kt index 31f1d06dc00..39dd953ff76 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInfixFunctionDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInfixFunctionDeclarationChecker.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.isInfix @@ -16,7 +17,7 @@ import org.jetbrains.kotlin.fir.declarations.isInfix object FirInfixFunctionDeclarationChecker : FirDeclarationChecker() { override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { if (declaration is FirSimpleFunction && declaration.isInfix) { - if (declaration.valueParameters.size != 1 || declaration.receiverTypeRef == null) { + if (declaration.valueParameters.size != 1 || !hasExtensionOrDispatchReceiver(declaration, context)) { reporter.report(declaration.source) } return @@ -26,7 +27,15 @@ object FirInfixFunctionDeclarationChecker : FirDeclarationChecker + } + private fun DiagnosticReporter.report(source: FirSourceElement?) { source?.let { report(FirErrors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt b/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt index 52f3a1f0369..02d28cc190b 100644 --- a/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt +++ b/compiler/testData/diagnostics/tests/AutoCreatedIt.fir.kt @@ -29,5 +29,5 @@ infix fun String.on(predicate : (s : URI) -> Boolean) : URI { } class URI(val body : Any) { - infix fun to(dest : String) {} + infix fun to(dest : String) {} } diff --git a/compiler/testData/diagnostics/tests/Infix.fir.kt b/compiler/testData/diagnostics/tests/Infix.fir.kt index f852458c439..97bccdbf03c 100644 --- a/compiler/testData/diagnostics/tests/Infix.fir.kt +++ b/compiler/testData/diagnostics/tests/Infix.fir.kt @@ -1,7 +1,7 @@ class Pair(val first: A, val second: B) class Example { - infix fun to(other: Example) = Pair(this, other) + infix fun to(other: Example) = Pair(this, other) fun toNonInfix(other: Example) = Pair(this, other) } @@ -35,4 +35,4 @@ fun test() { a toExtNonInfixDefaultValues b a withLambda { } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/InfixModifierApplicability.fir.kt b/compiler/testData/diagnostics/tests/InfixModifierApplicability.fir.kt index e276ad484b8..914bf5b0c45 100644 --- a/compiler/testData/diagnostics/tests/InfixModifierApplicability.fir.kt +++ b/compiler/testData/diagnostics/tests/InfixModifierApplicability.fir.kt @@ -6,7 +6,7 @@ infix fun A.to(that: B): Pair = Pair(this, that) // OK infix fun String.ok1(o: String) {} class OkTest { - infix fun ok2(o: String) {} + infix fun ok2(o: String) {} infix fun String.ok3(o: String) {} } @@ -24,4 +24,4 @@ class Example { infix fun e8(s: String, a: Int = 0) {} infix fun e9(s: String, a: Int) {} infix fun e10() {} -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/OperatorChecks.fir.kt b/compiler/testData/diagnostics/tests/OperatorChecks.fir.kt index ac4f09e9adc..8ee4b02279d 100644 --- a/compiler/testData/diagnostics/tests/OperatorChecks.fir.kt +++ b/compiler/testData/diagnostics/tests/OperatorChecks.fir.kt @@ -59,9 +59,9 @@ interface Example { operator fun hasNext(): Boolean operator fun hasNext(n: Int): String - infix fun i1(n: Int) + infix fun i1(n: Int) infix fun i1(n: Int, n2: Int) - infix fun i1(vararg n: Int) + infix fun i1(vararg n: Int) } class OkDelegates { diff --git a/compiler/testData/diagnostics/tests/functionLiterals/kt4529.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/kt4529.fir.kt deleted file mode 100644 index 38833e5c513..00000000000 --- a/compiler/testData/diagnostics/tests/functionLiterals/kt4529.fir.kt +++ /dev/null @@ -1,19 +0,0 @@ -//KT-4529 Lambdas are analyzed improperly in an infix call nested inside a println - -class G { - infix fun foo(bar: (Int) -> Int) = bar -} - -fun main() { - use( - G().foo {it + 11} // no error - ) - use( - G() foo {it + 11} // ERROR - ) - use( - G() foo ({it + 1}) // 2 ERRORs - ) -} - -fun use(a: Any?) = a \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt b/compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt index 886f4b9ebdc..2f6eb52cddb 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL //KT-4529 Lambdas are analyzed improperly in an infix call nested inside a println class G { diff --git a/compiler/testData/diagnostics/tests/functionLiterals/kt6541_extensionForExtensionFunction.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/kt6541_extensionForExtensionFunction.fir.kt index 69913673c8a..32a662a6ce9 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/kt6541_extensionForExtensionFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/kt6541_extensionForExtensionFunction.fir.kt @@ -4,7 +4,7 @@ interface Foo fun (Foo.() -> Unit).invoke(b : Foo.() -> Unit) {} object Z { - infix fun add(b : Foo.() -> Unit) : Z = Z + infix fun add(b : Foo.() -> Unit) : Z = Z } val t2 = Z add { } { } diff --git a/compiler/testData/diagnostics/tests/inline/nonLocalReturns/onlyLocalReturnLambdaBinaryExpr.fir.kt b/compiler/testData/diagnostics/tests/inline/nonLocalReturns/onlyLocalReturnLambdaBinaryExpr.fir.kt index 5a0533c202b..cf5ca794851 100644 --- a/compiler/testData/diagnostics/tests/inline/nonLocalReturns/onlyLocalReturnLambdaBinaryExpr.fir.kt +++ b/compiler/testData/diagnostics/tests/inline/nonLocalReturns/onlyLocalReturnLambdaBinaryExpr.fir.kt @@ -1,9 +1,9 @@ // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE class Z { - inline infix fun inlineFun(crossinline p: () -> R) { + inline infix fun inlineFun(crossinline p: () -> R) { p() - } + } } fun fun1(p: () -> R) { diff --git a/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.fir.kt b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.fir.kt index faa594795d5..514ef6a0ccc 100644 --- a/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/operatorInfix/MemberFunctions.fir.kt @@ -1,10 +1,10 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER class Example { - operator infix fun plus(other: Example) = 0 + operator infix fun plus(other: Example) = 0 fun minus(other: Example) = 0 - operator infix fun times(other: Example) = 0 + operator infix fun times(other: Example) = 0 fun div(other: Example) = 0 } @@ -42,4 +42,4 @@ fun a() { } fun consumeInt(i: Int) {} -fun consumeString(s: String) {} \ No newline at end of file +fun consumeString(s: String) {} diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.fir.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.fir.kt index feb0e66f806..619597777fa 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.fir.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/InfixCallNullability.fir.kt @@ -1,8 +1,8 @@ // !WITH_NEW_INFERENCE class A() { - operator infix fun plus(i : Int) {} + operator infix fun plus(i : Int) {} operator fun unaryMinus() {} - operator infix fun contains(a : Any?) : Boolean = true + operator infix fun contains(a : Any?) : Boolean = true } operator infix fun A.div(i : Int) {} diff --git a/compiler/testData/diagnostics/tests/redeclarations/shadowedExtension/infixExtensionVsNonInfixMember.fir.kt b/compiler/testData/diagnostics/tests/redeclarations/shadowedExtension/infixExtensionVsNonInfixMember.fir.kt index 40ec24b1d1b..675dc230b12 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/shadowedExtension/infixExtensionVsNonInfixMember.fir.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/shadowedExtension/infixExtensionVsNonInfixMember.fir.kt @@ -1,7 +1,7 @@ interface IFoo { fun foo(i: Int): Int - infix fun bar(i: Int): Int + infix fun bar(i: Int): Int } infix fun IFoo.foo(i: Int) = i -infix fun IFoo.bar(i: Int) = i \ No newline at end of file +infix fun IFoo.bar(i: Int) = i diff --git a/compiler/testData/diagnostics/tests/smartCasts/afterBinaryExpr.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/afterBinaryExpr.fir.kt index 5e3a87c5f02..bb3a944d6ef 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/afterBinaryExpr.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/afterBinaryExpr.fir.kt @@ -1,7 +1,7 @@ package o class A { - infix fun foo(b: B) = b + infix fun foo(b: B) = b } class B { @@ -11,4 +11,4 @@ class B { fun test(a: A, b: B?) { a foo b!! b.bar() -} \ No newline at end of file +}