[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
This commit is contained in:
Ilya Kirillov
2022-08-09 10:39:56 +02:00
parent 75787be2f8
commit 9f1ecdfaa1
16 changed files with 200 additions and 148 deletions
@@ -71,13 +71,13 @@ public inline fun buildErrorWithAttachment(
@OptIn(ExperimentalContracts::class) @OptIn(ExperimentalContracts::class)
public inline fun checkWithAttachmentBuilder( public inline fun checkWithAttachmentBuilder(
value: Boolean, condition: Boolean,
lazyMessage: () -> String, message: () -> String,
buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {} buildAttachment: ExceptionAttachmentBuilder.() -> Unit = {}
) { ) {
contract { returns() implies (value) } contract { returns() implies (condition) }
if (!value) { if (!condition) {
buildErrorWithAttachment(lazyMessage(), buildAttachment = buildAttachment) buildErrorWithAttachment(message(), buildAttachment = buildAttachment)
} }
} }
@@ -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.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder 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.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.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
@@ -61,7 +63,6 @@ internal class LLFirDesignatedAnnotationArgumentsResolveTransformer(
LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
@@ -69,17 +70,17 @@ internal class LLFirDesignatedAnnotationArgumentsResolveTransformer(
check(unresolvedAnnotation == null) { check(unresolvedAnnotation == null) {
"Unexpected annotationTypeRef annotation, expected resolvedType but actual ${unresolvedAnnotation?.annotationTypeRef}" "Unexpected annotationTypeRef annotation, expected resolvedType but actual ${unresolvedAnnotation?.annotationTypeRef}"
} }
when (declaration) { declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS)
is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer ->
declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) for (annotation in declaration.annotations) {
is FirProperty -> { for (argument in annotation.argumentMapping.mapping.values) {
declaration.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) checkTypeRefIsResolved(argument.typeRef, "annotation argument", declaration) {
// declaration.getter?.ensurePhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) withFirEntry("firAnnotation", annotation)
// declaration.setter?.ensurePhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) withFirEntry("firArgument", argument)
}
} }
is FirClass, is FirTypeAlias, is FirEnumEntry, is FirField -> Unit
else -> error("Unexpected type: ${declaration::class.simpleName}")
} }
checkNestedDeclarationsAreResolved(declaration)
} }
} }
@@ -56,18 +56,12 @@ internal class LLFirDesignatedAnnotationsResolveTransformed(
LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
when (declaration) { declaration.checkPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
is FirClass, is FirTypeAlias -> // todo add proper check that COMPILER_REQUIRED_ANNOTATIONS are resolved
declaration.checkPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) // checkNestedDeclarationsAreResolved(declaration)
is FirFunction, is FirProperty, is FirEnumEntry, is FirField, is FirAnonymousInitializer, is FirErrorProperty ->
Unit
else ->
error("Unexpected type: ${declaration::class.simpleName}")
}
} }
} }
@@ -63,21 +63,11 @@ internal class LLFirDesignatedBodyResolveTransformer(
ideDeclarationTransformer.ensureDesignationPassed() ideDeclarationTransformer.ensureDesignationPassed()
updatePhaseDeep(designation.declaration, FirResolvePhase.BODY_RESOLVE, withNonLocalDeclarations = true) updatePhaseDeep(designation.declaration, FirResolvePhase.BODY_RESOLVE, withNonLocalDeclarations = true)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
when (declaration) { declaration.checkPhase(FirResolvePhase.BODY_RESOLVE)
is FirSimpleFunction, is FirConstructor, is FirTypeAlias, is FirField, is FirAnonymousInitializer -> checkNestedDeclarationsAreResolved(declaration)
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}")
}
} }
} }
@@ -57,20 +57,13 @@ internal class LLFirDesignatedContractsResolveTransformer(
ideDeclarationTransformer.ensureDesignationPassed() ideDeclarationTransformer.ensureDesignationPassed()
updatePhaseDeep(designation.declaration, FirResolvePhase.CONTRACTS) updatePhaseDeep(designation.declaration, FirResolvePhase.CONTRACTS)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
when (declaration) { declaration.checkPhase(FirResolvePhase.CONTRACTS)
is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer -> if (declaration is FirContractDescriptionOwner) {
declaration.checkPhase(FirResolvePhase.CONTRACTS) // TODO checkContractDescriptionIsResolved(declaration)
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}")
} }
checkNestedDeclarationsAreResolved(declaration)
} }
} }
@@ -51,19 +51,12 @@ internal class LLFirDesignatedExpectActualMatcherTransformer(
declarationTransformer.ensureDesignationPassed() declarationTransformer.ensureDesignationPassed()
updatePhaseDeep(designation.declaration, FirResolvePhase.EXPECT_ACTUAL_MATCHING) updatePhaseDeep(designation.declaration, FirResolvePhase.EXPECT_ACTUAL_MATCHING)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
when (declaration) { declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING)
is FirSimpleFunction, is FirConstructor, is FirAnonymousInitializer -> // TODO check if expect-actual matching is present
declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING) checkNestedDeclarationsAreResolved(declaration)
is FirProperty -> {
declaration.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING)
}
is FirClass, is FirTypeAlias, is FirEnumEntry, is FirField -> Unit
else -> error("Unexpected type: ${declaration::class.simpleName}")
}
} }
} }
@@ -30,7 +30,6 @@ internal class LLFirDesignatedGeneratedCompanionObjectResolveTransformer(
LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPANION_GENERATION) LLFirLazyTransformer.updatePhaseDeep(designation.declaration, FirResolvePhase.COMPANION_GENERATION)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
@@ -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.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession 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.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.LLFirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile 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.element.builder.LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder 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.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.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 * 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 if (designation.declaration.resolvePhase >= FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) return
designation.declaration.checkPhase(FirResolvePhase.CONTRACTS) 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) { phaseRunner.runPhaseWithCustomResolve(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent) designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
} }
@@ -63,22 +63,13 @@ internal class LLFirDesignatedImplicitTypesTransformer(
ideDeclarationTransformer.ensureDesignationPassed() ideDeclarationTransformer.ensureDesignationPassed()
updatePhaseDeep(designation.declaration, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) updatePhaseDeep(designation.declaration, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
when (declaration) { declaration.checkPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
is FirSimpleFunction -> check(declaration.returnTypeRef is FirResolvedTypeRef) if (declaration is FirCallableDeclaration) {
is FirField -> check(declaration.returnTypeRef is FirResolvedTypeRef) checkReturnTypeRefIsResolved(declaration)
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}")
} }
checkNestedDeclarationsAreResolved(declaration)
} }
} }
@@ -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.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveTreeBuilder 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.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 import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
/** /**
@@ -50,27 +51,15 @@ internal class LLFirDesignatedStatusResolveTransformer(
transformer.designationTransformer.ensureDesignationPassed() transformer.designationTransformer.ensureDesignationPassed()
updatePhaseDeep(designation.declaration, FirResolvePhase.STATUS) updatePhaseDeep(designation.declaration, FirResolvePhase.STATUS)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
if (declaration !is FirAnonymousInitializer) { if (declaration !is FirAnonymousInitializer) {
declaration.checkPhase(FirResolvePhase.STATUS) declaration.checkPhase(FirResolvePhase.STATUS)
} }
when (declaration) { if (declaration is FirMemberDeclaration) {
is FirSimpleFunction -> check(declaration.status is FirResolvedDeclarationStatus) checkDeclarationStatusIsResolved(declaration)
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}")
} }
checkNestedDeclarationsAreResolved(declaration)
} }
} }
@@ -5,14 +5,6 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers 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.LLFirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignationWithFile 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.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.checkCanceled
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase 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 * 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) updatePhaseDeep(designation.declaration, FirResolvePhase.SUPER_TYPES)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
declaration.checkPhase(FirResolvePhase.SUPER_TYPES)
when (declaration) { when (declaration) {
is FirFunction, is FirProperty, is FirEnumEntry, is FirField, is FirAnonymousInitializer -> Unit is FirClass -> {
is FirRegularClass -> { for (superTypeRef in declaration.superTypeRefs) {
declaration.checkPhase(FirResolvePhase.SUPER_TYPES) checkTypeRefIsResolved(superTypeRef, "class super type", declaration)
check(declaration.superTypeRefs.all { it is FirResolvedTypeRef }) }
} }
is FirTypeAlias -> { is FirTypeAlias -> {
declaration.checkPhase(FirResolvePhase.SUPER_TYPES) checkTypeRefIsResolved(declaration.expandedTypeRef, typeRefName = "type alias expanded type", declaration)
check(declaration.expandedTypeRef is FirResolvedTypeRef)
} }
else -> error("Unexpected type: ${declaration::class.simpleName}")
else -> {}
} }
checkNestedDeclarationsAreResolved(declaration)
} }
} }
@@ -5,19 +5,16 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers 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.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer 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 * 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) updatePhaseDeep(designation.declaration, FirResolvePhase.TYPES)
checkIsResolved(designation.declaration) checkIsResolved(designation.declaration)
checkIsResolvedDeep(designation.declaration) checkClassMembersAreResolved(designation.declaration)
} }
override fun checkIsResolved(declaration: FirDeclaration) { override fun checkIsResolved(declaration: FirDeclaration) {
if (declaration !is FirAnonymousInitializer) { declaration.checkPhase(FirResolvePhase.TYPES)
declaration.checkPhase(FirResolvePhase.TYPES)
}
when (declaration) { when (declaration) {
is FirFunction -> { is FirCallableDeclaration -> {
check(declaration.returnTypeRef is FirResolvedTypeRef || declaration.returnTypeRef is FirImplicitTypeRef) checkReturnTypeRefIsResolved(declaration, acceptImplicitTypeRef = true)
check(declaration.receiverTypeRef?.let { it is FirResolvedTypeRef } ?: true) checkReceiverTypeRefIsResolved(declaration)
declaration.valueParameters.forEach { }
check(it.returnTypeRef is FirResolvedTypeRef || it.returnTypeRef is FirImplicitTypeRef)
is FirTypeParameter -> {
for (bound in declaration.bounds) {
checkTypeRefIsResolved(bound, "type parameter bound", declaration)
} }
} }
is FirProperty -> {
check(declaration.returnTypeRef is FirResolvedTypeRef || declaration.returnTypeRef is FirImplicitTypeRef) else -> {}
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}")
} }
checkNestedDeclarationsAreResolved(declaration)
checkTypeParametersAreResolved(declaration)
} }
} }
@@ -17,11 +17,44 @@ internal interface LLFirLazyTransformer {
fun checkIsResolved(declaration: FirDeclaration) fun checkIsResolved(declaration: FirDeclaration)
fun checkIsResolvedDeep(declaration: FirDeclaration) { fun checkNestedDeclarationsAreResolved(declaration: FirDeclaration) {
if (!enableDeepEnsure) return checkFunctionParametersAreResolved(declaration)
checkIsResolved(declaration) checkPropertyAccessorsAreResolved(declaration)
if (declaration is FirRegularClass) { checkClassMembersAreResolved(declaration)
declaration.declarations.forEach(::checkIsResolvedDeep) }
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 if (element.resolvePhase >= newPhase) return
element.replaceResolvePhase(newPhase) element.replaceResolvePhase(newPhase)
if (element is FirCallableDeclaration) { if (element is FirTypeParameterRefsOwner) {
element.typeParameters.forEach { typeParameter -> element.typeParameters.forEach { typeParameter ->
// if it is not a type parameter of outer declaration // if it is not a type parameter of outer declaration
if (typeParameter is FirTypeParameter) { if (typeParameter is FirTypeParameter) {
@@ -74,7 +107,7 @@ internal interface LLFirLazyTransformer {
} }
} }
internal var enableDeepEnsure: Boolean = false internal var needCheckingIfClassMembersAreResolved: Boolean = false
@TestOnly set @TestOnly set
val DUMMY = object : LLFirLazyTransformer { val DUMMY = object : LLFirLazyTransformer {
@@ -26,6 +26,7 @@ fun ExceptionAttachmentBuilder.withFirEntry(name: String, fir: FirElement) {
declarationRenderer = FirDeclarationRendererWithAttributes() declarationRenderer = FirDeclarationRendererWithAttributes()
).renderElementAsString(it) ).renderElementAsString(it)
} }
withEntry("${name}FirSourceElementKind", fir.source?.kind?.let { it::class.simpleName })
withPsiEntry("${name}Psi", fir.psi) withPsiEntry("${name}Psi", fir.psi)
} }
@@ -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)
}
}
@@ -5,16 +5,22 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.util 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.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation
internal fun FirDeclaration.checkPhase(firResolvePhase: FirResolvePhase) = internal fun FirDeclaration.checkPhase(requiredResolvePhase: FirResolvePhase) {
check(resolvePhase >= firResolvePhase) { val declarationResolvePhase = resolvePhase
"Element phase required to be $firResolvePhase but element resolved to $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) = internal fun FirDeclarationDesignation.checkPathPhase(firResolvePhase: FirResolvePhase) =
path.forEach { it.checkPhase(firResolvePhase) } path.forEach { it.checkPhase(firResolvePhase) }
@@ -23,6 +29,7 @@ internal fun FirDeclarationDesignation.checkDesignationPhase(firResolvePhase: Fi
checkPathPhase(firResolvePhase) checkPathPhase(firResolvePhase)
declaration.checkPhase(firResolvePhase) declaration.checkPhase(firResolvePhase)
} }
internal fun FirDeclarationDesignation.checkDesignationPhaseForClasses(firResolvePhase: FirResolvePhase) { internal fun FirDeclarationDesignation.checkDesignationPhaseForClasses(firResolvePhase: FirResolvePhase) {
checkPathPhase(firResolvePhase) checkPathPhase(firResolvePhase)
if (declaration is FirClassLikeDeclaration) { if (declaration is FirClassLikeDeclaration) {
@@ -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.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.TestInfrastructureInternals 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.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.firHandlersStep import org.jetbrains.kotlin.test.builders.firHandlersStep
import org.jetbrains.kotlin.test.builders.testConfiguration import org.jetbrains.kotlin.test.builders.testConfiguration
@@ -92,12 +90,12 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
if (ignoreTest(filePath, configuration)) { if (ignoreTest(filePath, configuration)) {
return return
} }
val oldEnableDeepEnsure = LLFirLazyTransformer.enableDeepEnsure val oldEnableDeepEnsure = LLFirLazyTransformer.needCheckingIfClassMembersAreResolved
try { try {
LLFirLazyTransformer.enableDeepEnsure = true LLFirLazyTransformer.needCheckingIfClassMembersAreResolved = true
super.runTest(filePath) super.runTest(filePath)
} finally { } finally {
LLFirLazyTransformer.enableDeepEnsure = oldEnableDeepEnsure LLFirLazyTransformer.needCheckingIfClassMembersAreResolved = oldEnableDeepEnsure
} }
} }
} }