From 9f1ecdfaa18f5ad2a8b2bb26683d221673490c63 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 9 Aug 2022 10:39:56 +0200 Subject: [PATCH] [LL FIR] add lazy resolve check to ensure that all nested declarations are resolved This bow includes: value parameters, property accessors and class members; before, only class members was checked --- .../errors/ExceptionAttachmentBuilder.kt | 10 +-- ...edAnnotationArgumentsResolveTransformer.kt | 21 +++--- ...DesignatedAnnotationsResolveTransformed.kt | 12 +--- .../LLFirDesignatedBodyResolveTransformer.kt | 14 +--- ...irDesignatedContractsResolveTransformer.kt | 15 ++-- ...esignatedExpectActualMatcherTransformer.kt | 13 +--- ...eratedCompanionObjectResolveTransformer.kt | 1 - ...LLFirDesignatedImplicitTypesTransformer.kt | 21 ++---- ...LLFirDesignatedStatusResolveTransformer.kt | 19 ++--- ...rDesignatedSupertypeResolverTransformer.kt | 34 ++++----- .../LLFirDesignatedTypeResolverTransformer.kt | 47 +++++-------- .../fir/transformers/LLFirLazyTransformer.kt | 47 +++++++++++-- .../low/level/api/fir/util/exceptionUtils.kt | 1 + .../api/fir/util/firCheckResolvedUtils.kt | 70 +++++++++++++++++++ .../util/firDeclarationDesignationUtils.kt | 15 ++-- .../based/AbstractCompilerBasedTestForFir.kt | 8 +-- 16 files changed, 200 insertions(+), 148 deletions(-) create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt index b96d13f9200..8c5d8e5688e 100644 --- a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/ExceptionAttachmentBuilder.kt @@ -71,13 +71,13 @@ public inline fun buildErrorWithAttachment( @OptIn(ExperimentalContracts::class) public inline fun checkWithAttachmentBuilder( - value: Boolean, - lazyMessage: () -> String, + condition: Boolean, + message: () -> String, buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {} ) { - contract { returns() implies (value) } + contract { returns() implies (condition) } - if (!value) { - buildErrorWithAttachment(lazyMessage(), buildAttachment = buildAttachment) + if (!condition) { + buildErrorWithAttachment(message(), buildAttachment = buildAttachment) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationArgumentsResolveTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationArgumentsResolveTransformer.kt index 5cf11018b03..9d542a8dc4a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationArgumentsResolveTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationArgumentsResolveTransformer.kt @@ -9,6 +9,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.ResolutionMode @@ -61,7 +63,6 @@ internal class LLFirDesignatedAnnotationArgumentsResolveTransformer( LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { @@ -69,17 +70,17 @@ internal class LLFirDesignatedAnnotationArgumentsResolveTransformer( check(unresolvedAnnotation == null) { "Unexpected annotationTypeRef annotation, expected resolvedType but actual ${unresolvedAnnotation?.annotationTypeRef}" } - when (declaration) { - is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer -> - declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) - is FirProperty -> { - declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) -// declaration.getter?.ensurePhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) -// declaration.setter?.ensurePhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) + declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) + + for (annotation in declaration.annotations) { + for (argument in annotation.argumentMapping.mapping.values) { + checkTypeRefIsResolved(argument.typeRef, "annotation argument", declaration) { + withFirEntry("firAnnotation", annotation) + withFirEntry("firArgument", argument) + } } - is FirClass, is FirTypeAlias, is FirEnumEntry, is FirField -> Unit - else -> error("Unexpected type: ${declaration::class.simpleName}") } + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt index 6306329d3ed..94d450fb2a9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt @@ -56,18 +56,12 @@ internal class LLFirDesignatedAnnotationsResolveTransformed( LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - when (declaration) { - is FirClass, is FirTypeAlias -> - declaration.checkPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) - is FirFunction, is FirProperty, is FirEnumEntry, is FirField, is FirAnonymousInitializer, is FirErrorProperty -> - Unit - else -> - error("Unexpected type: ${declaration::class.simpleName}") - } + declaration.checkPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) + // todo add proper check that COMPILER_REQUIRED_ANNOTATIONS are resolved +// checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedBodyResolveTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedBodyResolveTransformer.kt index 66a0619db0b..0995c0cb338 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedBodyResolveTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedBodyResolveTransformer.kt @@ -63,21 +63,11 @@ internal class LLFirDesignatedBodyResolveTransformer( ideDeclarationTransformer.ensureDesignationPassed() updatePhaseDeep(designation.declaration, FirResolvePhase.BODY_RESOLVE, withNonLocalDeclarations = true) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - when (declaration) { - is FirSimpleFunction, is FirConstructor, is FirTypeAlias, is FirField, is FirAnonymousInitializer -> - declaration.checkPhase(FirResolvePhase.BODY_RESOLVE) - is FirProperty -> { - declaration.checkPhase(FirResolvePhase.BODY_RESOLVE) -// declaration.getter?.ensurePhase(FirResolvePhase.BODY_RESOLVE) -// declaration.setter?.ensurePhase(FirResolvePhase.BODY_RESOLVE) - } - is FirEnumEntry, is FirClass -> Unit - else -> error("Unexpected type: ${declaration::class.simpleName}") - } + declaration.checkPhase(FirResolvePhase.BODY_RESOLVE) + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedContractsResolveTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedContractsResolveTransformer.kt index b8186e9de5f..a69d22bdca8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedContractsResolveTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedContractsResolveTransformer.kt @@ -57,20 +57,13 @@ internal class LLFirDesignatedContractsResolveTransformer( ideDeclarationTransformer.ensureDesignationPassed() updatePhaseDeep(designation.declaration, FirResolvePhase.CONTRACTS) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - when (declaration) { - is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer -> - declaration.checkPhase(FirResolvePhase.CONTRACTS) - is FirProperty -> { - declaration.checkPhase(FirResolvePhase.CONTRACTS) -// declaration.getter?.ensurePhase(FirResolvePhase.CONTRACTS) -// declaration.setter?.ensurePhase(FirResolvePhase.CONTRACTS) - } - is FirClass, is FirTypeAlias, is FirEnumEntry, is FirField -> Unit - else -> error("Unexpected type: ${declaration::class.simpleName}") + declaration.checkPhase(FirResolvePhase.CONTRACTS) + if (declaration is FirContractDescriptionOwner) { + // TODO checkContractDescriptionIsResolved(declaration) } + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedExpectActualMatcherTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedExpectActualMatcherTransformer.kt index b05be4e056c..aef8a23f8c3 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedExpectActualMatcherTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedExpectActualMatcherTransformer.kt @@ -51,19 +51,12 @@ internal class LLFirDesignatedExpectActualMatcherTransformer( declarationTransformer.ensureDesignationPassed() updatePhaseDeep(designation.declaration, FirResolvePhase.EXPECT_ACTUAL_MATCHING) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - when (declaration) { - is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer -> - declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING) - is FirProperty -> { - declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING) - } - is FirClass, is FirTypeAlias, is FirEnumEntry, is FirField -> Unit - else -> error("Unexpected type: ${declaration::class.simpleName}") - } + declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING) + // TODO check if expect-actual matching is present + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedGeneratedCompanionObjectResolveTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedGeneratedCompanionObjectResolveTransformer.kt index eb566f43735..f7501432cd6 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedGeneratedCompanionObjectResolveTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedGeneratedCompanionObjectResolveTransformer.kt @@ -30,7 +30,6 @@ internal class LLFirDesignatedGeneratedCompanionObjectResolveTransformer( LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPANION_GENERATION) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedImplicitTypesTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedImplicitTypesTransformer.kt index 55db153026d..10890722a68 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedImplicitTypesTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedImplicitTypesTransformer.kt @@ -13,13 +13,13 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitAwa import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer.Companion.updatePhaseDeep import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved /** * Transform designation into IMPLICIT_TYPES_BODY_RESOLVE declaration. Affects only for target declaration, it's children and dependents @@ -54,7 +54,7 @@ internal class LLFirDesignatedImplicitTypesTransformer( if (designation.declaration.resolvePhase >= FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) return designation.declaration.checkPhase(FirResolvePhase.CONTRACTS) - ResolveTreeBuilder.resolvePhase(designation.declaration, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { + ResolveTreeBuilder.resolvePhase(designation.declaration, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { phaseRunner.runPhaseWithCustomResolve(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { designation.firFile.transform(this, ResolutionMode.ContextIndependent) } @@ -63,22 +63,13 @@ internal class LLFirDesignatedImplicitTypesTransformer( ideDeclarationTransformer.ensureDesignationPassed() updatePhaseDeep(designation.declaration, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - when (declaration) { - is FirSimpleFunction -> check(declaration.returnTypeRef is FirResolvedTypeRef) - is FirField -> check(declaration.returnTypeRef is FirResolvedTypeRef) - is FirClass, is FirConstructor, is FirTypeAlias, is FirEnumEntry, is FirAnonymousInitializer -> Unit - is FirProperty -> { - check(declaration.returnTypeRef is FirResolvedTypeRef) - //Not resolved for some getters and setters #KT-46995 -// check(declaration.getter?.returnTypeRef?.let { it is FirResolvedTypeRef } ?: true) -// check(declaration.setter?.returnTypeRef?.let { it is FirResolvedTypeRef } ?: true) -// check(declaration.setter?.valueParameters?.get(0)?.returnTypeRef?.let { it is FirResolvedTypeRef } ?: true) - } - else -> error("Unexpected type: ${declaration::class.simpleName}") + declaration.checkPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) + if (declaration is FirCallableDeclaration) { + checkReturnTypeRefIsResolved(declaration) } + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedStatusResolveTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedStatusResolveTransformer.kt index 3a2d8f76ab9..debaf1a36ec 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedStatusResolveTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedStatusResolveTransformer.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer.Companion.updatePhaseDeep +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeclarationStatusIsResolved import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase /** @@ -50,27 +51,15 @@ internal class LLFirDesignatedStatusResolveTransformer( transformer.designationTransformer.ensureDesignationPassed() updatePhaseDeep(designation.declaration, FirResolvePhase.STATUS) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { if (declaration !is FirAnonymousInitializer) { declaration.checkPhase(FirResolvePhase.STATUS) } - when (declaration) { - is FirSimpleFunction -> check(declaration.status is FirResolvedDeclarationStatus) - is FirConstructor -> check(declaration.status is FirResolvedDeclarationStatus) - is FirTypeAlias -> check(declaration.status is FirResolvedDeclarationStatus) - is FirEnumEntry -> check(declaration.status is FirResolvedDeclarationStatus) - is FirField -> check(declaration.status is FirResolvedDeclarationStatus) - is FirProperty -> { - check(declaration.status is FirResolvedDeclarationStatus) - check(declaration.getter?.status?.let { it is FirResolvedDeclarationStatus } ?: true) - check(declaration.setter?.status?.let { it is FirResolvedDeclarationStatus } ?: true) - } - is FirRegularClass -> check(declaration.status is FirResolvedDeclarationStatus) - is FirAnonymousInitializer -> Unit - else -> error("Unexpected type: ${declaration::class.simpleName}") + if (declaration is FirMemberDeclaration) { + checkDeclarationStatusIsResolved(declaration) } + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt index b2494ccd368..b47b20f8997 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt @@ -5,14 +5,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass -import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.transformers.* -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.toSymbol import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile @@ -25,6 +17,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableS import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer.Companion.updatePhaseDeep import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.transformers.* +import org.jetbrains.kotlin.fir.types.toSymbol /** * Transform designation into SUPER_TYPES phase. Affects only for designation, target declaration, it's children and dependents @@ -155,21 +155,23 @@ internal class LLFirDesignatedSupertypeResolverTransformer( updatePhaseDeep(designation.declaration, FirResolvePhase.SUPER_TYPES) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { + declaration.checkPhase(FirResolvePhase.SUPER_TYPES) when (declaration) { - is FirFunction, is FirProperty, is FirEnumEntry, is FirField, is FirAnonymousInitializer -> Unit - is FirRegularClass -> { - declaration.checkPhase(FirResolvePhase.SUPER_TYPES) - check(declaration.superTypeRefs.all { it is FirResolvedTypeRef }) + is FirClass -> { + for (superTypeRef in declaration.superTypeRefs) { + checkTypeRefIsResolved(superTypeRef, "class super type", declaration) + } } + is FirTypeAlias -> { - declaration.checkPhase(FirResolvePhase.SUPER_TYPES) - check(declaration.expandedTypeRef is FirResolvedTypeRef) + checkTypeRefIsResolved(declaration.expandedTypeRef, typeRefName = "type alias expanded type", declaration) } - else -> error("Unexpected type: ${declaration::class.simpleName}") + + else -> {} } + checkNestedDeclarationsAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedTypeResolverTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedTypeResolverTransformer.kt index e96525c6c57..89b421cad7c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedTypeResolverTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedTypeResolverTransformer.kt @@ -5,19 +5,16 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer.Companion.updatePhaseDeep +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.* import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer -import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseRunner -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer.Companion.updatePhaseDeep -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase -import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder /** * Transform designation into TYPES phase. Affects only for designation, target declaration and it's children @@ -55,32 +52,26 @@ internal class LLFirDesignatedTypeResolverTransformer( updatePhaseDeep(designation.declaration, FirResolvePhase.TYPES) checkIsResolved(designation.declaration) - checkIsResolvedDeep(designation.declaration) + checkClassMembersAreResolved(designation.declaration) } override fun checkIsResolved(declaration: FirDeclaration) { - if (declaration !is FirAnonymousInitializer) { - declaration.checkPhase(FirResolvePhase.TYPES) - } + declaration.checkPhase(FirResolvePhase.TYPES) when (declaration) { - is FirFunction -> { - check(declaration.returnTypeRef is FirResolvedTypeRef || declaration.returnTypeRef is FirImplicitTypeRef) - check(declaration.receiverTypeRef?.let { it is FirResolvedTypeRef } ?: true) - declaration.valueParameters.forEach { - check(it.returnTypeRef is FirResolvedTypeRef || it.returnTypeRef is FirImplicitTypeRef) + is FirCallableDeclaration -> { + checkReturnTypeRefIsResolved(declaration, acceptImplicitTypeRef = true) + checkReceiverTypeRefIsResolved(declaration) + } + + is FirTypeParameter -> { + for (bound in declaration.bounds) { + checkTypeRefIsResolved(bound, "type parameter bound", declaration) } } - is FirProperty -> { - check(declaration.returnTypeRef is FirResolvedTypeRef || declaration.returnTypeRef is FirImplicitTypeRef) - check(declaration.receiverTypeRef?.let { it is FirResolvedTypeRef } ?: true) - declaration.getter?.run(::checkIsResolved) - declaration.setter?.run(::checkIsResolved) - } - is FirField -> check(declaration.returnTypeRef is FirResolvedTypeRef || declaration.returnTypeRef is FirImplicitTypeRef) - is FirClass, is FirTypeAlias, is FirAnonymousInitializer -> Unit - is FirEnumEntry -> check(declaration.returnTypeRef is FirResolvedTypeRef) - is FirDiagnosticHolder -> {} - else -> error("Unexpected type: ${declaration::class.simpleName}") + + else -> {} } + checkNestedDeclarationsAreResolved(declaration) + checkTypeParametersAreResolved(declaration) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirLazyTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirLazyTransformer.kt index 3f73f3c51e2..b2d1565cc07 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirLazyTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirLazyTransformer.kt @@ -17,11 +17,44 @@ internal interface LLFirLazyTransformer { fun checkIsResolved(declaration: FirDeclaration) - fun checkIsResolvedDeep(declaration: FirDeclaration) { - if (!enableDeepEnsure) return - checkIsResolved(declaration) - if (declaration is FirRegularClass) { - declaration.declarations.forEach(::checkIsResolvedDeep) + fun checkNestedDeclarationsAreResolved(declaration: FirDeclaration) { + checkFunctionParametersAreResolved(declaration) + checkPropertyAccessorsAreResolved(declaration) + checkClassMembersAreResolved(declaration) + } + + fun checkClassMembersAreResolved(declaration: FirDeclaration) { + if (!needCheckingIfClassMembersAreResolved) return + if (declaration is FirClass) { + for (member in declaration.declarations) { + checkClassMembersAreResolved(member) + } + } + } + + fun checkPropertyAccessorsAreResolved(declaration: FirDeclaration) { + if (declaration is FirProperty) { + declaration.getter?.let { checkIsResolved(it) } + declaration.setter?.let { checkIsResolved(it) } + } + } + + + fun checkFunctionParametersAreResolved(declaration: FirDeclaration) { + if (declaration is FirFunction) { + for (parameter in declaration.valueParameters) { + checkIsResolved(parameter) + } + } + } + + fun checkTypeParametersAreResolved(declaration: FirDeclaration) { + if (declaration is FirTypeParameterRefsOwner) { + for (parameter in declaration.typeParameters) { + if (parameter is FirTypeParameter) { + checkIsResolved(parameter) + } + } } } @@ -40,7 +73,7 @@ internal interface LLFirLazyTransformer { if (element.resolvePhase >= newPhase) return element.replaceResolvePhase(newPhase) - if (element is FirCallableDeclaration) { + if (element is FirTypeParameterRefsOwner) { element.typeParameters.forEach { typeParameter -> // if it is not a type parameter of outer declaration if (typeParameter is FirTypeParameter) { @@ -74,7 +107,7 @@ internal interface LLFirLazyTransformer { } } - internal var enableDeepEnsure: Boolean = false + internal var needCheckingIfClassMembersAreResolved: Boolean = false @TestOnly set val DUMMY = object : LLFirLazyTransformer { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt index 75ee4276e72..01bee613711 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/exceptionUtils.kt @@ -26,6 +26,7 @@ fun ExceptionAttachmentBuilder.withFirEntry(name: String, fir: FirElement) { declarationRenderer = FirDeclarationRendererWithAttributes() ).renderElementAsString(it) } + withEntry("${name}FirSourceElementKind", fir.source?.kind?.let { it::class.simpleName }) withPsiEntry("${name}Psi", fir.psi) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt new file mode 100644 index 00000000000..cce4bdbfa98 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firCheckResolvedUtils.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.util + +import org.jetbrains.kotlin.analysis.utils.errors.ExceptionAttachmentBuilder +import org.jetbrains.kotlin.analysis.utils.errors.checkWithAttachmentBuilder +import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription +import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef + +internal inline fun checkTypeRefIsResolved( + typeRef: FirTypeRef, + typeRefName: String, + owner: FirDeclaration, + acceptImplicitTypeRef: Boolean = false, + extraAttachment: ExceptionAttachmentBuilder.() -> Unit = {} +) { + checkWithAttachmentBuilder( + condition = typeRef is FirResolvedTypeRef || acceptImplicitTypeRef && typeRef is FirImplicitTypeRef, + message = { + buildString { + append("Expected ${FirResolvedTypeRef::class.simpleName}") + if (acceptImplicitTypeRef) { + append(" or ${FirImplicitTypeRef::class.simpleName}") + } + append(" for $typeRefName of ${owner::class.simpleName}(${owner.origin}) but ${typeRef::class.simpleName} found") + } + } + ) { + withFirEntry("typeRef", typeRef) + withFirEntry("firDeclaration", owner) + extraAttachment() + } +} + +internal fun checkReturnTypeRefIsResolved(declaration: FirCallableDeclaration, acceptImplicitTypeRef: Boolean = false) { + checkTypeRefIsResolved(declaration.returnTypeRef, typeRefName = "return type", declaration, acceptImplicitTypeRef) +} + +internal fun checkReceiverTypeRefIsResolved(declaration: FirCallableDeclaration, acceptImplicitTypeRef: Boolean = false) { + val receiverTypeRef = declaration.receiverTypeRef ?: return + checkTypeRefIsResolved(receiverTypeRef, typeRefName = "receiver type", declaration, acceptImplicitTypeRef) +} + + +internal fun checkContractDescriptionIsResolved(declaration: FirContractDescriptionOwner) { + val contractDescription = declaration.contractDescription + checkWithAttachmentBuilder( + condition = contractDescription is FirResolvedContractDescription || contractDescription is FirEmptyContractDescription, + message = { "Expected ${FirResolvedContractDescription::class.simpleName} or ${FirEmptyContractDescription::class.simpleName} but ${contractDescription::class.simpleName} found for ${declaration::class.simpleName}" } + ) { + withFirEntry("declaration", declaration) + } +} + +internal fun checkDeclarationStatusIsResolved(declaration: FirMemberDeclaration) { + val status = declaration.status + checkWithAttachmentBuilder( + condition = status is FirResolvedDeclarationStatus, + message = { "Expected ${FirResolvedDeclarationStatus::class.simpleName} but ${declaration::class.simpleName} found for ${declaration::class.simpleName}" } + ) { + withFirEntry("declaration", declaration) + } +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firDeclarationDesignationUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firDeclarationDesignationUtils.kt index 587705c0132..f3ed0640e4b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firDeclarationDesignationUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/firDeclarationDesignationUtils.kt @@ -5,16 +5,22 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation +import org.jetbrains.kotlin.analysis.utils.errors.checkWithAttachmentBuilder import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation -internal fun FirDeclaration.checkPhase(firResolvePhase: FirResolvePhase) = - check(resolvePhase >= firResolvePhase) { - "Element phase required to be $firResolvePhase but element resolved to $resolvePhase" +internal fun FirDeclaration.checkPhase(requiredResolvePhase: FirResolvePhase) { + val declarationResolvePhase = resolvePhase + checkWithAttachmentBuilder( + declarationResolvePhase >= requiredResolvePhase, + { "At least $requiredResolvePhase expected but $declarationResolvePhase found for ${this::class.simpleName}" } + ) { + withFirEntry("firDeclaration", this@checkPhase) } +} internal fun FirDeclarationDesignation.checkPathPhase(firResolvePhase: FirResolvePhase) = path.forEach { it.checkPhase(firResolvePhase) } @@ -23,6 +29,7 @@ internal fun FirDeclarationDesignation.checkDesignationPhase(firResolvePhase: Fi checkPathPhase(firResolvePhase) declaration.checkPhase(firResolvePhase) } + internal fun FirDeclarationDesignation.checkDesignationPhaseForClasses(firResolvePhase: FirResolvePhase) { checkPathPhase(firResolvePhase) if (declaration is FirClassLikeDeclaration) { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt index de24e0cea9d..16dd1c16b30 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt @@ -17,8 +17,6 @@ import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModulePr import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.TestInfrastructureInternals -import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider -import org.jetbrains.kotlin.test.bind import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.firHandlersStep import org.jetbrains.kotlin.test.builders.testConfiguration @@ -92,12 +90,12 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() { if (ignoreTest(filePath, configuration)) { return } - val oldEnableDeepEnsure = LLFirLazyTransformer.enableDeepEnsure + val oldEnableDeepEnsure = LLFirLazyTransformer.needCheckingIfClassMembersAreResolved try { - LLFirLazyTransformer.enableDeepEnsure = true + LLFirLazyTransformer.needCheckingIfClassMembersAreResolved = true super.runTest(filePath) } finally { - LLFirLazyTransformer.enableDeepEnsure = oldEnableDeepEnsure + LLFirLazyTransformer.needCheckingIfClassMembersAreResolved = oldEnableDeepEnsure } } }