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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user