diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.kt new file mode 100644 index 00000000000..507e3a6a3a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.kt @@ -0,0 +1,15 @@ +open class A { + open var value: Int = 4 + protected set +} + +class MutableA : A() { + override var value: Int = 4 + public set +} + +fun test(myA: A) { + if (myA is MutableA) { + myA.value = 5 + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.txt new file mode 100644 index 00000000000..e58f8379060 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.txt @@ -0,0 +1,19 @@ +package + +public fun test(/*0*/ myA: A): kotlin.Unit + +public open class A { + public constructor A() + public open var value: kotlin.Int + 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 final class MutableA : A { + public constructor MutableA() + public open override /*1*/ var value: kotlin.Int + 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/smartCasts/intersectionScope/moreSpecificVisibility.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.kt new file mode 100644 index 00000000000..14cd88dddaf --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.kt @@ -0,0 +1,16 @@ +abstract class A { + abstract protected fun foo(): String + abstract protected val bar: String +} + +interface B { + fun foo(): String + val bar: String +} + +fun test(x: A) { + if (x is B) { + x.foo() + x.bar + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.txt new file mode 100644 index 00000000000..90d0098ad7c --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.txt @@ -0,0 +1,20 @@ +package + +public fun test(/*0*/ x: A): kotlin.Unit + +public abstract class A { + public constructor A() + protected abstract val bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected abstract fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public abstract val bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + 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/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 336a482f9c6..4ef04b8b9ba 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16538,6 +16538,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("moreSpecificSetter.kt") + public void testMoreSpecificSetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificSetter.kt"); + doTest(fileName); + } + + @TestMetadata("moreSpecificVisibility.kt") + public void testMoreSpecificVisibility() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/moreSpecificVisibility.kt"); + doTest(fileName); + } + @TestMetadata("mostSpecific.kt") public void testMostSpecific() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index bc90d9476d4..0f58e054fca 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -338,6 +338,8 @@ public class OverridingUtil { assert aReturnType != null : "Return type of " + a + " is null"; assert bReturnType != null : "Return type of " + b + " is null"; + if (!isVisibilityMoreSpecific(a, b)) return false; + if (a instanceof SimpleFunctionDescriptor) { assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass(); @@ -348,6 +350,9 @@ public class OverridingUtil { PropertyDescriptor pa = (PropertyDescriptor) a; PropertyDescriptor pb = (PropertyDescriptor) b; + + if (!isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false; + if (pa.isVar() && pb.isVar()) { return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType); } @@ -359,6 +364,19 @@ public class OverridingUtil { throw new IllegalArgumentException("Unexpected callable: " + a.getClass()); } + private static boolean isVisibilityMoreSpecific( + @NotNull DeclarationDescriptorWithVisibility a, + @NotNull DeclarationDescriptorWithVisibility b + ) { + Integer result = Visibilities.compare(a.getVisibility(), b.getVisibility()); + return result == null || result >= 0; + } + + private static boolean isAccessorMoreSpecific(@Nullable PropertyAccessorDescriptor a, @Nullable PropertyAccessorDescriptor b) { + if (a == null || b == null) return true; + return isVisibilityMoreSpecific(a, b); + } + private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection descriptors) { // NB subtyping relation in Kotlin is not transitive in presence of flexible types: // String? <: String! <: String, but not String? <: String