From 4b3290dd8c0efe4c16e0f487d197348ad5643502 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 29 Dec 2015 12:41:52 +0300 Subject: [PATCH] Check specificity relation for generant types of the constraint system. Otherwise we can't properly chose between 'dynamic' and generic type. --- .../results/OverloadingConflictResolver.kt | 27 ++++++++++++------- .../dynamicTypes/dynamicVsGeneric.kt | 9 +++++++ .../dynamicTypes/dynamicVsGeneric.txt | 26 ++++++++++++++++++ .../DiagnosticsTestWithJsStdLibGenerated.java | 6 +++++ 4 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.txt 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 0cdf09e2be5..39fd761f4bb 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 @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition -import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.* import org.jetbrains.kotlin.resolve.calls.inference.toHandle import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -149,8 +149,10 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { if (discriminateGenerics) { val isGeneric1 = call1.isGeneric val isGeneric2 = call2.isGeneric + // generic loses to non-generic if (isGeneric1 && !isGeneric2) return false if (!isGeneric1 && isGeneric2) return true + // two generics are non-comparable if (isGeneric1 && isGeneric2) return false } @@ -167,17 +169,20 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { return false } } + else if (isDefinitelyLessSpecificByTypeSpecificity(type1, type2)) { + return false + } else { + hasConstraints = true val substitutedType2 = typeSubstitutor.safeSubstitute(type2, Variance.INVARIANT) constraintSystemBuilder.addSubtypeConstraint(type1, substitutedType2, constraintPosition) - hasConstraints = true } return true } val extensionReceiverType1 = call1.getExtensionReceiverType(false) val extensionReceiverType2 = call2.getExtensionReceiverType(false) - if (!compareTypesAndUpdateConstraints(extensionReceiverType1, extensionReceiverType2, ConstraintPositionKind.RECEIVER_POSITION.position())) { + if (!compareTypesAndUpdateConstraints(extensionReceiverType1, extensionReceiverType2, RECEIVER_POSITION.position())) { return false } @@ -190,7 +195,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { val type1 = call1.getValueParameterType(argumentKey, false) val type2 = call2.getValueParameterType(argumentKey, false) - if (!compareTypesAndUpdateConstraints(type1, type2, ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(index++))) { + if (!compareTypesAndUpdateConstraints(type1, type2, VALUE_PARAMETER_POSITION.position(index++))) { return false } } @@ -306,16 +311,18 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) { if (!isSubtype) return false - val sThanG = specific.getSpecificityRelationTo(general) - val gThanS = general.getSpecificityRelationTo(specific) - if (sThanG == Specificity.Relation.LESS_SPECIFIC && - gThanS != Specificity.Relation.LESS_SPECIFIC) { - return false - } + if (isDefinitelyLessSpecificByTypeSpecificity(specific, general)) return false return true } + private fun isDefinitelyLessSpecificByTypeSpecificity(specific: KotlinType, general: KotlinType): Boolean { + val sThanG = specific.getSpecificityRelationTo(general) + val gThanS = general.getSpecificityRelationTo(specific) + return sThanG == Specificity.Relation.LESS_SPECIFIC && + gThanS != Specificity.Relation.LESS_SPECIFIC + } + private fun numericTypeMoreSpecific(specific: KotlinType, general: KotlinType): Boolean { val _double = builtIns.doubleType val _float = builtIns.floatType diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt new file mode 100644 index 00000000000..3fa50ae9805 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt @@ -0,0 +1,9 @@ +object X1 +object X2 + +class Inv + +fun dynamic.foo() = X1 +fun Inv.foo() = X2 + +fun test(): X2 = Inv().foo() diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.txt new file mode 100644 index 00000000000..f6ca4acbf9b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.txt @@ -0,0 +1,26 @@ +package + +public fun test(): X2 +public fun Inv.foo(): X2 +public fun dynamic.foo(): X1 + +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 +} + +public object X1 { + private constructor X1() + 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 object X2 { + private constructor X2() + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index 86aca478415..00d875698db 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -115,6 +115,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("dynamicVsGeneric.kt") + public void testDynamicVsGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt"); + doTest(fileName); + } + @TestMetadata("extensionVals.kt") public void testExtensionVals() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVals.kt");