[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:
Vendored
+4
-4
@@ -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 }
|
||||
|
||||
Vendored
+4
-4
@@ -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 }
|
||||
|
||||
Vendored
+4
-4
@@ -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 }
|
||||
|
||||
Vendored
+4
-4
@@ -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 }
|
||||
|
||||
+2
-2
@@ -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")
|
||||
|
||||
+4
-4
@@ -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
-1
@@ -1,4 +1,4 @@
|
||||
val simpleNoTypeBlock
|
||||
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val simpleNoTypeBlock<!>
|
||||
get() {
|
||||
return <!UNRESOLVED_REFERENCE!>field<!>
|
||||
}
|
||||
|
||||
+13
-1
@@ -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,
|
||||
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
val x get() {
|
||||
return 1
|
||||
}
|
||||
+4
@@ -1,3 +1,7 @@
|
||||
// FIR_IDENTICAL
|
||||
|
||||
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val x<!> get() {
|
||||
return 1
|
||||
}
|
||||
|
||||
val y get() = 1
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
package
|
||||
|
||||
public val x: [Error type: Return type for property x cannot be resolved]
|
||||
public val y: kotlin.Int
|
||||
|
||||
|
||||
+4
-2
@@ -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<!>
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -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<!>
|
||||
}
|
||||
Vendored
+1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user