diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt index 6a9d54503ce..ab4c9295471 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadUtil.kt @@ -22,15 +22,17 @@ 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.INCOMPATIBLE +import org.jetbrains.kotlin.resolve.calls.inference.CallHandle +import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem +import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION +import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeIntersector +import org.jetbrains.kotlin.types.* 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. */ @@ -41,22 +43,55 @@ object OverloadUtil { if (aCategory != bCategory) return true if (a !is CallableDescriptor || b !is CallableDescriptor) return false + return checkOverloadability(a, b) + } + + private fun checkOverloadability(a: CallableDescriptor, b: CallableDescriptor): Boolean { + if (a.hasLowPriorityInOverloadResolution() != b.hasLowPriorityInOverloadResolution()) return true + if (a.typeParameters.isEmpty() != b.typeParameters.isEmpty()) return true + OverridingUtil.checkReceiverAndParameterCount(a, b)?.let { return it.result == INCOMPATIBLE } val aValueParameters = OverridingUtil.compiledValueParameters(a) val bValueParameters = OverridingUtil.compiledValueParameters(b) + val aTypeParameters = a.typeParameters + val bTypeParameters = b.typeParameters + + val avsbConstraintsBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl() + val avsbTypeSubstitutor = avsbConstraintsBuilder.registerTypeVariables(CallHandle.NONE, aTypeParameters) + val bvsaConstraintsBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl() + val bvsaTypeSubstitutor = bvsaConstraintsBuilder.registerTypeVariables(CallHandle.NONE, bTypeParameters) + + var constraintIndex = 0 + for ((aType, bType) in aValueParameters.zip(bValueParameters)) { - // TODO: check type parameters, create a substitution and compare parameter types according to it, like in OverridingUtil - val superValueParameterType = aType.upperBound - val subValueParameterType = bType.upperBound - if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) || - oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) { + if (aType.isError || bType.isError) return true + + if (oneMoreSpecificThanAnother(bType, aType)) return true + + if (!TypeUtils.dependsOnTypeParameters(aType, aTypeParameters) + && !TypeUtils.dependsOnTypeParameters(bType, bTypeParameters) + && !KotlinTypeChecker.DEFAULT.equalTypes(aType, bType)) { return true } + + constraintIndex++ + val aTypeSubstituted = avsbTypeSubstitutor.safeSubstitute(aType, Variance.INVARIANT) + val bTypeSubstituted = bvsaTypeSubstitutor.safeSubstitute(bType, Variance.INVARIANT) + avsbConstraintsBuilder.addSubtypeConstraint(bType, aTypeSubstituted, + VALUE_PARAMETER_POSITION.position(constraintIndex)) + bvsaConstraintsBuilder.addSubtypeConstraint(aType, bTypeSubstituted, + VALUE_PARAMETER_POSITION.position(constraintIndex)) } - return false + if (constraintIndex == 0) return false + + avsbConstraintsBuilder.fixVariables() + bvsaConstraintsBuilder.fixVariables() + + return avsbConstraintsBuilder.build().status.hasContradiction() + || bvsaConstraintsBuilder.build().status.hasContradiction() } private enum class DeclarationCategory { @@ -85,16 +120,6 @@ object OverloadUtil { error("Unexpected declaration kind: $a") } - private val KotlinType.upperBound: KotlinType - get() { - val classifier = constructor.declarationDescriptor - return when (classifier) { - is ClassDescriptor -> this - is TypeParameterDescriptor -> TypeIntersector.getUpperBoundsAsType(classifier) - else -> error("Unknown type constructor: $this") - } - } - @JvmStatic fun groupModulePackageMembersByFqName( c: BodiesResolveContext, overloadFilter: OverloadFilter diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/erasure/typeParameterWithBound.kt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/erasure/typeParameterWithBound.kt index ab5c6ef5fe2..71c3d36df23 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/erasure/typeParameterWithBound.kt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/erasure/typeParameterWithBound.kt @@ -2,5 +2,5 @@ interface Foo -fun foo(x: T): T {null!!} -fun foo(x: Foo): Foo {null!!} \ No newline at end of file +fun foo(x: T): T {null!!} +fun foo(x: Foo): Foo {null!!} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt b/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt index 53897603e81..f8798923c3d 100644 --- a/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt +++ b/compiler/testData/diagnostics/tests/inline/binaryExpressions/mathOperations.kt @@ -1,4 +1,4 @@ -// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -CONFLICTING_JVM_DECLARATIONS +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -CONFLICTING_JVM_DECLARATIONS -CONFLICTING_OVERLOADS operator fun Function1.minus(p: Function1) { } diff --git a/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.kt b/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.kt new file mode 100644 index 00000000000..a5ae854223d --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.kt @@ -0,0 +1,34 @@ +fun test1(x: List) = x +fun test1(x: List) = x + +fun List.test1a() {} +fun List.test1a() {} + +fun test2(x: List) = x +fun test2(x: List) = x + +fun List.test2a() {} +fun List.test2a() {} + +fun test3(x: List) = x +fun test3(x: List) = x + +fun List.test3a() {} +fun List.test3a() {} + +fun test4(x: Map) = x +fun test4(x: Map) = x + +fun Map.test4a() {} +fun Map.test4a() {} + +class Inv + +fun test5(x: Inv) = x +fun test5(x: Inv) = x + +fun test6(x: Array) = x +fun test6(x: Array) = x + +fun test7(x: Inv) = x +fun Inv.test7() {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.txt b/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.txt new file mode 100644 index 00000000000..99fddc47739 --- /dev/null +++ b/compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.txt @@ -0,0 +1,31 @@ +package + +public fun test1(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test1(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test2(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test2(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test3(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test3(/*0*/ x: kotlin.collections.List): kotlin.collections.List +public fun test4(/*0*/ x: kotlin.collections.Map): kotlin.collections.Map +public fun test4(/*0*/ x: kotlin.collections.Map): kotlin.collections.Map +public fun test5(/*0*/ x: Inv): Inv +public fun test5(/*0*/ x: Inv): Inv +public fun test6(/*0*/ x: kotlin.Array): kotlin.Array +public fun test6(/*0*/ x: kotlin.Array): kotlin.Array +public fun test7(/*0*/ x: Inv): Inv +public fun kotlin.collections.List.test1a(): kotlin.Unit +public fun kotlin.collections.List.test1a(): kotlin.Unit +public fun kotlin.collections.List.test2a(): kotlin.Unit +public fun kotlin.collections.List.test2a(): kotlin.Unit +public fun kotlin.collections.List.test3a(): kotlin.Unit +public fun kotlin.collections.List.test3a(): kotlin.Unit +public fun kotlin.collections.Map.test4a(): kotlin.Unit +public fun kotlin.collections.Map.test4a(): kotlin.Unit +public fun Inv.test7(): kotlin.Unit + +public final class Inv { + public constructor Inv() + 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/testData/diagnostics/tests/overload/ConflictingOverloadsIdenticalFunsTPInClass.kt b/compiler/testData/diagnostics/tests/overload/ConflictingOverloadsIdenticalFunsTPInClass.kt index 4663e891043..c2ab4d46377 100644 --- a/compiler/testData/diagnostics/tests/overload/ConflictingOverloadsIdenticalFunsTPInClass.kt +++ b/compiler/testData/diagnostics/tests/overload/ConflictingOverloadsIdenticalFunsTPInClass.kt @@ -1,4 +1,4 @@ class Aaa() { - fun f() = 1 - fun

f() = 1 + fun f() = 1 + fun

f() = 1 } diff --git a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/withVariance.kt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/withVariance.kt index c35e9d24789..55475c1f810 100644 --- a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/withVariance.kt +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/withVariance.kt @@ -3,7 +3,7 @@ object X2 class A -fun A.foo() = X1 -fun A.foo() = X2 +fun A.foo() = X1 +fun A.foo() = X2 fun A.test() = foo() // TODO fix constraint system \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 435c50ee971..25946ef8018 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -11697,6 +11697,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/overload"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("ConflictingOlverloadsGenericFunctions.kt") + public void testConflictingOlverloadsGenericFunctions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/ConflictingOlverloadsGenericFunctions.kt"); + doTest(fileName); + } + @TestMetadata("ConflictingOverloadsFunsDifferentReturnInClass.kt") public void testConflictingOverloadsFunsDifferentReturnInClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/ConflictingOverloadsFunsDifferentReturnInClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/types/KotlinOverloadTest.java b/compiler/tests/org/jetbrains/kotlin/types/KotlinOverloadTest.java index a2513070dfc..b354de1b721 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/KotlinOverloadTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/KotlinOverloadTest.java @@ -96,18 +96,15 @@ public class KotlinOverloadTest extends KotlinTestWithEnvironment { "fun a(a : Int?) : Int", "fun a(a : Int) : Int"); - assertNotOverloadable( + assertOverloadable( "fun a(a : Int) : Int", "fun a(a : Int) : Int"); - // TODO - /* - assertOverloadable( + assertNotOverloadable( "fun a(a : T1) : T1", "fun a(a : T) : T"); - */ - assertOverloadable( + assertNotOverloadable( "fun a(a : T1) : T1", "fun a(a : Y) : T"); @@ -115,30 +112,27 @@ public class KotlinOverloadTest extends KotlinTestWithEnvironment { "fun a(a : T1) : X", "fun a(a : T) : T"); - // TODO - /* assertNotOverloadable( "fun > a(a : Array) : T1", "fun > a(a : Array) : T"); - */ - assertOverloadable( + assertNotOverloadable( "fun > a(a : Array) : T1", "fun > a(a : Array) : T"); - assertOverloadable( + assertNotOverloadable( "fun > a(a : Array) : T1", "fun > a(a : Array) : T"); - assertOverloadable( + assertNotOverloadable( "fun > a(a : Array) : T1", "fun > a(a : Array) : T"); - assertOverloadable( + assertNotOverloadable( "fun > a(a : Array) : T1", "fun > a(a : Array) : T"); - assertOverloadable( + assertNotOverloadable( "fun > a(a : Array<*>) : T1", "fun > a(a : Array) : T");