From 55159694df642b897acdde879a84eed9b5baa5f8 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Sun, 18 Feb 2024 19:15:14 +0100 Subject: [PATCH] [FIR] Use `Operator` origin for `ITERATOR` and `HAS_NEXT` function calls instead of `Regular` It automatically fixes KT-62356 since iterators now are operators ^KT-62356 Fixed --- .../diagnostics/forLoopChecker.fir.txt | 6 ++-- .../diagnostics/forLoopChecker.kt | 2 +- .../checkers/expression/FirForLoopChecker.kt | 36 ++++++++++++------- .../LightTreeRawFirExpressionBuilder.kt | 3 ++ .../kotlin/fir/builder/PsiRawFirBuilder.kt | 3 ++ .../operator-call/p-4/neg/1.1.fir.kt | 8 ++--- .../operator-call/p-4/neg/1.1.kt | 4 +-- 7 files changed, 40 insertions(+), 22 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt index 35573b4787e..a04bd0bcaaf 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt @@ -260,9 +260,9 @@ FILE: forLoopChecker.kt } { - lval : R|ImproperIterator6| = R|/notRange9|.R|/NotRange9.iterator|() - while(R|/|.R|/ImproperIterator6.hasNext|()) { - lval i: R|kotlin/Int| = R|/|.R|/ImproperIterator6.next|() + lval : R|ImproperIterator6| = R|/notRange9|.R|/NotRange9.iterator#|() + while(R|/|.R|/ImproperIterator6.hasNext#|()) { + lval i: R|kotlin/Int| = R|/|.R|/ImproperIterator6.next#|() { } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt index 195b332a6a0..f8b372a49bf 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt @@ -105,7 +105,7 @@ fun test( for (i in notRange6); for (i in notRange7); for (i in notRange8); - for (i in notRange9); + for (i in notRange9); for (i in range0); for (i in range1); } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt index aacac839d45..5589e54362b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirWhileLoop import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.isError +import org.jetbrains.kotlin.fir.resolve.calls.OperatorCallOfNonOperatorFunction import org.jetbrains.kotlin.fir.resolve.calls.UnsafeCall import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -106,10 +107,13 @@ object FirForLoopChecker : FirBlockChecker(MppCheckerKind.Common) { when { calleeReference.isError() -> { when (val diagnostic = calleeReference.diagnostic) { - is ConeAmbiguityError -> if (diagnostic.applicability.isSuccess) { - reporter.reportOn(reportSource, ambiguityFactory, diagnostic.candidates.map { it.symbol }, context) - } else if (noneApplicableFactory != null) { - reporter.reportOn(reportSource, noneApplicableFactory, diagnostic.candidates.map { it.symbol }, context) + is ConeAmbiguityError -> { + reporter.reportOn( + reportSource, + noneApplicableFactory ?: ambiguityFactory, + diagnostic.candidates.map { it.symbol }, + context + ) } is ConeUnresolvedNameError -> { reporter.reportOn(reportSource, missingFactory, context) @@ -132,17 +136,25 @@ object FirForLoopChecker : FirBlockChecker(MppCheckerKind.Common) { is ConeInapplicableCandidateError -> { if (unsafeCallFactory != null || noneApplicableFactory != null) { diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.forEach { - if (it is UnsafeCall) { - if (unsafeCallFactory != null) { + when (it) { + is UnsafeCall -> { + if (unsafeCallFactory != null) { + reporter.reportOn( + reportSource, unsafeCallFactory, context + ) + } else { + reporter.reportOn( + reportSource, noneApplicableFactory!!, listOf(diagnostic.candidate.symbol), context + ) + } + return true + } + is OperatorCallOfNonOperatorFunction -> { + val symbol = it.function reporter.reportOn( - reportSource, unsafeCallFactory, context - ) - } else { - reporter.reportOn( - reportSource, noneApplicableFactory!!, listOf(diagnostic.candidate.symbol), context + reportSource, OPERATOR_MODIFIER_REQUIRED, symbol, symbol.name.asString(), context ) } - return true } } } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt index 2b6699ef074..fa64ae2cb90 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt @@ -1172,6 +1172,7 @@ class LightTreeRawFirExpressionBuilder( name = OperatorNameConventions.ITERATOR } explicitReceiver = calculatedRangeExpression + origin = FirFunctionCallOrigin.Operator } ) statements += iteratorVal @@ -1184,6 +1185,7 @@ class LightTreeRawFirExpressionBuilder( name = OperatorNameConventions.HAS_NEXT } explicitReceiver = generateResolvedAccessExpression(rangeSource, iteratorVal) + origin = FirFunctionCallOrigin.Operator } // break/continue in the for loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. @@ -1204,6 +1206,7 @@ class LightTreeRawFirExpressionBuilder( name = OperatorNameConventions.NEXT } explicitReceiver = generateResolvedAccessExpression(rangeSource, iteratorVal) + origin = FirFunctionCallOrigin.Operator }, valueParameter.returnTypeRef, extractedAnnotations = valueParameter.annotations diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt index 1317aedbaaa..2097b0cb87e 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt @@ -2743,6 +2743,7 @@ open class PsiRawFirBuilder( name = OperatorNameConventions.ITERATOR } explicitReceiver = rangeExpression + origin = FirFunctionCallOrigin.Operator }, ) statements += iteratorVal @@ -2755,6 +2756,7 @@ open class PsiRawFirBuilder( name = OperatorNameConventions.HAS_NEXT } explicitReceiver = generateResolvedAccessExpression(rangeSource, iteratorVal) + origin = FirFunctionCallOrigin.Operator } // break/continue in the for loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. @@ -2776,6 +2778,7 @@ open class PsiRawFirBuilder( name = OperatorNameConventions.NEXT } explicitReceiver = generateResolvedAccessExpression(rangeSource, iteratorVal) + origin = FirFunctionCallOrigin.Operator }, typeRef = ktParameter.typeReference.toFirOrImplicitType(), extractedAnnotations = ktParameter.modifierList?.annotationEntries?.map { it.convert() }, diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt index b53de572038..24d9c3534e2 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt @@ -187,13 +187,13 @@ class B(var a: Int = 0) { * TESTCASE NUMBER: 7 * NOTE: for-loop operators * UNEXPECTED BEHAVIOUR - * ISSUES: KT-36898 + * ISSUES: KT-36898, KT-62356 */ package testPackCase7 fun case7 () { val iterable: Iterable = Iterable(Inv('s')) - for (i in iterable) { + for (i in iterable) { println(i) } } @@ -220,13 +220,13 @@ class Inv(val c: Char) { * TESTCASE NUMBER: 8 * NOTE: for-loop operators * UNEXPECTED BEHAVIOUR - * ISSUES: KT-36898 + * ISSUES: KT-36898, KT-62356 */ package testPackCase8 fun case8 () { val iterable: Iterable = Iterable() - for (i in iterable) { + for (i in iterable) { println(i) } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt index 483b80c4d2b..c114f265522 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt @@ -187,7 +187,7 @@ class B(var a: Int = 0) { * TESTCASE NUMBER: 7 * NOTE: for-loop operators * UNEXPECTED BEHAVIOUR - * ISSUES: KT-36898 + * ISSUES: KT-36898, KT-62356 */ package testPackCase7 @@ -220,7 +220,7 @@ class Inv(val c: Char) { * TESTCASE NUMBER: 8 * NOTE: for-loop operators * UNEXPECTED BEHAVIOUR - * ISSUES: KT-36898 + * ISSUES: KT-36898, KT-62356 */ package testPackCase8