From 8b5a194dd64826233dd8e41487635bd15609fd94 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Fri, 18 Dec 2015 01:35:43 +0300 Subject: [PATCH] Do not discriminate synthesized candidates. #KT-9965 Fixed --- .../kotlin/resolve/calls/tower/ScopeTower.kt | 8 +++-- .../kotlin/resolve/calls/tower/TowerLevels.kt | 2 ++ .../resolve/calls/tower/TowerResolver.kt | 18 ++++++----- .../kotlin/resolve/calls/tower/TowerUtils.kt | 8 ++--- .../tests/resolve/priority/kt9965.kt | 20 +++++++++++++ .../tests/resolve/priority/kt9965.txt | 30 +++++++++++++++++++ .../priority/synthesizedMembersVsExtension.kt | 10 +++++++ .../synthesizedMembersVsExtension.txt | 14 +++++++++ .../resolve/samConstructorVsFun.kt | 30 +++++++++++++++++++ .../resolve/samConstructorVsFun.txt | 9 ++++++ .../checkers/DiagnosticsTestGenerated.java | 21 +++++++++++++ .../DiagnosticsTestWithStdLibGenerated.java | 6 ++++ .../localCallables/multiDeclaration.kt | 5 +++- .../lookupTracker/classifierMembers/usages.kt | 2 +- 14 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/priority/kt9965.txt create mode 100644 compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt index 269cb3442ab..b3d79d15633 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt @@ -74,7 +74,8 @@ data class ResolutionCandidateStatus(val diagnostics: List enum class ResolutionCandidateApplicability { RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate - RESOLVED_SYNTHESIZED, + RESOLVED_SYNTHESIZED, // todo remove it (need for SAM adapters which created inside some MemberScope) + RESOLVED_LOW_PRIORITY, CONVENTION_ERROR, // missing infix, operator etc MAY_THROW_RUNTIME_ERROR, // unsafe call or unstable smart cast RUNTIME_ERROR, // problems with visibility @@ -94,8 +95,9 @@ class UnsupportedInnerClassCall(val message: String): ResolutionDiagnostic(Resol class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED) object ErrorDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED) // todo discuss and change to INAPPLICABLE -object SynthesizedDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) -object DynamicDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) +object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY) +object SynthesizedDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) +object DynamicDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY) object UnstableSmartCastDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) object ExtensionWithStaticTypeWithDynamicReceiver: ResolutionDiagnostic(ResolutionCandidateApplicability.HIDDEN) object HiddenDescriptor: ResolutionDiagnostic(ResolutionCandidateApplicability.HIDDEN) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index 35e2e0d6d98..6539d9b4a76 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor +import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.ResolutionScope @@ -55,6 +56,7 @@ internal abstract class AbstractScopeTowerLevel( diagnostics.add(ErrorDescriptorDiagnostic) } else { + if (descriptor.hasLowPriorityInOverloadResolution()) diagnostics.add(LowPriorityDescriptorDiagnostic) if (descriptor.isSynthesized) diagnostics.add(SynthesizedDescriptorDiagnostic) if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType)) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index 520ec22fd76..0ddc8df3a9d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -85,7 +85,7 @@ class TowerResolver { for (candidatesGroup in candidatesGroups) { resultCollector.pushCandidates(candidatesGroup) - resultCollector.getResolved()?.let { return it } + resultCollector.getSuccessfulCandidates()?.let { return it } } return null } @@ -108,7 +108,7 @@ class TowerResolver { internal abstract class ResultCollector(val context: TowerContext) { - abstract fun getResolved(): Collection? + abstract fun getSuccessfulCandidates(): Collection? abstract fun getFinalCandidates(): Collection @@ -125,7 +125,7 @@ class TowerResolver { internal class AllCandidatesCollector(context: TowerContext): ResultCollector(context) { private val allCandidates = ArrayList() - override fun getResolved(): Collection? = null + override fun getSuccessfulCandidates(): Collection? = null override fun getFinalCandidates(): Collection = allCandidates @@ -139,15 +139,19 @@ class TowerResolver { private var currentCandidates: Collection = emptyList() private var currentLevel: ResolutionCandidateApplicability? = null - override fun getResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED } + override fun getSuccessfulCandidates(): Collection? = getResolved() ?: getResolvedSynthetic() - fun getSyntheticResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED } + fun getResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED } + + fun getResolvedSynthetic() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED } + + fun getResolvedLowPriority() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY } fun getErrors() = currentCandidates.check { - currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED + currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY } - override fun getFinalCandidates() = getResolved() ?: getSyntheticResolved() ?: getErrors() ?: emptyList() + override fun getFinalCandidates() = getResolved() ?: getResolvedSynthetic() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList() override fun addCandidates(candidates: Collection) { val minimalLevel = candidates.map { context.getStatus(it).resultingApplicability }.min()!! diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt index b3755d4d171..5f2227c83e4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus -import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue @Deprecated("Temporary error") @@ -37,11 +36,10 @@ internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResol } internal val ResolutionCandidateApplicability.isSuccess: Boolean - get() = this == ResolutionCandidateApplicability.RESOLVED || this == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED + get() = this <= ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY -internal val CallableDescriptor.isSynthesized: Boolean // todo dynamics calls - get() = (this is CallableMemberDescriptor && isOrOverridesSynthesized(this)) - || hasLowPriorityInOverloadResolution() +internal val CallableDescriptor.isSynthesized: Boolean + get() = (this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED) internal val CandidateWithBoundDispatchReceiver<*>.requiresExtensionReceiver: Boolean get() = descriptor.extensionReceiverParameter != null diff --git a/compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt b/compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt new file mode 100644 index 00000000000..593d66c0c29 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt @@ -0,0 +1,20 @@ +// !CHECK_TYPE +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +enum class Foo { + FOO; + + companion object { + fun valueOf(something: String) = 2 + + fun values() = 1 + } +} + +fun test() { + Foo.values() checkType { _>() } + Foo.Companion.values() checkType { _() } + + Foo.valueOf("") checkType { _() } + Foo.Companion.valueOf("") checkType { _() } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/priority/kt9965.txt b/compiler/testData/diagnostics/tests/resolve/priority/kt9965.txt new file mode 100644 index 00000000000..2281f0442af --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/priority/kt9965.txt @@ -0,0 +1,30 @@ +package + +public fun test(): kotlin.Unit + +public final enum class Foo : kotlin.Enum { + enum entry FOO + + private constructor Foo() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Foo): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + 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 fun valueOf(/*0*/ something: kotlin.String): kotlin.Int + public final fun values(): kotlin.Int + } + + // Static members + @kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Use 'values()' function instead", replaceWith = kotlin.ReplaceWith(expression = "this.values()", imports = {})) public final /*synthesized*/ val values: kotlin.Array + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Foo + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt b/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt new file mode 100644 index 00000000000..1780db676c2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt @@ -0,0 +1,10 @@ +// !CHECK_TYPE + +data class A(val foo: Int) + +operator fun A.component1(): String = "" + +fun test(a: A) { + val (b) = a + b checkType { _() } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.txt b/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.txt new file mode 100644 index 00000000000..0ac093b3d7e --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.txt @@ -0,0 +1,14 @@ +package + +public fun test(/*0*/ a: A): kotlin.Unit +public operator fun A.component1(): kotlin.String + +public final data class A { + public constructor A(/*0*/ foo: kotlin.Int) + public final val foo: kotlin.Int + public final operator /*synthesized*/ fun component1(): kotlin.Int + public final /*synthesized*/ fun copy(/*0*/ foo: kotlin.Int = ...): 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 +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.kt b/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.kt new file mode 100644 index 00000000000..57eb8e96916 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.kt @@ -0,0 +1,30 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +// FILE: s/SamConstructor.java +package s; + +public class SamConstructor { + public SamConstructor(Runnable r) { + } + + public static void foo(Runnable r) {} +} + +// FILE: 1.kt +package a + +fun SamConstructor(a: () -> Unit) {} + +// FILE: 2.kt + +package b + +import s.SamConstructor +import a.* + +fun test() { + val a: s.SamConstructor = SamConstructor { } + + val b: s.SamConstructor = SamConstructor(null) + + SamConstructor.foo(null) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.txt b/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.txt new file mode 100644 index 00000000000..6926e3b907d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.txt @@ -0,0 +1,9 @@ +package + +package a { + public fun SamConstructor(/*0*/ a: () -> kotlin.Unit): kotlin.Unit +} + +package b { + public fun test(): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e7e0598d6f6..d33abb3c10b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13710,6 +13710,27 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/resolve/priority") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Priority extends AbstractDiagnosticsTest { + public void testAllFilesPresentInPriority() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/priority"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("kt9965.kt") + public void testKt9965() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/kt9965.kt"); + doTest(fileName); + } + + @TestMetadata("synthesizedMembersVsExtension.kt") + public void testSynthesizedMembersVsExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/priority/synthesizedMembersVsExtension.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/resolve/specialConstructions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 0e3176d846b..84365996d30 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1014,6 +1014,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/resolve/kt4711.kt"); doTest(fileName); } + + @TestMetadata("samConstructorVsFun.kt") + public void testSamConstructorVsFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/resolve/samConstructorVsFun.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/smartcasts") diff --git a/idea/testData/unifier/equivalence/declarations/localCallables/multiDeclaration.kt b/idea/testData/unifier/equivalence/declarations/localCallables/multiDeclaration.kt index 648498afe34..4d5ab61d93b 100644 --- a/idea/testData/unifier/equivalence/declarations/localCallables/multiDeclaration.kt +++ b/idea/testData/unifier/equivalence/declarations/localCallables/multiDeclaration.kt @@ -1,4 +1,7 @@ -data class A(val a: Int, val b: String) +class A(val a: Int, val b: String) + +operator fun A.component1() = a +operator fun A.component2() = b fun foo1() { val (a, b) = A(1, "2") diff --git a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt index 26ae83188a3..84872a2ebe8 100644 --- a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt +++ b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt @@ -34,7 +34,7 @@ import bar.* /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/X /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/X./*c:foo.E*/a /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/Y./*c:foo.E*/foo() - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E p:foo(invoke) p:bar(invoke) p:java.lang(invoke) p:kotlin(invoke) p:kotlin.annotation(invoke) p:kotlin.jvm(invoke) p:kotlin.collections(invoke) p:kotlin.ranges(invoke) p:kotlin.sequences(invoke) p:kotlin.text(invoke) p:kotlin.io(invoke)*/values() + /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/values() /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/valueOf("") /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/foo /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.collections p:kotlin.ranges p:kotlin.sequences p:kotlin.text p:kotlin.io*/E./*c:foo.E*/bar()