[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
|
KT element: KtBinaryExpression
|
||||||
FIR element: FirFunctionCallImpl
|
FIR element: FirFunctionCallImpl
|
||||||
FIR source kind: DesugaredCompoundAssignment
|
FIR source kind: KtRealSourceElementKind
|
||||||
|
|
||||||
FIR element rendered:
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("companionInvoke.kt")
|
@TestMetadata("companionInvoke.kt")
|
||||||
public void testCompanionInvoke() throws Exception {
|
public void testCompanionInvoke() throws Exception {
|
||||||
@@ -893,6 +899,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
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
|
@Test
|
||||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
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);
|
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")
|
@TestMetadata("companionInvoke.kt")
|
||||||
public void testCompanionInvoke() throws Exception {
|
public void testCompanionInvoke() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/companionInvoke.kt");
|
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");
|
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")
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt");
|
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| {
|
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| {
|
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>) {
|
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) {
|
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() {
|
fun test() {
|
||||||
var f = Foo()
|
var f = Foo()
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>f += f<!>
|
f <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> f
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ fun testOperatorAssignment() {
|
|||||||
val c = C()
|
val c = C()
|
||||||
c += ""
|
c += ""
|
||||||
<!CAN_BE_VAL!>var<!> c1 = C()
|
<!CAN_BE_VAL!>var<!> c1 = C()
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
|
c1 <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> ""
|
||||||
|
|
||||||
var a = 1
|
var a = 1
|
||||||
a += 12
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("companionInvoke.kt")
|
@TestMetadata("companionInvoke.kt")
|
||||||
public void testCompanionInvoke() throws Exception {
|
public void testCompanionInvoke() throws Exception {
|
||||||
@@ -893,6 +899,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
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
|
@Test
|
||||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("companionInvoke.kt")
|
@TestMetadata("companionInvoke.kt")
|
||||||
public void testCompanionInvoke() throws Exception {
|
public void testCompanionInvoke() throws Exception {
|
||||||
@@ -893,6 +899,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/errorCandidates.kt");
|
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
|
@Test
|
||||||
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
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) {
|
val OVERLOAD_RESOLUTION_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
parameter<Collection<Symbol>>("candidates")
|
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")
|
parameter<Collection<Symbol>>("candidates")
|
||||||
}
|
}
|
||||||
val ITERATOR_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
val ITERATOR_AMBIGUITY by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
|
|||||||
+1
-1
@@ -351,7 +351,7 @@ object FirErrors {
|
|||||||
|
|
||||||
// Ambiguity
|
// Ambiguity
|
||||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
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 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 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)
|
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,
|
null,
|
||||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
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.arrayAccessSource = arrayAccessSource
|
||||||
this.annotations += annotations
|
this.annotations += annotations
|
||||||
}
|
}
|
||||||
|
|||||||
+233
-165
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fakeElement
|
import org.jetbrains.kotlin.fakeElement
|
||||||
import org.jetbrains.kotlin.fir.*
|
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.references.impl.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
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.dfa.unwrapSmartcastExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.FirStubInferenceSession
|
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.Name
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
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.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
@@ -516,28 +515,17 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
assignmentOperatorStatement: FirAssignmentOperatorStatement,
|
assignmentOperatorStatement: FirAssignmentOperatorStatement,
|
||||||
data: ResolutionMode
|
data: ResolutionMode
|
||||||
): FirStatement {
|
): FirStatement {
|
||||||
require(assignmentOperatorStatement.operation != FirOperation.ASSIGN)
|
val operation = assignmentOperatorStatement.operation
|
||||||
|
require(operation != FirOperation.ASSIGN)
|
||||||
|
|
||||||
assignmentOperatorStatement.transformAnnotations(transformer, ResolutionMode.ContextIndependent)
|
assignmentOperatorStatement.transformAnnotations(transformer, ResolutionMode.ContextIndependent)
|
||||||
val leftArgument = assignmentOperatorStatement.leftArgument.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
val leftArgument = assignmentOperatorStatement.leftArgument.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||||
val rightArgument = assignmentOperatorStatement.rightArgument.transformSingle(transformer, ResolutionMode.ContextDependent)
|
val rightArgument = assignmentOperatorStatement.rightArgument.transformSingle(transformer, ResolutionMode.ContextDependent)
|
||||||
|
|
||||||
fun createFunctionCall(name: Name): FirFunctionCall = buildFunctionCall {
|
val generator = GeneratorOfPlusAssignCalls(assignmentOperatorStatement, operation, leftArgument, rightArgument)
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// x.plusAssign(y)
|
// x.plusAssign(y)
|
||||||
val assignmentOperatorName = FirOperationNameConventions.ASSIGNMENTS.getValue(assignmentOperatorStatement.operation)
|
val assignOperatorCall = generator.createAssignOperatorCall()
|
||||||
val assignOperatorCall = createFunctionCall(assignmentOperatorName)
|
|
||||||
val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall {
|
val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall {
|
||||||
assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||||
}
|
}
|
||||||
@@ -545,8 +533,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
val assignIsSuccessful = assignCallReference?.isError == false
|
val assignIsSuccessful = assignCallReference?.isError == false
|
||||||
|
|
||||||
// x = x + y
|
// x = x + y
|
||||||
val simpleOperatorName = FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(assignmentOperatorStatement.operation)
|
val simpleOperatorCall = generator.createSimpleOperatorCall()
|
||||||
val simpleOperatorCall = createFunctionCall(simpleOperatorName)
|
|
||||||
val resolvedOperatorCall = resolveCandidateForAssignmentOperatorCall {
|
val resolvedOperatorCall = resolveCandidateForAssignmentOperatorCall {
|
||||||
simpleOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
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)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
override fun transformAugmentedArraySetCall(
|
override fun transformAugmentedArraySetCall(
|
||||||
augmentedArraySetCall: FirAugmentedArraySetCall,
|
augmentedArraySetCall: FirAugmentedArraySetCall,
|
||||||
data: ResolutionMode
|
data: ResolutionMode
|
||||||
): FirStatement {
|
): 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)
|
augmentedArraySetCall.transformAnnotations(transformer, data)
|
||||||
val operatorName = FirOperationNameConventions.ASSIGNMENTS.getValue(augmentedArraySetCall.operation)
|
|
||||||
|
|
||||||
val transformedLhsCall =
|
// transformedLhsCall: a.get(index)
|
||||||
augmentedArraySetCall.lhsGetCall.transformSingle(transformer, ResolutionMode.ContextIndependent).takeIf { it.isSuccessful() }
|
val transformedLhsCall = augmentedArraySetCall.lhsGetCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||||
|
val transformedRhs = augmentedArraySetCall.rhs.transformSingle(transformer, ResolutionMode.ContextDependent)
|
||||||
|
|
||||||
val blockForGetSetVersion: FirBlock? =
|
val generator = GeneratorOfPlusAssignCalls(augmentedArraySetCall, operation, transformedLhsCall, transformedRhs)
|
||||||
transformedLhsCall?.let { augmentedArraySetCall.tryResolveAugmentedArraySetCallAsSetGetBlock(it) }
|
|
||||||
val assignResolvedCall: FirFunctionCall? =
|
|
||||||
transformedLhsCall?.let { augmentedArraySetCall.tryResolveWithOperatorAssignConvention(it) }
|
|
||||||
|
|
||||||
val result: FirStatement = when {
|
// a.get(b).plusAssign(c)
|
||||||
assignResolvedCall != null && blockForGetSetVersion != null -> {
|
val assignOperatorCall = generator.createAssignOperatorCall()
|
||||||
augmentedArraySetCall.also {
|
val resolvedAssignCall = resolveCandidateForAssignmentOperatorCall {
|
||||||
it.replaceCalleeReference(
|
assignOperatorCall.transformSingle(this, ResolutionMode.ContextDependent)
|
||||||
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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result
|
val assignCallReference = resolvedAssignCall.calleeReference as? FirNamedReferenceWithCandidate
|
||||||
}
|
val assignIsSuccessful = assignCallReference?.isError == false
|
||||||
|
|
||||||
private fun FirFunctionCall.isSuccessful(): Boolean =
|
// <array>.set(<index_i>, <array>.get(<index_i>).plus(c))
|
||||||
typeRef !is FirErrorTypeRef && calleeReference is FirResolvedNamedReference
|
val info = tryResolveAugmentedArraySetCallAsSetGetBlock(augmentedArraySetCall, transformedLhsCall, transformedRhs)
|
||||||
|
val resolvedOperatorCall = info.operatorCall
|
||||||
|
val operatorCallReference = resolvedOperatorCall.calleeReference as? FirNamedReferenceWithCandidate
|
||||||
|
val operatorIsSuccessful = operatorCallReference?.isError == false
|
||||||
|
|
||||||
|
fun completeAssignCall() {
|
||||||
/**
|
dataFlowAnalyzer.enterFunctionCall(resolvedAssignCall)
|
||||||
* Desugarings of a[x, y] += z to
|
callCompleter.completeCall(resolvedAssignCall, noExpectedType)
|
||||||
* a.get(x, y).plusAssign(z)
|
dataFlowAnalyzer.exitFunctionCall(resolvedAssignCall, callCompleted = true)
|
||||||
*
|
|
||||||
* @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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val transformedCall = assignCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
fun chooseAssign(): FirStatement {
|
||||||
return transformedCall.takeIf { it.isSuccessful() }
|
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 null if `set` or `plus` calls are unresolved
|
||||||
* @return block defined as described above, otherwise
|
* @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(
|
val arrayVariable = generateTemporaryVariable(
|
||||||
session.moduleData,
|
session.moduleData,
|
||||||
source = null,
|
source = lhsGetCall.explicitReceiver?.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment),
|
||||||
specialName = "<array>",
|
specialName = "<array>",
|
||||||
initializer = lhsGetCall.explicitReceiver ?: buildErrorExpression {
|
initializer = lhsGetCall.explicitReceiver ?: buildErrorExpression {
|
||||||
source =
|
source = augmentedArraySetCall.source
|
||||||
this@tryResolveAugmentedArraySetCallAsSetGetBlock.source
|
?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||||
?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
|
||||||
diagnostic = ConeSimpleDiagnostic("No receiver for array access", DiagnosticKind.Syntax)
|
diagnostic = ConeSimpleDiagnostic("No receiver for array access", DiagnosticKind.Syntax)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1235,88 +1313,78 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
else
|
else
|
||||||
listOf(it)
|
listOf(it)
|
||||||
}.mapIndexed { i, index ->
|
}.mapIndexed { i, index ->
|
||||||
generateTemporaryVariable(session.moduleData, source = null, specialName = "<index_$i>", initializer = index)
|
generateTemporaryVariable(
|
||||||
}
|
session.moduleData,
|
||||||
|
source = index.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment),
|
||||||
val getCall = buildFunctionCall {
|
specialName = "<index_$i>",
|
||||||
source = arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
initializer = index
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayVariable.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
arrayVariable.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||||
indexVariables.forEach { it.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 =
|
val getCall = buildFunctionCall {
|
||||||
transformedSet.argumentList.arguments.last().let {
|
source = augmentedArraySetCall.arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||||
if (it is FirNamedArgumentExpression)
|
explicitReceiver = arrayAccess
|
||||||
it.expression
|
if (lhsGetCall.explicitReceiver == lhsGetCall.dispatchReceiver) {
|
||||||
else
|
dispatchReceiver = arrayAccess
|
||||||
it
|
extensionReceiver = lhsGetCall.extensionReceiver
|
||||||
|
} else {
|
||||||
|
extensionReceiver = arrayAccess
|
||||||
|
dispatchReceiver = lhsGetCall.dispatchReceiver
|
||||||
}
|
}
|
||||||
|
calleeReference = lhsGetCall.calleeReference
|
||||||
require(transformedOperator is FirFunctionCall) {
|
argumentList = buildArgumentList {
|
||||||
"Last argument of set call should be an operator but $transformedOperator found"
|
var i = 0
|
||||||
}
|
for (argument in lhsGetCall.argumentList.arguments) {
|
||||||
|
arguments += if (argument is FirVarargArgumentsExpression) {
|
||||||
if (!transformedOperator.isSuccessful()) return null
|
buildVarargArgumentsExpression {
|
||||||
|
val varargSize = argument.arguments.size
|
||||||
return buildBlock {
|
arguments += indicesQualifiedAccess.subList(i, i + varargSize)
|
||||||
statements += arrayVariable
|
i += varargSize
|
||||||
statements += indexVariables
|
source = argument.source
|
||||||
statements += setCall
|
typeRef = argument.typeRef
|
||||||
}.also {
|
varargElementType = argument.varargElementType
|
||||||
it.replaceTypeRef(
|
}
|
||||||
buildResolvedTypeRef {
|
} else {
|
||||||
source = this@tryResolveAugmentedArraySetCallAsSetGetBlock.source
|
indicesQualifiedAccess[i++]
|
||||||
type = session.builtinTypes.unitType.type
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
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 {
|
override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement {
|
||||||
if (data is ResolutionMode.ContextDependent) {
|
if (data is ResolutionMode.ContextDependent) {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ abstract class FirAugmentedArraySetCall : FirPureAbstractElement(), FirStatement
|
|||||||
abstract override val annotations: List<FirAnnotation>
|
abstract override val annotations: List<FirAnnotation>
|
||||||
abstract val lhsGetCall: FirFunctionCall
|
abstract val lhsGetCall: FirFunctionCall
|
||||||
abstract val rhs: FirExpression
|
abstract val rhs: FirExpression
|
||||||
abstract val rhs2: FirExpression
|
|
||||||
abstract val operation: FirOperation
|
abstract val operation: FirOperation
|
||||||
abstract val calleeReference: FirReference
|
abstract val calleeReference: FirReference
|
||||||
abstract val arrayAccessSource: KtSourceElement?
|
abstract val arrayAccessSource: KtSourceElement?
|
||||||
|
|||||||
-2
@@ -30,7 +30,6 @@ class FirAugmentedArraySetCallBuilder : FirAnnotationContainerBuilder {
|
|||||||
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
||||||
lateinit var lhsGetCall: FirFunctionCall
|
lateinit var lhsGetCall: FirFunctionCall
|
||||||
lateinit var rhs: FirExpression
|
lateinit var rhs: FirExpression
|
||||||
lateinit var rhs2: FirExpression
|
|
||||||
lateinit var operation: FirOperation
|
lateinit var operation: FirOperation
|
||||||
var calleeReference: FirReference = FirStubReference
|
var calleeReference: FirReference = FirStubReference
|
||||||
var arrayAccessSource: KtSourceElement? = null
|
var arrayAccessSource: KtSourceElement? = null
|
||||||
@@ -41,7 +40,6 @@ class FirAugmentedArraySetCallBuilder : FirAnnotationContainerBuilder {
|
|||||||
annotations,
|
annotations,
|
||||||
lhsGetCall,
|
lhsGetCall,
|
||||||
rhs,
|
rhs,
|
||||||
rhs2,
|
|
||||||
operation,
|
operation,
|
||||||
calleeReference,
|
calleeReference,
|
||||||
arrayAccessSource,
|
arrayAccessSource,
|
||||||
|
|||||||
-3
@@ -24,7 +24,6 @@ internal class FirAugmentedArraySetCallImpl(
|
|||||||
override val annotations: MutableList<FirAnnotation>,
|
override val annotations: MutableList<FirAnnotation>,
|
||||||
override var lhsGetCall: FirFunctionCall,
|
override var lhsGetCall: FirFunctionCall,
|
||||||
override var rhs: FirExpression,
|
override var rhs: FirExpression,
|
||||||
override var rhs2: FirExpression,
|
|
||||||
override val operation: FirOperation,
|
override val operation: FirOperation,
|
||||||
override var calleeReference: FirReference,
|
override var calleeReference: FirReference,
|
||||||
override val arrayAccessSource: KtSourceElement?,
|
override val arrayAccessSource: KtSourceElement?,
|
||||||
@@ -33,7 +32,6 @@ internal class FirAugmentedArraySetCallImpl(
|
|||||||
annotations.forEach { it.accept(visitor, data) }
|
annotations.forEach { it.accept(visitor, data) }
|
||||||
lhsGetCall.accept(visitor, data)
|
lhsGetCall.accept(visitor, data)
|
||||||
rhs.accept(visitor, data)
|
rhs.accept(visitor, data)
|
||||||
rhs2.accept(visitor, data)
|
|
||||||
calleeReference.accept(visitor, data)
|
calleeReference.accept(visitor, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +39,6 @@ internal class FirAugmentedArraySetCallImpl(
|
|||||||
transformAnnotations(transformer, data)
|
transformAnnotations(transformer, data)
|
||||||
lhsGetCall = lhsGetCall.transform(transformer, data)
|
lhsGetCall = lhsGetCall.transform(transformer, data)
|
||||||
rhs = rhs.transform(transformer, data)
|
rhs = rhs.transform(transformer, data)
|
||||||
rhs2 = rhs2.transform(transformer, data)
|
|
||||||
calleeReference = calleeReference.transform(transformer, data)
|
calleeReference = calleeReference.transform(transformer, data)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.fakeElement
|
import org.jetbrains.kotlin.fakeElement
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
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.FirVariable
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
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
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
fun FirVariable.toQualifiedAccess(): FirQualifiedAccessExpression = buildPropertyAccessExpression {
|
fun FirVariable.toQualifiedAccess(): FirQualifiedAccessExpression = buildPropertyAccessExpression {
|
||||||
|
val fakeSource = this@toQualifiedAccess.source?.fakeElement(KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)
|
||||||
|
source = fakeSource
|
||||||
calleeReference = buildResolvedNamedReference {
|
calleeReference = buildResolvedNamedReference {
|
||||||
source = this@toQualifiedAccess.source?.fakeElement(KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)
|
source = fakeSource
|
||||||
name = this@toQualifiedAccess.name
|
name = this@toQualifiedAccess.name
|
||||||
resolvedSymbol = this@toQualifiedAccess.symbol
|
resolvedSymbol = this@toQualifiedAccess.symbol
|
||||||
}
|
}
|
||||||
|
typeRef = this@toQualifiedAccess.returnTypeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateTemporaryVariable(
|
fun generateTemporaryVariable(
|
||||||
@@ -39,7 +43,7 @@ fun generateTemporaryVariable(
|
|||||||
initializer: FirExpression,
|
initializer: FirExpression,
|
||||||
typeRef: FirTypeRef? = null,
|
typeRef: FirTypeRef? = null,
|
||||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||||
): FirVariable =
|
): FirProperty =
|
||||||
buildProperty {
|
buildProperty {
|
||||||
this.source = source
|
this.source = source
|
||||||
this.moduleData = moduleData
|
this.moduleData = moduleData
|
||||||
@@ -66,7 +70,7 @@ fun generateTemporaryVariable(
|
|||||||
specialName: String,
|
specialName: String,
|
||||||
initializer: FirExpression,
|
initializer: FirExpression,
|
||||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||||
): FirVariable =
|
): FirProperty =
|
||||||
generateTemporaryVariable(
|
generateTemporaryVariable(
|
||||||
moduleData,
|
moduleData,
|
||||||
source,
|
source,
|
||||||
|
|||||||
-1
@@ -463,7 +463,6 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
|||||||
augmentedArraySetCall.configure {
|
augmentedArraySetCall.configure {
|
||||||
+field("lhsGetCall", functionCall)
|
+field("lhsGetCall", functionCall)
|
||||||
+field("rhs", expression)
|
+field("rhs", expression)
|
||||||
+field("rhs2", expression)
|
|
||||||
+field("operation", operationType)
|
+field("operation", operationType)
|
||||||
// Used for resolution errors reporting in case
|
// Used for resolution errors reporting in case
|
||||||
+field("calleeReference", reference, withReplace = true)
|
+field("calleeReference", reference, withReplace = true)
|
||||||
|
|||||||
+1
-1
@@ -16,4 +16,4 @@ fun withVararg(vararg xs: Int) = 42
|
|||||||
|
|
||||||
fun test1() {
|
fun test1() {
|
||||||
A[::withVararg] += 1
|
A[::withVararg] += 1
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -34,7 +34,7 @@ fun testArrayAssignment4(n: Nothing) {
|
|||||||
|
|
||||||
fun testArrayPlusAssign(array: Array<Any>) {
|
fun testArrayPlusAssign(array: Array<Any>) {
|
||||||
operator fun Any.plusAssign(a: 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()
|
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
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
object RemAndRemAssign {
|
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
|
//KT-1820 Write test for ASSIGN_OPERATOR_AMBIGUITY
|
||||||
package kt1820
|
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]++<!>
|
<!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
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
class C {
|
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
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
class C
|
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
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
|
|||||||
Vendored
+4
-4
@@ -13,8 +13,8 @@ fun <T> id(x: T) = x
|
|||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
var newValue = A()
|
var newValue = A()
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id { total -> A() }<!>
|
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id { total -> A() }
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(fun(total) = A())<!>
|
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue<!> += id(fun(total) = A())
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(fun(total): A { return A() })<!>
|
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id(fun(total): A { return A() })
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>newValue += id(::foo)<!>
|
newValue <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> id(::foo)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -20,14 +20,14 @@ class B() {
|
|||||||
|
|
||||||
fun case7(){
|
fun case7(){
|
||||||
var b =B()
|
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
|
this <!PROPERTY_AS_OPERATOR!>+=<!> 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun case1() {
|
fun case1() {
|
||||||
var b = B()
|
var b = B()
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b += 1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
b <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||||
}
|
}
|
||||||
|
|
||||||
// FILE: TestCase2.kt
|
// FILE: TestCase2.kt
|
||||||
@@ -52,7 +52,7 @@ class B() {
|
|||||||
b += 1 //ok
|
b += 1 //ok
|
||||||
|
|
||||||
var b1 = B()
|
var b1 = B()
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b1 += 1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
b1 <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1 //ASSIGN_OPERATOR_AMBIGUITY
|
||||||
|
|
||||||
this += 1 //ok
|
this += 1 //ok
|
||||||
}
|
}
|
||||||
@@ -60,5 +60,5 @@ class B() {
|
|||||||
|
|
||||||
fun case2() {
|
fun case2() {
|
||||||
var b = B()
|
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
|
// TESTCASE NUMBER: 1
|
||||||
fun case1() {
|
fun case1() {
|
||||||
var b = B(1)
|
var b = B(1)
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b += 1<!>
|
b <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
fun case_1(x: Class?) {
|
fun case_1(x: Class?) {
|
||||||
x!!
|
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<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>[0].inv()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Class? & Class")!>x<!>[0].inv()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
fun case_1() {
|
fun case_1() {
|
||||||
var x: MutableList<Int>? = mutableListOf(1)
|
var x: MutableList<Int>? = mutableListOf(1)
|
||||||
x!!
|
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<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>
|
||||||
<!UNSAFE_CALL!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>[0]<!>.inv()
|
<!UNSAFE_CALL!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.MutableList<kotlin.Int>?")!>x<!>[0]<!>.inv()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user