From 51703416243a22aa4b25dc5e67f9133408d9c3e9 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 20 Oct 2015 17:18:11 +0300 Subject: [PATCH] OverloadResolver: fix redeclaration diagnostics issue in incremental compilation (KT-6165) J2K: OverloadUtil.kt --- .../kotlin/resolve/OverloadResolver.java | 19 +- .../jetbrains/kotlin/resolve/OverloadUtil.kt | 183 ++++++++++-------- .../pureKotlin/funRedeclaration/build.log | 9 +- .../propertyRedeclaration/build.log | 4 +- 4 files changed, 104 insertions(+), 111 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.java index 21ad9c916a4..060732db4f9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.java @@ -91,24 +91,7 @@ public class OverloadResolver { @NotNull BodiesResolveContext c, @NotNull MultiMap inPackages ) { - - MultiMap functionsByName = MultiMap.create(); - - for (SimpleFunctionDescriptor function : c.getFunctions().values()) { - if (function.getContainingDeclaration() instanceof PackageFragmentDescriptor) { - functionsByName.putValue(getFqName(function), function); - } - } - - for (PropertyDescriptor property : c.getProperties().values()) { - if (property.getContainingDeclaration() instanceof PackageFragmentDescriptor) { - functionsByName.putValue(getFqName(property), property); - } - } - - for (Map.Entry> entry : inPackages.entrySet()) { - functionsByName.putValues(entry.getKey(), entry.getValue()); - } + MultiMap functionsByName = OverloadUtil.groupModulePackageMembersByFqName(c, inPackages); for (Map.Entry> e : functionsByName.entrySet()) { // TODO: don't render FQ name here, extract this logic to somewhere diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt index f995fb4f386..e64a3739bcb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt @@ -14,119 +14,136 @@ * limitations under the License. */ -package org.jetbrains.kotlin.resolve; +package org.jetbrains.kotlin.resolve -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyDescriptor; -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.TypeCapabilitiesKt; -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.* +import org.jetbrains.kotlin.resolve.scopes.KtScope +import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother -import java.util.List; - -import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE; - -public class OverloadUtil { +object OverloadUtil { /** * Does not check names. */ - public static OverloadCompatibilityInfo isOverloadable(CallableDescriptor a, CallableDescriptor b) { - int abc = braceCount(a); - int bbc = braceCount(b); - + public @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): OverloadCompatibilityInfo { + val abc = braceCount(a) + val bbc = braceCount(b) + if (abc != bbc) { - return OverloadCompatibilityInfo.success(); + return OverloadCompatibilityInfo.success() } - - OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = isOverloadableBy(a, b); - switch (overrideCompatibilityInfo.getResult()) { - case OVERRIDABLE: - case CONFLICT: - return OverloadCompatibilityInfo.someError(); - case INCOMPATIBLE: - return OverloadCompatibilityInfo.success(); - default: - throw new IllegalStateException(); + + val overrideCompatibilityInfo = isOverloadableBy(a, b) + when (overrideCompatibilityInfo.result) { + OVERRIDABLE, CONFLICT -> return OverloadCompatibilityInfo.someError() + INCOMPATIBLE -> return OverloadCompatibilityInfo.success() + else -> throw IllegalStateException() } } - @NotNull - private static OverridingUtil.OverrideCompatibilityInfo isOverloadableBy( - @NotNull CallableDescriptor superDescriptor, - @NotNull CallableDescriptor subDescriptor - ) { - OverridingUtil.OverrideCompatibilityInfo - receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor); + private fun isOverloadableBy( + superDescriptor: CallableDescriptor, + subDescriptor: CallableDescriptor): OverridingUtil.OverrideCompatibilityInfo { + val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor) if (receiverAndParameterResult != null) { - return receiverAndParameterResult; + return receiverAndParameterResult } - List superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor); - List subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor); + val superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor) + val subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor) - for (int i = 0; i < superValueParameters.size(); ++i) { - KotlinType superValueParameterType = OverridingUtil.getUpperBound(superValueParameters.get(i)); - KotlinType subValueParameterType = OverridingUtil.getUpperBound(subValueParameters.get(i)); - if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) - || TypeCapabilitiesKt.oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) { - return OverridingUtil.OverrideCompatibilityInfo - .valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE); + for (i in superValueParameters.indices) { + val superValueParameterType = OverridingUtil.getUpperBound(superValueParameters[i]) + val subValueParameterType = OverridingUtil.getUpperBound(subValueParameters[i]) + if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) || oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) { + return OverridingUtil.OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE) } } - return OverridingUtil.OverrideCompatibilityInfo.success(); + return OverridingUtil.OverrideCompatibilityInfo.success() } - private static int braceCount(CallableDescriptor a) { - if (a instanceof PropertyDescriptor) { - return 0; - } - else if (a instanceof SimpleFunctionDescriptor) { - return 1; - } - else if (a instanceof ConstructorDescriptor) { - return 1; - } - else { - throw new IllegalStateException(); + private fun braceCount(a: CallableDescriptor): Int = + when (a) { + is PropertyDescriptor -> 0 + is SimpleFunctionDescriptor -> 1 + is ConstructorDescriptor -> 1 + else -> throw IllegalStateException() + } + + class OverloadCompatibilityInfo(val isSuccess: Boolean, val message: String) { + companion object { + + private val SUCCESS = OverloadCompatibilityInfo(true, "SUCCESS") + + fun success() = SUCCESS + + fun someError() = OverloadCompatibilityInfo(false, "XXX") } } - public static class OverloadCompatibilityInfo { + public @JvmStatic fun groupModulePackageMembersByFqName( + c: BodiesResolveContext, + constructorsInPackages: MultiMap + ): MultiMap { + val packageMembersByName = MultiMap() - private static final OverloadCompatibilityInfo SUCCESS = new OverloadCompatibilityInfo(true, "SUCCESS"); - - public static OverloadCompatibilityInfo success() { - return SUCCESS; - } - - public static OverloadCompatibilityInfo someError() { - return new OverloadCompatibilityInfo(false, "XXX"); - } - - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private final boolean isSuccess; - private final String message; - - public OverloadCompatibilityInfo(boolean success, String message) { - isSuccess = success; - this.message = message; + collectModulePackageMembersWithSameName(packageMembersByName, c.functions.values) { + scope, name -> + scope.getFunctions(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS) } - public boolean isSuccess() { - return isSuccess; + collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values) { + scope, name -> + scope.getProperties(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS).filterIsInstance() } - public String getMessage() { - return message; + // TODO handle constructor redeclarations in modules. See also https://youtrack.jetbrains.com/issue/KT-3632 + packageMembersByName.putAllValues(constructorsInPackages) + + return packageMembersByName + } + + private inline fun collectModulePackageMembersWithSameName( + packageMembersByName: MultiMap, + interestingDescriptors: Collection, + getMembersByName: (KtScope, Name) -> Collection + ) { + val observedFQNs = hashSetOf() + for (descriptor in interestingDescriptors) { + if (descriptor.containingDeclaration !is PackageFragmentDescriptor) continue + + val descriptorFQN = DescriptorUtils.getFqName(descriptor) + if (observedFQNs.contains(descriptorFQN)) continue + observedFQNs.add(descriptorFQN) + + val packageMembersWithSameName = getModulePackageMembersWithSameName(descriptor, getMembersByName) + packageMembersByName.putValues(descriptorFQN, packageMembersWithSameName) + } + } + + private inline fun getModulePackageMembersWithSameName( + packageMember: CallableMemberDescriptor, + getMembersByName: (KtScope, Name) -> Collection + ): Collection { + val containingPackage = packageMember.containingDeclaration + if (containingPackage !is PackageFragmentDescriptor) { + throw AssertionError("$packageMember is not a top-level package member") } + val containingModule = DescriptorUtils.getContainingModuleOrNull(packageMember) ?: return listOf(packageMember) + + val containingPackageScope = containingModule.getPackage(containingPackage.fqName).memberScope + val possibleOverloads = getMembersByName(containingPackageScope, packageMember.name) + + // NB memberScope for PackageViewDescriptor includes module dependencies + return possibleOverloads.filter { DescriptorUtils.getContainingModule(it) == containingModule } } } diff --git a/jps-plugin/testData/incremental/pureKotlin/funRedeclaration/build.log b/jps-plugin/testData/incremental/pureKotlin/funRedeclaration/build.log index 8581a0c52c8..1e5f3f89482 100644 --- a/jps-plugin/testData/incremental/pureKotlin/funRedeclaration/build.log +++ b/jps-plugin/testData/incremental/pureKotlin/funRedeclaration/build.log @@ -5,10 +5,5 @@ End of files Compiling files: src/fun2.kt End of files -Cleaning output files: -out/production/module/META-INF/module.kotlin_module -out/production/module/test/Fun1Kt.class -End of files -Compiling files: -src/fun1.kt -End of files \ No newline at end of file +COMPILATION FAILED +'public fun function(): kotlin.Unit' is already defined in test \ No newline at end of file diff --git a/jps-plugin/testData/incremental/pureKotlin/propertyRedeclaration/build.log b/jps-plugin/testData/incremental/pureKotlin/propertyRedeclaration/build.log index 03c96004241..60cc1bf3937 100644 --- a/jps-plugin/testData/incremental/pureKotlin/propertyRedeclaration/build.log +++ b/jps-plugin/testData/incremental/pureKotlin/propertyRedeclaration/build.log @@ -6,6 +6,4 @@ Compiling files: src/prop2.kt End of files COMPILATION FAILED -Platform declaration clash: The following declarations have the same JVM signature (getProperty()I): - fun (): kotlin.Int - fun (): kotlin.Int \ No newline at end of file +Redeclaration: property \ No newline at end of file