diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index d38c2b955ea..c9ff97f42b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -42,7 +42,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope -import org.jetbrains.kotlin.resolve.validation.InfixValidator +import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType @@ -251,6 +251,11 @@ public class TaskPrioritizer( c.context.call ) } + + if (explicitReceiver.types.size > 1) { + members.retainAll( members.selectMostSpecificInEachOverridableGroup { descriptor } ) + } + members } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index 92c85bda791..77ee99b9152 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -25,7 +25,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.ResolutionScope -import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.isDynamic @@ -71,7 +75,7 @@ internal class ReceiverScopeTowerLevel( val dispatchReceiver: ReceiverValue ): AbstractScopeTowerLevel(scopeTower) { - private fun collectMembers( + private fun collectMembers( getMembers: ResolutionScope.(KotlinType?) -> Collection ): Collection> { val result = ArrayList>(0) @@ -81,13 +85,23 @@ internal class ReceiverScopeTowerLevel( val smartCastPossibleTypes = scopeTower.dataFlowInfo.getSmartCastTypes(dispatchReceiver) val unstableError = if (scopeTower.dataFlowInfo.isStableReceiver(dispatchReceiver)) null else UnstableSmartCastDiagnostic + val unstableCandidates = if (unstableError != null) ArrayList>(0) else null for (possibleType in smartCastPossibleTypes) { - possibleType.memberScope.getMembers(possibleType).mapTo(result) { + possibleType.memberScope.getMembers(possibleType).mapTo(unstableCandidates ?: result) { createCandidateDescriptor(it, dispatchReceiver.smartCastReceiver(possibleType), unstableError, dispatchReceiverSmartCastType = possibleType) } } + if (smartCastPossibleTypes.isNotEmpty()) { + if (unstableCandidates == null) { + result.retainAll(result.selectMostSpecificInEachOverridableGroup { descriptor }) + } + else { + result.addAll(unstableCandidates.selectMostSpecificInEachOverridableGroup { descriptor }) + } + } + if (dispatchReceiver.type.isDynamic()) { scopeTower.dynamicScope.getMembers(null).mapTo(result) { createCandidateDescriptor(it, dispatchReceiver, DynamicDescriptorDiagnostic) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 555be20c322..0958d5bc46f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl; import org.jetbrains.kotlin.resolve.scopes.ChainedScope; import org.jetbrains.kotlin.resolve.scopes.MemberScope; +import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import java.util.*; @@ -124,19 +125,12 @@ public class TypeIntersector { TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.Companion.getEMPTY(), resultingTypes); - MemberScope[] scopes = new MemberScope[resultingTypes.size()]; - int i = 0; - for (KotlinType type : resultingTypes) { - scopes[i] = type.getMemberScope(); - i++; - } - return KotlinTypeImpl.create( Annotations.Companion.getEMPTY(), constructor, allNullable, Collections.emptyList(), - new ChainedScope("member scope for intersection type " + constructor, scopes) + TypeIntersectionScope.create("member scope for intersection type " + constructor, resultingTypes) ); } diff --git a/compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt b/compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt new file mode 100644 index 00000000000..31183798872 --- /dev/null +++ b/compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt @@ -0,0 +1,22 @@ +interface A { + fun foo(): Any? + fun bar(): String +} + +interface B { + fun foo(): String +} + +fun bar(x: T): String where T : A, T : B { + if (x.foo().length != 2 || x.foo() != "OK") return "fail 1" + if (x.bar() != "ok") return "fail 2" + + return "OK" +} + +class C : A, B { + override fun foo() = "OK" + override fun bar() = "ok" +} + +fun box(): String = bar(C()) \ No newline at end of file diff --git a/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt b/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt new file mode 100644 index 00000000000..509ef35fabd --- /dev/null +++ b/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt @@ -0,0 +1,27 @@ +interface A { + fun foo(): Any? +} + +interface B { + fun foo(): String +} + +fun bar(x: Any?): String { + if (x is A) { + val k = x.foo() + if (k != "OK") return "fail 1" + } + + if (x is B) { + val k = x.foo() + if (k.length != 2) return "fail 2" + } + + if (x is A && x is B) { + return x.foo() + } + + return "fail 4" +} + +fun box(): String = bar(object : A, B { override fun foo() = "OK" }) \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/falseSmartCast.kt b/compiler/testData/codegen/bytecodeText/falseSmartCast.kt index dd6368542b7..ae68e2c2c8d 100644 --- a/compiler/testData/codegen/bytecodeText/falseSmartCast.kt +++ b/compiler/testData/codegen/bytecodeText/falseSmartCast.kt @@ -10,6 +10,6 @@ open class SuperFoo { class Foo : SuperFoo() -// 0 INVOKEVIRTUAL SuperFoo.baz -// 1 CHECKCAST Foo -// 1 INVOKEVIRTUAL Foo.baz \ No newline at end of file +// 1 INVOKEVIRTUAL SuperFoo.baz +// 0 CHECKCAST Foo +// 0 INVOKEVIRTUAL Foo.baz \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/smartcasts/SmartcastAmbiguitites.kt b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/smartcasts/SmartcastAmbiguitites.kt index 74e7f6924e8..fd62c2ebc16 100644 --- a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/smartcasts/SmartcastAmbiguitites.kt +++ b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/smartcasts/SmartcastAmbiguitites.kt @@ -10,7 +10,7 @@ class C() { fun test(a : Any?) { if (a is B) { if (a is C) { - a.bar(); + a.bar(); } } } diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt new file mode 100644 index 00000000000..a939089fe4b --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt @@ -0,0 +1,13 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence +} + +interface B { + fun foo(): String? +} + +fun test(x: T) where T : B, T : A { + x.foo() +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.txt new file mode 100644 index 00000000000..a358c9a0584 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ x: T): kotlin.Unit where T : A + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + 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/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt new file mode 100644 index 00000000000..275d06f6eac --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt @@ -0,0 +1,19 @@ +// !CHECK_TYPE +// FILE: A.java +public interface A { + String foo(); +} + +// FILE: main.kt + +interface B { + fun foo(): String? +} + +interface C { + fun foo(): String +} + +fun test(x: T) where T : B, T : A, T : C { + x.foo().checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.txt new file mode 100644 index 00000000000..a46b0c08834 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.txt @@ -0,0 +1,25 @@ +package + +public /*synthesized*/ fun A(/*0*/ function: () -> kotlin.String!): A +public fun test(/*0*/ x: T): kotlin.Unit where T : A, T : C + +public interface A { + 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 +} + +public interface B { + 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 +} + +public interface C { + 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/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt new file mode 100644 index 00000000000..d636e50ce2c --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt @@ -0,0 +1,13 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence? +} + +interface B { + fun foo(): String +} + +fun test(x: T) where T : B, T : A { + x.foo().checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.txt new file mode 100644 index 00000000000..d79cbf951db --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ x: T): kotlin.Unit where T : A + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + 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/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt new file mode 100644 index 00000000000..6f548bd7aa5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt @@ -0,0 +1,19 @@ +// !CHECK_TYPE + +interface A { + val foo: Any? +} + +interface C: A { + override val foo: String? +} +interface B: A { + override var foo: String +} + +fun test(a: T) where T : B, T : C { + a.foo = "" + a.foo = null + + a.foo.checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.txt new file mode 100644 index 00000000000..3bb306c0f29 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ a: T): kotlin.Unit where T : C + +public interface A { + public abstract val foo: kotlin.Any? + 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 B : A { + public abstract override /*1*/ var foo: kotlin.String + 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 C : A { + public abstract override /*1*/ val foo: kotlin.String? + 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/generics/multipleBoundsMemberScope/propertiesConflict.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.kt new file mode 100644 index 00000000000..3e52e91e150 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.kt @@ -0,0 +1,19 @@ +// !CHECK_TYPE + +interface A { + val foo: Any? +} + +interface C: A { + override val foo: String +} +interface B: A { + override var foo: String? +} + +fun test(a: T) where T : B, T : C { + a.foo = "" + a.foo = null + + a.foo.checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.txt new file mode 100644 index 00000000000..37056b22465 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ a: T): kotlin.Unit where T : C + +public interface A { + public abstract val foo: kotlin.Any? + 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 B : A { + public abstract override /*1*/ var foo: kotlin.String? + 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 C : A { + public abstract override /*1*/ val foo: kotlin.String + 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/generics/multipleBoundsMemberScope/simple.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.kt new file mode 100644 index 00000000000..161252d172c --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.kt @@ -0,0 +1,13 @@ +interface A { + fun foo() +} + +interface C: A +interface B: A + +fun test(x: T) where T : C?, T : B? { + x?.foo() + if (x != null) { + x.foo() + } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.txt new file mode 100644 index 00000000000..6d227b3c79d --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ x: T): kotlin.Unit where T : B? + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun foo(): 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/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt new file mode 100644 index 00000000000..ecb4c6ac2c4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt @@ -0,0 +1,13 @@ +// !CHECK_TYPE + +interface A { + fun foo(): E +} + +interface B { + fun foo(): W +} + +fun test(x: T) where T : B, T : A { + x.foo().checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.txt b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.txt new file mode 100644 index 00000000000..f33410954e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ x: T): kotlin.Unit where T : A + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): E + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): W + 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/generics/nullability/smartCasts.kt b/compiler/testData/diagnostics/tests/generics/nullability/smartCasts.kt index 3cab07bfe72..af429a2a70c 100644 --- a/compiler/testData/diagnostics/tests/generics/nullability/smartCasts.kt +++ b/compiler/testData/diagnostics/tests/generics/nullability/smartCasts.kt @@ -27,7 +27,7 @@ fun foo(x: T) { if (x is String) { x.length - x?.length + x?.length x.bar1() x.bar2() diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParams.kt index 0e18c8328c5..5b0df4dc633 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParams.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo("") + b?.foo("") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.kt index 579a71baea5..2bd33d184da 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.kt @@ -33,6 +33,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo(null) + b?.foo(null) } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt index 29319ea33d2..3a6fd9ff269 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?, y: Y) { if (b is C) { - b?.foo(y) + b?.foo(y) } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInReturnType.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInReturnType.kt index c34bad8053e..14093a54c25 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInReturnType.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInReturnType.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo() + b?.foo() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/covariantReturnTypes.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/covariantReturnTypes.kt index 526164bc3fb..f51728c8124 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/covariantReturnTypes.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/covariantReturnTypes.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.getParent() + b?.getParent() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differenceInParamNames.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differenceInParamNames.kt index 8216b3b3826..5f278c9cf55 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differenceInParamNames.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differenceInParamNames.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo(1, "") + b?.foo(1, "") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/extensionMatch.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/extensionMatch.kt index 07d94ee0396..60d54f8cf72 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/extensionMatch.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/extensionMatch.kt @@ -31,6 +31,6 @@ import p.* fun B.test() { if (this is C) { - "".getParent() + "".getParent() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParams.kt index 5a77fca6ea8..ff4d22e7a93 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParams.kt @@ -31,12 +31,12 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo("") + b?.foo("") } } fun test1(b: B?) { if (b is C) { - b?.foo("") + b?.foo("") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsNotIs.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsNotIs.kt index fbee8deeebb..e24aee75faf 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsNotIs.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsNotIs.kt @@ -31,10 +31,10 @@ import p.* fun test(b: B?) { if (b !is C) return - b?.foo("") + b?.foo("") } fun test1(b: B?) { if (b !is C) return - b?.foo("") -} \ No newline at end of file + b?.foo("") +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnFooT.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnFooT.kt index eedb07f2980..5e775bc5e72 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnFooT.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnFooT.kt @@ -35,10 +35,10 @@ import p.* fun test(b: B?) { if (b !is C) return - b?.foo("") + b?.foo("") } fun test1(b: B?) { if (b !is C) return - b?.foo("") + b?.foo("") } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnT.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnT.kt index 41dc5643fc5..494c865981b 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnT.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsReturnT.kt @@ -31,10 +31,10 @@ import p.* fun test(b: B?) { if (b !is C) return - b?.foo("") + b?.foo("") } fun test1(b: B?) { if (b !is C) return - b?.foo("") -} \ No newline at end of file + b?.foo("") +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noGenericsInParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noGenericsInParams.kt index 84cbfb3e873..5a5eb3c618f 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noGenericsInParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noGenericsInParams.kt @@ -30,6 +30,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo(1, "") + b?.foo(1, "") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noParams.kt index 93d62b46463..67a86edc2e1 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noParams.kt @@ -31,6 +31,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.getParent() + b?.getParent() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sameGenericsInParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sameGenericsInParams.kt index 5b09a2c6188..2e8bfca20f5 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sameGenericsInParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sameGenericsInParams.kt @@ -38,6 +38,6 @@ import p.* fun test(b: B?, a: G1, b1: G2) { if (b is C) { - b?.foo(a, b1) + b?.foo(a, b1) } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/simpleWithInheritance.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/simpleWithInheritance.kt index edc17bba4e5..8dadc86fd5b 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/simpleWithInheritance.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/simpleWithInheritance.kt @@ -33,6 +33,6 @@ import p.* fun test(b: B?) { if (b is C && b is D) { - b?.getParent() + b?.getParent() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt index 4048de592bf..6266f2e7e4e 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt @@ -29,6 +29,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo("") + b?.foo("") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/scopes/stopResolutionOnAmbiguity.kt b/compiler/testData/diagnostics/tests/scopes/stopResolutionOnAmbiguity.kt index 28db2c26a69..e0cb029626f 100644 --- a/compiler/testData/diagnostics/tests/scopes/stopResolutionOnAmbiguity.kt +++ b/compiler/testData/diagnostics/tests/scopes/stopResolutionOnAmbiguity.kt @@ -12,7 +12,7 @@ class C() { fun test(a : Any?) { if (a is B) { if (a is C) { - a.bar(); + a.bar(); } } } diff --git a/compiler/testData/diagnostics/tests/smartCasts/implicitToGrandSon.kt b/compiler/testData/diagnostics/tests/smartCasts/implicitToGrandSon.kt index 8f3898da7b1..aa90fc31447 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/implicitToGrandSon.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/implicitToGrandSon.kt @@ -1,7 +1,7 @@ open class A { open fun foo() = "FAIL" - fun bar() = if (this is C) foo() else "FAIL" + fun bar() = if (this is C) foo() else "FAIL" } open class B : A() diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt new file mode 100644 index 00000000000..d390ca274ae --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt @@ -0,0 +1,13 @@ +interface A { + fun foo(): E +} + +interface B { + fun foo(): Q +} + +fun test(c: Any) { + if (c is B && c is A) { + c.foo() + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.txt new file mode 100644 index 00000000000..49e81c50c6d --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ c: kotlin.Any): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): E + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): Q + 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/conflictingReturnType.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.kt new file mode 100644 index 00000000000..c3c1e32a961 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.kt @@ -0,0 +1,15 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence +} + +interface B { + fun foo(): String? +} + +fun test(c: Any) { + if (c is B && c is A) { + c.foo() + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.txt new file mode 100644 index 00000000000..6c0de52ffbf --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ c: kotlin.Any): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + 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/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt new file mode 100644 index 00000000000..cf2be42b3c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt @@ -0,0 +1,52 @@ +// !CHECK_TYPE +// FILE: A.java +public interface A { + String foo(); +} + +// FILE: main.kt + +interface B { + fun foo(): String? +} + +interface C { + fun foo(): String +} + +fun foo(x: Any?) { + if (x is A && x is B) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is B && x is A) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is A && x is C) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is C && x is A) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is A && x is B && x is C) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is B && x is A && x is C) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } + + if (x is B && x is C && x is A) { + x.foo().checkType { _() } + x.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.txt new file mode 100644 index 00000000000..923e3f71c36 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.txt @@ -0,0 +1,25 @@ +package + +public /*synthesized*/ fun A(/*0*/ function: () -> kotlin.String!): A +public fun foo(/*0*/ x: kotlin.Any?): kotlin.Unit + +public interface A { + 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 +} + +public interface B { + 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 +} + +public interface C { + 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/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt new file mode 100644 index 00000000000..5d28699e918 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt @@ -0,0 +1,19 @@ +// !CHECK_TYPE + +interface Common { + fun foo(): CharSequence? +} + +interface A : Common { + override fun foo(): CharSequence +} + +interface B : Common { + override fun foo(): String +} + +fun test(c: Common) { + if (c is B && c is A) { + c.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.txt new file mode 100644 index 00000000000..45d83963092 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ c: Common): kotlin.Unit + +public interface A : Common { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun foo(): kotlin.CharSequence + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : Common { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ 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 Common { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence? + 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/mostSpecificIrrelevant.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.kt new file mode 100644 index 00000000000..fd9072159dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.kt @@ -0,0 +1,15 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence? +} + +interface B { + fun foo(): String +} + +fun test(c: Any) { + if (c is B && c is A) { + c.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.txt new file mode 100644 index 00000000000..fb58a5ba1b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ c: kotlin.Any): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + 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/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt new file mode 100644 index 00000000000..eb45198cc90 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt @@ -0,0 +1,21 @@ +// !CHECK_TYPE + +interface A { + val foo: Any? +} + +interface C: A { + override val foo: String? +} +interface B: A { + override var foo: String +} + +fun test(a: A) { + if (a is B && a is C) { + a.foo = "" + a.foo = null + + a.foo.checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.txt new file mode 100644 index 00000000000..bd6d710b5a7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ a: A): kotlin.Unit + +public interface A { + public abstract val foo: kotlin.Any? + 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 B : A { + public abstract override /*1*/ var foo: kotlin.String + 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 C : A { + public abstract override /*1*/ val foo: kotlin.String? + 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/propertiesConflict.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.kt new file mode 100644 index 00000000000..c754e2c5064 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.kt @@ -0,0 +1,20 @@ +// !CHECK_TYPE + +interface A { + val foo: Any? +} + +interface C: A { + override val foo: String +} +interface B: A { + override var foo: String? +} + +fun test(a: A) { + if (a is B && a is C) { + a.foo = "" + a.foo = null + a.foo + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.txt new file mode 100644 index 00000000000..74c40d3ef11 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ a: A): kotlin.Unit + +public interface A { + public abstract val foo: kotlin.Any? + 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 B : A { + public abstract override /*1*/ var foo: kotlin.String? + 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 C : A { + public abstract override /*1*/ val foo: kotlin.String + 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/refineReturnType.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.kt new file mode 100644 index 00000000000..3ce2d5e7fac --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.kt @@ -0,0 +1,16 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence? +} + +interface B : A { + override fun foo(): String +} + +fun test(a: A) { + if (a is B) { + a.foo() + a.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.txt new file mode 100644 index 00000000000..f70c91e166b --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ a: A): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ 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/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt new file mode 100644 index 00000000000..27b0b8f0f0f --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt @@ -0,0 +1,12 @@ +interface A { + fun foo() +} + +interface C: A +interface B: A + +fun test(c: C) { + if (c is B) { + c.foo() // OVERLOAD_RESOLUTION_AMBIGUITY: B.foo() and C.foo() + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.txt new file mode 100644 index 00000000000..a49bff72b3e --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.txt @@ -0,0 +1,24 @@ +package + +public fun test(/*0*/ c: C): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun foo(): 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/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt new file mode 100644 index 00000000000..e8db585a64d --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt @@ -0,0 +1,37 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence? + fun baz(x: Any) {} +} + +interface B { + fun foo(): String + fun baz(x: Int): String ="" + fun baz(x: Int, y: Int) {} + + fun foobar(): CharSequence? +} + +interface C { + fun foo(): String + fun baz(x: Int): String ="" + fun baz(x: Int, y: Int) {} + + fun foobar(): String +} + +var x: A = null!! + +fun test() { + x.foo().checkType { _() } + + if (x is B && x is C) { + x.foo().checkType { _() } + x.baz("") + x.baz(1).checkType { _() } + x.baz(1, 2) + + x.foobar().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.txt new file mode 100644 index 00000000000..95f0f5c640a --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.txt @@ -0,0 +1,32 @@ +package + +public var x: A +public fun test(): kotlin.Unit + +public interface A { + public open fun baz(/*0*/ x: kotlin.Any): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.CharSequence? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open fun baz(/*0*/ x: kotlin.Int): kotlin.String + public open fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public abstract fun foobar(): kotlin.CharSequence? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C { + public open fun baz(/*0*/ x: kotlin.Int): kotlin.String + public open fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public abstract fun foobar(): 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/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt new file mode 100644 index 00000000000..f7e1b0cbb6a --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt @@ -0,0 +1,15 @@ +// !CHECK_TYPE + +interface A { + fun foo(): E +} + +interface B { + fun foo(): W +} + +fun test(c: Any) { + if (c is B && c is A) { + c.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.txt new file mode 100644 index 00000000000..89e5546b3f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ c: kotlin.Any): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): E + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): W + 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/validTypeParametersNoSmartCast.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.kt new file mode 100644 index 00000000000..d17eaa3f9a1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.kt @@ -0,0 +1,15 @@ +// !CHECK_TYPE + +interface A { + fun foo(): E +} + +interface B : A { + override fun foo(): W +} + +fun test(a: A) { + if (a is B) { + a.foo().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.txt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.txt new file mode 100644 index 00000000000..0e8ad043ef3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.txt @@ -0,0 +1,17 @@ +package + +public fun test(/*0*/ a: A): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): E + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun foo(): W + 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/kt3224.kt b/compiler/testData/diagnostics/tests/smartCasts/kt3224.kt index b3f59dd0f3e..ce8393eec86 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/kt3224.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/kt3224.kt @@ -4,5 +4,5 @@ fun test(c : Class<*>) { val sc = c as Class // No ambiguous overload c.getAnnotations(); - sc.getAnnotations(); -} \ No newline at end of file + sc.getAnnotations(); +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/objectLiterals/assignment.kt b/compiler/testData/diagnostics/tests/smartCasts/objectLiterals/assignment.kt index c28aed5c0b5..1eb36807c45 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/objectLiterals/assignment.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/objectLiterals/assignment.kt @@ -12,7 +12,7 @@ fun foo(): Int { override fun run() = Unit } // Unnecessary but not important smart cast - k.run() + k.run() return c + d } else return -1 diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/kt7599.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/kt7599.kt index 84dbc6bce2e..7bd807aadbc 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/kt7599.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/kt7599.kt @@ -14,10 +14,10 @@ fun foo(): Boolean { var v: A v = B() // No smart cast needed, but not a problem if ever - if (v.ok()) { + if (v.ok()) { v = C() } // No smart cast needed, and no smart cast possible! // We cannot choose between B and C return v.ok() -} \ No newline at end of file +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 53174091738..0e562648459 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -6909,6 +6909,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MultipleBoundsMemberScope extends AbstractDiagnosticsTest { + public void testAllFilesPresentInMultipleBoundsMemberScope() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("conflictingReturnType.kt") + public void testConflictingReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("flexibleTypes.kt") + public void testFlexibleTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt"); + doTest(fileName); + } + + @TestMetadata("mostSpecific.kt") + public void testMostSpecific() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt"); + doTest(fileName); + } + + @TestMetadata("properties.kt") + public void testProperties() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt"); + doTest(fileName); + } + + @TestMetadata("propertiesConflict.kt") + public void testPropertiesConflict() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.kt"); + doTest(fileName); + } + + @TestMetadata("validTypeParameters.kt") + public void testValidTypeParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/generics/nullability") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -15474,6 +15525,87 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IntersectionScope extends AbstractDiagnosticsTest { + public void testAllFilesPresentInIntersectionScope() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/intersectionScope"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("conflictTypeParameters.kt") + public void testConflictTypeParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt"); + doTest(fileName); + } + + @TestMetadata("conflictingReturnType.kt") + public void testConflictingReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("flexibleTypes.kt") + public void testFlexibleTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt"); + doTest(fileName); + } + + @TestMetadata("mostSpecific.kt") + public void testMostSpecific() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt"); + doTest(fileName); + } + + @TestMetadata("mostSpecificIrrelevant.kt") + public void testMostSpecificIrrelevant() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.kt"); + doTest(fileName); + } + + @TestMetadata("properties.kt") + public void testProperties() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt"); + doTest(fileName); + } + + @TestMetadata("propertiesConflict.kt") + public void testPropertiesConflict() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.kt"); + doTest(fileName); + } + + @TestMetadata("refineReturnType.kt") + public void testRefineReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt"); + doTest(fileName); + } + + @TestMetadata("unstableSmartCast.kt") + public void testUnstableSmartCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt"); + doTest(fileName); + } + + @TestMetadata("validTypeParameters.kt") + public void testValidTypeParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt"); + doTest(fileName); + } + + @TestMetadata("validTypeParametersNoSmartCast.kt") + public void testValidTypeParametersNoSmartCast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/smartCasts/loops") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 1f71348886c..02711497bb8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -928,6 +928,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("intersectionTypeMultipleBounds.kt") + public void testIntersectionTypeMultipleBounds() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt"); + doTest(fileName); + } + + @TestMetadata("intersectionTypeSmartcast.kt") + public void testIntersectionTypeSmartcast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt"); + doTest(fileName); + } + @TestMetadata("is.kt") public void testIs() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/casts/is.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java index 355433135cb..7428ec8bba6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeParameterDescriptor.java @@ -23,14 +23,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.resolve.scopes.ChainedScope; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter; +import org.jetbrains.kotlin.resolve.scopes.MemberScope; +import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope; import org.jetbrains.kotlin.storage.NotNullLazyValue; import org.jetbrains.kotlin.storage.StorageManager; import org.jetbrains.kotlin.types.*; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -79,14 +78,7 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip new Function0() { @Override public MemberScope invoke() { - List scopes = new ArrayList(); - for (KotlinType bound : getUpperBounds()) { - scopes.add(bound.getMemberScope()); - } - return new ChainedScope( - "Scope for type parameter " + name.asString(), - scopes.toArray(new MemberScope[scopes.size()]) - ); + return TypeIntersectionScope.create("Scope for type parameter " + name.asString(), getUpperBounds()); } } )) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 81c8f744ed6..c0a1caf5480 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve; import kotlin.CollectionsKt; import kotlin.Unit; import kotlin.jvm.functions.Function1; +import org.jetbrains.annotations.Mutable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; @@ -331,7 +332,7 @@ public class OverridingUtil { } } - public static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) { + public static boolean isMoreSpecific(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) { KotlinType aReturnType = a.getReturnType(); KotlinType bReturnType = b.getReturnType(); @@ -341,7 +342,7 @@ public class OverridingUtil { if (a instanceof SimpleFunctionDescriptor) { assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass(); - return KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType); + return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType); } if (a instanceof PropertyDescriptor) { assert b instanceof PropertyDescriptor : "b is " + b.getClass(); @@ -349,20 +350,20 @@ public class OverridingUtil { PropertyDescriptor pa = (PropertyDescriptor) a; PropertyDescriptor pb = (PropertyDescriptor) b; if (pa.isVar() && pb.isVar()) { - return KotlinTypeChecker.DEFAULT.equalTypes(aReturnType, bReturnType); + return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType); } else { // both vals or var vs val: val can't be more specific then var - return !(!pa.isVar() && pb.isVar()) && KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType); + return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType); } } throw new IllegalArgumentException("Unexpected callable: " + a.getClass()); } - private static boolean isMoreSpecificThenAllOf(@NotNull CallableMemberDescriptor candidate, @NotNull Collection descriptors) { + 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 - for (CallableMemberDescriptor descriptor : descriptors) { + for (CallableDescriptor descriptor : descriptors) { if (!isMoreSpecific(candidate, descriptor)) { return false; } @@ -370,20 +371,40 @@ public class OverridingUtil { return true; } - private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection overridables) { + private static boolean isReturnTypeMoreSpecific( + @NotNull CallableDescriptor a, + @NotNull KotlinType aReturnType, + @NotNull CallableDescriptor b, + @NotNull KotlinType bReturnType + ) { + KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()); + return typeChecker.isSubtypeOf(aReturnType, bReturnType); + } + + @NotNull + public static H selectMostSpecificMember( + @NotNull Collection overridables, + @NotNull Function1 descriptorByHandle + ) { assert !overridables.isEmpty() : "Should have at least one overridable descriptor"; if (overridables.size() == 1) { return CollectionsKt.first(overridables); } - Collection candidates = new ArrayList(2); - CallableMemberDescriptor transitivelyMostSpecific = null; - for (CallableMemberDescriptor overridable : overridables) { - if (isMoreSpecificThenAllOf(overridable, overridables)) { + Collection candidates = new ArrayList(2); + List callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle); + + H transitivelyMostSpecific = CollectionsKt.first(overridables); + CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific); + + for (H overridable : overridables) { + CallableDescriptor descriptor = descriptorByHandle.invoke(overridable); + if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) { candidates.add(overridable); } - if (transitivelyMostSpecific == null || isMoreSpecific(overridable, transitivelyMostSpecific)) { + if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor) + && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) { transitivelyMostSpecific = overridable; } } @@ -395,9 +416,9 @@ public class OverridingUtil { return CollectionsKt.first(candidates); } - CallableMemberDescriptor firstNonFlexible = null; - for (CallableMemberDescriptor candidate : candidates) { - if (firstNonFlexible == null && !FlexibleTypesKt.isFlexible(candidate.getReturnType())) { + H firstNonFlexible = null; + for (H candidate : candidates) { + if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) { firstNonFlexible = candidate; break; } @@ -427,7 +448,14 @@ public class OverridingUtil { // Should be 'foo(s: String): String'. Modality modality = getMinimalModality(effectiveOverridden); Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED; - CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden); + CallableMemberDescriptor mostSpecific = + selectMostSpecificMember(effectiveOverridden, + new Function1() { + @Override + public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) { + return descriptor; + } + }); CallableMemberDescriptor fakeOverride = mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false); for (CallableMemberDescriptor descriptor : effectiveOverridden) { @@ -462,35 +490,79 @@ public class OverridingUtil { }); } + /** + * @param is something that handles CallableDescriptor inside + * @return + */ @NotNull - private static Collection extractMembersOverridableInBothWays( - @NotNull CallableMemberDescriptor overrider, - @NotNull Queue extractFrom, - @NotNull DescriptorSink sink + public static Collection extractMembersOverridableInBothWays( + @NotNull H overrider, + @NotNull @Mutable Collection extractFrom, + @NotNull Function1 descriptorByHandle, + @NotNull Function1 onConflict ) { - Collection overridable = new ArrayList(); + Collection overridable = new ArrayList(); overridable.add(overrider); - for (Iterator iterator = extractFrom.iterator(); iterator.hasNext(); ) { - CallableMemberDescriptor candidate = iterator.next(); + CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider); + for (Iterator iterator = extractFrom.iterator(); iterator.hasNext(); ) { + H candidate = iterator.next(); + CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate); if (overrider == candidate) { iterator.remove(); continue; } - OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidate, overrider, null).getResult(); - OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overrider, candidate, null).getResult(); - if (result1 == OVERRIDABLE && result2 == OVERRIDABLE) { + OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor); + + if (finalResult == OVERRIDABLE) { overridable.add(candidate); iterator.remove(); } - else if (result1 == CONFLICT || result2 == CONFLICT) { - sink.conflict(overrider, candidate); + else if (finalResult == CONFLICT) { + onConflict.invoke(candidate); iterator.remove(); } } return overridable; } + @Nullable + public static OverrideCompatibilityInfo.Result getBothWaysOverridability( + CallableDescriptor overriderDescriptor, + CallableDescriptor candidateDescriptor + ) { + OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult(); + OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult(); + + return result1 == OVERRIDABLE && result2 == OVERRIDABLE + ? OVERRIDABLE + : ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE); + } + + @NotNull + private static Collection extractMembersOverridableInBothWays( + @NotNull final CallableMemberDescriptor overrider, + @NotNull Queue extractFrom, + @NotNull final DescriptorSink sink + ) { + return extractMembersOverridableInBothWays(overrider, extractFrom, + // ID + new Function1() { + @Override + public CallableDescriptor invoke(CallableMemberDescriptor descriptor) { + return descriptor; + } + }, + new Function1() { + @Override + public Unit invoke(CallableMemberDescriptor descriptor) { + sink.conflict(overrider, descriptor); + return Unit.INSTANCE; + } + }); + } + + public static void resolveUnknownVisibilityForMember( @NotNull CallableMemberDescriptor memberDescriptor, @Nullable Function1 cannotInferVisibility diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt index 12230c57842..b9e449f86ce 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt @@ -17,12 +17,8 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.utils.DFS +import org.jetbrains.kotlin.utils.SmartSet import java.util.* fun TDescriptor.findTopMostOverriddenDescriptors(): List { @@ -46,3 +42,42 @@ fun TDescriptor.findOriginalTopMostOverridden (it.original as TDescriptor) } } + +/** + * @param is something that handles CallableDescriptor inside + */ +public fun Collection.selectMostSpecificInEachOverridableGroup( + descriptorByHandle: H.() -> CallableDescriptor +): Collection { + if (size <= 1) return this + val queue = LinkedList(this) + val result = SmartSet.create() + + while (queue.isNotEmpty()) { + val nextHandle: H = queue.first() + + val conflictedHandles = SmartSet.create() + + val overridableGroup = + OverridingUtil.extractMembersOverridableInBothWays(nextHandle, queue, descriptorByHandle) { conflictedHandles.add(it) } + + if (overridableGroup.size == 1 && overridableGroup.isEmpty()) { + result.add(overridableGroup.single()) + continue + } + + val mostSpecific = OverridingUtil.selectMostSpecificMember(overridableGroup, descriptorByHandle) + val mostSpecificDescriptor = mostSpecific.descriptorByHandle() + + overridableGroup.filterNotTo(conflictedHandles) { + OverridingUtil.isMoreSpecific(mostSpecificDescriptor, it.descriptorByHandle()) + } + + if (conflictedHandles.isNotEmpty()) { + result.addAll(conflictedHandles) + } + + result.add(mostSpecific) + } + return result +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt index dcff3af4c75..5b7bb7cca88 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.util.collectionUtils.getFromAllScopes import org.jetbrains.kotlin.utils.Printer public class ChainedScope( - private val debugName: String, + internal val debugName: String, vararg scopes: MemberScope ) : MemberScope { private val scopeChain = scopes.clone() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt new file mode 100644 index 00000000000..0301fd5476a --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.scopes + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.Printer + +class TypeIntersectionScope private constructor(override val workerScope: ChainedScope) : AbstractScopeAdapter() { + override fun getContributedFunctions(name: Name, location: LookupLocation) = + super.getContributedFunctions(name, location).selectMostSpecificInEachOverridableGroup { this } + + override fun getContributedVariables(name: Name, location: LookupLocation) = + super.getContributedVariables(name, location).selectMostSpecificInEachOverridableGroup { this } + + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { + val (callables, other) = super.getContributedDescriptors(kindFilter, nameFilter).partition { it is CallableDescriptor } + + @Suppress("UNCHECKED_CAST") + return (callables as Collection).selectMostSpecificInEachOverridableGroup { this } + other + } + + override fun printScopeStructure(p: Printer) { + p.print("TypeIntersectionScope for: " + workerScope.debugName) + super.printScopeStructure(p) + } + + companion object { + @JvmStatic + fun create(message: String, types: List): MemberScope { + val chainedScope = ChainedScope(message, *types.map { it.memberScope }.toTypedArray()) + if (types.size <= 1) return chainedScope + + return TypeIntersectionScope(chainedScope) + } + } +} diff --git a/idea/testData/checker/infos/SmartCastsWithSafeAccess.kt b/idea/testData/checker/infos/SmartCastsWithSafeAccess.kt index 5cfb03c2275..cdeb128af5f 100644 --- a/idea/testData/checker/infos/SmartCastsWithSafeAccess.kt +++ b/idea/testData/checker/infos/SmartCastsWithSafeAccess.kt @@ -30,6 +30,6 @@ fun test(a: A?) { if (a is B && a is D) { //when it's resolved, the message should be 'Smart cast to A' - a.foo + a.foo } }