OverloadResolver:
fix redeclaration diagnostics issue in incremental compilation (KT-6165) J2K: OverloadUtil.kt
This commit is contained in:
@@ -91,24 +91,7 @@ public class OverloadResolver {
|
|||||||
@NotNull BodiesResolveContext c,
|
@NotNull BodiesResolveContext c,
|
||||||
@NotNull MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages
|
@NotNull MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages
|
||||||
) {
|
) {
|
||||||
|
MultiMap<FqNameUnsafe, CallableMemberDescriptor> functionsByName = OverloadUtil.groupModulePackageMembersByFqName(c, inPackages);
|
||||||
MultiMap<FqNameUnsafe, CallableMemberDescriptor> 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<FqNameUnsafe, Collection<ConstructorDescriptor>> entry : inPackages.entrySet()) {
|
|
||||||
functionsByName.putValues(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
|
for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
|
||||||
// TODO: don't render FQ name here, extract this logic to somewhere
|
// TODO: don't render FQ name here, extract this logic to somewhere
|
||||||
|
|||||||
@@ -14,119 +14,136 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.resolve;
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import com.intellij.util.containers.MultiMap
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*
|
||||||
import org.jetbrains.kotlin.types.TypeCapabilitiesKt;
|
import org.jetbrains.kotlin.resolve.scopes.KtScope
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother
|
||||||
|
|
||||||
import java.util.List;
|
object OverloadUtil {
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE;
|
|
||||||
|
|
||||||
public class OverloadUtil {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does not check names.
|
* Does not check names.
|
||||||
*/
|
*/
|
||||||
public static OverloadCompatibilityInfo isOverloadable(CallableDescriptor a, CallableDescriptor b) {
|
public @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): OverloadCompatibilityInfo {
|
||||||
int abc = braceCount(a);
|
val abc = braceCount(a)
|
||||||
int bbc = braceCount(b);
|
val bbc = braceCount(b)
|
||||||
|
|
||||||
if (abc != bbc) {
|
if (abc != bbc) {
|
||||||
return OverloadCompatibilityInfo.success();
|
return OverloadCompatibilityInfo.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = isOverloadableBy(a, b);
|
val overrideCompatibilityInfo = isOverloadableBy(a, b)
|
||||||
switch (overrideCompatibilityInfo.getResult()) {
|
when (overrideCompatibilityInfo.result) {
|
||||||
case OVERRIDABLE:
|
OVERRIDABLE, CONFLICT -> return OverloadCompatibilityInfo.someError()
|
||||||
case CONFLICT:
|
INCOMPATIBLE -> return OverloadCompatibilityInfo.success()
|
||||||
return OverloadCompatibilityInfo.someError();
|
else -> throw IllegalStateException()
|
||||||
case INCOMPATIBLE:
|
|
||||||
return OverloadCompatibilityInfo.success();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun isOverloadableBy(
|
||||||
private static OverridingUtil.OverrideCompatibilityInfo isOverloadableBy(
|
superDescriptor: CallableDescriptor,
|
||||||
@NotNull CallableDescriptor superDescriptor,
|
subDescriptor: CallableDescriptor): OverridingUtil.OverrideCompatibilityInfo {
|
||||||
@NotNull CallableDescriptor subDescriptor
|
val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor)
|
||||||
) {
|
|
||||||
OverridingUtil.OverrideCompatibilityInfo
|
|
||||||
receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor);
|
|
||||||
if (receiverAndParameterResult != null) {
|
if (receiverAndParameterResult != null) {
|
||||||
return receiverAndParameterResult;
|
return receiverAndParameterResult
|
||||||
}
|
}
|
||||||
|
|
||||||
List<KotlinType> superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor);
|
val superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor)
|
||||||
List<KotlinType> subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor);
|
val subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor)
|
||||||
|
|
||||||
for (int i = 0; i < superValueParameters.size(); ++i) {
|
for (i in superValueParameters.indices) {
|
||||||
KotlinType superValueParameterType = OverridingUtil.getUpperBound(superValueParameters.get(i));
|
val superValueParameterType = OverridingUtil.getUpperBound(superValueParameters[i])
|
||||||
KotlinType subValueParameterType = OverridingUtil.getUpperBound(subValueParameters.get(i));
|
val subValueParameterType = OverridingUtil.getUpperBound(subValueParameters[i])
|
||||||
if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)
|
if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) || oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
|
||||||
|| TypeCapabilitiesKt.oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
|
return OverridingUtil.OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE)
|
||||||
return OverridingUtil.OverrideCompatibilityInfo
|
|
||||||
.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OverridingUtil.OverrideCompatibilityInfo.success();
|
return OverridingUtil.OverrideCompatibilityInfo.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int braceCount(CallableDescriptor a) {
|
private fun braceCount(a: CallableDescriptor): Int =
|
||||||
if (a instanceof PropertyDescriptor) {
|
when (a) {
|
||||||
return 0;
|
is PropertyDescriptor -> 0
|
||||||
}
|
is SimpleFunctionDescriptor -> 1
|
||||||
else if (a instanceof SimpleFunctionDescriptor) {
|
is ConstructorDescriptor -> 1
|
||||||
return 1;
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
else if (a instanceof ConstructorDescriptor) {
|
|
||||||
return 1;
|
class OverloadCompatibilityInfo(val isSuccess: Boolean, val message: String) {
|
||||||
}
|
companion object {
|
||||||
else {
|
|
||||||
throw new IllegalStateException();
|
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<FqNameUnsafe, ConstructorDescriptor>
|
||||||
|
): MultiMap<FqNameUnsafe, CallableMemberDescriptor> {
|
||||||
|
val packageMembersByName = MultiMap<FqNameUnsafe, CallableMemberDescriptor>()
|
||||||
|
|
||||||
private static final OverloadCompatibilityInfo SUCCESS = new OverloadCompatibilityInfo(true, "SUCCESS");
|
collectModulePackageMembersWithSameName(packageMembersByName, c.functions.values) {
|
||||||
|
scope, name ->
|
||||||
public static OverloadCompatibilityInfo success() {
|
scope.getFunctions(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuccess() {
|
collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values) {
|
||||||
return isSuccess;
|
scope, name ->
|
||||||
|
scope.getProperties(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS).filterIsInstance<CallableMemberDescriptor>()
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
// TODO handle constructor redeclarations in modules. See also https://youtrack.jetbrains.com/issue/KT-3632
|
||||||
return message;
|
packageMembersByName.putAllValues(constructorsInPackages)
|
||||||
|
|
||||||
|
return packageMembersByName
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun collectModulePackageMembersWithSameName(
|
||||||
|
packageMembersByName: MultiMap<FqNameUnsafe, CallableMemberDescriptor>,
|
||||||
|
interestingDescriptors: Collection<CallableMemberDescriptor>,
|
||||||
|
getMembersByName: (KtScope, Name) -> Collection<CallableMemberDescriptor>
|
||||||
|
) {
|
||||||
|
val observedFQNs = hashSetOf<FqNameUnsafe>()
|
||||||
|
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<CallableMemberDescriptor>
|
||||||
|
): Collection<CallableMemberDescriptor> {
|
||||||
|
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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,5 @@ End of files
|
|||||||
Compiling files:
|
Compiling files:
|
||||||
src/fun2.kt
|
src/fun2.kt
|
||||||
End of files
|
End of files
|
||||||
Cleaning output files:
|
COMPILATION FAILED
|
||||||
out/production/module/META-INF/module.kotlin_module
|
'public fun function(): kotlin.Unit' is already defined in test
|
||||||
out/production/module/test/Fun1Kt.class
|
|
||||||
End of files
|
|
||||||
Compiling files:
|
|
||||||
src/fun1.kt
|
|
||||||
End of files
|
|
||||||
@@ -6,6 +6,4 @@ Compiling files:
|
|||||||
src/prop2.kt
|
src/prop2.kt
|
||||||
End of files
|
End of files
|
||||||
COMPILATION FAILED
|
COMPILATION FAILED
|
||||||
Platform declaration clash: The following declarations have the same JVM signature (getProperty()I):
|
Redeclaration: property
|
||||||
fun <get-property>(): kotlin.Int
|
|
||||||
fun <get-property>(): kotlin.Int
|
|
||||||
Reference in New Issue
Block a user