From d1531f9cdd5852352c0133198706125dc63b6007 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Tue, 25 May 2021 23:10:15 +0000 Subject: [PATCH] FIR: Choose a resolved candidate for augmented assignment when both assign and operator candidates are unsuccessful. --- .../FirExpressionsResolveTransformer.kt | 30 ++++++++++++------- .../tests/BinaryCallsOnNullableValues.fir.kt | 2 +- .../augmentedAssignment.fir.kt | 17 ----------- .../augmentedAssignment.kt | 1 + ...assignmentOperationsCheckReturnType.fir.kt | 16 +++++----- .../tests/smartCasts/alwaysNull.fir.kt | 2 +- .../diagnostics/notLinked/dfa/neg/12.fir.kt | 2 +- .../augmentedAssignmentNotAvailable.kt | 4 +-- .../augmentedAssignmentNotAvailable.kt.after | 4 +-- 9 files changed, 34 insertions(+), 44 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.fir.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 6de302c4a19..949d55fe153 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -39,7 +39,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.types.TypeApproximatorConfiguration -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) { private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes @@ -386,7 +386,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent) } val assignCallReference = resolvedAssignCall.calleeReference as? FirNamedReferenceWithCandidate - val assignIsResolvable = assignCallReference?.isError == false + val assignIsSuccessful = assignCallReference?.isError == false // x = x + y val simpleOperatorName = FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(assignmentOperatorStatement.operation) @@ -395,7 +395,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform simpleOperatorCall.transformSingle(this, ResolutionMode.ContextDependent) } val operatorCallReference = resolvedOperatorCall.calleeReference as? FirNamedReferenceWithCandidate - val operatorIsResolvable = operatorCallReference?.isError == false + val operatorIsSuccessful = operatorCallReference?.isError == false fun operatorReturnTypeMatches(candidate: Candidate): Boolean { // After KT-45503, non-assign flavor of operator is checked more strictly: the return type must be assignable to the variable. @@ -408,8 +408,8 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform leftArgument.typeRef.coneType ) } - // following `!!` is safe since `operatorIsResolvable = true` implies `operatorCallReference != null` - val operatorReturnTypeMatches = operatorIsResolvable && operatorReturnTypeMatches(operatorCallReference!!.candidate) + // following `!!` is safe since `operatorIsSuccessful = true` implies `operatorCallReference != null` + val operatorReturnTypeMatches = operatorIsSuccessful && operatorReturnTypeMatches(operatorCallReference!!.candidate) val lhsReference = leftArgument.toResolvedCallableReference() val lhsSymbol = lhsReference?.resolvedSymbol as? FirVariableSymbol<*> @@ -467,11 +467,21 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform } return when { - assignIsResolvable && !lhsIsVar -> chooseAssign() - !assignIsResolvable && !operatorIsResolvable -> chooseAssign() - !assignIsResolvable && operatorIsResolvable -> chooseOperator() - assignIsResolvable && !operatorIsResolvable -> chooseAssign() - assignIsResolvable && operatorIsResolvable && !operatorReturnTypeMatches -> chooseAssign() + assignIsSuccessful && !lhsIsVar -> chooseAssign() + !assignIsSuccessful && !operatorIsSuccessful -> { + // If neither candidate is successful, choose whichever is resolved, prioritizing assign + val isAssignResolved = assignCallReference.safeAs()?.diagnostic !is ConeUnresolvedNameError + val isOperatorResolved = + operatorCallReference.safeAs()?.diagnostic !is ConeUnresolvedNameError + when { + isAssignResolved -> chooseAssign() + isOperatorResolved -> chooseOperator() + else -> chooseAssign() + } + } + !assignIsSuccessful && operatorIsSuccessful -> chooseOperator() + assignIsSuccessful && !operatorIsSuccessful -> chooseAssign() + assignIsSuccessful && operatorIsSuccessful && !operatorReturnTypeMatches -> chooseAssign() else -> reportAmbiguity() } } diff --git a/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt b/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt index 6c290ba4952..8058722c1ae 100644 --- a/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt +++ b/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt @@ -8,7 +8,7 @@ fun f(): Unit { x + 1 x plus 1 x < 1 - x += 1 + x += 1 x == 1 x != 1 diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.fir.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.fir.kt deleted file mode 100644 index a2c0dc24b08..00000000000 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -class A { - operator fun plusAssign(s: String) {} -} - -fun test() { - var a: A? = A() - a += "" -} - -class B { - operator fun plus(other: B) = this -} - -fun test2() { - var b: B? = B() - b += B() -} diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt index 0231a992bff..1ed6e137e16 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/augmentedAssignment.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class A { operator fun plusAssign(s: String) {} } diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt index a1298941e5c..7466d989ab7 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt @@ -1,14 +1,14 @@ fun intBinEq() { var x = 0 - x += 'a' + x += 'a' x += 1.toByte() x += 1.toShort() x += 1L x += 1f x += 1.0 - x *= 'a' - x *= 1.toByte() - x *= 1.toShort() + x *= 'a' + x *= 1.toByte() + x *= 1.toShort() x *= 1L x *= 1f x *= 1.0 @@ -16,16 +16,16 @@ fun intBinEq() { fun shortBinEq() { var x = 0.toShort() - x += 'a' + x += 'a' x += 1.toByte() x += 1.toShort() x += 1L x += 1f x += 1.0 - x *= 'a' - x *= 1.toByte() - x *= 1.toShort() + x *= 'a' + x *= 1.toByte() + x *= 1.toShort() x *= 1L x *= 1f x *= 1.0 diff --git a/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt index 2db01d2ff39..b52ad579826 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt @@ -7,7 +7,7 @@ fun foo(): String { var t: String? = "y" if (t == null) t = "x" var x: Int? = null - if (x == null) x += null + if (x == null) x += null return t + s } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt index 69eed526113..6832caf333f 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt @@ -6,7 +6,7 @@ fun case_1() { var x: Int? = 11 x!! - try {x = null;} finally { x += 10; } + try {x = null;} finally { x += 10; } } // TESTCASE NUMBER: 2 diff --git a/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt b/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt index cb7de177495..fc09d6990e4 100644 --- a/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt +++ b/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt @@ -6,6 +6,4 @@ class A { fun foo(b: A) { var a: A? = A() a += b -} - -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt.after b/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt.after index ff7f8ce3e9c..5f8e0a586db 100644 --- a/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt.after +++ b/idea/testData/quickfix/replaceInfixOrOperatorCall/augmentedAssignmentNotAvailable.kt.after @@ -6,6 +6,4 @@ class A { fun foo(b: A) { var a: A? = A() a = a?.plus(b) -} - -/* IGNORE_FIR */ +} \ No newline at end of file