diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt index 6012eacf72a..da551873415 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirImplicitTypesLazyResolver.kt @@ -8,9 +8,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDeclarationModificationService +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkInitializerIsResolved import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.isConst import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.isCopyCreatedInScope import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitAwareBodyResolveTransformer @@ -30,6 +32,10 @@ internal object LLFirImplicitTypesLazyResolver : LLFirLazyResolver(FirResolvePha override fun phaseSpecificCheckIsResolved(target: FirElementWithResolveState) { if (target !is FirCallableDeclaration) return checkReturnTypeRefIsResolved(target) + + if (target is FirProperty && target.isConst) { + checkInitializerIsResolved(target) + } } } @@ -180,7 +186,7 @@ internal class LLFirImplicitBodyTargetResolver( } target is FirProperty -> { - if (target.returnTypeRef is FirImplicitTypeRef || target.backingField?.returnTypeRef is FirImplicitTypeRef) { + if (target.isConst || target.returnTypeRef is FirImplicitTypeRef || target.backingField?.returnTypeRef is FirImplicitTypeRef) { resolve(target, BodyStateKeepers.PROPERTY) } } diff --git a/analysis/low-level-api-fir/testData/lazyResolve/properties/constCyclePropertyWithExplicitType.txt b/analysis/low-level-api-fir/testData/lazyResolve/properties/constCyclePropertyWithExplicitType.txt index 5b441b3a080..a34d9fc1d21 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/properties/constCyclePropertyWithExplicitType.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/properties/constCyclePropertyWithExplicitType.txt @@ -81,28 +81,28 @@ FILE: [ResolvedTo(IMPORTS)] constCyclePropertyWithExplicitType.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] constCyclePropertyWithExplicitType.kt - public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val withCycle1: R|kotlin/Int| = IntegerLiteral(1).plus#(withCycle2#) + public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val withCycle1: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(R|/withCycle2|) public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] get(): R|kotlin/Int| - public? final? const [ResolvedTo(RAW_FIR)] val withCycle2: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int + public final const [ResolvedTo(CONTRACTS)] val withCycle2: R|kotlin/Int| = IntegerLiteral(2).plus#(withCycle3#) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| public? final? const [ResolvedTo(RAW_FIR)] val withCycle3: Int = LAZY_EXPRESSION public? [ResolvedTo(RAW_FIR)] get(): Int CONSTANT_EVALUATION: FILE: [ResolvedTo(IMPORTS)] constCyclePropertyWithExplicitType.kt - public final const [ResolvedTo(CONSTANT_EVALUATION)] val withCycle1: R|kotlin/Int| = IntegerLiteral(1).plus#(withCycle2#) + public final const [ResolvedTo(CONSTANT_EVALUATION)] val withCycle1: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(R|/withCycle2|) public [ResolvedTo(CONSTANT_EVALUATION)] get(): R|kotlin/Int| - public? final? const [ResolvedTo(RAW_FIR)] val withCycle2: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int + public final const [ResolvedTo(CONTRACTS)] val withCycle2: R|kotlin/Int| = IntegerLiteral(2).plus#(withCycle3#) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| public? final? const [ResolvedTo(RAW_FIR)] val withCycle3: Int = LAZY_EXPRESSION public? [ResolvedTo(RAW_FIR)] get(): Int ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] constCyclePropertyWithExplicitType.kt - public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val withCycle1: R|kotlin/Int| = IntegerLiteral(1).plus#(withCycle2#) + public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val withCycle1: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(R|/withCycle2|) public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| - public? final? const [ResolvedTo(RAW_FIR)] val withCycle2: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int + public final const [ResolvedTo(CONTRACTS)] val withCycle2: R|kotlin/Int| = IntegerLiteral(2).plus#(withCycle3#) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| public? final? const [ResolvedTo(RAW_FIR)] val withCycle3: Int = LAZY_EXPRESSION public? [ResolvedTo(RAW_FIR)] get(): Int diff --git a/analysis/low-level-api-fir/testData/lazyResolve/properties/constErrorPropertyWithExplicitType.txt b/analysis/low-level-api-fir/testData/lazyResolve/properties/constErrorPropertyWithExplicitType.txt index 8514ff0d454..e5e3749b310 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/properties/constErrorPropertyWithExplicitType.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/properties/constErrorPropertyWithExplicitType.txt @@ -54,20 +54,26 @@ FILE: [ResolvedTo(IMPORTS)] constErrorPropertyWithExplicitType.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] constErrorPropertyWithExplicitType.kt - public? final? [ResolvedTo(RAW_FIR)] fun foo(): Int { LAZY_BLOCK } - public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val nonConstantInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(foo#()) + public final [ResolvedTo(CONTRACTS)] fun foo(): R|kotlin/Int| { + ^foo IntegerLiteral(0) + } + public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val nonConstantInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/foo|()) public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] get(): R|kotlin/Int| CONSTANT_EVALUATION: FILE: [ResolvedTo(IMPORTS)] constErrorPropertyWithExplicitType.kt - public? final? [ResolvedTo(RAW_FIR)] fun foo(): Int { LAZY_BLOCK } - public final const [ResolvedTo(CONSTANT_EVALUATION)] val nonConstantInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(foo#()) + public final [ResolvedTo(CONTRACTS)] fun foo(): R|kotlin/Int| { + ^foo IntegerLiteral(0) + } + public final const [ResolvedTo(CONSTANT_EVALUATION)] val nonConstantInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/foo|()) public [ResolvedTo(CONSTANT_EVALUATION)] get(): R|kotlin/Int| ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] constErrorPropertyWithExplicitType.kt - public? final? [ResolvedTo(RAW_FIR)] fun foo(): Int { LAZY_BLOCK } - public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val nonConstantInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(foo#()) + public final [ResolvedTo(CONTRACTS)] fun foo(): R|kotlin/Int| { + ^foo IntegerLiteral(0) + } + public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val nonConstantInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/foo|()) public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| BODY_RESOLVE: diff --git a/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertiesWithExplicitType.txt b/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertiesWithExplicitType.txt index 6cf3d04f57b..dc016bfb496 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertiesWithExplicitType.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertiesWithExplicitType.txt @@ -54,19 +54,19 @@ FILE: [ResolvedTo(IMPORTS)] constPropertiesWithExplicitType.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] constPropertiesWithExplicitType.kt - public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] var simple: R|kotlin/Int| = Int(24) public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] get(): R|kotlin/Int| public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] set([ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] value: R|kotlin/Int|): R|kotlin/Unit| CONSTANT_EVALUATION: FILE: [ResolvedTo(IMPORTS)] constPropertiesWithExplicitType.kt - public final const [ResolvedTo(CONSTANT_EVALUATION)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public final const [ResolvedTo(CONSTANT_EVALUATION)] var simple: R|kotlin/Int| = Int(24) public [ResolvedTo(CONSTANT_EVALUATION)] get(): R|kotlin/Int| public [ResolvedTo(CONSTANT_EVALUATION)] set([ResolvedTo(CONSTANT_EVALUATION)] value: R|kotlin/Int|): R|kotlin/Unit| ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] constPropertiesWithExplicitType.kt - public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] var simple: R|kotlin/Int| = Int(24) public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| public [ResolvedTo(ANNOTATION_ARGUMENTS)] set([ResolvedTo(ANNOTATION_ARGUMENTS)] value: R|kotlin/Int|): R|kotlin/Unit| diff --git a/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertyWithExplicitTypeAndInitializer.txt b/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertyWithExplicitTypeAndInitializer.txt index cd6f1762588..5e450ac72c5 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertyWithExplicitTypeAndInitializer.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/properties/constPropertyWithExplicitTypeAndInitializer.txt @@ -72,26 +72,26 @@ FILE: [ResolvedTo(IMPORTS)] constPropertyWithExplicitTypeAndInitializer.kt IMPLICIT_TYPES_BODY_RESOLVE: FILE: [ResolvedTo(IMPORTS)] constPropertyWithExplicitTypeAndInitializer.kt - public? final? const [ResolvedTo(RAW_FIR)] var simple: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int - public? [ResolvedTo(RAW_FIR)] set([ResolvedTo(RAW_FIR)] value: Int): R|kotlin/Unit| - public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val withConstInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(simple#) + public final const [ResolvedTo(CONTRACTS)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| + public [ResolvedTo(CONTRACTS)] set([ResolvedTo(CONTRACTS)] value: R|kotlin/Int|): R|kotlin/Unit| + public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val withConstInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/simple|) public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] get(): R|kotlin/Int| CONSTANT_EVALUATION: FILE: [ResolvedTo(IMPORTS)] constPropertyWithExplicitTypeAndInitializer.kt - public? final? const [ResolvedTo(RAW_FIR)] var simple: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int - public? [ResolvedTo(RAW_FIR)] set([ResolvedTo(RAW_FIR)] value: Int): R|kotlin/Unit| - public final const [ResolvedTo(CONSTANT_EVALUATION)] val withConstInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(simple#) + public final const [ResolvedTo(CONTRACTS)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| + public [ResolvedTo(CONTRACTS)] set([ResolvedTo(CONTRACTS)] value: R|kotlin/Int|): R|kotlin/Unit| + public final const [ResolvedTo(CONSTANT_EVALUATION)] val withConstInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/simple|) public [ResolvedTo(CONSTANT_EVALUATION)] get(): R|kotlin/Int| ANNOTATION_ARGUMENTS: FILE: [ResolvedTo(IMPORTS)] constPropertyWithExplicitTypeAndInitializer.kt - public? final? const [ResolvedTo(RAW_FIR)] var simple: Int = LAZY_EXPRESSION - public? [ResolvedTo(RAW_FIR)] get(): Int - public? [ResolvedTo(RAW_FIR)] set([ResolvedTo(RAW_FIR)] value: Int): R|kotlin/Unit| - public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val withConstInitializer: R|kotlin/Int| = IntegerLiteral(1).plus#(IntegerLiteral(5)).plus#(simple#) + public final const [ResolvedTo(CONTRACTS)] var simple: R|kotlin/Int| = IntegerLiteral(24) + public [ResolvedTo(CONTRACTS)] get(): R|kotlin/Int| + public [ResolvedTo(CONTRACTS)] set([ResolvedTo(CONTRACTS)] value: R|kotlin/Int|): R|kotlin/Unit| + public final const [ResolvedTo(ANNOTATION_ARGUMENTS)] val withConstInitializer: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(5)).R|kotlin/Int.plus|(R|/simple|) public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| BODY_RESOLVE: diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 26f2fc10ab8..798a1150b59 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField +import org.jetbrains.kotlin.fir.declarations.utils.isConst import org.jetbrains.kotlin.fir.declarations.utils.isInline import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic @@ -144,7 +145,7 @@ open class FirDeclarationsResolveTransformer( val returnTypeRefBeforeResolve = property.returnTypeRef val cannotHaveDeepImplicitTypeRefs = property.backingField?.returnTypeRef !is FirImplicitTypeRef - if (implicitTypeOnly && returnTypeRefBeforeResolve !is FirImplicitTypeRef && cannotHaveDeepImplicitTypeRefs) { + if (!property.isConst && implicitTypeOnly && returnTypeRefBeforeResolve !is FirImplicitTypeRef && cannotHaveDeepImplicitTypeRefs) { return property } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt index 7d7ed1a7f41..387ac364715 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty +import org.jetbrains.kotlin.fir.declarations.utils.isConst import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic @@ -167,7 +168,8 @@ open class FirImplicitAwareBodyResolveTransformer( } val canHaveDeepImplicitTypeRefs = member is FirProperty && member.backingField?.returnTypeRef is FirResolvedTypeRef == false - if (member.returnTypeRef is FirResolvedTypeRef && !canHaveDeepImplicitTypeRefs) return member + val isConstProperty = member is FirProperty && member.isConst + if (member.returnTypeRef is FirResolvedTypeRef && !canHaveDeepImplicitTypeRefs && !isConstProperty) return member val symbol = member.symbol val status = implicitBodyResolveComputationSession.getStatus(symbol) if (status is ImplicitBodyResolveComputationStatus.Computed) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt index db468059383..63adb7351b5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt @@ -172,6 +172,8 @@ enum class FirResolvePhase(val noProcessor: Boolean = false) { * val baz get() = foo() // implicit type is Int * ``` * + * Also resolve initializers of const properties. + * * This is a [*jumping phase*][FirResolvePhase]. * * @see TYPES @@ -180,6 +182,12 @@ enum class FirResolvePhase(val noProcessor: Boolean = false) { /** * The compiler evaluates expressions that are used as initializers for const properties and defaults of annotation's constructor. + * + * This phase has two reasons to exist as a separate phase: + * 1. It is a synchronization point. + * Compiler visits this phase only when all const properties are resolved. + * This is especially useful when evaluating const properties from the Java world. + * 2. The Analysis API can get results of constant evaluation before [BODY_RESOLVE] phase. */ CONSTANT_EVALUATION, diff --git a/docs/fir/fir-basics.md b/docs/fir/fir-basics.md index f4d6ff3f972..711d3e6bba9 100644 --- a/docs/fir/fir-basics.md +++ b/docs/fir/fir-basics.md @@ -23,7 +23,8 @@ List of all FIR phases that exist in the compiler right now with a short descrip - **STATUS**: The compiler resolves modality, visibility, and modifiers for member declarations. - **EXPECT_ACTUAL_MATCHING**: The compiler matches and records an `expect` member declaration for `actual` member declarations. - **CONTRACTS**: The compiler resolves a contract definition in property accessors, functions, and constructors. -- **IMPLICIT_TYPES_BODY_RESOLVE**: The compiler resolves types for callable declarations without an explicit return type. +- **IMPLICIT_TYPES_BODY_RESOLVE**: The compiler resolves types for callable declarations without an explicit return type. +Also resolves initializers of const properties. - **CONSTANT_EVALUATION**: The compiler evaluates values of const properties and defaults of annotations' constructors. - **ANNOTATION_ARGUMENTS**: The compiler resolves arguments of annotations in declaration headers. - **BODY_RESOLVE**: The compiler resolves bodies for declarations.