[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:
|
BEFORE MODIFICATION:
|
||||||
public final [ResolvedTo(BODY_RESOLVE)] val x: 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(): R|kotlin/Int| {
|
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
^ R|/doSmth|(String(str))
|
^ R|/doSmth|(String(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
AFTER MODIFICATION:
|
AFTER MODIFICATION:
|
||||||
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int|
|
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(): R|kotlin/Int| { LAZY_BLOCK }
|
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:
|
BEFORE MODIFICATION:
|
||||||
public final [ResolvedTo(BODY_RESOLVE)] val x: 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(): R|kotlin/Int| {
|
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
^ R|/doSmth|(String(str))
|
^ R|/doSmth|(String(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
AFTER MODIFICATION:
|
AFTER MODIFICATION:
|
||||||
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int|
|
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(): R|kotlin/Int| { LAZY_BLOCK }
|
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:
|
BEFORE MODIFICATION:
|
||||||
public final [ResolvedTo(BODY_RESOLVE)] val x: 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(): R|kotlin/Int| {
|
public [ResolvedTo(BODY_RESOLVE)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
^ R|/doSmth|(String(str))
|
^ R|/doSmth|(String(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
AFTER MODIFICATION:
|
AFTER MODIFICATION:
|
||||||
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int|
|
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
|
||||||
public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| { LAZY_BLOCK }
|
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:
|
BEFORE MODIFICATION:
|
||||||
public final [ResolvedTo(BODY_RESOLVE)] val x: 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(): R|kotlin/Int| {
|
public [ResolvedTo(BODY_RESOLVE)] get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
^ R|/doSmth|(String(str))
|
^ R|/doSmth|(String(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
AFTER MODIFICATION:
|
AFTER MODIFICATION:
|
||||||
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: R|kotlin/Int|
|
public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val x: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
|
||||||
public [ResolvedTo(ANNOTATION_ARGUMENTS)] get(): R|kotlin/Int| { LAZY_BLOCK }
|
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
|
FILE: propertyGetterWithoutType.kt
|
||||||
public final val prop: <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: empty body> {
|
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
local final fun smth(s: R|kotlin/String|): R|kotlin/Int| {
|
local final fun smth(s: R|kotlin/String|): R|kotlin/Int| {
|
||||||
^smth Int(1)
|
^smth Int(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ISSUE: KT-59649
|
// ISSUE: KT-59649
|
||||||
val prop
|
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val prop<!>
|
||||||
get() {
|
get() {
|
||||||
fun smth(s: String) = 1
|
fun smth(s: String) = 1
|
||||||
return smth("awd")
|
return smth("awd")
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
FILE: untypedPropertyWithBackingFieldUsage.kt
|
FILE: untypedPropertyWithBackingFieldUsage.kt
|
||||||
public final val simpleNoTypeBlock: <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: Unresolved name: field> {
|
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate> {
|
||||||
^ <Unresolved name: field>#
|
^ <Unresolved name: field>#
|
||||||
}
|
}
|
||||||
public final val simpleNoTypeExpression: <ERROR TYPE REF: 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| {
|
public get(): R|kotlin/Int| {
|
||||||
^ F|/simpleTypeExpression|
|
^ 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)
|
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|()
|
^ <Unresolved name: field>#.R|kotlin/text/toInt|()
|
||||||
}
|
}
|
||||||
public final val withFieldNoTypeExpression: R|kotlin/Int|
|
public final val withFieldNoTypeExpression: R|kotlin/Int|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
val simpleNoTypeBlock
|
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val simpleNoTypeBlock<!>
|
||||||
get() {
|
get() {
|
||||||
return <!UNRESOLVED_REFERENCE!>field<!>
|
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.dfa.controlFlowGraph
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrInitializer
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrInitializer
|
||||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
|
||||||
// See old FE's [DeclarationsChecker]
|
// See old FE's [DeclarationsChecker]
|
||||||
@@ -85,7 +86,7 @@ internal fun checkPropertyInitializer(
|
|||||||
val returnTypeRef = property.returnTypeRef
|
val returnTypeRef = property.returnTypeRef
|
||||||
if (property.initializer == null &&
|
if (property.initializer == null &&
|
||||||
property.delegate == null &&
|
property.delegate == null &&
|
||||||
returnTypeRef is FirErrorTypeRef && returnTypeRef.diagnostic is ConeLocalVariableNoTypeOrInitializer
|
returnTypeRef.noExplicitType()
|
||||||
) {
|
) {
|
||||||
property.source?.let {
|
property.source?.let {
|
||||||
reporter.reportOn(it, FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, context)
|
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 (property.isLateInit) {
|
||||||
if (isExpect) {
|
if (isExpect) {
|
||||||
reporter.reportOn(propertySource, FirErrors.EXPECTED_LATEINIT_PROPERTY, context)
|
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(
|
private fun reportMustBeInitialized(
|
||||||
property: FirProperty,
|
property: FirProperty,
|
||||||
isDefinitelyAssigned: Boolean,
|
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.ConeSimpleDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
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.FirResolvedErrorReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
@@ -1211,7 +1212,7 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
val unwrappedInitializer = initializer.unwrapSmartcastExpression()
|
val unwrappedInitializer = initializer.unwrapSmartcastExpression()
|
||||||
unwrappedInitializer.resolvedType.toFirResolvedTypeRef()
|
unwrappedInitializer.resolvedType.toFirResolvedTypeRef()
|
||||||
}
|
}
|
||||||
variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> variable.getter?.returnTypeRef
|
variable.getter?.body is FirSingleExpressionBlock -> variable.getter?.returnTypeRef
|
||||||
else -> null
|
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() {
|
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>val x<!> get() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val y get() = 1
|
||||||
|
|||||||
+2
@@ -1,3 +1,5 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public val x: [Error type: Return type for property x cannot be resolved]
|
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)
|
// 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 <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<!> }
|
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
|
||||||
set(nv) { <!UNRESOLVED_REFERENCE!>p<!>.let {} }
|
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<!>
|
<!PROPERTY_WITH_NO_TYPE_NO_INITIALIZER!>var test5<!>
|
||||||
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
|
get() { return <!UNRESOLVED_REFERENCE!>p<!> }
|
||||||
set(nv) { <!UNRESOLVED_REFERENCE!>p<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>let<!> {} }
|
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 test2: kotlin.Any
|
||||||
public final val test4: [Error type: Return type for property test4 cannot be resolved]
|
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 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 v: kotlin.Any
|
||||||
public final val </*0*/ T> kotlin.collections.List<T>.test3: kotlin.String
|
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
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user