From 20a8e5d7420781c165aa63f7d00f6cd1141c3519 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Tue, 26 Apr 2022 20:13:56 +0300 Subject: [PATCH] [FE] Determine intersection type emptiness by looking at supertypes properly: substitute their type arguments --- ...CompilerTestFE10TestdataTestGenerated.java | 18 ++++++ ...irOldFrontendDiagnosticsTestGenerated.java | 18 ++++++ ...DiagnosticsWithLightTreeTestGenerated.java | 18 ++++++ .../kotlin/fir/types/ConeInferenceContext.kt | 4 ++ .../contravariance.fir.kt | 9 +++ .../emptyIntersectionTypes/contravariance.kt | 9 +++ .../emptyIntersectionTypes/contravariance.txt | 5 ++ .../substitutingSuperTypes.fir.kt | 16 +++++ .../substitutingSuperTypes.kt | 16 +++++ .../substitutingSuperTypes.txt | 43 ++++++++++++++ .../substitutingSuperTypes2.fir.kt | 18 ++++++ .../substitutingSuperTypes2.kt | 18 ++++++ .../substitutingSuperTypes2.txt | 55 ++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 18 ++++++ .../kotlin/types/model/TypeSystemContext.kt | 58 ++++++++++++++----- .../resolve/scopes/SubstitutingScope.kt | 3 +- .../types/checker/ClassicTypeSystemContext.kt | 6 ++ 17 files changed, 315 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.txt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.txt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt create mode 100644 compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.txt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 166f2e3d48b..ad6053a6a11 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -15217,6 +15217,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/compatibilityResolveWhenVariableHasComplexIntersectionType.kt"); } + @Test + @TestMetadata("contravariance.kt") + public void testContravariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt"); + } + @Test @TestMetadata("kt45461.kt") public void testKt45461() throws Exception { @@ -15510,6 +15516,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag public void testSelectFromCovariantAndContravariantTypes() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/selectFromCovariantAndContravariantTypes.kt"); } + + @Test + @TestMetadata("substitutingSuperTypes.kt") + public void testSubstitutingSuperTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt"); + } + + @Test + @TestMetadata("substitutingSuperTypes2.kt") + public void testSubstitutingSuperTypes2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 472f27f9ff3..a0748eb5d9d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -15217,6 +15217,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/compatibilityResolveWhenVariableHasComplexIntersectionType.kt"); } + @Test + @TestMetadata("contravariance.kt") + public void testContravariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt"); + } + @Test @TestMetadata("kt45461.kt") public void testKt45461() throws Exception { @@ -15510,6 +15516,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti public void testSelectFromCovariantAndContravariantTypes() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/selectFromCovariantAndContravariantTypes.kt"); } + + @Test + @TestMetadata("substitutingSuperTypes.kt") + public void testSubstitutingSuperTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt"); + } + + @Test + @TestMetadata("substitutingSuperTypes2.kt") + public void testSubstitutingSuperTypes2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index ed4da1f2235..f68c3d4e6cb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -15217,6 +15217,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/compatibilityResolveWhenVariableHasComplexIntersectionType.kt"); } + @Test + @TestMetadata("contravariance.kt") + public void testContravariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt"); + } + @Test @TestMetadata("kt45461.kt") public void testKt45461() throws Exception { @@ -15510,6 +15516,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac public void testSelectFromCovariantAndContravariantTypes() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/selectFromCovariantAndContravariantTypes.kt"); } + + @Test + @TestMetadata("substitutingSuperTypes.kt") + public void testSubstitutingSuperTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt"); + } + + @Test + @TestMetadata("substitutingSuperTypes2.kt") + public void testSubstitutingSuperTypes2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt"); + } } @Nested diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 9208316c375..ec5228e8a11 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.types import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType +import org.jetbrains.kotlin.fir.resolve.createSubstitutionForSupertype import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider @@ -563,4 +564,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo override fun SimpleTypeMarker.createConstraintPartForLowerBoundAndFlexibleTypeVariable(): KotlinTypeMarker = createFlexibleType(this.makeSimpleTypeDefinitelyNotNullOrNotNull(), this.withNullability(true)) + + override fun createSubstitutorForSuperTypes(baseType: KotlinTypeMarker): TypeSubstitutorMarker? = + if (baseType is ConeLookupTagBasedType) createSubstitutionForSupertype(baseType, session) else null } diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.fir.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.fir.kt new file mode 100644 index 00000000000..e297233678f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.fir.kt @@ -0,0 +1,9 @@ +// WITH_STDLIB + +fun expandMaskConditionsAndUpdateVariableNodes(validOffsets: Collection) {} + +fun main(x: List, y: Int) { + expandMaskConditionsAndUpdateVariableNodes( + x.mapTo(mutableSetOf()) { y } + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt new file mode 100644 index 00000000000..88f380b2832 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt @@ -0,0 +1,9 @@ +// WITH_STDLIB + +fun expandMaskConditionsAndUpdateVariableNodes(validOffsets: Collection) {} + +fun main(x: List, y: Int) { + expandMaskConditionsAndUpdateVariableNodes( + x.mapTo(mutableSetOf()) { y } + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.txt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.txt new file mode 100644 index 00000000000..d4615857b80 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.txt @@ -0,0 +1,5 @@ +package + +public fun expandMaskConditionsAndUpdateVariableNodes(/*0*/ validOffsets: kotlin.collections.Collection): kotlin.Unit +public fun main(/*0*/ x: kotlin.collections.List, /*1*/ y: kotlin.Int): kotlin.Unit + diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.fir.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.fir.kt new file mode 100644 index 00000000000..059f34839f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.fir.kt @@ -0,0 +1,16 @@ +class Foo + +class Bar { + fun takeFoo(foo: Foo) {} +} + +class Out + +interface A +interface B : A +interface C : A + +fun > main() { + val foo = Foo() + Bar>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31 +} diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt new file mode 100644 index 00000000000..df71825011f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt @@ -0,0 +1,16 @@ +class Foo + +class Bar { + fun takeFoo(foo: Foo) {} +} + +class Out + +interface A +interface B : A +interface C : A + +fun > main() { + val foo = Foo() + Bar>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31 +} diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.txt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.txt new file mode 100644 index 00000000000..74b33ebfd36 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.txt @@ -0,0 +1,43 @@ +package + +public fun > main(): kotlin.Unit + +public interface A { + 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 open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Bar { + public constructor Bar() + 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 final fun takeFoo(/*0*/ foo: Foo): kotlin.Unit + 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 open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out() + 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/inference/emptyIntersectionTypes/substitutingSuperTypes2.fir.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.fir.kt new file mode 100644 index 00000000000..838f43b2613 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.fir.kt @@ -0,0 +1,18 @@ +class Foo + +class Bar { + fun takeFoo(foo: Foo) {} +} + +class Out + +interface A +interface B2 : A +interface C2 : A +interface B : B2 +interface C : C2 + +fun > main() { + val foo = Foo() + Bar>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt new file mode 100644 index 00000000000..57874a1edf1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt @@ -0,0 +1,18 @@ +class Foo + +class Bar { + fun takeFoo(foo: Foo) {} +} + +class Out + +interface A +interface B2 : A +interface C2 : A +interface B : B2 +interface C : C2 + +fun > main() { + val foo = Foo() + Bar>().takeFoo(foo) // error in 1.3.72, no error in 1.4.31 +} diff --git a/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.txt b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.txt new file mode 100644 index 00000000000..c3aef8d7a43 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.txt @@ -0,0 +1,55 @@ +package + +public fun > main(): kotlin.Unit + +public interface A { + 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 : B2 { + 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 B2 : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Bar { + public constructor Bar() + 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 final fun takeFoo(/*0*/ foo: Foo): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C : C2 { + 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 C2 : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 9063004c811..d4d8238cf0f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -15223,6 +15223,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/compatibilityResolveWhenVariableHasComplexIntersectionType.kt"); } + @Test + @TestMetadata("contravariance.kt") + public void testContravariance() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/contravariance.kt"); + } + @Test @TestMetadata("kt45461.kt") public void testKt45461() throws Exception { @@ -15516,6 +15522,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { public void testSelectFromCovariantAndContravariantTypes() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/selectFromCovariantAndContravariantTypes.kt"); } + + @Test + @TestMetadata("substitutingSuperTypes.kt") + public void testSubstitutingSuperTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes.kt"); + } + + @Test + @TestMetadata("substitutingSuperTypes2.kt") + public void testSubstitutingSuperTypes2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/substitutingSuperTypes2.kt"); + } } @Nested diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index b5ebf47ea13..53155f75e27 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -343,33 +343,61 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui return EmptyIntersectionTypeKind.NOT_EMPTY_INTERSECTION } + fun createSubstitutorForSuperTypes(baseType: KotlinTypeMarker): TypeSubstitutorMarker? + + private fun areIncompatibleSuperTypes(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker): Boolean = + firstType.typeConstructor() == secondType.typeConstructor() + && !AbstractTypeChecker.equalTypes(context = this, firstType, secondType) + + // interface A + // interface B : A + // interface C : A + // => B and C have incompatible supertypes + private fun hasIncompatibleSuperTypes(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker): Boolean { + val superTypesOfFirst = firstType.typeConstructor().supertypes() + val firstTypeSubstitutor = createSubstitutorForSuperTypes(firstType) + val superTypesOfSecond = secondType.typeConstructor().supertypes() + val secondTypeSubstitutor = createSubstitutorForSuperTypes(secondType) + + for (superTypeOfFirst in superTypesOfFirst) { + @Suppress("NAME_SHADOWING") + val superTypeOfFirst = firstTypeSubstitutor?.safeSubstitute(superTypeOfFirst) ?: superTypeOfFirst + + if (areIncompatibleSuperTypes(superTypeOfFirst, secondType)) + return true + + for (superTypeOfSecond in superTypesOfSecond) { + @Suppress("NAME_SHADOWING") + val superTypeOfSecond = secondTypeSubstitutor?.safeSubstitute(superTypeOfSecond) ?: superTypeOfSecond + + if ( + areIncompatibleSuperTypes(firstType, superTypeOfSecond) + || areIncompatibleSuperTypes(superTypeOfFirst, superTypeOfSecond) + ) return true + + if (hasIncompatibleSuperTypes(superTypeOfFirst, superTypeOfSecond)) + return true + } + } + + return false + } + private fun canHaveCommonSubtypeWithInterface(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker): Boolean { require(firstType.typeConstructor().isInterface() || secondType.typeConstructor().isInterface()) { "One of the passed type should be an interface" } @Suppress("NAME_SHADOWING") - val firstType = firstType.withNullability(false) + val firstType = firstType.withNullability(false).eraseContainingTypeParameters() @Suppress("NAME_SHADOWING") - val secondType = secondType.withNullability(false) + val secondType = secondType.withNullability(false).eraseContainingTypeParameters() // interface A // interface B: A // interface C: A // B & C can't have common subtype due to having incompatible supertypes: A and A - val haveIncompatibleSupertypes = firstType.anySuperTypeConstructor { superTypeOfFirst -> - secondType.anySuperTypeConstructor { superTypeOfSecond -> - val erasedSuperTypeOfSecond by lazy { superTypeOfSecond.eraseContainingTypeParameters() } - superTypeOfFirst.typeConstructor() == superTypeOfSecond.typeConstructor() - && !AbstractTypeChecker.equalTypes( - context = this, - superTypeOfFirst.eraseContainingTypeParameters(), - erasedSuperTypeOfSecond - ) - } - } - - return !haveIncompatibleSupertypes + return !hasIncompatibleSuperTypes(firstType, secondType) } private fun canHaveCommonSubtype(first: KotlinTypeMarker, second: KotlinTypeMarker): Boolean { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt index b73640908cb..5f9d0ce122b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt @@ -30,8 +30,7 @@ import org.jetbrains.kotlin.utils.sure import java.util.* class SubstitutingScope(private val workerScope: MemberScope, givenSubstitutor: TypeSubstitutor) : MemberScope { - - private val substitutor = givenSubstitutor.substitution.wrapWithCapturingSubstitution().buildSubstitutor() + val substitutor = givenSubstitutor.substitution.wrapWithCapturingSubstitution().buildSubstitutor() private var substitutedDescriptors: MutableMap? = null diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 431477879db..2cfcdbba650 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.inference.CapturedType import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.scopes.SubstitutingScope import org.jetbrains.kotlin.resolve.substitutedUnderlyingType import org.jetbrains.kotlin.resolve.unsubstitutedUnderlyingType import org.jetbrains.kotlin.types.* @@ -870,6 +871,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return getKFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor } + override fun createSubstitutorForSuperTypes(baseType: KotlinTypeMarker): TypeSubstitutorMarker? { + require(baseType is KotlinType, baseType::errorMessage) + return (baseType.memberScope as? SubstitutingScope)?.substitutor + } + override fun SimpleTypeMarker.createConstraintPartForLowerBoundAndFlexibleTypeVariable(): KotlinTypeMarker = if (this.isMarkedNullable()) { this