diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/DelegatingResolvedCall.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/DelegatingResolvedCall.java index 70940f4362e..b61d811ab70 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/DelegatingResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/DelegatingResolvedCall.java @@ -87,6 +87,12 @@ public abstract class DelegatingResolvedCall imple return resolvedCall.getValueArguments(); } + @NotNull + @Override + public Map getUnsubstitutedValueArguments() { + return resolvedCall.getUnsubstitutedValueArguments(); + } + @NotNull @Override public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCall.java index a23dbea9533..d04c472bbfb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCall.java @@ -64,6 +64,10 @@ public interface ResolvedCall { @NotNull Map getValueArguments(); + /** Values (arguments) for value parameters, no type parameter substitution */ + @NotNull + Map getUnsubstitutedValueArguments(); + /** Values (arguments) for value parameters indexed by parameter index */ @Nullable List getValueArgumentsByIndex(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java index 5dc5cd8db37..8931a32fc2c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java @@ -84,6 +84,7 @@ public class ResolvedCallImpl implements MutableRe private final Map typeArguments = Maps.newLinkedHashMap(); private final Map valueArguments = Maps.newLinkedHashMap(); + private Map valueArgumentsBeforeSubstitution; private final MutableDataFlowInfoForArguments dataFlowInfoForArguments; private final Map argumentToParameterMap = Maps.newHashMap(); @@ -199,9 +200,9 @@ public class ResolvedCallImpl implements MutableRe substitutedParametersMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); } - Map originalValueArguments = Maps.newLinkedHashMap(valueArguments); + valueArgumentsBeforeSubstitution = Maps.newLinkedHashMap(valueArguments); valueArguments.clear(); - for (Map.Entry entry : originalValueArguments.entrySet()) { + for (Map.Entry entry : valueArgumentsBeforeSubstitution.entrySet()) { ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(entry.getKey().getOriginal()); assert substitutedVersion != null : entry.getKey(); valueArguments.put(substitutedVersion, entry.getValue()); @@ -263,6 +264,14 @@ public class ResolvedCallImpl implements MutableRe return valueArguments; } + @Override + @NotNull + public Map getUnsubstitutedValueArguments() { + // TODO We need unsubstituted value arguments to compare signatures for specificity when explicit type arguments are provided. + // Current implementation is questionable (mostly due to lack of well-defined contract for MutableResolvedCall). + return valueArgumentsBeforeSubstitution != null ? valueArgumentsBeforeSubstitution : valueArguments; + } + @Nullable @Override public List getValueArgumentsByIndex() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/CandidateCallWithArgumentMapping.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/CandidateCallWithArgumentMapping.kt index 980e7f58bb5..816fd0dd0a6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/CandidateCallWithArgumentMapping.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/CandidateCallWithArgumentMapping.kt @@ -17,15 +17,12 @@ package org.jetbrains.kotlin.resolve.calls.results import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument -import org.jetbrains.kotlin.types.BoundsSubstitutor import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.Variance - class CandidateCallWithArgumentMapping private constructor( val resolvedCall: MutableResolvedCall, @@ -35,8 +32,14 @@ class CandidateCallWithArgumentMapping private constr override fun toString(): String = "${resolvedCall.call}: $parametersWithDefaultValuesCount defaults in ${resolvedCall.candidateDescriptor}" - val resultingDescriptor: D - get() = resolvedCall.resultingDescriptor + val candidateDescriptor: D + get() = resolvedCall.candidateDescriptor + + val hasVarargs: Boolean + get() = candidateDescriptor.valueParameters.any { it.varargElementType != null } + + val typeParameters: List + get() = candidateDescriptor.original.typeParameters val argumentsCount: Int get() = argumentsToParameters.size @@ -44,13 +47,10 @@ class CandidateCallWithArgumentMapping private constr val argumentKeys: Collection get() = argumentsToParameters.keys - val callElement: KtElement - get() = resolvedCall.call.callElement - - val isGeneric: Boolean = resolvedCall.resultingDescriptor.original.typeParameters.isNotEmpty() + val isGeneric: Boolean = typeParameters.isNotEmpty() val extensionReceiverType: KotlinType? - get() = resultingDescriptor.extensionReceiverParameter?.type + get() = candidateDescriptor.extensionReceiverParameter?.type /** * Returns the type of a value that can be used in place of the corresponding parameter. @@ -69,14 +69,14 @@ class CandidateCallWithArgumentMapping private constr val argumentsToParameters = hashMapOf() var parametersWithDefaultValuesCount = 0 - for ((valueParameterDescriptor, resolvedValueArgument) in call.valueArguments.entries) { + for ((valueParameterDescriptor, resolvedValueArgument) in call.unsubstitutedValueArguments.entries) { if (resolvedValueArgument is DefaultValueArgument) { parametersWithDefaultValuesCount++ } else { val keys = resolvedArgumentToKeys(resolvedValueArgument) for (argumentKey in keys) { - argumentsToParameters[argumentKey] = valueParameterDescriptor + argumentsToParameters[argumentKey] = valueParameterDescriptor.original } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt index ca4f1e983e5..2abcf636058 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt @@ -136,7 +136,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { call2: CandidateCallWithArgumentMapping, discriminateGenerics: Boolean ): Boolean { - return tryCompareDescriptorsFromScripts(call1.resultingDescriptor, call2.resultingDescriptor) ?: + return tryCompareDescriptorsFromScripts(call1.candidateDescriptor, call2.candidateDescriptor) ?: compareCallsByUsedArguments(call1, call2, discriminateGenerics) } @@ -159,7 +159,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { if (isGeneric1 && isGeneric2) return false } - val typeParameters = call2.resolvedCall.resultingDescriptor.typeParameters + val typeParameters = call2.typeParameters val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl() var hasConstraints = false val typeSubstitutor = constraintSystemBuilder.registerTypeVariables(call1.resolvedCall.call.toHandle(), typeParameters) @@ -219,8 +219,8 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { call1: CandidateCallWithArgumentMapping, call2: CandidateCallWithArgumentMapping ): Boolean { - val hasVarargs1 = call1.resultingDescriptor.hasVarargs - val hasVarargs2 = call2.resultingDescriptor.hasVarargs + val hasVarargs1 = call1.hasVarargs + val hasVarargs2 = call2.hasVarargs if (hasVarargs1 && !hasVarargs2) return false if (!hasVarargs1 && hasVarargs2) return true diff --git a/compiler/testData/diagnostics/tests/generics/Projections.kt b/compiler/testData/diagnostics/tests/generics/Projections.kt index 7ee0af5c475..9dfc8a80d30 100644 --- a/compiler/testData/diagnostics/tests/generics/Projections.kt +++ b/compiler/testData/diagnostics/tests/generics/Projections.kt @@ -20,7 +20,7 @@ class Inv() { fun testInOut() { In().f("1"); (null as In<in String>).f("1") - (null as In<*>).f("1") // Wrong Arg + (null as In<*>).f("1") // Wrong Arg In().f(1); (null as In<in String>).f(1) diff --git a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.kt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.kt new file mode 100644 index 00000000000..2a33eb00bf6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -REDUNDANT_PROJECTION + +class In() { + fun f(t : T) {} + fun f(t : Int) = t +} + +fun test1(x: In): Unit = x.f("1") +fun test2(x: In): Unit = x.f("1") +fun test3(x: In<out String>): Unit = x.f("1") +fun test4(x: In<*>): Unit = x.f("1") \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.txt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.txt new file mode 100644 index 00000000000..fbe8789f180 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.txt @@ -0,0 +1,15 @@ +package + +public fun test1(/*0*/ x: In): kotlin.Unit +public fun test2(/*0*/ x: In): kotlin.Unit +public fun test3(/*0*/ x: In): kotlin.Unit +public fun test4(/*0*/ x: In<*>): kotlin.Unit + +public final class In { + public constructor In() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun f(/*0*/ t: T): kotlin.Unit + public final fun f(/*0*/ t: kotlin.Int): kotlin.Int + 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/resolve/overloadConflicts/kt10640.kt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt new file mode 100644 index 00000000000..50b30912c56 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt @@ -0,0 +1,9 @@ +interface AutoCloseable +interface Closeable : AutoCloseable + +fun T1.myUse(f: (T1) -> R1): R1 = f(this) +fun T2.myUse(f: (T2) -> R2): R2 = f(this) + +fun test1(x: Closeable) = x.myUse { 42 } +fun test2(x: Closeable) = x.myUse { 42 } +fun test3(x: Closeable) = x.myUse<AutoCloseable, Int> { 42 } // TODO KT-10681 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.txt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.txt new file mode 100644 index 00000000000..c82afee66e2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.txt @@ -0,0 +1,19 @@ +package + +public fun test1(/*0*/ x: Closeable): kotlin.Int +public fun test2(/*0*/ x: Closeable): kotlin.Int +public fun test3(/*0*/ x: Closeable): kotlin.Int +public fun T1.myUse(/*0*/ f: (T1) -> R1): R1 +public fun T2.myUse(/*0*/ f: (T2) -> R2): R2 + +public interface AutoCloseable { + 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 +} + +public interface Closeable : AutoCloseable { + 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/secondaryConstructors/constructorCallType.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/constructorCallType.kt index 2db834b529a..0237b353ad3 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/constructorCallType.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/constructorCallType.kt @@ -17,8 +17,8 @@ val y2: B = B("") val y3: B = B(1) val y4: B = B("") -val y5: B = B(1) -val y6: B = B("") // TODO: doesn't work here but ok on y8 +val y5: B = B(1) +val y6: B = B("") val y7: B = B(1) val y8: B = B("") diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/generics2.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/generics2.kt index 550319f69b8..03dbd57b149 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/generics2.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/generics2.kt @@ -6,9 +6,9 @@ class A0 { constructor(x: T1, y: T2, z: T2): this(x, 1) // ok, delegates to constructor(x: T1, y: Int) - constructor(x: T1, y: Int): this(x, "") + constructor(x: T1, y: Int): this(x, "") constructor(x: T1): this(x, 1) - constructor(x: T1, y: T2, z: String): this(y, x) + constructor(x: T1, y: T2, z: String): this(y, x) } class A1 : B { diff --git a/compiler/testData/resolve/Projections.resolve b/compiler/testData/resolve/Projections.resolve index 3831c12fdda..42232750344 100644 --- a/compiler/testData/resolve/Projections.resolve +++ b/compiler/testData/resolve/Projections.resolve @@ -18,8 +18,8 @@ class Inv() { fun testInOut() { In().`In.f:T->Unit`f("1"); (return as In).`In.f:T->Unit`f("1"); - (return as In).`In.f:T->Unit`f("1") - (return as In<*>).`In.f:T->Unit`f("1"); + (return as In).`!null`f("1") + (return as In<*>).`!null`f("1"); In().`In.f:Int->Int`f(1); (return as In).`In.f:Int->Int`f(1); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 68fc8ba4e7a..d97013c60e5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13952,12 +13952,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("genericWithProjection.kt") + public void testGenericWithProjection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.kt"); + doTest(fileName); + } + @TestMetadata("kt10472.kt") public void testKt10472() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10472.kt"); doTest(fileName); } + @TestMetadata("kt10640.kt") + public void testKt10640() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt"); + doTest(fileName); + } + @TestMetadata("numberOfDefaults.kt") public void testNumberOfDefaults() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/numberOfDefaults.kt");