From 50cd560d099976427bd43ae347b3a320483364f8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 25 Oct 2022 13:24:19 +0200 Subject: [PATCH] K1: add more tests for BI assignment checker, fix corner cases Related to KT-54004 --- .../BuilderInferenceAssignmentChecker.kt | 8 +- .../builderInference/unsafeAssignment.fir.kt | 7 +- .../builderInference/unsafeAssignment.kt | 7 +- .../unsafeAssignmentExtra.fir.kt | 17 +++ .../unsafeAssignmentExtra.fir.txt | 103 ++++++++++++++++++ .../builderInference/unsafeAssignmentExtra.kt | 17 +++ 6 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/BuilderInferenceAssignmentChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/BuilderInferenceAssignmentChecker.kt index 3f681ab7302..00fa1f36a62 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/BuilderInferenceAssignmentChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/BuilderInferenceAssignmentChecker.kt @@ -9,16 +9,11 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl -import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo import org.jetbrains.kotlin.resolve.calls.util.getType import org.jetbrains.kotlin.types.StubTypeForBuilderInference import org.jetbrains.kotlin.types.checker.KotlinTypeChecker @@ -34,6 +29,7 @@ object BuilderInferenceAssignmentChecker : CallChecker { val callElement = resolvedCall.call.callElement if (callElement !is KtNameReferenceExpression) return val binaryExpression = callElement.getParentOfType(strict = true) ?: return + if (binaryExpression.operationToken != KtTokens.EQ) return if (!BasicExpressionTypingVisitor.isLValue(callElement, binaryExpression)) return val leftType = resultingDescriptor.returnType?.takeIf { !it.isError } ?: return diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.fir.kt index 647aa3e5274..dfdcf247720 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.fir.kt @@ -9,8 +9,13 @@ fun main(arg: Any) { val x = 57 val value = myBuilder { doSmthng("one ") - a = 57 + run { a; this }.a = 10 + a += 1 + this.a = 57 + this.(a) = 57 a = x + (a) = x + a.hashCode = 99 if (arg is String) { a = arg } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.kt index 270a8e34c09..08aa7d2c9a7 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignment.kt @@ -9,8 +9,13 @@ fun main(arg: Any) { val x = 57 val value = myBuilder { doSmthng("one ") - a = 57 + run { a; this }.a = 10 + a += 1 + this.a = 57 + this.(a) = 57 a = x + (a) = x + a.hashCode = 99 if (arg is String) { a = arg } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.kt index 055ae3e448a..8fad6167aa6 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.kt @@ -1,4 +1,5 @@ // WITH_REFLECT +// FIR_DUMP import kotlin.reflect.* interface Foo { @@ -57,4 +58,20 @@ fun main(arg: Any, condition: Boolean) { a = 67 } } + + // See KT-54664 + val value3 = myBuilder { + accept("") + a = 45 + bar(::a) + } + + fun baz(t: Int) {} + + val value4 = myBuilder { + accept("") + a = 45 + b[0] = 123 + baz(a) + } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.txt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.txt new file mode 100644 index 00000000000..2189bd14d9c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.fir.txt @@ -0,0 +1,103 @@ +FILE: unsafeAssignmentExtra.fir.kt + public abstract interface Foo : R|kotlin/Any| { + public abstract var a: R|T| + public get(): R|T| + public set(value: R|T|): R|kotlin/Unit| + + public abstract val b: R|kotlin/Array| + public get(): R|kotlin/Array| + + public abstract fun accept(arg: R|T|): R|kotlin/Unit| + + } + public final class FooImpl : R|Foo| { + public constructor(): R|FooImpl| { + super() + } + + } + public final fun bar(p: R|kotlin/reflect/KMutableProperty0|): R|kotlin/Unit| { + R|/p|.R|SubstitutionOverride|(Int(100)) + } + public final fun myBuilder(block: R|Foo.() -> kotlin/Unit|): R|Foo| { + ^myBuilder R|/FooImpl.FooImpl|().R|kotlin/apply||>(R|/block|) + } + public final fun R|Foo|.change(block: R|Foo.() -> kotlin/Unit|): R|Foo| { + R|/block|.R|SubstitutionOverride|(this@R|/change|) + ^change this@R|/change| + } + public final fun main(arg: R|kotlin/Any|, condition: R|kotlin/Boolean|): R|kotlin/Unit| { + lval value: R|Foo| = R|/myBuilder|( = myBuilder@fun R|Foo|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride|>|.R|SubstitutionOverride|(Int(0), Int(123)) + this@R|special/anonymous|.R|SubstitutionOverride| = Int(45) + lval : R|kotlin/Int| = this@R|special/anonymous|.R|SubstitutionOverride| + this@R|special/anonymous|.R|SubstitutionOverride| = R|/|.#() + R|/| + R|/bar|(::R|SubstitutionOverride|) + when () { + (this@R|special/anonymous|.R|SubstitutionOverride| is R|kotlin/Int|) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(67) + lval : R|kotlin/Int| = this@R|special/anonymous|.R|SubstitutionOverride| + this@R|special/anonymous|.R|SubstitutionOverride| = R|/|.#() + R|/| + R|/bar|(::R|SubstitutionOverride|) + } + } + + when (R|/condition|) { + ==($subj$, Boolean(true)) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(87) + } + ==($subj$, Boolean(false)) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(65) + } + } + + lval x: by this@R|special/anonymous|.R|SubstitutionOverride| + this@R|special/anonymous|.R|/change|( = change@fun R|Foo|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(99) + } + ) + } + ) + lval value2: R|Foo| = R|/myBuilder|( = myBuilder@fun R|Foo|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride|(String()) + this@R|special/anonymous|.R|SubstitutionOverride| = Int(45) + when (R|/condition|) { + ==($subj$, Boolean(true)) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(87) + } + ==($subj$, Boolean(false)) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(65) + } + } + + this@R|special/anonymous|.R|/change|( = change@fun R|Foo|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(99) + } + ) + when () { + (this@R|special/anonymous|.R|SubstitutionOverride| is R|kotlin/Int|) -> { + this@R|special/anonymous|.R|SubstitutionOverride| = Int(67) + } + } + + } + ) + lval value3: R|Foo| = R|/myBuilder|( = myBuilder@fun R|Foo|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride|(String()) + this@R|special/anonymous|.R|SubstitutionOverride| = Int(45) + R|/bar|(::R|SubstitutionOverride|) + } + ) + local final fun baz(t: R|kotlin/Int|): R|kotlin/Unit| { + } + + lval value4: R|Foo & java/io/Serializable)>| = R|/myBuilder| & java/io/Serializable)|>( = myBuilder@fun R|Foo & java/io/Serializable)>|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|SubstitutionOverride|(String()) + this@R|special/anonymous|.R|SubstitutionOverride| = Int(45) + this@R|special/anonymous|.R|SubstitutionOverride|>|.R|SubstitutionOverride|(Int(0), Int(123)) + R|/baz|(this@R|special/anonymous|.R|SubstitutionOverride|) + } + ) + } diff --git a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.kt b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.kt index 1bfd7c09b8b..e33c3c36680 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/builderInference/unsafeAssignmentExtra.kt @@ -1,4 +1,5 @@ // WITH_REFLECT +// FIR_DUMP import kotlin.reflect.* interface Foo { @@ -57,4 +58,20 @@ fun main(arg: Any, condition: Boolean) { a = 67 } } + + // See KT-54664 + val value3 = myBuilder { + accept("") + a = 45 + bar(::a) + } + + fun baz(t: Int) {} + + val value4 = myBuilder { + accept("") + a = 45 + b[0] = 123 + baz(a) + } }