Check conflicting overloads for generic signatures.
This commit is contained in:
@@ -22,15 +22,17 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE
|
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.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeIntersector
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother
|
|
||||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||||
|
|
||||||
object OverloadUtil {
|
object OverloadUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does not check names.
|
* Does not check names.
|
||||||
*/
|
*/
|
||||||
@@ -41,22 +43,55 @@ object OverloadUtil {
|
|||||||
if (aCategory != bCategory) return true
|
if (aCategory != bCategory) return true
|
||||||
if (a !is CallableDescriptor || b !is CallableDescriptor) return false
|
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 }
|
OverridingUtil.checkReceiverAndParameterCount(a, b)?.let { return it.result == INCOMPATIBLE }
|
||||||
|
|
||||||
val aValueParameters = OverridingUtil.compiledValueParameters(a)
|
val aValueParameters = OverridingUtil.compiledValueParameters(a)
|
||||||
val bValueParameters = OverridingUtil.compiledValueParameters(b)
|
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)) {
|
for ((aType, bType) in aValueParameters.zip(bValueParameters)) {
|
||||||
// TODO: check type parameters, create a substitution and compare parameter types according to it, like in OverridingUtil
|
if (aType.isError || bType.isError) return true
|
||||||
val superValueParameterType = aType.upperBound
|
|
||||||
val subValueParameterType = bType.upperBound
|
if (oneMoreSpecificThanAnother(bType, aType)) return true
|
||||||
if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) ||
|
|
||||||
oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
|
if (!TypeUtils.dependsOnTypeParameters(aType, aTypeParameters)
|
||||||
|
&& !TypeUtils.dependsOnTypeParameters(bType, bTypeParameters)
|
||||||
|
&& !KotlinTypeChecker.DEFAULT.equalTypes(aType, bType)) {
|
||||||
return true
|
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 {
|
private enum class DeclarationCategory {
|
||||||
@@ -85,16 +120,6 @@ object OverloadUtil {
|
|||||||
error("Unexpected declaration kind: $a")
|
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(
|
@JvmStatic fun groupModulePackageMembersByFqName(
|
||||||
c: BodiesResolveContext,
|
c: BodiesResolveContext,
|
||||||
overloadFilter: OverloadFilter
|
overloadFilter: OverloadFilter
|
||||||
|
|||||||
Vendored
+2
-2
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
interface Foo
|
interface Foo
|
||||||
|
|
||||||
<!CONFLICTING_OVERLOADS!>fun <T: Foo> foo(x: T): T<!> {null!!}
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T: Foo> foo(x: T): T<!> {null!!}
|
||||||
<!CONFLICTING_OVERLOADS!>fun foo(x: Foo): Foo<!> {null!!}
|
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(x: Foo): Foo<!> {null!!}
|
||||||
+1
-1
@@ -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 <T, U> Function1<T, U>.minus(p: Function1<T, U>) {
|
operator fun <T, U> Function1<T, U>.minus(p: Function1<T, U>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
<!CONFLICTING_OVERLOADS!>fun <T1> test1(x: List<T1>)<!> = x
|
||||||
|
<!CONFLICTING_OVERLOADS!>fun <T2> test1(x: List<T2>)<!> = x
|
||||||
|
|
||||||
|
<!CONFLICTING_OVERLOADS!>fun <T1> List<T1>.test1a()<!> {}
|
||||||
|
<!CONFLICTING_OVERLOADS!>fun <T2> List<T2>.test1a()<!> {}
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T> test2(x: List<T>)<!> = x
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun test2(x: List<String>)<!> = x
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T> List<T>.test2a()<!> {}
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun List<String>.test2a()<!> {}
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T : Any> test3(x: List<T>)<!> = x
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun test3(x: List<Any>)<!> = x
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T : Any> List<T>.test3a()<!> {}
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun List<Any>.test3a()<!> {}
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T> test4(x: Map<T, T>)<!> = x
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <K, V> test4(x: Map<K, V>)<!> = x
|
||||||
|
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <T> Map<T, T>.test4a()<!> {}
|
||||||
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <K, V> Map<K, V>.test4a()<!> {}
|
||||||
|
|
||||||
|
class Inv<T>
|
||||||
|
|
||||||
|
<!CONFLICTING_OVERLOADS!>fun <T> test5(x: Inv<T>)<!> = x
|
||||||
|
<!CONFLICTING_OVERLOADS!>fun <T> test5(x: Inv<out T>)<!> = x
|
||||||
|
|
||||||
|
fun <T> test6(x: Array<T>) = x
|
||||||
|
fun test6(x: Array<String>) = x
|
||||||
|
|
||||||
|
fun <T> test7(x: Inv<T>) = x
|
||||||
|
fun <T> Inv<T>.test7() {}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ T1> test1(/*0*/ x: kotlin.collections.List<T1>): kotlin.collections.List<T1>
|
||||||
|
public fun </*0*/ T2> test1(/*0*/ x: kotlin.collections.List<T2>): kotlin.collections.List<T2>
|
||||||
|
public fun </*0*/ T> test2(/*0*/ x: kotlin.collections.List<T>): kotlin.collections.List<T>
|
||||||
|
public fun test2(/*0*/ x: kotlin.collections.List<kotlin.String>): kotlin.collections.List<kotlin.String>
|
||||||
|
public fun </*0*/ T : kotlin.Any> test3(/*0*/ x: kotlin.collections.List<T>): kotlin.collections.List<T>
|
||||||
|
public fun test3(/*0*/ x: kotlin.collections.List<kotlin.Any>): kotlin.collections.List<kotlin.Any>
|
||||||
|
public fun </*0*/ K, /*1*/ V> test4(/*0*/ x: kotlin.collections.Map<K, V>): kotlin.collections.Map<K, V>
|
||||||
|
public fun </*0*/ T> test4(/*0*/ x: kotlin.collections.Map<T, T>): kotlin.collections.Map<T, T>
|
||||||
|
public fun </*0*/ T> test5(/*0*/ x: Inv<T>): Inv<T>
|
||||||
|
public fun </*0*/ T> test5(/*0*/ x: Inv<out T>): Inv<out T>
|
||||||
|
public fun </*0*/ T> test6(/*0*/ x: kotlin.Array<T>): kotlin.Array<T>
|
||||||
|
public fun test6(/*0*/ x: kotlin.Array<kotlin.String>): kotlin.Array<kotlin.String>
|
||||||
|
public fun </*0*/ T> test7(/*0*/ x: Inv<T>): Inv<T>
|
||||||
|
public fun </*0*/ T1> kotlin.collections.List<T1>.test1a(): kotlin.Unit
|
||||||
|
public fun </*0*/ T2> kotlin.collections.List<T2>.test1a(): kotlin.Unit
|
||||||
|
public fun </*0*/ T> kotlin.collections.List<T>.test2a(): kotlin.Unit
|
||||||
|
public fun kotlin.collections.List<kotlin.String>.test2a(): kotlin.Unit
|
||||||
|
public fun </*0*/ T : kotlin.Any> kotlin.collections.List<T>.test3a(): kotlin.Unit
|
||||||
|
public fun kotlin.collections.List<kotlin.Any>.test3a(): kotlin.Unit
|
||||||
|
public fun </*0*/ K, /*1*/ V> kotlin.collections.Map<K, V>.test4a(): kotlin.Unit
|
||||||
|
public fun </*0*/ T> kotlin.collections.Map<T, T>.test4a(): kotlin.Unit
|
||||||
|
public fun </*0*/ T> Inv<T>.test7(): kotlin.Unit
|
||||||
|
|
||||||
|
public final class Inv</*0*/ T> {
|
||||||
|
public constructor Inv</*0*/ T>()
|
||||||
|
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
|
||||||
|
}
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
class Aaa() {
|
class Aaa() {
|
||||||
<!CONFLICTING_OVERLOADS!>fun f()<!> = 1
|
<!CONFLICTING_JVM_DECLARATIONS!>fun f()<!> = 1
|
||||||
<!CONFLICTING_OVERLOADS!>fun <P> f()<!> = 1
|
<!CONFLICTING_JVM_DECLARATIONS!>fun <P> f()<!> = 1
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@ object X2
|
|||||||
|
|
||||||
class A<T>
|
class A<T>
|
||||||
|
|
||||||
fun <T1> A<T1>.foo() = X1
|
<!CONFLICTING_OVERLOADS!>fun <T1> A<T1>.foo()<!> = X1
|
||||||
fun <T2> A<out T2>.foo() = X2
|
<!CONFLICTING_OVERLOADS!>fun <T2> A<out T2>.foo()<!> = X2
|
||||||
|
|
||||||
fun <T> A<out T>.test() = <!CANNOT_COMPLETE_RESOLVE!>foo<!>() // TODO fix constraint system
|
fun <T> A<out T>.test() = <!CANNOT_COMPLETE_RESOLVE!>foo<!>() // TODO fix constraint system
|
||||||
@@ -11697,6 +11697,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/overload"), Pattern.compile("^(.+)\\.kt$"), true);
|
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")
|
@TestMetadata("ConflictingOverloadsFunsDifferentReturnInClass.kt")
|
||||||
public void testConflictingOverloadsFunsDifferentReturnInClass() throws Exception {
|
public void testConflictingOverloadsFunsDifferentReturnInClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/ConflictingOverloadsFunsDifferentReturnInClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/overload/ConflictingOverloadsFunsDifferentReturnInClass.kt");
|
||||||
|
|||||||
@@ -96,18 +96,15 @@ public class KotlinOverloadTest extends KotlinTestWithEnvironment {
|
|||||||
"fun a(a : Int?) : Int",
|
"fun a(a : Int?) : Int",
|
||||||
"fun a(a : Int) : Int");
|
"fun a(a : Int) : Int");
|
||||||
|
|
||||||
assertNotOverloadable(
|
assertOverloadable(
|
||||||
"fun <T> a(a : Int) : Int",
|
"fun <T> a(a : Int) : Int",
|
||||||
"fun a(a : Int) : Int");
|
"fun a(a : Int) : Int");
|
||||||
|
|
||||||
// TODO
|
assertNotOverloadable(
|
||||||
/*
|
|
||||||
assertOverloadable(
|
|
||||||
"fun <T1, X : T1> a(a : T1) : T1",
|
"fun <T1, X : T1> a(a : T1) : T1",
|
||||||
"fun <T, Y> a(a : T) : T");
|
"fun <T, Y> a(a : T) : T");
|
||||||
*/
|
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : T1> a(a : T1) : T1",
|
"fun <T1, X : T1> a(a : T1) : T1",
|
||||||
"fun <T, Y : T> a(a : Y) : T");
|
"fun <T, Y : T> a(a : Y) : T");
|
||||||
|
|
||||||
@@ -115,30 +112,27 @@ public class KotlinOverloadTest extends KotlinTestWithEnvironment {
|
|||||||
"fun <T1, X : T1> a(a : T1) : X",
|
"fun <T1, X : T1> a(a : T1) : X",
|
||||||
"fun <T, Y : T> a(a : T) : T");
|
"fun <T, Y : T> a(a : T) : T");
|
||||||
|
|
||||||
// TODO
|
|
||||||
/*
|
|
||||||
assertNotOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
||||||
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
||||||
*/
|
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<T1>> a(a : Array<in T1>) : T1",
|
"fun <T1, X : Array<T1>> a(a : Array<in T1>) : T1",
|
||||||
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
||||||
"fun <T, Y : Array<in T>> a(a : Array<in T>) : T");
|
"fun <T, Y : Array<in T>> a(a : Array<in T>) : T");
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
||||||
"fun <T, Y : Array<*>> a(a : Array<in T>) : T");
|
"fun <T, Y : Array<*>> a(a : Array<in T>) : T");
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
"fun <T1, X : Array<out T1>> a(a : Array<in T1>) : T1",
|
||||||
"fun <T, Y : Array<out T>> a(a : Array<out T>) : T");
|
"fun <T, Y : Array<out T>> a(a : Array<out T>) : T");
|
||||||
|
|
||||||
assertOverloadable(
|
assertNotOverloadable(
|
||||||
"fun <T1, X : Array<out T1>> a(a : Array<*>) : T1",
|
"fun <T1, X : Array<out T1>> a(a : Array<*>) : T1",
|
||||||
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
"fun <T, Y : Array<out T>> a(a : Array<in T>) : T");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user