From 01a757cbd61d1fabd43704c7acffc78efa556d89 Mon Sep 17 00:00:00 2001 From: Brian Norman Date: Mon, 23 Oct 2023 14:32:26 -0500 Subject: [PATCH] [FIR] Report PROPERTY_WITH_NO_TYPE_NO_INITIALIZER for all properties Currently, PROPERTY_WITH_NO_TYPE_NO_INITIALIZER is reported for local variables, but not reported for member or top-level properties. Add a check to the common `checkPropertyInitializer` for when a property type cannot be determined from the getter. This also corrects a K1 versus K2 inconsistency, where K2 would allow blocks from getters to determine property type instead of only allowing expression bodies. ^KT-59935 Fixed ^KT-60117 Fixed ^KT-60123 Fixed --- .../memberGetterWithoutTypeWithBody.txt | 8 ++++---- .../memberGetterWithoutTypeWithBodyScript.txt | 8 ++++---- .../topLevelGetterWithoutTypeWithBody.txt | 8 ++++---- .../topLevelGetterWithoutTypeWithBodyScript.txt | 8 ++++---- .../resolve/propertyGetterWithoutType.fir.txt | 4 ++-- .../testData/resolve/propertyGetterWithoutType.kt | 2 +- .../untypedPropertyWithBackingFieldUsage.fir.txt | 8 ++++---- .../untypedPropertyWithBackingFieldUsage.kt | 2 +- .../declaration/FirTopLevelPropertiesChecker.kt | 14 +++++++++++++- .../resolve/FirDeclarationsResolveTransformer.kt | 3 ++- .../inferenceFromGetters/blockBodyGetter.fir.kt | 3 --- .../inferenceFromGetters/blockBodyGetter.kt | 4 ++++ .../inferenceFromGetters/blockBodyGetter.txt | 2 ++ .../primaryConstructorParameter.fir.kt | 6 ++++-- .../primaryConstructorParameter.kt | 2 ++ .../primaryConstructorParameter.txt | 1 + 16 files changed, 52 insertions(+), 31 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.fir.kt diff --git a/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBody.txt b/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBody.txt index 07cb1460f71..9d5460623d8 100644 --- a/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBody.txt +++ b/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBody.txt @@ -1,9 +1,9 @@ BEFORE MODIFICATION: -public final [ResolvedTo(BODY_RESOLVE)] val x: R|kotlin/Int| - public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): R|kotlin/Int| { +public final [ResolvedTo(BODY_RESOLVE)] val x: + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): { ^ R|/doSmth|(String(str)) } AFTER MODIFICATION: -public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int| - public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): R|kotlin/Int| { LAZY_BLOCK } +public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: + public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): { LAZY_BLOCK } diff --git a/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBodyScript.txt b/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBodyScript.txt index 07cb1460f71..9d5460623d8 100644 --- a/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBodyScript.txt +++ b/analysis/low-level-api-fir/testData/inBlockModification/memberGetterWithoutTypeWithBodyScript.txt @@ -1,9 +1,9 @@ BEFORE MODIFICATION: -public final [ResolvedTo(BODY_RESOLVE)] val x: R|kotlin/Int| - public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): R|kotlin/Int| { +public final [ResolvedTo(BODY_RESOLVE)] val x: + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): { ^ R|/doSmth|(String(str)) } AFTER MODIFICATION: -public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int| - public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): R|kotlin/Int| { LAZY_BLOCK } +public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: + public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): { LAZY_BLOCK } diff --git a/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBody.txt b/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBody.txt index c5b3edd10f8..81e2f9fbf37 100644 --- a/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBody.txt +++ b/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBody.txt @@ -1,9 +1,9 @@ BEFORE MODIFICATION: -public final [ResolvedTo(BODY_RESOLVE)] val x: R|kotlin/Int| - public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/Int| { +public final [ResolvedTo(BODY_RESOLVE)] val x: + public [ResolvedTo(BODY_RESOLVE)] get(): { ^ R|/doSmth|(String(str)) } AFTER MODIFICATION: -public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int| - public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| { LAZY_BLOCK } +public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: + public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): { LAZY_BLOCK } diff --git a/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBodyScript.txt b/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBodyScript.txt index c5b3edd10f8..81e2f9fbf37 100644 --- a/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBodyScript.txt +++ b/analysis/low-level-api-fir/testData/inBlockModification/topLevelGetterWithoutTypeWithBodyScript.txt @@ -1,9 +1,9 @@ BEFORE MODIFICATION: -public final [ResolvedTo(BODY_RESOLVE)] val x: R|kotlin/Int| - public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/Int| { +public final [ResolvedTo(BODY_RESOLVE)] val x: + public [ResolvedTo(BODY_RESOLVE)] get(): { ^ R|/doSmth|(String(str)) } AFTER MODIFICATION: -public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int| - public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| { LAZY_BLOCK } +public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: + public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): { LAZY_BLOCK } diff --git a/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.fir.txt b/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.fir.txt index dd971c837b6..0118a4f84c8 100644 --- a/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.fir.txt @@ -1,6 +1,6 @@ FILE: propertyGetterWithoutType.kt - public final val prop: - public get(): { + public final val prop: + public get(): { local final fun smth(s: R|kotlin/String|): R|kotlin/Int| { ^smth Int(1) } diff --git a/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.kt b/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.kt index c2ccbfd4b45..b874bc1b8d2 100644 --- a/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.kt +++ b/compiler/fir/analysis-tests/testData/resolve/propertyGetterWithoutType.kt @@ -1,5 +1,5 @@ // ISSUE: KT-59649 -val prop +val prop get() { fun smth(s: String) = 1 return smth("awd") diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.fir.txt index 4b5b2a72f9e..e2ebefd6378 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.fir.txt @@ -1,6 +1,6 @@ FILE: untypedPropertyWithBackingFieldUsage.kt - public final val simpleNoTypeBlock: - public get(): { + public final val simpleNoTypeBlock: + public get(): { ^ # } public final val simpleNoTypeExpression: @@ -15,9 +15,9 @@ FILE: untypedPropertyWithBackingFieldUsage.kt public get(): R|kotlin/Int| { ^ F|/simpleTypeExpression| } - public final val withFieldNoTypeBlock: R|kotlin/Int| + public final val withFieldNoTypeBlock: private : R|kotlin/Double| = Double(3.14) - public get(): R|kotlin/Int| { + public get(): { ^ #.R|kotlin/text/toInt|() } public final val withFieldNoTypeExpression: R|kotlin/Int| diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.kt index 02bee414ad3..c4966d7f182 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/properties/backingField/untypedPropertyWithBackingFieldUsage.kt @@ -1,4 +1,4 @@ -val simpleNoTypeBlock +val simpleNoTypeBlock get() { return field } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt index 466118c1959..c2be84b6b69 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.dfa.cfg.NormalPath import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrInitializer import org.jetbrains.kotlin.fir.types.FirErrorTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.lexer.KtTokens // See old FE's [DeclarationsChecker] @@ -85,7 +86,7 @@ internal fun checkPropertyInitializer( val returnTypeRef = property.returnTypeRef if (property.initializer == null && property.delegate == null && - returnTypeRef is FirErrorTypeRef && returnTypeRef.diagnostic is ConeLocalVariableNoTypeOrInitializer + returnTypeRef.noExplicitType() ) { property.source?.let { reporter.reportOn(it, FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, context) @@ -171,7 +172,14 @@ internal fun checkPropertyInitializer( ) } } + } else if ( + property.returnTypeRef.noExplicitType() && + !property.hasExplicitBackingField && + (property.getter is FirDefaultPropertyAccessor || (property.getter?.hasBody == true && property.getter?.returnTypeRef?.noExplicitType() == true)) + ) { + reporter.reportOn(propertySource, FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, context) } + if (property.isLateInit) { if (isExpect) { reporter.reportOn(propertySource, FirErrors.EXPECTED_LATEINIT_PROPERTY, context) @@ -187,6 +195,10 @@ internal fun checkPropertyInitializer( } } +private fun FirTypeRef.noExplicitType(): Boolean { + return this is FirErrorTypeRef && diagnostic is ConeLocalVariableNoTypeOrInitializer +} + private fun reportMustBeInitialized( property: FirProperty, isDefinitelyAssigned: Boolean, 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 2cc3d6b8a20..7aa2ead5346 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 @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* @@ -1211,7 +1212,7 @@ open class FirDeclarationsResolveTransformer( val unwrappedInitializer = initializer.unwrapSmartcastExpression() unwrappedInitializer.resolvedType.toFirResolvedTypeRef() } - variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> variable.getter?.returnTypeRef + variable.getter?.body is FirSingleExpressionBlock -> variable.getter?.returnTypeRef else -> null } diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.fir.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.fir.kt deleted file mode 100644 index 45062a5af6c..00000000000 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.fir.kt +++ /dev/null @@ -1,3 +0,0 @@ -val x get() { - return 1 -} diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt index 38d500a9c42..6661967a7fa 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.kt @@ -1,3 +1,7 @@ +// FIR_IDENTICAL + val x get() { return 1 } + +val y get() = 1 diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt index 14a3d84121f..b58b6792cb4 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/blockBodyGetter.txt @@ -1,3 +1,5 @@ package public val x: [Error type: Return type for property x cannot be resolved] +public val y: kotlin.Int + diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.fir.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.fir.kt index 6bddfb22a0e..c4b805a4436 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.fir.kt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.fir.kt @@ -15,9 +15,11 @@ class C(p: Any, val v: Any) { // NB here we can use both 'T' (property type parameter) and 'p' (primary constructor parameter) val List.test3 by delegateFactory(p) - val test4 get() { return p } + val test4 get() { return p } - var test5 + var test5 get() { return p } set(nv) { p.let {} } + + lateinit var test6 } diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.kt index c68f85c30e6..66ca42528b4 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.kt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.kt @@ -20,4 +20,6 @@ class C(p: Any, val v: Any) { var test5 get() { return p } set(nv) { p.let {} } + + lateinit var test6 } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.txt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.txt index 3238dd2f642..85ba2c3b209 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.txt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/primaryConstructorParameter.txt @@ -8,6 +8,7 @@ public final class C { public final val test2: kotlin.Any public final val test4: [Error type: Return type for property test4 cannot be resolved] public final var test5: [Error type: Return type for property test5 cannot be resolved] + public final lateinit var test6: [Error type: Return type for property test6 cannot be resolved] public final val v: kotlin.Any public final val kotlin.collections.List.test3: kotlin.String public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean