From 013dd7261e06042de36fe246ef510325c044ed0c Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 28 Sep 2014 08:48:48 +0400 Subject: [PATCH] Extensible specificity expressed as a type capability --- .../results/OverloadingConflictResolver.java | 20 ++++--------- .../platformTypes/intVsIntegerAmbiguity.kt | 5 ++++ .../methodCall/overloadingForSubclass.kt | 30 +++++++++++++++++++ .../methodCall/overloadingForSubclass.txt | 12 ++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 6 ++++ .../java/lazy/types/LazyJavaTypeResolver.kt | 20 +++++++++++-- .../jet/lang/types/TypeCapabilities.kt | 15 ++++++++-- 7 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.kt create mode 100644 compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java index 05f0a91d569..79267cd3448 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java @@ -25,9 +25,7 @@ import org.jetbrains.jet.lang.resolve.OverrideResolver; import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; -import org.jetbrains.jet.lang.types.BoundsSubstitutor; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -240,21 +238,15 @@ public class OverloadingConflictResolver { private boolean typeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { boolean isSubtype = JetTypeChecker.DEFAULT.isSubtypeOf(specific, general) || - numericTypeMoreSpecific(specific, general); + numericTypeMoreSpecific(specific, general); + if (!isSubtype) return false; - boolean specificIsFlexible = specific.isFlexible(); - boolean generalIsFlexible = general.isFlexible(); - - if (specificIsFlexible && !generalIsFlexible) { - // Int! lessSpecific Int - // Int! >< Int? + Specificity.Relation sThanG = TypesPackage.getSpecificityRelationTo(specific, general); + Specificity.Relation gThanS = TypesPackage.getSpecificityRelationTo(general, specific); + if (sThanG == Specificity.Relation.LESS_SPECIFIC && gThanS != Specificity.Relation.LESS_SPECIFIC) { return false; } - else if (!specificIsFlexible && generalIsFlexible) { - // Int? >< Int! - if (specific.isNullable()) return false; - } return true; } diff --git a/compiler/testData/diagnostics/tests/platformTypes/intVsIntegerAmbiguity.kt b/compiler/testData/diagnostics/tests/platformTypes/intVsIntegerAmbiguity.kt index 1f4e96bc6e2..5955ac3bf7b 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/intVsIntegerAmbiguity.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/intVsIntegerAmbiguity.kt @@ -9,6 +9,8 @@ public class J { public interface B {} public static B foo(Integer s); + + public static Integer getInteger(); } // FILE: k.kt @@ -25,5 +27,8 @@ fun test(i: Int, ni: Int?) { foo(i) : J.A J.foo(ni) : J.B foo(ni) + + foo(J.getInteger()) + J.foo(J.getInteger()) } diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.kt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.kt new file mode 100644 index 00000000000..fdef1520e3f --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.kt @@ -0,0 +1,30 @@ +// FILE: p/Super.java +package p; + +public interface Super {} + +// FILE: p/Sub.java +package p; + +public interface Sub extends Super {} + +// FILE: p/Util.java + +package p; + +public abstract class Util { + public abstract void foo(String s, Super sup) + public void foo(String s, Sub sub) {} +} + +// FILE: k.kt + +import p.* + +class C: Util() { + override fun foo(s: String, sub: Super) {} +} + +fun foo(sub: Sub) { + C().foo("", sub) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.txt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.txt new file mode 100644 index 00000000000..e5d0e605ebf --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.txt @@ -0,0 +1,12 @@ +package + +internal fun foo(/*0*/ sub: p.Sub): kotlin.Unit + +internal final class C : p.Util { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(/*0*/ s: kotlin.String, /*1*/ sub: p.Super): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun foo(/*0*/ s: kotlin.String!, /*1*/ sub: p.Sub!): kotlin.Unit + 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/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 8d5b9e2915f..5352c710ce8 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -7863,6 +7863,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("overloadingForSubclass.kt") + public void testOverloadingForSubclass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall/overloadingForSubclass.kt"); + doTest(fileName); + } + @TestMetadata("sam.kt") public void testSam() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall/sam.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt index cb4738618df..3d20ecd84fb 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt @@ -34,8 +34,6 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker import org.jetbrains.jet.lang.resolve.java.PLATFORM_TYPES import org.jetbrains.jet.lang.resolve.java.lazy.types.Flexibility.* import org.jetbrains.jet.lang.descriptors.annotations.Annotations -import org.jetbrains.jet.lang.resolve.name.FqName -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames class LazyJavaTypeResolver( @@ -273,7 +271,7 @@ class LazyJavaTypeResolver( public open class FlexibleJavaClassifierType protected ( lowerBound: JetType, upperBound: JetType - ) : DelegatingFlexibleType(lowerBound, upperBound), CustomTypeVariable { + ) : DelegatingFlexibleType(lowerBound, upperBound), CustomTypeVariable, Specificity { public class object { public fun create(lowerBound: JetType, upperBound: JetType): JetType { if (lowerBound == upperBound) return lowerBound @@ -294,6 +292,22 @@ class LazyJavaTypeResolver( return if (replacement.isFlexible()) replacement else FlexibleJavaClassifierType(TypeUtils.makeNotNullable(replacement), TypeUtils.makeNullable(replacement)) } + + override fun getSpecificityRelationTo(otherType: JetType): Specificity.Relation { + // For primitive types we have to take care of the case when there are two overloaded methods like + // foo(int) and foo(Integer) + // if we do not discriminate one of them, any call to foo(kotlin.Int) will result in overload resolution ambiguity + // so, for such cases, we discriminate Integer in favour of int + if (!KotlinBuiltIns.getInstance().isPrimitiveType(otherType) || !KotlinBuiltIns.getInstance().isPrimitiveType(getLowerBound())) { + return Specificity.Relation.DONT_KNOW + } + // Int! >< Int? + if (otherType.isFlexible()) return Specificity.Relation.DONT_KNOW + // Int? >< Int! + if (otherType.isNullable()) return Specificity.Relation.DONT_KNOW + // Int! lessSpecific Int + return Specificity.Relation.LESS_SPECIFIC + } } /* diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeCapabilities.kt b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeCapabilities.kt index 125f30cdf64..8c186980f94 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeCapabilities.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeCapabilities.kt @@ -16,6 +16,17 @@ package org.jetbrains.jet.lang.types -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +public trait TypeCapability -public trait TypeCapability \ No newline at end of file +public trait Specificity : TypeCapability { + + public enum class Relation { + LESS_SPECIFIC + MORE_SPECIFIC + DONT_KNOW + } + + public fun getSpecificityRelationTo(otherType: JetType): Relation +} + +fun JetType.getSpecificityRelationTo(otherType: JetType) = this.getCapability(javaClass())?.getSpecificityRelationTo(otherType) ?: Specificity.Relation.DONT_KNOW \ No newline at end of file