From aed2f2b9936fcb365b3a51ba3a9cb3ad24d2df23 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 10 Feb 2016 16:37:50 +0300 Subject: [PATCH] Property vs classifier conflict. TODO get rid of duplicate diagnostics (looks like OverloadResolver and DeclarationResolver are partially redundant; refactor them). --- .../kotlin/resolve/jvm/JvmOverloadFilter.kt | 5 +- .../kotlin/resolve/LazyTopDownAnalyzer.kt | 2 +- .../kotlin/resolve/OverloadFilter.kt | 6 +- .../kotlin/resolve/OverloadResolver.kt | 52 ++++++------- .../jetbrains/kotlin/resolve/OverloadUtil.kt | 73 ++++++++++++------- .../duplicateJvmSignature/missingNames.kt | 6 +- .../tests/redeclarations/Redeclarations.kt | 4 +- .../TopLevelPropertyVsClassifier.kt | 13 ++++ .../TopLevelPropertyVsClassifier.txt | 46 ++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++ .../recovery/namelessToplevelDeclarations.kt | 6 +- 11 files changed, 154 insertions(+), 65 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.kt create mode 100644 compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmOverloadFilter.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmOverloadFilter.kt index e12f68f3f1c..1b2ab874dbe 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmOverloadFilter.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmOverloadFilter.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.jvm import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorNonRoot import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider @@ -30,8 +31,8 @@ import java.util.* object JvmOverloadFilter : OverloadFilter { - override fun filterPackageMemberOverloads(overloads: Collection): Collection { - val result = ArrayList() + override fun filterPackageMemberOverloads(overloads: Collection): Collection { + val result = ArrayList() val sourceClassesFQNs = HashSet() for (overload in overloads) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index a3e5e8db3a3..bea8893754f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -187,7 +187,7 @@ class LazyTopDownAnalyzer( declarationResolver.resolveAnnotationsOnFiles(c, fileScopeProvider) - overloadResolver.process(c) + overloadResolver.checkOverloads(c) bodyResolver.resolveBodies(c) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadFilter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadFilter.kt index a64d770cc6a..a81a85ce44d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadFilter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadFilter.kt @@ -16,14 +16,14 @@ package org.jetbrains.kotlin.resolve -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorNonRoot interface OverloadFilter { - fun filterPackageMemberOverloads(overloads: Collection): Collection + fun filterPackageMemberOverloads(overloads: Collection): Collection object DEFAULT : OverloadFilter { - override fun filterPackageMemberOverloads(overloads: Collection): Collection = + override fun filterPackageMemberOverloads(overloads: Collection): Collection = overloads } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt index 7d354ab3b7b..d6d09cb5f68 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt @@ -28,11 +28,7 @@ class OverloadResolver( private val trace: BindingTrace, private val overloadFilter: OverloadFilter) { - fun process(c: BodiesResolveContext) { - checkOverloads(c) - } - - private fun checkOverloads(c: BodiesResolveContext) { + fun checkOverloads(c: BodiesResolveContext) { val inClasses = findConstructorsInNestedClasses(c) for (entry in c.declaredClasses.entries) { @@ -93,7 +89,7 @@ class OverloadResolver( } } - private fun checkOverloadsInPackage(members: Collection) { + private fun checkOverloadsInPackage(members: Collection) { if (members.size == 1) return for (redeclarationGroup in OverloadUtil.getPossibleRedeclarationGroups(members)) { reportRedeclarations(findRedeclarations(redeclarationGroup)) @@ -105,10 +101,13 @@ class OverloadResolver( reportRedeclarations(findRedeclarations(members)) } - private fun findRedeclarations(members: Collection): Set> { - val redeclarations = linkedSetOf>() + private fun DeclarationDescriptor.isSynthesized() = + this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED + + private fun findRedeclarations(members: Collection): Set> { + val redeclarations = linkedSetOf>() for (member1 in members) { - if (member1.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) continue + if (member1.isSynthesized()) continue for (member2 in members) { if (member1 == member2) continue @@ -124,7 +123,7 @@ class OverloadResolver( return redeclarations } - private fun isConstructorsOfDifferentRedeclaredClasses(member1: CallableMemberDescriptor, member2: CallableMemberDescriptor): Boolean { + private fun isConstructorsOfDifferentRedeclaredClasses(member1: DeclarationDescriptor, member2: DeclarationDescriptor): Boolean { if (member1 !is ConstructorDescriptor || member2 !is ConstructorDescriptor) return false // ignore conflicting overloads for constructors of different classes because their redeclarations will be reported // but don't ignore if there's possibility that classes redeclarations will not be reported @@ -134,7 +133,7 @@ class OverloadResolver( return parent1 !== parent2 && parent1.containingDeclaration == parent2.containingDeclaration } - private fun isTopLevelMainInDifferentFiles(member1: CallableMemberDescriptor, member2: CallableMemberDescriptor): Boolean { + private fun isTopLevelMainInDifferentFiles(member1: DeclarationDescriptor, member2: DeclarationDescriptor): Boolean { if (!MainFunctionDetector.isMain(member1) || !MainFunctionDetector.isMain(member2)) { return false } @@ -144,7 +143,7 @@ class OverloadResolver( return file1 == null || file2 == null || file1 !== file2 } - private fun reportRedeclarations(redeclarations: Set>) { + private fun reportRedeclarations(redeclarations: Set>) { if (redeclarations.isEmpty()) return val redeclarationsIterator = redeclarations.iterator() @@ -154,20 +153,23 @@ class OverloadResolver( for ((ktDeclaration, memberDescriptor) in redeclarations) { if (ktDeclaration == null) continue - if (memberDescriptor is PropertyDescriptor) { - trace.report(Errors.REDECLARATION.on(ktDeclaration, memberDescriptor.getName().asString())) - } - else { - val redeclarationDescriptor = - if (otherRedeclarationDescriptor == null) - firstRedeclarationDescriptor - else if (memberDescriptor == firstRedeclarationDescriptor) - otherRedeclarationDescriptor - else - firstRedeclarationDescriptor + when (memberDescriptor) { + is PropertyDescriptor, + is ClassifierDescriptor -> { + trace.report(Errors.REDECLARATION.on(ktDeclaration, memberDescriptor.name.asString())) + } + is FunctionDescriptor -> { + val redeclarationDescriptor = + if (otherRedeclarationDescriptor == null) + firstRedeclarationDescriptor + else if (memberDescriptor == firstRedeclarationDescriptor) + otherRedeclarationDescriptor + else + firstRedeclarationDescriptor - trace.report(Errors.CONFLICTING_OVERLOADS.on(ktDeclaration, memberDescriptor, - redeclarationDescriptor.containingDeclaration)) + trace.report(Errors.CONFLICTING_OVERLOADS.on(ktDeclaration, memberDescriptor, + redeclarationDescriptor.containingDeclaration)) + } } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt index 9a0371bd6ab..6a9d54503ce 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt @@ -27,24 +27,21 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeIntersector import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother +import org.jetbrains.kotlin.utils.singletonOrEmptyList object OverloadUtil { /** * Does not check names. */ - @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): Boolean { - val abc = braceCount(a) - val bbc = braceCount(b) + @JvmStatic fun isOverloadable(a: DeclarationDescriptor, b: DeclarationDescriptor): Boolean { + val aCategory = getDeclarationCategory(a) + val bCategory = getDeclarationCategory(b) - if (abc != bbc) { - return true - } + if (aCategory != bCategory) return true + if (a !is CallableDescriptor || b !is CallableDescriptor) return false - val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(a, b) - if (receiverAndParameterResult != null) { - return receiverAndParameterResult.result == INCOMPATIBLE - } + OverridingUtil.checkReceiverAndParameterCount(a, b)?.let { return it.result == INCOMPATIBLE } val aValueParameters = OverridingUtil.compiledValueParameters(a) val bValueParameters = OverridingUtil.compiledValueParameters(b) @@ -62,12 +59,30 @@ object OverloadUtil { return false } - private fun braceCount(a: CallableDescriptor): Int = + private enum class DeclarationCategory { + TYPE_OR_VALUE, + FUNCTION, + EXTENSION_PROPERTY + } + + private fun DeclarationDescriptor.isExtensionProperty() = + this is PropertyDescriptor && + extensionReceiverParameter != null + + private fun getDeclarationCategory(a: DeclarationDescriptor): DeclarationCategory = when (a) { - is PropertyDescriptor -> 0 - is SimpleFunctionDescriptor -> 1 - is ConstructorDescriptor -> 1 - else -> throw IllegalStateException() + is PropertyDescriptor -> + if (a.isExtensionProperty()) + DeclarationCategory.EXTENSION_PROPERTY + else + DeclarationCategory.TYPE_OR_VALUE + is ConstructorDescriptor, + is SimpleFunctionDescriptor -> + DeclarationCategory.FUNCTION + is ClassifierDescriptor -> + DeclarationCategory.TYPE_OR_VALUE + else -> + error("Unexpected declaration kind: $a") } private val KotlinType.upperBound: KotlinType @@ -83,8 +98,8 @@ object OverloadUtil { @JvmStatic fun groupModulePackageMembersByFqName( c: BodiesResolveContext, overloadFilter: OverloadFilter - ): MultiMap { - val packageMembersByName = MultiMap() + ): MultiMap { + val packageMembersByName = MultiMap() collectModulePackageMembersWithSameName(packageMembersByName, c.functions.values + c.declaredClasses.values, overloadFilter) { scope, name -> @@ -98,17 +113,19 @@ object OverloadUtil { collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values, overloadFilter) { scope, name -> - scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS).filterIsInstance() + val variables = scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS) + val classifier = scope.getContributedClassifier(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS) + variables + classifier.singletonOrEmptyList() } return packageMembersByName } private inline fun collectModulePackageMembersWithSameName( - packageMembersByName: MultiMap, + packageMembersByName: MultiMap, interestingDescriptors: Collection, overloadFilter: OverloadFilter, - getMembersByName: (MemberScope, Name) -> Collection + getMembersByName: (MemberScope, Name) -> Collection ) { val observedFQNs = hashSetOf() for (descriptor in interestingDescriptors) { @@ -126,8 +143,8 @@ object OverloadUtil { private inline fun getModulePackageMembersWithSameName( descriptor: DeclarationDescriptor, overloadFilter: OverloadFilter, - getMembersByName: (MemberScope, Name) -> Collection - ): Collection { + getMembersByName: (MemberScope, Name) -> Collection + ): Collection { val containingPackage = descriptor.containingDeclaration if (containingPackage !is PackageFragmentDescriptor) { throw AssertionError("$descriptor is not a top-level package member") @@ -150,17 +167,21 @@ object OverloadUtil { return overloadFilter.filterPackageMemberOverloads(possibleOverloads) } - private fun MemberDescriptor.isPrivate() = Visibilities.isPrivate(this.visibility) + private fun DeclarationDescriptor.isPrivate() = + this is DeclarationDescriptorWithVisibility && + Visibilities.isPrivate(this.visibility) - @JvmStatic fun getPossibleRedeclarationGroups(members: Collection): Collection> { - val result = arrayListOf>() + @JvmStatic fun getPossibleRedeclarationGroups( + members: Collection + ): Collection> { + val result = arrayListOf>() val nonPrivates = members.filter { !it.isPrivate() } if (nonPrivates.size > 1) { result.add(nonPrivates) } - val bySourceFile = MultiMap.createSmart() + val bySourceFile = MultiMap.createSmart() for (member in members) { val sourceFile = DescriptorUtils.getContainingSourceFile(member) if (sourceFile != SourceFile.NO_SOURCE_FILE) { diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/missingNames.kt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/missingNames.kt index 0d8919d3ec8..cfd1849fa0e 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/missingNames.kt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/missingNames.kt @@ -7,11 +7,11 @@ } -val : Int = 1 +val : Int = 1 -class { +class { -} +} object { diff --git a/compiler/testData/diagnostics/tests/redeclarations/Redeclarations.kt b/compiler/testData/diagnostics/tests/redeclarations/Redeclarations.kt index 5bde0b1df84..39a8126cfe8 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/Redeclarations.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/Redeclarations.kt @@ -1,6 +1,6 @@ // FILE: f.kt package redeclarations - object A { + object A { val x : Int = 0 val A = 1 @@ -8,7 +8,7 @@ package redeclarations class A {} - val A = 1 + val A = 1 // FILE: f.kt package redeclarations.A diff --git a/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.kt b/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.kt new file mode 100644 index 00000000000..db613dee644 --- /dev/null +++ b/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.kt @@ -0,0 +1,13 @@ +val Test1 = null +class Test1 + +val Test2 = null +interface Test2 + +val Test3 = null +object Test3 + +val Test4 = null +class Test4 +interface Test4 +object Test4 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.txt b/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.txt new file mode 100644 index 00000000000..0559d78caaf --- /dev/null +++ b/compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.txt @@ -0,0 +1,46 @@ +package + +public val Test1: kotlin.Nothing? = null +public val Test2: kotlin.Nothing? = null +public val Test3: kotlin.Nothing? = null +public val Test4: kotlin.Nothing? = null + +public final class Test1 { + public constructor Test1() + 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 interface Test2 { + 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 object Test3 { + private constructor Test3() + 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 Test4 { + public constructor Test4() + 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 interface Test4 { + 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 object Test4 { + private constructor Test4() + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e9350e00b24..d238121c87e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13275,6 +13275,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("TopLevelPropertyVsClassifier.kt") + public void testTopLevelPropertyVsClassifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/redeclarations/TopLevelPropertyVsClassifier.kt"); + doTest(fileName); + } + @TestMetadata("typeParameterWithTwoBounds.kt") public void testTypeParameterWithTwoBounds() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/redeclarations/typeParameterWithTwoBounds.kt"); diff --git a/idea/testData/checker/recovery/namelessToplevelDeclarations.kt b/idea/testData/checker/recovery/namelessToplevelDeclarations.kt index b521fc256ac..0688386365e 100644 --- a/idea/testData/checker/recovery/namelessToplevelDeclarations.kt +++ b/idea/testData/checker/recovery/namelessToplevelDeclarations.kt @@ -4,12 +4,12 @@ package } -val : Int = 1 +val : Int = 1 -class { +class { -} +} interface {