[FIR] Fix exponential analysis of augmented array access calls
^KT-50861 Fixed
This commit is contained in:
committed by
teamcity
parent
c4735f9f29
commit
ade2307345
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
KT element: KtBinaryExpression
|
||||
FIR element: FirFunctionCallImpl
|
||||
FIR source kind: DesugaredCompoundAssignment
|
||||
FIR source kind: KtRealSourceElementKind
|
||||
|
||||
FIR element rendered:
|
||||
R|<local>/<<array>>|.R|SubstitutionOverride</MyMap.set: R|kotlin/Unit|>|(R|<local>/<<index_0>>|, R|<local>/<<array>>|.R|SubstitutionOverride</MyMap.get: R|kotlin/Int|>|(R|<local>/<<index_0>>|).R|kotlin/Int.plus|(Int(1)))
|
||||
R|<local>/<<array>>|.R|SubstitutionOverride</MyMap.set: R|kotlin/Unit|>|(R|<local>/<<index_0>>|, R|<local>/<<array>>|.R|SubstitutionOverride</MyMap.get: R|kotlin/Int|>|(R|<local>/<<index_0>>|).R|kotlin/Int.plus|(Int(1)))
|
||||
|
||||
+12
@@ -863,6 +863,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/callResolution"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("arraySetWithPlusAssign.kt")
|
||||
public void testArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/arraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionInvoke.kt")
|
||||
public void testCompanionInvoke() throws Exception {
|
||||
@@ -893,6 +899,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exponentialArraySetWithPlusAssign.kt")
|
||||
public void testExponentialArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/exponentialArraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||
|
||||
+10
@@ -745,6 +745,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/callResolution"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("arraySetWithPlusAssign.kt")
|
||||
public void testArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/arraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("companionInvoke.kt")
|
||||
public void testCompanionInvoke() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/companionInvoke.kt");
|
||||
@@ -770,6 +775,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("exponentialArraySetWithPlusAssign.kt")
|
||||
public void testExponentialArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/exponentialArraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt");
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@ FILE: arraySetWithOperation.kt
|
||||
|
||||
}
|
||||
public final fun test_3(a: R|A<D>|): R|kotlin/Unit| {
|
||||
ArraySet:[R|<local>/a|.R|SubstitutionOverride</A.get: R|D|>|(Int(0)) += R|/D.D|()]
|
||||
R|<local>/a|.R|SubstitutionOverride</A.get: R|D|>|(Int(0)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /A.set]>#(R|/D.D|())
|
||||
}
|
||||
public final fun test_4(b: R|B|): R|kotlin/Unit| {
|
||||
ArraySet:[R|<local>/b|.<Unresolved name: get>#(Int(0)) += R|/B.B|()]
|
||||
R|<local>/b|.<Unresolved name: get>#(Int(0)).<Unresolved name: +=>#(R|/B.B|())
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,9 +28,9 @@ fun test_2(a: A<C>) {
|
||||
}
|
||||
|
||||
fun test_3(a: A<D>) {
|
||||
a[0] <!OVERLOAD_RESOLUTION_AMBIGUITY!>+=<!> D() // ambiguity
|
||||
a[0] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> D() // ambiguity
|
||||
}
|
||||
|
||||
fun test_4(b: B) {
|
||||
b<!NO_GET_METHOD!>[0]<!> <!UNRESOLVED_REFERENCE!>+=<!> B() // unresolved
|
||||
b<!NO_GET_METHOD!>[0]<!> += B() // unresolved
|
||||
}
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
FILE: arraySetWithPlusAssign.kt
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|A| {
|
||||
^get this@R|/A|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(v: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_1(x: R|A|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class B : R|kotlin/Any| {
|
||||
public constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|B| {
|
||||
^get this@R|/B|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(a: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(x: R|kotlin/String|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(x: R|B|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/B.get|(Int(1)).R|/B.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/B.get|(Int(1)).R|/B.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class C : R|kotlin/Any| {
|
||||
public constructor(): R|C| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|C| {
|
||||
^get this@R|/C|
|
||||
}
|
||||
|
||||
public final operator fun set(i: R|kotlin/Int|, v: R|kotlin/String|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(a: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(v: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_3(x: R|C|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/C.get|(Int(1)).R|/C.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/C.get|(Int(1)).R|/C.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class D : R|kotlin/Any| {
|
||||
public constructor(): R|D| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun set(i: R|kotlin/Int|, x: R|D|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|D| {
|
||||
^get this@R|/D|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(v: R|() -> kotlin/Unit|): R|D| {
|
||||
^plus this@R|/D|
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_4(x: R|D|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class E : R|kotlin/Any| {
|
||||
public constructor(): R|E| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_5(x: R|E|): R|kotlin/Unit| {
|
||||
R|<local>/x|.<Unresolved name: get>#(Int(1)).<Unresolved name: +=>#(fun <anonymous>(): <ERROR TYPE REF: Unresolved name: plusAssign> <inline=Unknown> {
|
||||
R|/someCallInsideLambda|()
|
||||
^ R|<local>/x|.<Unresolved name: get>#(Int(1)).<Unresolved name: +=>#(fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class F : R|kotlin/Any| {
|
||||
public constructor(): R|F| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun set(i: R|kotlin/Int|, x: R|F|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|F| {
|
||||
^get this@R|/F|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(x: R|() -> kotlin/String|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(v: R|() -> kotlin/Int|): R|F| {
|
||||
^plus this@R|/F|
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_6(x: R|F|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/F.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/F.plusAssign, /F.set]>#(fun <anonymous>(): R|kotlin/String| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
^ String(please choose String)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class G : R|kotlin/Any| {
|
||||
public constructor(): R|G| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|, j: R|kotlin/Int|, k: R|kotlin/Int|): R|G| {
|
||||
^get this@R|/G|
|
||||
}
|
||||
|
||||
public final operator fun set(i: R|kotlin/Int|, j: R|kotlin/Int|, k: R|kotlin/Int|, x: R|G|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(v: R|() -> kotlin/Unit|): R|G| {
|
||||
^plus this@R|/G|
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_7(x: R|G|): R|kotlin/Unit| {
|
||||
{
|
||||
lval <<array>>: R|G| = R|<local>/x|
|
||||
lval <<index_0>>: R|kotlin/Int| = Int(1)
|
||||
lval <<index_1>>: R|kotlin/Int| = Int(2)
|
||||
lval <<index_2>>: R|kotlin/Int| = Int(3)
|
||||
R|<local>/<<array>>|.R|/G.set|(R|<local>/<<index_0>>|, R|<local>/<<index_1>>|, R|<local>/<<index_2>>|, R|<local>/<<array>>|.R|/G.get|(R|<local>/<<index_0>>|, R|<local>/<<index_1>>|, R|<local>/<<index_2>>|).R|/G.plus|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
{
|
||||
lval <<array>>: R|G| = R|<local>/x|
|
||||
lval <<index_0>>: R|kotlin/Int| = Int(1)
|
||||
lval <<index_1>>: R|kotlin/Int| = Int(2)
|
||||
lval <<index_2>>: R|kotlin/Int| = Int(3)
|
||||
R|<local>/<<array>>|.R|/G.set|(R|<local>/<<index_0>>|, R|<local>/<<index_1>>|, R|<local>/<<index_2>>|, R|<local>/<<array>>|.R|/G.get|(R|<local>/<<index_0>>|, R|<local>/<<index_1>>|, R|<local>/<<index_2>>|).R|/G.plus|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
public final fun someCallInsideLambda(): R|kotlin/Unit| {
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
// ISSUE: KT-50861
|
||||
|
||||
/*
|
||||
* a[b] += c desugars to:
|
||||
*
|
||||
* 1. a.get(b).plusAssign(c)
|
||||
* 2. a.set(b, a.get(b).plus(c))
|
||||
*/
|
||||
|
||||
// only plusAssign, no set
|
||||
class A {
|
||||
operator fun get(i: Int): A = this
|
||||
operator fun plusAssign(v: () -> Unit) {}
|
||||
}
|
||||
|
||||
fun test_1(x: A) {
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only plusAssign, plus doesn't fit
|
||||
class B {
|
||||
operator fun get(i: Int): B = this
|
||||
operator fun plusAssign(a: () -> Unit) {}
|
||||
operator fun plus(x: String) {}
|
||||
}
|
||||
|
||||
fun test_2(x: B) {
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only plusAssign, set doesn't fit
|
||||
class C {
|
||||
operator fun get(i: Int): C = this
|
||||
operator fun set(i: Int, v: String) {}
|
||||
operator fun plusAssign(a: () -> Unit) {}
|
||||
operator fun plus(v: () -> Unit) {}
|
||||
}
|
||||
|
||||
fun test_3(x: C) {
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// both fit
|
||||
class D {
|
||||
operator fun set(i: Int, x: D) {}
|
||||
operator fun get(i: Int): D = this
|
||||
operator fun plusAssign(x: () -> Unit) {}
|
||||
operator fun plus(v: () -> Unit): D = this
|
||||
}
|
||||
|
||||
fun test_4(x: D) {
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nothing fit
|
||||
class E
|
||||
|
||||
fun test_5(x: E) {
|
||||
x<!NO_GET_METHOD!>[1]<!> += {
|
||||
someCallInsideLambda()
|
||||
x<!NO_GET_METHOD!>[1]<!> += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// only plus, plusAssign doesn't fir because of lambda
|
||||
class F {
|
||||
operator fun set(i: Int, x: F) {}
|
||||
operator fun get(i: Int): F = this
|
||||
operator fun plusAssign(x: () -> String) {}
|
||||
operator fun plus(v: () -> Int): F = this
|
||||
}
|
||||
|
||||
fun test_6(x: F) {
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
"please choose String"
|
||||
}
|
||||
}
|
||||
|
||||
// only plus, no set. 3 indices in get/set
|
||||
class G {
|
||||
operator fun get(i: Int, j: Int, k: Int): G = this
|
||||
operator fun set(i: Int, j: Int, k: Int, x: G) {}
|
||||
operator fun plus(v: () -> Unit): G = this
|
||||
}
|
||||
|
||||
fun test_7(x: G) {
|
||||
x[1, 2, 3] += {
|
||||
someCallInsideLambda()
|
||||
x[1, 2, 3] += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun someCallInsideLambda() {}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
FILE: exponentialArraySetWithPlusAssign.kt
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|A| {
|
||||
^get this@R|/A|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(v: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_1(x: R|A|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/A.get|(Int(1)).R|/A.plusAssign|(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final class D : R|kotlin/Any| {
|
||||
public constructor(): R|D| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final operator fun set(i: R|kotlin/Int|, x: R|D|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun get(i: R|kotlin/Int|): R|D| {
|
||||
^get this@R|/D|
|
||||
}
|
||||
|
||||
public final operator fun plusAssign(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final operator fun plus(v: R|() -> kotlin/Unit|): R|D| {
|
||||
^plus this@R|/D|
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(x: R|D|): R|kotlin/Unit| {
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
R|<local>/x|.R|/D.get|(Int(1)).<Operator overload ambiguity. Compatible candidates: [/D.plusAssign, /D.set]>#(fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
R|/someCallInsideLambda|()
|
||||
Q|kotlin/Unit|
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
public final fun someCallInsideLambda(): R|kotlin/Unit| {
|
||||
}
|
||||
Vendored
+116
@@ -0,0 +1,116 @@
|
||||
// ISSUE: KT-50861
|
||||
|
||||
// only plusAssign, no set
|
||||
class A {
|
||||
operator fun get(i: Int): A = this
|
||||
operator fun plusAssign(v: () -> Unit) {}
|
||||
}
|
||||
|
||||
fun test_1(x: A) {
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
x[1] += {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// both fit
|
||||
class D {
|
||||
operator fun set(i: Int, x: D) {}
|
||||
operator fun get(i: Int): D = this
|
||||
operator fun plusAssign(x: () -> Unit) {}
|
||||
operator fun plus(v: () -> Unit): D = this
|
||||
}
|
||||
|
||||
fun test_2(x: D) {
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
x[1] <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> {
|
||||
someCallInsideLambda()
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun someCallInsideLambda() {}
|
||||
+1
-1
@@ -5,5 +5,5 @@ class Foo {
|
||||
|
||||
fun test() {
|
||||
var f = Foo()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>f += f<!>
|
||||
f <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> f
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ fun testOperatorAssignment() {
|
||||
val c = C()
|
||||
c += ""
|
||||
<!CAN_BE_VAL!>var<!> c1 = C()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
|
||||
c1 <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> ""
|
||||
|
||||
var a = 1
|
||||
a += 12
|
||||
|
||||
+12
@@ -863,6 +863,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/callResolution"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("arraySetWithPlusAssign.kt")
|
||||
public void testArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/arraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionInvoke.kt")
|
||||
public void testCompanionInvoke() throws Exception {
|
||||
@@ -893,6 +899,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exponentialArraySetWithPlusAssign.kt")
|
||||
public void testExponentialArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/exponentialArraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||
|
||||
+12
@@ -863,6 +863,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/callResolution"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("arraySetWithPlusAssign.kt")
|
||||
public void testArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/arraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionInvoke.kt")
|
||||
public void testCompanionInvoke() throws Exception {
|
||||
@@ -893,6 +899,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exponentialArraySetWithPlusAssign.kt")
|
||||
public void testExponentialArraySetWithPlusAssign() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/exponentialArraySetWithPlusAssign.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||
|
||||
+1
-1
@@ -518,7 +518,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Collection<Symbol>>("candidates")
|
||||
}
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error<PsiElement> {
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<Collection<Symbol>>("candidates")
|
||||
}
|
||||
val ITERATOR_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
|
||||
+1
-1
@@ -351,7 +351,7 @@ object FirErrors {
|
||||
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>()
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val ITERATOR_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val HAS_NEXT_FUNCTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NEXT_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
-8
@@ -1058,14 +1058,6 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
null,
|
||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
||||
)
|
||||
// Second copy of rhs is used because we analyze it twice in different contexts
|
||||
// and now they should be different expressions instances to make everything work properly.
|
||||
// But this lead to exponential time already at FIR building stage,
|
||||
// so we hope this hack will be removed with KT-50861
|
||||
this.rhs2 = rhs?.convert() ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
||||
)
|
||||
this.arrayAccessSource = arrayAccessSource
|
||||
this.annotations += annotations
|
||||
}
|
||||
|
||||
+233
-165
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
@@ -25,7 +26,6 @@ import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.coneType
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.unwrapSmartcastExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.FirStubInferenceSession
|
||||
@@ -46,7 +46,6 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
||||
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
|
||||
@@ -516,28 +515,17 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
assignmentOperatorStatement: FirAssignmentOperatorStatement,
|
||||
data: ResolutionMode
|
||||
): FirStatement {
|
||||
require(assignmentOperatorStatement.operation != FirOperation.ASSIGN)
|
||||
val operation = assignmentOperatorStatement.operation
|
||||
require(operation != FirOperation.ASSIGN)
|
||||
|
||||
assignmentOperatorStatement.transformAnnotations(transformer, ResolutionMode.ContextIndependent)
|
||||
val leftArgument = assignmentOperatorStatement.leftArgument.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
val rightArgument = assignmentOperatorStatement.rightArgument.transformSingle(transformer, ResolutionMode.ContextDependent)
|
||||
|
||||
fun createFunctionCall(name: Name): FirFunctionCall = buildFunctionCall {
|
||||
source = assignmentOperatorStatement.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = leftArgument
|
||||
argumentList = buildUnaryArgumentList(rightArgument)
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
// TODO: Use source of operator for callee reference source
|
||||
source = assignmentOperatorStatement.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
this.name = name
|
||||
candidateSymbol = null
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
val generator = GeneratorOfPlusAssignCalls(assignmentOperatorStatement, operation, leftArgument, rightArgument)
|
||||
|
||||
// x.plusAssign(y)
|
||||
val assignmentOperatorName = FirOperationNameConventions.ASSIGNMENTS.getValue(assignmentOperatorStatement.operation)
|
||||
val assignOperatorCall = createFunctionCall(assignmentOperatorName)
|
||||
val assignOperatorCall = generator.createAssignOperatorCall()
|
||||
val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall {
|
||||
assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||
}
|
||||
@@ -545,8 +533,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
val assignIsSuccessful = assignCallReference?.isError == false
|
||||
|
||||
// x = x + y
|
||||
val simpleOperatorName = FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(assignmentOperatorStatement.operation)
|
||||
val simpleOperatorCall = createFunctionCall(simpleOperatorName)
|
||||
val simpleOperatorCall = generator.createSimpleOperatorCall()
|
||||
val resolvedOperatorCall = resolveCandidateForAssignmentOperatorCall {
|
||||
simpleOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||
}
|
||||
@@ -1118,90 +1105,155 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
}
|
||||
}
|
||||
|
||||
private class GeneratorOfPlusAssignCalls(
|
||||
val baseElement: FirStatement,
|
||||
val operation: FirOperation,
|
||||
val lhs: FirExpression,
|
||||
val rhs: FirExpression
|
||||
) {
|
||||
companion object {
|
||||
fun createFunctionCall(
|
||||
name: Name,
|
||||
source: KtSourceElement?,
|
||||
receiver: FirExpression,
|
||||
vararg arguments: FirExpression
|
||||
): FirFunctionCall = buildFunctionCall {
|
||||
this.source = source
|
||||
explicitReceiver = receiver
|
||||
argumentList = when(arguments.size) {
|
||||
0 -> FirEmptyArgumentList
|
||||
1 -> buildUnaryArgumentList(arguments.first())
|
||||
else -> buildArgumentList {
|
||||
this.arguments.addAll(arguments)
|
||||
}
|
||||
}
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
// TODO: Use source of operator for callee reference source
|
||||
this.source = source
|
||||
this.name = name
|
||||
candidateSymbol = null
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFunctionCall(name: Name): FirFunctionCall {
|
||||
return createFunctionCall(name, baseElement.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment), lhs, rhs)
|
||||
}
|
||||
|
||||
fun createAssignOperatorCall(): FirFunctionCall {
|
||||
return createFunctionCall(FirOperationNameConventions.ASSIGNMENTS.getValue(operation))
|
||||
}
|
||||
|
||||
fun createSimpleOperatorCall(): FirFunctionCall {
|
||||
return createFunctionCall(FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(operation))
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun transformAugmentedArraySetCall(
|
||||
augmentedArraySetCall: FirAugmentedArraySetCall,
|
||||
data: ResolutionMode
|
||||
): FirStatement {
|
||||
assert(augmentedArraySetCall.operation in FirOperation.ASSIGNMENTS)
|
||||
assert(augmentedArraySetCall.operation != FirOperation.ASSIGN)
|
||||
/*
|
||||
* a[b] += c can be desugared to:
|
||||
*
|
||||
* 1. a.get(b).plusAssign(c)
|
||||
* 2. a.set(b, a.get(b).plus(c))
|
||||
*/
|
||||
|
||||
val operation = augmentedArraySetCall.operation
|
||||
assert(operation in FirOperation.ASSIGNMENTS)
|
||||
assert(operation != FirOperation.ASSIGN)
|
||||
|
||||
augmentedArraySetCall.transformAnnotations(transformer, data)
|
||||
val operatorName = FirOperationNameConventions.ASSIGNMENTS.getValue(augmentedArraySetCall.operation)
|
||||
|
||||
val transformedLhsCall =
|
||||
augmentedArraySetCall.lhsGetCall.transformSingle(transformer, ResolutionMode.ContextIndependent).takeIf { it.isSuccessful() }
|
||||
// transformedLhsCall: a.get(index)
|
||||
val transformedLhsCall = augmentedArraySetCall.lhsGetCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
val transformedRhs = augmentedArraySetCall.rhs.transformSingle(transformer, ResolutionMode.ContextDependent)
|
||||
|
||||
val blockForGetSetVersion: FirBlock? =
|
||||
transformedLhsCall?.let { augmentedArraySetCall.tryResolveAugmentedArraySetCallAsSetGetBlock(it) }
|
||||
val assignResolvedCall: FirFunctionCall? =
|
||||
transformedLhsCall?.let { augmentedArraySetCall.tryResolveWithOperatorAssignConvention(it) }
|
||||
val generator = GeneratorOfPlusAssignCalls(augmentedArraySetCall, operation, transformedLhsCall, transformedRhs)
|
||||
|
||||
val result: FirStatement = when {
|
||||
assignResolvedCall != null && blockForGetSetVersion != null -> {
|
||||
augmentedArraySetCall.also {
|
||||
it.replaceCalleeReference(
|
||||
buildErrorNamedReference {
|
||||
// TODO: add better diagnostic
|
||||
source = augmentedArraySetCall.source
|
||||
diagnostic = ConeAmbiguityError(operatorName, CandidateApplicability.RESOLVED, emptyList())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
blockForGetSetVersion != null -> {
|
||||
//checking secondResult leave erroneous nodes in dfa graph,
|
||||
//we add another block so final type of expression will be correct
|
||||
//todo replace this hack with proper graph cleaning
|
||||
transformer.components.dataFlowAnalyzer.enterBlock(blockForGetSetVersion)
|
||||
transformer.components.dataFlowAnalyzer.exitBlock(blockForGetSetVersion)
|
||||
blockForGetSetVersion
|
||||
}
|
||||
assignResolvedCall != null -> assignResolvedCall
|
||||
else -> {
|
||||
augmentedArraySetCall.rhs.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
augmentedArraySetCall.rhs2.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
|
||||
augmentedArraySetCall.also {
|
||||
it.replaceCalleeReference(
|
||||
buildErrorNamedReference {
|
||||
source = augmentedArraySetCall.source
|
||||
diagnostic = ConeUnresolvedNameError(operatorName)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
// a.get(b).plusAssign(c)
|
||||
val assignOperatorCall = generator.createAssignOperatorCall()
|
||||
val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall {
|
||||
assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||
}
|
||||
return result
|
||||
}
|
||||
val assignCallReference = resolvedAssignCall.calleeReference as? FirNamedReferenceWithCandidate
|
||||
val assignIsSuccessful = assignCallReference?.isError == false
|
||||
|
||||
private fun FirFunctionCall.isSuccessful(): Boolean =
|
||||
typeRef !is FirErrorTypeRef && calleeReference is FirResolvedNamedReference
|
||||
// <array>.set(<index_i>, <array>.get(<index_i>).plus(c))
|
||||
val info = tryResolveAugmentedArraySetCallAsSetGetBlock(augmentedArraySetCall, transformedLhsCall, transformedRhs)
|
||||
val resolvedOperatorCall = info.operatorCall
|
||||
val operatorCallReference = resolvedOperatorCall.calleeReference as? FirNamedReferenceWithCandidate
|
||||
val operatorIsSuccessful = operatorCallReference?.isError == false
|
||||
|
||||
|
||||
/**
|
||||
* Desugarings of a[x, y] += z to
|
||||
* a.get(x, y).plusAssign(z)
|
||||
*
|
||||
* @return null if `plusAssign` is unresolved
|
||||
* @return block defined as described above, otherwise
|
||||
*/
|
||||
private fun FirAugmentedArraySetCall.tryResolveWithOperatorAssignConvention(lhsGetCall: FirFunctionCall): FirFunctionCall? {
|
||||
val assignCall = buildFunctionCall {
|
||||
source = this@tryResolveWithOperatorAssignConvention.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = FirOperationNameConventions.ASSIGNMENTS.getValue(operation)
|
||||
}
|
||||
explicitReceiver = lhsGetCall
|
||||
argumentList = buildArgumentList {
|
||||
arguments += rhs2
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
annotations += this@tryResolveWithOperatorAssignConvention.annotations
|
||||
fun completeAssignCall() {
|
||||
dataFlowAnalyzer.enterFunctionCall(resolvedAssignCall)
|
||||
callCompleter.completeCall(resolvedAssignCall, noExpectedType)
|
||||
dataFlowAnalyzer.exitFunctionCall(resolvedAssignCall, callCompleted = true)
|
||||
}
|
||||
|
||||
val transformedCall = assignCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
return transformedCall.takeIf { it.isSuccessful() }
|
||||
fun chooseAssign(): FirStatement {
|
||||
completeAssignCall()
|
||||
return resolvedAssignCall
|
||||
}
|
||||
|
||||
// if `plus` call already inapplicable then there is no need to try to resolve `set` call
|
||||
if (assignIsSuccessful && !operatorIsSuccessful) {
|
||||
return chooseAssign()
|
||||
}
|
||||
|
||||
// a.set(b, a.get(b).plus(c))
|
||||
val resolvedSetCall = info.setCall
|
||||
val setCallReference = resolvedSetCall.calleeReference as? FirNamedReferenceWithCandidate
|
||||
val setIsSuccessful = setCallReference?.isError == false
|
||||
|
||||
fun chooseSetOperator(): FirStatement {
|
||||
dataFlowAnalyzer.enterFunctionCall(resolvedSetCall)
|
||||
dataFlowAnalyzer.enterFunctionCall(resolvedOperatorCall)
|
||||
callCompleter.completeCall(
|
||||
resolvedSetCall,
|
||||
noExpectedType,
|
||||
expectedTypeMismatchIsReportedInChecker = true
|
||||
)
|
||||
dataFlowAnalyzer.exitFunctionCall(resolvedOperatorCall, callCompleted = true)
|
||||
dataFlowAnalyzer.exitFunctionCall(resolvedSetCall, callCompleted = true)
|
||||
return info.toBlock()
|
||||
}
|
||||
|
||||
fun reportError(diagnostic: ConeDiagnostic): FirStatement {
|
||||
completeAssignCall()
|
||||
val errorReference = buildErrorNamedReference {
|
||||
source = augmentedArraySetCall.source
|
||||
this.diagnostic = diagnostic
|
||||
}
|
||||
resolvedAssignCall.replaceCalleeReference(errorReference)
|
||||
|
||||
return resolvedAssignCall
|
||||
}
|
||||
|
||||
fun reportAmbiguity(
|
||||
firstReference: FirNamedReferenceWithCandidate?,
|
||||
secondReference: FirNamedReferenceWithCandidate?
|
||||
): FirStatement {
|
||||
val firstCandidate = firstReference?.candidate
|
||||
val secondCandidate = secondReference?.candidate
|
||||
requireNotNull(firstCandidate)
|
||||
requireNotNull(secondCandidate)
|
||||
return reportError(ConeOperatorAmbiguityError(listOf(firstCandidate, secondCandidate)))
|
||||
}
|
||||
|
||||
fun reportUnresolvedReference(): FirStatement {
|
||||
return reportError(ConeUnresolvedNameError(Name.identifier(operation.operator)))
|
||||
}
|
||||
|
||||
return when {
|
||||
assignIsSuccessful && setIsSuccessful -> reportAmbiguity(assignCallReference, setCallReference)
|
||||
assignIsSuccessful -> chooseAssign()
|
||||
setIsSuccessful -> chooseSetOperator()
|
||||
else -> reportUnresolvedReference()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1216,15 +1268,41 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
* @return null if `set` or `plus` calls are unresolved
|
||||
* @return block defined as described above, otherwise
|
||||
*/
|
||||
private fun FirAugmentedArraySetCall.tryResolveAugmentedArraySetCallAsSetGetBlock(lhsGetCall: FirFunctionCall): FirBlock? {
|
||||
private inner class AugmentedArraySetAsGetSetCallDesugaringInfo(
|
||||
val augmentedArraySetCall: FirAugmentedArraySetCall,
|
||||
val arrayVariable: FirProperty,
|
||||
val indexVariables: List<FirProperty>,
|
||||
val operatorCall: FirFunctionCall,
|
||||
val setCall: FirFunctionCall
|
||||
) {
|
||||
fun toBlock(): FirBlock {
|
||||
return buildBlock {
|
||||
annotations += augmentedArraySetCall.annotations
|
||||
statements += arrayVariable
|
||||
statements += indexVariables
|
||||
statements += setCall
|
||||
}.also {
|
||||
it.replaceTypeRef(
|
||||
buildResolvedTypeRef {
|
||||
type = session.builtinTypes.unitType.type
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryResolveAugmentedArraySetCallAsSetGetBlock(
|
||||
augmentedArraySetCall: FirAugmentedArraySetCall,
|
||||
lhsGetCall: FirFunctionCall,
|
||||
transformedRhs: FirExpression
|
||||
): AugmentedArraySetAsGetSetCallDesugaringInfo {
|
||||
val arrayVariable = generateTemporaryVariable(
|
||||
session.moduleData,
|
||||
source = null,
|
||||
source = lhsGetCall.explicitReceiver?.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment),
|
||||
specialName = "<array>",
|
||||
initializer = lhsGetCall.explicitReceiver ?: buildErrorExpression {
|
||||
source =
|
||||
this@tryResolveAugmentedArraySetCallAsSetGetBlock.source
|
||||
?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
source = augmentedArraySetCall.source
|
||||
?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
diagnostic = ConeSimpleDiagnostic("No receiver for array access", DiagnosticKind.Syntax)
|
||||
}
|
||||
)
|
||||
@@ -1235,88 +1313,78 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
else
|
||||
listOf(it)
|
||||
}.mapIndexed { i, index ->
|
||||
generateTemporaryVariable(session.moduleData, source = null, specialName = "<index_$i>", initializer = index)
|
||||
}
|
||||
|
||||
val getCall = buildFunctionCall {
|
||||
source = arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = arrayVariable.toQualifiedAccess()
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = OperatorNameConventions.GET
|
||||
}
|
||||
argumentList = buildArgumentList {
|
||||
for (indexVariable in indexVariables) {
|
||||
arguments += indexVariable.toQualifiedAccess()
|
||||
}
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
|
||||
val operatorCall = buildFunctionCall {
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(operation)
|
||||
}
|
||||
explicitReceiver = getCall
|
||||
argumentList = buildArgumentList {
|
||||
arguments += rhs
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
|
||||
val setCall = buildFunctionCall {
|
||||
source =
|
||||
this@tryResolveAugmentedArraySetCallAsSetGetBlock.source
|
||||
?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = arrayVariable.toQualifiedAccess()
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = OperatorNameConventions.SET
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
argumentList = buildArgumentList {
|
||||
for (indexVariable in indexVariables) {
|
||||
arguments += indexVariable.toQualifiedAccess()
|
||||
}
|
||||
|
||||
arguments += operatorCall
|
||||
}
|
||||
|
||||
annotations += this@tryResolveAugmentedArraySetCallAsSetGetBlock.annotations
|
||||
generateTemporaryVariable(
|
||||
session.moduleData,
|
||||
source = index.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment),
|
||||
specialName = "<index_$i>",
|
||||
initializer = index
|
||||
)
|
||||
}
|
||||
|
||||
arrayVariable.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
indexVariables.forEach { it.transformSingle(transformer, ResolutionMode.ContextIndependent) }
|
||||
val transformedSet = setCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
|
||||
if (!transformedSet.isSuccessful()) return null
|
||||
val arrayAccess = arrayVariable.toQualifiedAccess()
|
||||
val indicesQualifiedAccess = indexVariables.map { it.toQualifiedAccess() }
|
||||
|
||||
val transformedOperator =
|
||||
transformedSet.argumentList.arguments.last().let {
|
||||
if (it is FirNamedArgumentExpression)
|
||||
it.expression
|
||||
else
|
||||
it
|
||||
val getCall = buildFunctionCall {
|
||||
source = augmentedArraySetCall.arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = arrayAccess
|
||||
if (lhsGetCall.explicitReceiver == lhsGetCall.dispatchReceiver) {
|
||||
dispatchReceiver = arrayAccess
|
||||
extensionReceiver = lhsGetCall.extensionReceiver
|
||||
} else {
|
||||
extensionReceiver = arrayAccess
|
||||
dispatchReceiver = lhsGetCall.dispatchReceiver
|
||||
}
|
||||
|
||||
require(transformedOperator is FirFunctionCall) {
|
||||
"Last argument of set call should be an operator but $transformedOperator found"
|
||||
}
|
||||
|
||||
if (!transformedOperator.isSuccessful()) return null
|
||||
|
||||
return buildBlock {
|
||||
statements += arrayVariable
|
||||
statements += indexVariables
|
||||
statements += setCall
|
||||
}.also {
|
||||
it.replaceTypeRef(
|
||||
buildResolvedTypeRef {
|
||||
source = this@tryResolveAugmentedArraySetCallAsSetGetBlock.source
|
||||
type = session.builtinTypes.unitType.type
|
||||
calleeReference = lhsGetCall.calleeReference
|
||||
argumentList = buildArgumentList {
|
||||
var i = 0
|
||||
for (argument in lhsGetCall.argumentList.arguments) {
|
||||
arguments += if (argument is FirVarargArgumentsExpression) {
|
||||
buildVarargArgumentsExpression {
|
||||
val varargSize = argument.arguments.size
|
||||
arguments += indicesQualifiedAccess.subList(i, i + varargSize)
|
||||
i += varargSize
|
||||
source = argument.source
|
||||
typeRef = argument.typeRef
|
||||
varargElementType = argument.varargElementType
|
||||
}
|
||||
} else {
|
||||
indicesQualifiedAccess[i++]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
typeRef = lhsGetCall.typeRef
|
||||
}
|
||||
}
|
||||
|
||||
val generator = GeneratorOfPlusAssignCalls(augmentedArraySetCall, augmentedArraySetCall.operation, getCall, transformedRhs)
|
||||
|
||||
val operatorCall = generator.createSimpleOperatorCall()
|
||||
val resolvedOperatorCall = resolveCandidateForAssignmentOperatorCall {
|
||||
operatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||
}
|
||||
|
||||
val setCall = GeneratorOfPlusAssignCalls.createFunctionCall(
|
||||
OperatorNameConventions.SET,
|
||||
augmentedArraySetCall.source,
|
||||
receiver = arrayAccess, // a
|
||||
*indicesQualifiedAccess.toTypedArray(), // indices
|
||||
resolvedOperatorCall // a.get(b).plus(c)
|
||||
)
|
||||
val resolvedSetCall = resolveCandidateForAssignmentOperatorCall {
|
||||
setCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||
}
|
||||
|
||||
return AugmentedArraySetAsGetSetCallDesugaringInfo(
|
||||
augmentedArraySetCall,
|
||||
arrayVariable,
|
||||
indexVariables,
|
||||
resolvedOperatorCall,
|
||||
resolvedSetCall
|
||||
)
|
||||
}
|
||||
|
||||
override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement {
|
||||
if (data is ResolutionMode.ContextDependent) {
|
||||
|
||||
@@ -21,7 +21,6 @@ abstract class FirAugmentedArraySetCall : FirPureAbstractElement(), FirStatement
|
||||
abstract override val annotations: List<FirAnnotation>
|
||||
abstract val lhsGetCall: FirFunctionCall
|
||||
abstract val rhs: FirExpression
|
||||
abstract val rhs2: FirExpression
|
||||
abstract val operation: FirOperation
|
||||
abstract val calleeReference: FirReference
|
||||
abstract val arrayAccessSource: KtSourceElement?
|
||||
|
||||
-2
@@ -30,7 +30,6 @@ class FirAugmentedArraySetCallBuilder : FirAnnotationContainerBuilder {
|
||||
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
||||
lateinit var lhsGetCall: FirFunctionCall
|
||||
lateinit var rhs: FirExpression
|
||||
lateinit var rhs2: FirExpression
|
||||
lateinit var operation: FirOperation
|
||||
var calleeReference: FirReference = FirStubReference
|
||||
var arrayAccessSource: KtSourceElement? = null
|
||||
@@ -41,7 +40,6 @@ class FirAugmentedArraySetCallBuilder : FirAnnotationContainerBuilder {
|
||||
annotations,
|
||||
lhsGetCall,
|
||||
rhs,
|
||||
rhs2,
|
||||
operation,
|
||||
calleeReference,
|
||||
arrayAccessSource,
|
||||
|
||||
-3
@@ -24,7 +24,6 @@ internal class FirAugmentedArraySetCallImpl(
|
||||
override val annotations: MutableList<FirAnnotation>,
|
||||
override var lhsGetCall: FirFunctionCall,
|
||||
override var rhs: FirExpression,
|
||||
override var rhs2: FirExpression,
|
||||
override val operation: FirOperation,
|
||||
override var calleeReference: FirReference,
|
||||
override val arrayAccessSource: KtSourceElement?,
|
||||
@@ -33,7 +32,6 @@ internal class FirAugmentedArraySetCallImpl(
|
||||
annotations.forEach { it.accept(visitor, data) }
|
||||
lhsGetCall.accept(visitor, data)
|
||||
rhs.accept(visitor, data)
|
||||
rhs2.accept(visitor, data)
|
||||
calleeReference.accept(visitor, data)
|
||||
}
|
||||
|
||||
@@ -41,7 +39,6 @@ internal class FirAugmentedArraySetCallImpl(
|
||||
transformAnnotations(transformer, data)
|
||||
lhsGetCall = lhsGetCall.transform(transformer, data)
|
||||
rhs = rhs.transform(transformer, data)
|
||||
rhs2 = rhs2.transform(transformer, data)
|
||||
calleeReference = calleeReference.transform(transformer, data)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
@@ -25,11 +26,14 @@ import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
fun FirVariable.toQualifiedAccess(): FirQualifiedAccessExpression = buildPropertyAccessExpression {
|
||||
val fakeSource = this@toQualifiedAccess.source?.fakeElement(KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)
|
||||
source = fakeSource
|
||||
calleeReference = buildResolvedNamedReference {
|
||||
source = this@toQualifiedAccess.source?.fakeElement(KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)
|
||||
source = fakeSource
|
||||
name = this@toQualifiedAccess.name
|
||||
resolvedSymbol = this@toQualifiedAccess.symbol
|
||||
}
|
||||
typeRef = this@toQualifiedAccess.returnTypeRef
|
||||
}
|
||||
|
||||
fun generateTemporaryVariable(
|
||||
@@ -39,7 +43,7 @@ fun generateTemporaryVariable(
|
||||
initializer: FirExpression,
|
||||
typeRef: FirTypeRef? = null,
|
||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||
): FirVariable =
|
||||
): FirProperty =
|
||||
buildProperty {
|
||||
this.source = source
|
||||
this.moduleData = moduleData
|
||||
@@ -66,7 +70,7 @@ fun generateTemporaryVariable(
|
||||
specialName: String,
|
||||
initializer: FirExpression,
|
||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||
): FirVariable =
|
||||
): FirProperty =
|
||||
generateTemporaryVariable(
|
||||
moduleData,
|
||||
source,
|
||||
|
||||
-1
@@ -463,7 +463,6 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
augmentedArraySetCall.configure {
|
||||
+field("lhsGetCall", functionCall)
|
||||
+field("rhs", expression)
|
||||
+field("rhs2", expression)
|
||||
+field("operation", operationType)
|
||||
// Used for resolution errors reporting in case
|
||||
+field("calleeReference", reference, withReplace = true)
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ fun withVararg(vararg xs: Int) = 42
|
||||
|
||||
fun test1() {
|
||||
A[::withVararg] += 1
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -34,7 +34,7 @@ fun testArrayAssignment4(n: Nothing) {
|
||||
|
||||
fun testArrayPlusAssign(array: Array<Any>) {
|
||||
operator fun Any.plusAssign(a: Any) {}
|
||||
array[1] <!UNREACHABLE_CODE!>+=<!> todo()
|
||||
<!UNREACHABLE_CODE!>array<!><!UNREACHABLE_CODE!>[<!><!UNREACHABLE_CODE!>1<!><!UNREACHABLE_CODE!>] +=<!> todo()
|
||||
}
|
||||
|
||||
fun todo(): Nothing = throw Exception()
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object RemAndRemAssign {
|
||||
operator fun rem(x: Int) = RemAndRemAssign
|
||||
}
|
||||
|
||||
operator fun RemAndRemAssign.remAssign(x: Int) {}
|
||||
|
||||
fun test() {
|
||||
var c = RemAndRemAssign
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c %= 1<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object RemAndRemAssign {
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
//KT-1820 Write test for ASSIGN_OPERATOR_AMBIGUITY
|
||||
package kt1820
|
||||
|
||||
class MyInt(val i: Int) {
|
||||
operator fun plus(m: MyInt) : MyInt = MyInt(m.i + i)
|
||||
}
|
||||
|
||||
operator fun Any.plusAssign(a: Any) {}
|
||||
|
||||
fun test(m: MyInt) {
|
||||
m += m
|
||||
|
||||
var i = 1
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>i += 34<!>
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
//KT-1820 Write test for ASSIGN_OPERATOR_AMBIGUITY
|
||||
package kt1820
|
||||
|
||||
|
||||
+1
-1
@@ -40,6 +40,6 @@ fun testMismatchingArities() {
|
||||
|
||||
<!NO_VALUE_FOR_PARAMETER!>++MismatchingArities2[0]<!>
|
||||
<!NO_VALUE_FOR_PARAMETER!>MismatchingArities2[0]++<!>
|
||||
<!NO_VALUE_FOR_PARAMETER!>MismatchingArities2[0]<!> <!UNRESOLVED_REFERENCE!>+=<!> 1
|
||||
<!NO_VALUE_FOR_PARAMETER!>MismatchingArities2[0]<!> += 1
|
||||
}
|
||||
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C {
|
||||
operator fun get(i: Int): C = this
|
||||
}
|
||||
|
||||
operator fun C.plus(a: Any): C = this
|
||||
operator fun C.plusAssign(a: Any) {}
|
||||
|
||||
class C1 {
|
||||
operator fun get(i: Int): C = C()
|
||||
operator fun set(i: Int, v: C) {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val c = C()
|
||||
c[0] += ""
|
||||
var c1 = C1()
|
||||
c1[0] <!OVERLOAD_RESOLUTION_AMBIGUITY!>+=<!> ""
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C {
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C
|
||||
|
||||
operator fun C.plus(a: Any): C = this
|
||||
operator fun C.plusAssign(a: Any) {}
|
||||
|
||||
fun test() {
|
||||
val c = C()
|
||||
c += ""
|
||||
var c1 = C()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C {
|
||||
val c: C = C()
|
||||
}
|
||||
|
||||
operator fun C.plus(a: Any): C = this
|
||||
operator fun C.plusAssign(a: Any) {}
|
||||
|
||||
class C1 {
|
||||
var c: C = C()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
val c = C()
|
||||
c.c += ""
|
||||
var c1 = C1()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c1.c += ""<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class C {
|
||||
|
||||
Vendored
+4
-4
@@ -13,8 +13,8 @@ fun <T> id(x: T) = x
|
||||
|
||||
fun main() {
|
||||
var newValue = A()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id { total -> A() }<!>
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(fun(total) = A())<!>
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(fun(total): A { return A() })<!>
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(::foo)<!>
|
||||
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id { total -> A() }
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue<!> += id(fun(total) = A())
|
||||
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id(fun(total): A { return A() })
|
||||
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id(::foo)
|
||||
}
|
||||
|
||||
+4
-4
@@ -20,14 +20,14 @@ class B() {
|
||||
|
||||
fun case7(){
|
||||
var b =B()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b+=1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
||||
b<!ASSIGN_OPERATOR_AMBIGUITY!>+=<!>1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||
this <!PROPERTY_AS_OPERATOR!>+=<!> 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR
|
||||
}
|
||||
}
|
||||
|
||||
fun case1() {
|
||||
var b = B()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b += 1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
||||
b <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||
}
|
||||
|
||||
// FILE: TestCase2.kt
|
||||
@@ -52,7 +52,7 @@ class B() {
|
||||
b += 1 //ok
|
||||
|
||||
var b1 = B()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b1 += 1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
||||
b1 <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||
|
||||
this += 1 //ok
|
||||
}
|
||||
@@ -60,5 +60,5 @@ class B() {
|
||||
|
||||
fun case2() {
|
||||
var b = B()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b += 1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
||||
b <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,5 +15,5 @@ class B(var a: Int) {
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case1() {
|
||||
var b = B(1)
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b += 1<!>
|
||||
b <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Class?) {
|
||||
x!!
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Class & Class"), DEBUG_INFO_EXPRESSION_TYPE("Class?")!>x<!>[if (true) {<!VAL_REASSIGNMENT!>x<!>=null;0} else 0] += <!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>[0]
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Class & Class"), DEBUG_INFO_EXPRESSION_TYPE("Class?"), DEBUG_INFO_EXPRESSION_TYPE("Class"), DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>[if (true) {<!VAL_REASSIGNMENT!>x<!>=null;0} else 0] += <!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>[0]
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>[0].inv()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
fun case_1() {
|
||||
var x: MutableList<Int>? = mutableListOf(1)
|
||||
x!!
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>? & kotlin.collections.MutableList<kotlin.Int>")!>x<!>[if (true) {x=null;0} else 0] += <!UNSAFE_CALL!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>[0]<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>? & kotlin.collections.MutableList<kotlin.Int>")!>x<!>[if (true) {x=null;0} else 0] <!UNRESOLVED_REFERENCE!>+=<!> <!UNSAFE_CALL!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>[0]<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>
|
||||
<!UNSAFE_CALL!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>[0]<!>.inv()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user