From ee74e10f2830fcfcc4a4dbcbc66a2f10e1d00146 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Sun, 7 May 2023 15:48:10 +0200 Subject: [PATCH] [FIR] avoid jumping from super type transformer for local classes to unresolved non-local classes In the worst case, we will visit the entire hierarchy of a local class, where non-local classes are not yet resolved ^KT-56550 --- .../testdata/lazyResolve/localNestedClass.kt | 24 + .../testdata/lazyResolve/localNestedClass.txt | 414 ++++++++++++++++++ ...otLazyDeclarationResolveTestGenerated.java | 6 + ...ceLazyDeclarationResolveTestGenerated.java | 6 + .../transformers/FirSupertypesResolution.kt | 54 ++- 5 files changed, 495 insertions(+), 9 deletions(-) create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.txt diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt b/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt new file mode 100644 index 00000000000..40ed0f352de --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt @@ -0,0 +1,24 @@ +open class TopLevelClass { + open fun foo(i: Int) { + + } + + open fun boo(b: String) { + + } +} + +open class AnotherTopLevelClass : TopLevelClass() { + override fun foo(i: Int) { + + } +} + +fun resolveMe() { + class LocalClass : AnotherTopLevelClass() { + override fun foo(i: Int) { + } + + class NestedLocalClass + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.txt b/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.txt new file mode 100644 index 00000000000..ca30fffa905 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.txt @@ -0,0 +1,414 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(RAW_FIR)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(RAW_FIR)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(COMPANION_GENERATION)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(SUPER_TYPES)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? final? [ResolvedTo(TYPES)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(STATUS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(EXPECT_ACTUAL_MATCHING)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(CONTRACTS)] fun resolveMe(): R|kotlin/Unit| { + local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| { + super() + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { + } + + local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| { + super() + } + + } + + } + + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| { + local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| { + super() + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { + } + + local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| { + super() + } + + } + + } + + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] fun resolveMe(): R|kotlin/Unit| { + local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| { + super() + } + + public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { + } + + local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| { + super() + } + + } + + } + + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + public open [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] i: R|kotlin/Int|): R|kotlin/Unit| { LAZY_BLOCK } + + public open [ResolvedTo(STATUS)] fun boo([ResolvedTo(STATUS)] b: R|kotlin/String|): R|kotlin/Unit| { LAZY_BLOCK } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + public open override [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] i: R|kotlin/Int|): R|kotlin/Unit| { LAZY_BLOCK } + + } + public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| { + local final [ResolvedTo(BODY_RESOLVE)] class LocalClass : R|AnotherTopLevelClass| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| { + super() + } + + public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| { + } + + local final [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| { + super() + } + + } + + } + + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] localNestedClass.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public open [ResolvedTo(BODY_RESOLVE)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + super() + } + + public open [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| { + } + + public open [ResolvedTo(BODY_RESOLVE)] fun boo([ResolvedTo(BODY_RESOLVE)] b: R|kotlin/String|): R|kotlin/Unit| { + } + + } + public open [ResolvedTo(BODY_RESOLVE)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + super() + } + + public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| { + } + + } + public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| { + local final [ResolvedTo(BODY_RESOLVE)] class LocalClass : R|AnotherTopLevelClass| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| { + super() + } + + public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| { + } + + local final [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| { + super() + } + + } + + } + + } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java index d5f3d092d47..be2e1627e59 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java @@ -198,6 +198,12 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst runTest("analysis/low-level-api-fir/testdata/lazyResolve/lazyProperty.kt"); } + @Test + @TestMetadata("localNestedClass.kt") + public void testLocalNestedClass() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt"); + } + @Test @TestMetadata("parameterOfNonLocalSetter.kt") public void testParameterOfNonLocalSetter() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java index b974d22defe..ca5e3d7a3e0 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java @@ -198,6 +198,12 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou runTest("analysis/low-level-api-fir/testdata/lazyResolve/lazyProperty.kt"); } + @Test + @TestMetadata("localNestedClass.kt") + public void testLocalNestedClass() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt"); + } + @Test @TestMetadata("parameterOfNonLocalSetter.kt") public void testParameterOfNonLocalSetter() 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 8dec585ee6d..101ee123038 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 @@ -43,6 +43,8 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.types.model.TypeArgumentMarker import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.declarations.utils.isLocal class FirSupertypeResolverProcessor(session: FirSession, scopeSession: ScopeSession) : FirTransformerBasedResolveProcessor( session, scopeSession, FirResolvePhase.SUPER_TYPES @@ -81,7 +83,7 @@ fun F.runSupertypeResolvePhaseForLocalClass( useSiteFile: FirFile, containingDeclarations: List, ): F { - val supertypeComputationSession = SupertypeComputationSession() + val supertypeComputationSession = SupertypeComputationSessionForLocalClasses() val supertypeResolverVisitor = FirSupertypeResolverVisitor( session, supertypeComputationSession, scopeSession, currentScopeList.toPersistentList(), @@ -97,6 +99,41 @@ fun F.runSupertypeResolvePhaseForLocalClass( return this.transform(applySupertypesTransformer, null) } +/** + * We should resolve non-local classes to [FirResolvePhase.SUPER_TYPES] explicitly + * to avoid unsafe access to unresolved super type references + * + * Example: + * ``` + * open class TopLevelClass + * open class AnotherTopLevelClass : TopLevelClass() + * + * fun resolveMe() { + * class LocalClass : AnotherTopLevelClass() { + * class NestedLocalClass + * } + * } + * ``` + * + * During the resolution of local classes, in the best case, we will only try + * to access the unresolved super type reference of "AnotherTopLevelClass" that is unsafe in the context of parallel resolution. + * In the worst case, from NestedLocalClass we will visit the entire hierarchy of "LocalClass" + */ +private class SupertypeComputationSessionForLocalClasses : SupertypeComputationSession() { + override fun getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration: FirClassLikeDeclaration): List? { + classLikeDeclaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES) + return super.getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration) + } + + override fun supertypeRefs(declaration: FirClassLikeDeclaration): List { + if (!declaration.isLocal) { + declaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES) + } + + return super.supertypeRefs(declaration) + } +} + private class FirApplySupertypesTransformer( private val supertypeComputationSession: SupertypeComputationSession, private val session: FirSession, @@ -285,16 +322,10 @@ class FirSupertypeResolverVisitor( if (supertype !is ConeClassLikeType) continue val supertypeModuleSession = supertype.toSymbol(session)?.moduleData?.session ?: continue val fir = supertype.lookupTag.toSymbol(supertypeModuleSession)?.fir ?: continue - resolveAllSupertypes(fir, fir.supertypeRefs(), visited) + resolveAllSupertypes(fir, supertypeComputationSession.supertypeRefs(fir), visited) } } - private fun FirClassLikeDeclaration.supertypeRefs() = when (this) { - is FirRegularClass -> superTypeRefs - is FirTypeAlias -> listOf(expandedTypeRef) - else -> emptyList() - } - private fun prepareScopes(classLikeDeclaration: FirClassLikeDeclaration): PersistentList { val classId = classLikeDeclaration.symbol.classId val classModuleSession = classLikeDeclaration.moduleData.session @@ -580,6 +611,12 @@ open class SupertypeComputationSession { else -> null } + internal open fun supertypeRefs(declaration: FirClassLikeDeclaration): List = when (declaration) { + is FirRegularClass -> declaration.superTypeRefs + is FirTypeAlias -> listOf(declaration.expandedTypeRef) + else -> emptyList() + } + /** * @param declaration declaration to be checked for loops * @param visited visited declarations during the current loop search @@ -725,7 +762,6 @@ open class SupertypeComputationSession { } } - sealed class SupertypeComputationStatus { object NotComputed : SupertypeComputationStatus() object Computing : SupertypeComputationStatus()