From b4bb92d1368a7cdacff62fcbcbd22b6781ad8b61 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 15 Dec 2015 12:55:40 +0300 Subject: [PATCH] Fix overload resolution ambiguity for types intersection There are two different forms of types intestion: 1. Type parameters with multiple bounds 2. Smart casts The problem was that when member scope of type intersection contained effective duplicates and that lead to overload resolution ambiguity in strange cases like `x.hashCode()` For first type we do effectively the same thing as when building member scope for class extending several interfaces: group all descriptors by both-way-overridability relation and then choose most-specific in each group. For smart casts we do basically the same thing but with special treatments: 1. From all descriptors that _equal_ to most specific we choose the one that works without smartcast if possible (i.e. we choose first from candidates list) 2. If smart-cast value seems to be unstable we use only member scope of receiver type + all descriptors from smart cast possible types that has incompatible signature. If we'd include all of them and choose one as more specific, and it would lead to false SMART_CAST_IMPOSIBLE (see test unstableSmartCast.kt) #KT-3996 Fixed #KT-10315 Fixed --- .../resolve/calls/tasks/TaskPrioritizer.kt | 7 +- .../kotlin/resolve/calls/tower/TowerLevels.kt | 20 ++- .../kotlin/types/TypeIntersector.java | 10 +- .../casts/intersectionTypeMultipleBounds.kt | 22 +++ .../box/casts/intersectionTypeSmartcast.kt | 27 ++++ .../codegen/bytecodeText/falseSmartCast.kt | 6 +- .../smartcasts/SmartcastAmbiguitites.kt | 2 +- .../conflictingReturnType.kt | 13 ++ .../conflictingReturnType.txt | 17 +++ .../flexibleTypes.kt | 19 +++ .../flexibleTypes.txt | 25 ++++ .../multipleBoundsMemberScope/mostSpecific.kt | 13 ++ .../mostSpecific.txt | 17 +++ .../multipleBoundsMemberScope/properties.kt | 19 +++ .../multipleBoundsMemberScope/properties.txt | 24 ++++ .../propertiesConflict.kt | 19 +++ .../propertiesConflict.txt | 24 ++++ .../multipleBoundsMemberScope/simple.kt | 13 ++ .../multipleBoundsMemberScope/simple.txt | 24 ++++ .../validTypeParameters.kt | 13 ++ .../validTypeParameters.txt | 17 +++ .../tests/generics/nullability/smartCasts.kt | 2 +- .../duplicateMethod/classGenericsInParams.kt | 4 +- .../classGenericsInParamsBoundMismatch.kt | 4 +- .../classGenericsInParamsNameMismatch.kt | 4 +- .../classGenericsInReturnType.kt | 4 +- .../duplicateMethod/covariantReturnTypes.kt | 4 +- .../duplicateMethod/differenceInParamNames.kt | 4 +- .../duplicateMethod/extensionMatch.kt | 4 +- .../functionGenericsInParams.kt | 6 +- .../functionGenericsInParamsNotIs.kt | 6 +- .../functionGenericsInParamsReturnFooT.kt | 4 +- .../functionGenericsInParamsReturnT.kt | 6 +- .../duplicateMethod/noGenericsInParams.kt | 4 +- .../multimodule/duplicateMethod/noParams.kt | 4 +- .../duplicateMethod/sameGenericsInParams.kt | 4 +- .../duplicateMethod/simpleWithInheritance.kt | 4 +- .../substitutedGenericInParams.kt | 4 +- .../tests/scopes/stopResolutionOnAmbiguity.kt | 2 +- .../tests/smartCasts/implicitToGrandSon.kt | 2 +- .../conflictTypeParameters.kt | 13 ++ .../conflictTypeParameters.txt | 17 +++ .../conflictingReturnType.kt | 15 ++ .../conflictingReturnType.txt | 17 +++ .../intersectionScope/flexibleTypes.kt | 52 +++++++ .../intersectionScope/flexibleTypes.txt | 25 ++++ .../intersectionScope/mostSpecific.kt | 19 +++ .../intersectionScope/mostSpecific.txt | 24 ++++ .../mostSpecificIrrelevant.kt | 15 ++ .../mostSpecificIrrelevant.txt | 17 +++ .../intersectionScope/properties.kt | 21 +++ .../intersectionScope/properties.txt | 24 ++++ .../intersectionScope/propertiesConflict.kt | 20 +++ .../intersectionScope/propertiesConflict.txt | 24 ++++ .../intersectionScope/refineReturnType.kt | 16 +++ .../intersectionScope/refineReturnType.txt | 17 +++ .../smartCasts/intersectionScope/simple.kt | 12 ++ .../smartCasts/intersectionScope/simple.txt | 24 ++++ .../intersectionScope/unstableSmartCast.kt | 37 +++++ .../intersectionScope/unstableSmartCast.txt | 32 +++++ .../intersectionScope/validTypeParameters.kt | 15 ++ .../intersectionScope/validTypeParameters.txt | 17 +++ .../validTypeParametersNoSmartCast.kt | 15 ++ .../validTypeParametersNoSmartCast.txt | 17 +++ .../diagnostics/tests/smartCasts/kt3224.kt | 4 +- .../smartCasts/objectLiterals/assignment.kt | 2 +- .../tests/smartCasts/variables/kt7599.kt | 4 +- .../checkers/DiagnosticsTestGenerated.java | 132 ++++++++++++++++++ .../BlackBoxCodegenTestGenerated.java | 12 ++ .../impl/AbstractTypeParameterDescriptor.java | 14 +- .../kotlin/resolve/OverridingUtil.java | 128 +++++++++++++---- .../kotlin/resolve/overridingUtils.kt | 45 +++++- .../kotlin/resolve/scopes/ChainedScope.kt | 2 +- .../resolve/scopes/TypeIntersectionScope.kt | 54 +++++++ .../checker/infos/SmartCastsWithSafeAccess.kt | 2 +- 75 files changed, 1226 insertions(+), 105 deletions(-) create mode 100644 compiler/testData/codegen/box/casts/intersectionTypeMultipleBounds.kt create mode 100644 compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/conflictingReturnType.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/flexibleTypes.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/mostSpecific.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/properties.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/propertiesConflict.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/simple.txt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.kt create mode 100644 compiler/testData/diagnostics/tests/generics/multipleBoundsMemberScope/validTypeParameters.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictTypeParameters.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/conflictingReturnType.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/flexibleTypes.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecific.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/mostSpecificIrrelevant.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/properties.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/propertiesConflict.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/refineReturnType.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/simple.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParameters.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/validTypeParametersNoSmartCast.txt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/TypeIntersectionScope.kt 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 } }