From 3c36a4fabd8cfcc3e710bfbb31eb7e6c5ac8c8ea Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Thu, 16 Feb 2023 17:48:38 +0000 Subject: [PATCH] [FIR] KT-56665: Filter-out valid cycles ^KT-56665 Fixed Merge-request: KT-MR-8861 Merged-by: Nikolay Lunyak --- ...CompilerTestFE10TestdataTestGenerated.java | 6 +++ ...irOldFrontendDiagnosticsTestGenerated.java | 6 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 +++ .../transformers/FirSupertypesResolution.kt | 37 ++++++++++++++++--- .../testData/diagnostics/tests/kt56665.kt | 11 ++++++ .../testData/diagnostics/tests/kt56665.txt | 24 ++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 +++ 7 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/kt56665.kt create mode 100644 compiler/testData/diagnostics/tests/kt56665.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 6cd35819347..5c61d155333 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 @@ -489,6 +489,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/kt55733.kt"); } + @Test + @TestMetadata("kt56665.kt") + public void testKt56665() throws Exception { + runTest("compiler/testData/diagnostics/tests/kt56665.kt"); + } + @Test @TestMetadata("LValueAssignment.kt") public void testLValueAssignment() throws Exception { 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 631591cd018..8a0b93dce5d 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 @@ -489,6 +489,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/kt55733.kt"); } + @Test + @TestMetadata("kt56665.kt") + public void testKt56665() throws Exception { + runTest("compiler/testData/diagnostics/tests/kt56665.kt"); + } + @Test @TestMetadata("LValueAssignment.kt") public void testLValueAssignment() throws Exception { 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 3c3cfba58fc..0f5e52f6578 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 @@ -489,6 +489,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/kt55733.kt"); } + @Test + @TestMetadata("kt56665.kt") + public void testKt56665() throws Exception { + runTest("compiler/testData/diagnostics/tests/kt56665.kt"); + } + @Test @TestMetadata("LValueAssignment.kt") public void testLValueAssignment() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index fcb1e5ecd9a..8d72f5c8d6e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -560,8 +560,15 @@ class SupertypeComputationSession { val path = mutableListOf() val pathSet = mutableSetOf() - fun checkIsInLoop(classLikeDecl: FirClassLikeDeclaration?) { + fun checkIsInLoop( + classLikeDecl: FirClassLikeDeclaration?, + wasSubtypingInvolved: Boolean, + wereTypeArgumentsInvolved: Boolean, + ) { if (classLikeDecl == null) return + require(!wasSubtypingInvolved || !wereTypeArgumentsInvolved) { + "This must hold by induction, because otherwise such a loop is allowed" + } val supertypeRefs: List val supertypeComputationStatus = supertypeStatusMap[classLikeDecl] @@ -596,24 +603,42 @@ class SupertypeComputationSession { if (!parentId.isRoot) { val parentSymbol = session.symbolProvider.getClassLikeSymbolByClassId(ClassId.fromString(parentId.asString())) if (parentSymbol is FirRegularClassSymbol) { - checkIsInLoop(parentSymbol.fir) + checkIsInLoop(parentSymbol.fir, wasSubtypingInvolved, wereTypeArgumentsInvolved) } } val isTypeAlias = classLikeDecl is FirTypeAlias + val isSubtypingCurrentlyInvolved = !isTypeAlias + + // This is an optimization that prevents collecting + // loops we don't want to report anyway. + if (wereTypeArgumentsInvolved && isSubtypingCurrentlyInvolved) { + path.removeAt(path.size - 1) + pathSet.remove(classLikeDecl) + return + } + + val isSubtypingInvolved = wasSubtypingInvolved || isSubtypingCurrentlyInvolved var isErrorInSupertypesFound = false val resultSupertypeRefs = mutableListOf() for (supertypeRef in supertypeRefs) { val supertypeFir = supertypeRef.firClassLike(session) - checkIsInLoop(supertypeFir) + checkIsInLoop(supertypeFir, isSubtypingInvolved, wereTypeArgumentsInvolved) + + // This is an optimization that prevents collecting + // loops we don't want to report anyway. + if (!isSubtypingInvolved) { + val areTypeArgumentsCurrentlyInvolved = true - if (isTypeAlias) { fun checkTypeArgumentsRecursively(type: ConeKotlinType, visitedTypes: MutableSet) { if (type in visitedTypes) return visitedTypes += type for (typeArgument in type.typeArguments) { if (typeArgument is ConeClassLikeType) { - checkIsInLoop(typeArgument.lookupTag.toSymbol(session)?.fir) + checkIsInLoop( + typeArgument.lookupTag.toSymbol(session)?.fir, + wasSubtypingInvolved, areTypeArgumentsCurrentlyInvolved, + ) checkTypeArgumentsRecursively(typeArgument, visitedTypes) } } @@ -645,7 +670,7 @@ class SupertypeComputationSession { } for (classifier in newClassifiersForBreakingLoops) { - checkIsInLoop(classifier) + checkIsInLoop(classifier, wasSubtypingInvolved = false, wereTypeArgumentsInvolved = false) require(path.isEmpty()) { "Path should be empty" } diff --git a/compiler/testData/diagnostics/tests/kt56665.kt b/compiler/testData/diagnostics/tests/kt56665.kt new file mode 100644 index 00000000000..be863f9f9cc --- /dev/null +++ b/compiler/testData/diagnostics/tests/kt56665.kt @@ -0,0 +1,11 @@ +// FIR_IDENTICAL + +private typealias Bar = Foo +internal class Gau : Bar + +internal class Gau2 : Bar2 +private typealias Bar2 = Foo + +//internal class Gau : Foo + +interface Foo diff --git a/compiler/testData/diagnostics/tests/kt56665.txt b/compiler/testData/diagnostics/tests/kt56665.txt new file mode 100644 index 00000000000..652779fbc15 --- /dev/null +++ b/compiler/testData/diagnostics/tests/kt56665.txt @@ -0,0 +1,24 @@ +package + +public interface 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 +} + +internal final class Gau : Bar /* = Foo */ { + public constructor Gau() + 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 +} + +internal final class Gau2 : Bar2 /* = Foo */ { + public constructor Gau2() + 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 +} +private typealias Bar = Foo +private typealias Bar2 = Foo + 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 1f72e5319bf..dc0c1e42cfd 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 @@ -489,6 +489,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/kt55733.kt"); } + @Test + @TestMetadata("kt56665.kt") + public void testKt56665() throws Exception { + runTest("compiler/testData/diagnostics/tests/kt56665.kt"); + } + @Test @TestMetadata("LValueAssignment.kt") public void testLValueAssignment() throws Exception {