[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
This commit is contained in:
Brian Norman
2023-10-23 14:32:26 -05:00
committed by Space Team
parent b154283149
commit 01a757cbd6
16 changed files with 52 additions and 31 deletions
@@ -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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ 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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> { LAZY_BLOCK }
@@ -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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ 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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(ANNOTATION_ARGUMENTS)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> { LAZY_BLOCK }
@@ -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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(BODY_RESOLVE)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ 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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> { LAZY_BLOCK }
@@ -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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(BODY_RESOLVE)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ 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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> { LAZY_BLOCK }
@@ -1,6 +1,6 @@
FILE: propertyGetterWithoutType.kt
public final val prop: <ERROR TYPE REF: empty body>
public get(): <ERROR TYPE REF: empty body> {
public final val prop: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
local final fun smth(s: R|kotlin/String|): R|kotlin/Int| {
^smth Int(1)
}
@@ -1,5 +1,5 @@
// ISSUE: KT-59649
val prop
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val prop<!>
get() {
fun smth(s: String) = 1
return smth("awd")
@@ -1,6 +1,6 @@
FILE: untypedPropertyWithBackingFieldUsage.kt
public final val simpleNoTypeBlock: <ERROR TYPE REF: Unresolved name: field>
public get(): <ERROR TYPE REF: Unresolved name: field> {
public final val simpleNoTypeBlock: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ <Unresolved name: field>#
}
public final val simpleNoTypeExpression: <ERROR TYPE REF: Unresolved name: field>
@@ -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: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
private <explicit backing field>: R|kotlin/Double| = Double(3.14)
public get(): R|kotlin/Int| {
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
^ <Unresolved name: field>#.R|kotlin/text/toInt|()
}
public final val withFieldNoTypeExpression: R|kotlin/Int|
@@ -1,4 +1,4 @@
val simpleNoTypeBlock
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val simpleNoTypeBlock<!>
get() {
return <!UNRESOLVED_REFERENCE!>field<!>
}
@@ -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,
@@ -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
}
@@ -1,3 +0,0 @@
val x get() {
return 1
}
@@ -1,3 +1,7 @@
// FIR_IDENTICAL
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val x<!> get() {
return 1
}
val y get() = 1
@@ -1,3 +1,5 @@
package
public val x: [Error type: Return type for property x cannot be resolved]
public val y: kotlin.Int
@@ -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 <T> List<T>.test3 by delegateFactory<T>(p)
val test4 get() { return <!UNRESOLVED_REFERENCE!>p<!> }
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val test4<!> get() { return <!UNRESOLVED_REFERENCE!>p<!> }
var test5
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>var test5<!>
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
set(nv) { <!UNRESOLVED_REFERENCE!>p<!>.let {} }
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>lateinit var test6<!>
}
@@ -20,4 +20,6 @@ class C(p: Any, val v: Any) {
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>var test5<!>
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
set(nv) { <!UNRESOLVED_REFERENCE!>p<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>let<!> {} }
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>lateinit var test6<!>
}
@@ -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 </*0*/ T> kotlin.collections.List<T>.test3: kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean