[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)
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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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) {
@@ -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<FirFile, ResolutionMode>(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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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 {
@@ -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)
}
@@ -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
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) {
@@ -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
}
}
}