Change resolution priority about implicit receivers and synthesized member-like descriptors.

Change resolution to consider extensions to implicit receiver before members of another implicit receiver.
Make synthesized member-like extensions resolve right after the members.

#KT-10510 Fixed
#KT-10219 Fixed
This commit is contained in:
Stanislav Erokhin
2016-01-13 16:34:16 +03:00
parent dee040a5b5
commit 3a9ecf0bce
28 changed files with 357 additions and 44 deletions
@@ -72,16 +72,9 @@ class TowerResolver {
return run(context, processor, false, AllCandidatesCollector(context))
}
private fun ScopeTower.createLevels(): List<ScopeTowerLevel> {
private fun ScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> {
val result = ArrayList<ScopeTowerLevel>()
// locals win
lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().
filter { it.kind.withLocalDescriptors }.
mapTo(result) { ScopeBasedTowerLevel(this, it) }
var isFirstImportingScope = true
lexicalScope.parentsWithSelf.forEach { scope ->
if (scope is LexicalScope) {
if (!scope.kind.withLocalDescriptors) result.add(ScopeBasedTowerLevel(this, scope))
@@ -89,10 +82,6 @@ class TowerResolver {
scope.implicitReceiver?.let { result.add(ReceiverScopeTowerLevel(this, it.value)) }
}
else {
if (isFirstImportingScope) {
isFirstImportingScope = false
result.add(SyntheticScopeBasedTowerLevel(this, syntheticScopes))
}
result.add(ImportingScopeBasedTowerLevel(this, scope as ImportingScope))
}
}
@@ -103,18 +92,56 @@ class TowerResolver {
private fun ScopeTower.createTowerDataList(): List<TowerData> = ArrayList<TowerData>().apply {
operator fun TowerData.unaryPlus() = add(this)
// this Data needs for InvokeProcessors
for (implicitReceiver in implicitReceivers) {
+ TowerData.OnlyImplicitReceiver(implicitReceiver)
}
// possible there is explicit member
+ TowerData.Empty
val localLevels = lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors }.
map { ScopeBasedTowerLevel(this@createTowerDataList, it) }
for (level in createLevels()) {
for (implicitReceiver in implicitReceivers) {
+ TowerData.BothTowerLevelAndImplicitReceiver(level, implicitReceiver)
val nonLocalLevels = createNonLocalLevels()
val syntheticLevel = SyntheticScopeBasedTowerLevel(this@createTowerDataList, syntheticScopes)
// possibly there is explicit member
+ TowerData.Empty
// synthetic member for explicit receiver
+ TowerData.TowerLevel(syntheticLevel)
// local non-extensions or extension for explicit receiver
for (localLevel in localLevels) {
+ TowerData.TowerLevel(localLevel)
}
for (scope in lexicalScope.parentsWithSelf) {
if (scope is LexicalScope) {
// statics
if (!scope.kind.withLocalDescriptors) {
+ TowerData.TowerLevel(ScopeBasedTowerLevel(this@createTowerDataList, scope))
}
val implicitReceiver = scope.implicitReceiver?.value
if (implicitReceiver != null) {
// members of implicit receiver or member extension for explicit receiver
+ TowerData.TowerLevel(ReceiverScopeTowerLevel(this@createTowerDataList, implicitReceiver))
// synthetic members
+ TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver)
// invokeExtension on local variable
+ TowerData.OnlyImplicitReceiver(implicitReceiver)
// local extensions for implicit receiver
for (localLevel in localLevels) {
+ TowerData.BothTowerLevelAndImplicitReceiver(localLevel, implicitReceiver)
}
// extension for implicit receiver
for (nonLocalLevel in nonLocalLevels) {
+ TowerData.BothTowerLevelAndImplicitReceiver(nonLocalLevel, implicitReceiver)
}
}
}
else {
// functions with no receiver or extension for explicit receiver
+ TowerData.TowerLevel(ImportingScopeBasedTowerLevel(this@createTowerDataList, scope as ImportingScope))
}
+ TowerData.TowerLevel(level)
}
}
@@ -0,0 +1,20 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
class A
class B {
fun foo() = this
}
fun test(foo: A.() -> Int) {
with(A()) {
foo() checkType { _<Int>() }
with(B()) {
foo() checkType { _<B>() }
this.foo() checkType { _<B>() }
}
}
}
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
@@ -0,0 +1,19 @@
package
public fun test(/*0*/ foo: A.() -> kotlin.Int): kotlin.Unit
public fun </*0*/ T, /*1*/ R> with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): B
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,15 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
class A {
fun foo() = this
}
fun test(foo: A.() -> Int) {
with(A()) {
foo() checkType { _<A>() }
this.foo() checkType { _<A>() }
}
}
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
@@ -0,0 +1,12 @@
package
public fun test(/*0*/ foo: A.() -> kotlin.Int): kotlin.Unit
public fun </*0*/ T, /*1*/ R> with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): A
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,23 @@
// FILE: Calendar.java
public class Calendar {
public void setTimeInMillis(long millis) {}
public long getTimeInMillis() { return 1; }
}
// FILE: 1.kt
class A
var A.timeInMillis: String
get() = ""
set(v) {}
fun a(c: Calendar) {
A().apply {
c.apply {
timeInMillis = 5 // synthesized variable for get|setTimeInMillis
timeInMillis = <!TYPE_MISMATCH!>""<!>
}
timeInMillis = ""
}
}
fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
@@ -0,0 +1,21 @@
package
public var A.timeInMillis: kotlin.String
public fun a(/*0*/ c: Calendar): kotlin.Unit
public fun </*0*/ T> T.apply(/*0*/ f: T.() -> kotlin.Unit): T
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class Calendar {
public constructor Calendar()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun getTimeInMillis(): kotlin.Long
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open fun setTimeInMillis(/*0*/ millis: kotlin.Long): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,13 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
class ClassA {
fun method1() = this
fun String.method2() {
method1() checkType { _<String>() }
this.method1() checkType { _<String>() }
}
}
fun String.method1() = this
@@ -0,0 +1,12 @@
package
public fun kotlin.String.method1(): kotlin.String
public final class ClassA {
public constructor ClassA()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun method1(): ClassA
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final fun kotlin.String.method2(): kotlin.Unit
}
@@ -0,0 +1,19 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
class A
fun A.foo() = this
fun test(a: A) {
fun A.foo() = 3
a.foo() checkType { _<Int>() }
with(a) {
foo() checkType { _<Int>() }
}
}
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
@@ -0,0 +1,12 @@
package
public fun test(/*0*/ a: A): kotlin.Unit
public fun </*0*/ T, /*1*/ R> with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R
public fun A.foo(): A
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,20 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
class A {
fun foo() = this
}
fun test(a: A) {
fun A.foo() = 4
a.foo() checkType { _<A>() }
with(a) {
foo() checkType { _<A>() }
this.foo() checkType { _<A>() }
}
}
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
@@ -0,0 +1,12 @@
package
public fun test(/*0*/ a: A): kotlin.Unit
public fun </*0*/ T, /*1*/ R> with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R
public final class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): A
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,19 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
// FILE: A.java
public class A {
public static void foo() {}
}
// FILE: 1.kt
class C {
fun foo() = this
inner class B : A() {
fun test() {
foo() checkType { _<Unit>() }
}
}
}
@@ -0,0 +1,27 @@
package
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun foo(): kotlin.Unit
}
public final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): C
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class B : A {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -21,9 +21,9 @@ class B {
private val A.foo: B get() = this@B
fun test(a: A) {
a.foo checkType { _<B>() } // todo
a.foo checkType { _<A>() }
with(a) {
foo checkType { _<B>() } // todo
foo checkType { _<A>() }
}
}
}
@@ -30,7 +30,7 @@ fun test(a: A, b: B, c: C) {
with(c) {
with(a) {
foo checkType { _<C>() } // todo
foo checkType { _<A>() }
}
}
}
@@ -5,5 +5,5 @@ class A {
class B {
~A.foo~fun A.foo() = 1
fun A.bar() = `foo`foo()
fun A.bar() = `A.foo`foo()
}
@@ -3,7 +3,7 @@ class A
class B {
~foo~fun foo() = 2
fun A.bar() = `foo`foo()
fun A.bar() = `A.foo`foo()
}
~A.foo~fun A.foo() = 1
@@ -8,7 +8,7 @@ class B {
fun test(a: A, b: B) {
with (a) {
with (b) {
`A.foo`foo()
`B.foo`foo()
}
}
}
@@ -13985,12 +13985,54 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/priority"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("invokeExtensionVsOther.kt")
public void testInvokeExtensionVsOther() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/invokeExtensionVsOther.kt");
doTest(fileName);
}
@TestMetadata("invokeExtensionVsOther2.kt")
public void testInvokeExtensionVsOther2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/invokeExtensionVsOther2.kt");
doTest(fileName);
}
@TestMetadata("kt10219.kt")
public void testKt10219() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/kt10219.kt");
doTest(fileName);
}
@TestMetadata("kt10510.kt")
public void testKt10510() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/kt10510.kt");
doTest(fileName);
}
@TestMetadata("kt9965.kt")
public void testKt9965() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt");
doTest(fileName);
}
@TestMetadata("localExtVsNonLocalExt.kt")
public void testLocalExtVsNonLocalExt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/localExtVsNonLocalExt.kt");
doTest(fileName);
}
@TestMetadata("memberVsLocalExt.kt")
public void testMemberVsLocalExt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/memberVsLocalExt.kt");
doTest(fileName);
}
@TestMetadata("staticVsImplicitReceiverMember.kt")
public void testStaticVsImplicitReceiverMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/staticVsImplicitReceiverMember.kt");
doTest(fileName);
}
@TestMetadata("synthesizedMembersVsExtension.kt")
public void testSynthesizedMembersVsExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt");