Property vs classifier conflict.

TODO get rid of duplicate diagnostics
(looks like OverloadResolver and DeclarationResolver are partially redundant; refactor them).
This commit is contained in:
Dmitry Petrov
2016-02-10 16:37:50 +03:00
parent b2eb4200af
commit aed2f2b993
11 changed files with 154 additions and 65 deletions
@@ -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<CallableMemberDescriptor>): Collection<CallableMemberDescriptor> {
val result = ArrayList<CallableMemberDescriptor>()
override fun filterPackageMemberOverloads(overloads: Collection<DeclarationDescriptorNonRoot>): Collection<DeclarationDescriptorNonRoot> {
val result = ArrayList<DeclarationDescriptorNonRoot>()
val sourceClassesFQNs = HashSet<FqName>()
for (overload in overloads) {
@@ -187,7 +187,7 @@ class LazyTopDownAnalyzer(
declarationResolver.resolveAnnotationsOnFiles(c, fileScopeProvider)
overloadResolver.process(c)
overloadResolver.checkOverloads(c)
bodyResolver.resolveBodies(c)
@@ -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<CallableMemberDescriptor>): Collection<CallableMemberDescriptor>
fun filterPackageMemberOverloads(overloads: Collection<DeclarationDescriptorNonRoot>): Collection<DeclarationDescriptorNonRoot>
object DEFAULT : OverloadFilter {
override fun filterPackageMemberOverloads(overloads: Collection<CallableMemberDescriptor>): Collection<CallableMemberDescriptor> =
override fun filterPackageMemberOverloads(overloads: Collection<DeclarationDescriptorNonRoot>): Collection<DeclarationDescriptorNonRoot> =
overloads
}
}
@@ -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<CallableMemberDescriptor>) {
private fun checkOverloadsInPackage(members: Collection<DeclarationDescriptorNonRoot>) {
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<CallableMemberDescriptor>): Set<Pair<KtDeclaration?, CallableMemberDescriptor>> {
val redeclarations = linkedSetOf<Pair<KtDeclaration?, CallableMemberDescriptor>>()
private fun DeclarationDescriptor.isSynthesized() =
this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED
private fun findRedeclarations(members: Collection<DeclarationDescriptorNonRoot>): Set<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>> {
val redeclarations = linkedSetOf<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>>()
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<Pair<KtDeclaration?, CallableMemberDescriptor>>) {
private fun reportRedeclarations(redeclarations: Set<Pair<KtDeclaration?, DeclarationDescriptorNonRoot>>) {
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))
}
}
}
}
@@ -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<FqNameUnsafe, CallableMemberDescriptor> {
val packageMembersByName = MultiMap<FqNameUnsafe, CallableMemberDescriptor>()
): MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot> {
val packageMembersByName = MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>()
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<CallableMemberDescriptor>()
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<FqNameUnsafe, CallableMemberDescriptor>,
packageMembersByName: MultiMap<FqNameUnsafe, DeclarationDescriptorNonRoot>,
interestingDescriptors: Collection<DeclarationDescriptor>,
overloadFilter: OverloadFilter,
getMembersByName: (MemberScope, Name) -> Collection<CallableMemberDescriptor>
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
) {
val observedFQNs = hashSetOf<FqNameUnsafe>()
for (descriptor in interestingDescriptors) {
@@ -126,8 +143,8 @@ object OverloadUtil {
private inline fun getModulePackageMembersWithSameName(
descriptor: DeclarationDescriptor,
overloadFilter: OverloadFilter,
getMembersByName: (MemberScope, Name) -> Collection<CallableMemberDescriptor>
): Collection<CallableMemberDescriptor> {
getMembersByName: (MemberScope, Name) -> Collection<DeclarationDescriptorNonRoot>
): Collection<DeclarationDescriptorNonRoot> {
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<CallableMemberDescriptor>): Collection<Collection<CallableMemberDescriptor>> {
val result = arrayListOf<Collection<CallableMemberDescriptor>>()
@JvmStatic fun getPossibleRedeclarationGroups(
members: Collection<DeclarationDescriptorNonRoot>
): Collection<Collection<DeclarationDescriptorNonRoot>> {
val result = arrayListOf<Collection<DeclarationDescriptorNonRoot>>()
val nonPrivates = members.filter { !it.isPrivate() }
if (nonPrivates.size > 1) {
result.add(nonPrivates)
}
val bySourceFile = MultiMap.createSmart<SourceFile, CallableMemberDescriptor>()
val bySourceFile = MultiMap.createSmart<SourceFile, DeclarationDescriptorNonRoot>()
for (member in members) {
val sourceFile = DescriptorUtils.getContainingSourceFile(member)
if (sourceFile != SourceFile.NO_SOURCE_FILE) {
@@ -7,11 +7,11 @@
}
val<!SYNTAX!><!> : Int = 1
<!REDECLARATION!>val<!SYNTAX!><!> : Int = 1<!>
class<!SYNTAX!><!> {
<!REDECLARATION!>class<!SYNTAX!><!> {
}
}<!>
object<!SYNTAX!><!> {
@@ -1,6 +1,6 @@
// FILE: f.kt
package redeclarations
object <!REDECLARATION!>A<!> {
object <!REDECLARATION, REDECLARATION!>A<!> {
val x : Int = 0
val A = 1
@@ -8,7 +8,7 @@ package redeclarations
class <!REDECLARATION!>A<!> {}
val <!REDECLARATION!>A<!> = 1
val <!REDECLARATION, REDECLARATION!>A<!> = 1
// FILE: f.kt
package redeclarations.<!REDECLARATION!>A<!>
@@ -0,0 +1,13 @@
val <!REDECLARATION!>Test1<!> = null
class <!REDECLARATION!>Test1<!>
val <!REDECLARATION!>Test2<!> = null
interface <!REDECLARATION!>Test2<!>
val <!REDECLARATION!>Test3<!> = null
object <!REDECLARATION!>Test3<!>
val <!REDECLARATION, REDECLARATION!>Test4<!> = null
class <!REDECLARATION, REDECLARATION!>Test4<!>
interface <!REDECLARATION!>Test4<!>
object <!REDECLARATION!>Test4<!>
@@ -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
}
@@ -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");
@@ -4,12 +4,12 @@ package<EOLError></EOLError>
}
val<error> </error>: Int = 1
<error>val<error> </error>: Int = 1</error>
class<error> </error>{
<error>class<error> </error>{
}
}</error>
interface<error> </error>{