From e009b71f8877c02d175e7ab795bcfea262d356eb Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 23 Feb 2021 14:33:44 -0800 Subject: [PATCH] FIR checker: report uninitialized member/extension properties --- .../testData/resolve/constantValues.kt | 4 +- .../diagnostics/annotationClassMember.kt | 2 +- .../properties/noBackingFieldInProperty.kt | 2 +- .../testData/resolve/simpleClass.kt | 2 +- .../resolve/visibility/exposedPropertyType.kt | 12 +- .../callableReferences/ifWithCR.kt | 4 +- .../diagnostics/FirDiagnosticsList.kt | 4 + .../fir/analysis/diagnostics/FirErrors.kt | 3 + .../kotlin/fir/analysis/cfa/CfaUtils.kt | 16 ++- .../declaration/FirDeclarationCheckerUtils.kt | 65 +++++++--- .../declaration/FirMemberPropertyChecker.kt | 116 +++++++++++++++++- .../declaration/FirTopLevelPropertyChecker.kt | 2 +- .../diagnostics/FirDefaultErrorMessages.kt | 14 ++- .../fir/declarations/FirDeclarationUtil.kt | 29 ++++- compiler/testData/cli/jvm/firError.out | 3 + .../diagnostics/tests/Abstract.fir.kt | 16 +-- .../tests/AbstractInAbstractClass.fir.kt | 19 +-- .../diagnostics/tests/AbstractInClass.fir.kt | 16 +-- .../diagnostics/tests/Constructors.fir.kt | 2 +- .../tests/ExternalAccessors.fir.kt | 19 --- .../diagnostics/tests/ExternalAccessors.kt | 1 + .../tests/PrimaryConstructors.fir.kt | 29 ----- .../diagnostics/tests/PrimaryConstructors.kt | 1 + ...iagnosticFileAnnotationInWrongPlace.fir.kt | 4 +- .../backingField/InitCustomSetter.fir.kt | 2 +- .../tests/backingField/InitOpenSetter.fir.kt | 2 +- .../UninitializedOrReassignedVariables.fir.kt | 8 +- .../initializationInLocalClass.fir.kt | 2 +- .../tests/controlFlowAnalysis/kt6788.fir.kt | 2 +- ...ropertiesInitWithOtherInstanceInner.fir.kt | 2 +- .../tests/enum/AbstractInEnum.fir.kt | 18 +-- .../extensions/ExtensionFunctions.fir.kt | 2 +- .../checkBackingFieldException.fir.kt | 17 --- .../checkBackingFieldException.kt | 1 + .../tests/inference/kt11963.fir.kt | 2 +- .../infos/PropertiesWithBackingFields.fir.kt | 22 ++-- .../tests/modifiers/IllegalModifiers.fir.kt | 2 +- .../headerClass/nestedClasses.fir.kt | 69 +++++++++++ .../headerClass/nestedClasses.kt | 12 +- .../headerClass/nestedClasses.txt | 22 ++++ .../tests/override/NonGenerics.fir.kt | 2 +- ...opertyMustHaveAccessorsOrBeAbstract.fir.kt | 25 ---- ...onPropertyMustHaveAccessorsOrBeAbstract.kt | 1 + .../inferenceFromGetters/vars.fir.kt | 2 +- .../tests/regressions/kt10243a.fir.kt | 11 -- .../diagnostics/tests/regressions/kt10243a.kt | 1 + .../propertyInitializationWithPrimary.fir.kt | 2 +- ...ropertyInitializationWithoutPrimary.fir.kt | 2 +- .../unreachableCode.fir.kt | 4 +- .../useOfPropertiesWithPrimary.fir.kt | 2 +- .../useOfPropertiesWithoutPrimary.fir.kt | 10 +- .../useOfPropertiesWithoutPrimary.kt | 8 +- .../noMultiplatformProjects.fir.kt | 2 +- .../valDefiniteInitialization.fir.kt | 2 +- .../valIndefiniteInitialization.fir.kt | 2 +- .../abstract-classes/p-1/neg/1.1.fir.kt | 4 +- .../controlFlow/initialization/neg/1.fir.kt | 8 +- .../controlFlow/initialization/neg/3.fir.kt | 2 +- .../diagnostics/KtFirDataClassConverters.kt | 18 +++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 12 ++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 21 ++++ idea/testData/checker/PrimaryConstructors.kt | 3 +- .../infos/PropertiesWithBackingFields.kt | 3 +- 63 files changed, 487 insertions(+), 230 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/ExternalAccessors.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/PrimaryConstructors.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/regressions/kt10243a.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/constantValues.kt b/compiler/fir/analysis-tests/testData/resolve/constantValues.kt index cc31e1c6fca..7e6b5b5d5a1 100644 --- a/compiler/fir/analysis-tests/testData/resolve/constantValues.kt +++ b/compiler/fir/analysis-tests/testData/resolve/constantValues.kt @@ -8,8 +8,8 @@ class KotlinType class KClassValue(value: Value) : ConstantValue(value) { sealed class Value { data class NormalClass(val value: ClassLiteralValue) : Value() { - val classId: ClassId - val arrayDimensions: Int + val classId: ClassId + val arrayDimensions: Int } data class LocalClass(val type: KotlinType) : Value() diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt index 4c459a52221..c216b670713 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt @@ -2,6 +2,6 @@ annotation class A() { constructor(s: Nothing?) {} init {} fun foo() {} - val bar: Nothing? + val bar: Nothing? val baz get() = Unit } diff --git a/compiler/fir/analysis-tests/testData/resolve/properties/noBackingFieldInProperty.kt b/compiler/fir/analysis-tests/testData/resolve/properties/noBackingFieldInProperty.kt index 092c73a2786..56ea3e92a2f 100644 --- a/compiler/fir/analysis-tests/testData/resolve/properties/noBackingFieldInProperty.kt +++ b/compiler/fir/analysis-tests/testData/resolve/properties/noBackingFieldInProperty.kt @@ -10,6 +10,6 @@ class A { class B { val field: String = "" - val x: Int + val x: Int get() = field.length // should be an error } diff --git a/compiler/fir/analysis-tests/testData/resolve/simpleClass.kt b/compiler/fir/analysis-tests/testData/resolve/simpleClass.kt index e78036d2670..56b63486d4b 100644 --- a/compiler/fir/analysis-tests/testData/resolve/simpleClass.kt +++ b/compiler/fir/analysis-tests/testData/resolve/simpleClass.kt @@ -15,5 +15,5 @@ class SomeClass : SomeInterface { get() = true set(value) {} - var fau: Double + var fau: Double } diff --git a/compiler/fir/analysis-tests/testData/resolve/visibility/exposedPropertyType.kt b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedPropertyType.kt index e3aef127280..c9fac1fd624 100644 --- a/compiler/fir/analysis-tests/testData/resolve/visibility/exposedPropertyType.kt +++ b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedPropertyType.kt @@ -14,10 +14,10 @@ class A { } class Property { - var var1: String - var var2: String - var var3: Int - var var4: A.AInnerPrivate - var var5: A.AInnerPublic - var var6: A.AInnerProtectedEnum + var var1: String + var var2: String + var var3: Int + var var4: A.AInnerPrivate + var var5: A.AInnerPublic + var var6: A.AInnerProtectedEnum } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/ifWithCR.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/ifWithCR.kt index d74affe830e..1eacfbff8c8 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/ifWithCR.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/ifWithCR.kt @@ -1,5 +1,5 @@ -private var Int.readOnlyWrapper: CharSequence? get() = null -private var Int.mutableWrapper: CharSequence? get() = null +private var Int.readOnlyWrapper: CharSequence? get() = null +private var Int.mutableWrapper: CharSequence? get() = null fun main(x: Int) { val x = if (x > 1) x::readOnlyWrapper else x::mutableWrapper diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index dbbf45b7420..fe0341ca87f 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -319,6 +319,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val PROPERTY_INITIALIZER_IN_INTERFACE by error() val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error(PositioningStrategy.DECLARATION_SIGNATURE) + val MUST_BE_INITIALIZED by error(PositioningStrategy.DECLARATION_SIGNATURE) + val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error(PositioningStrategy.DECLARATION_SIGNATURE) + val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error(PositioningStrategy.DECLARATION_SIGNATURE) + val BACKING_FIELD_IN_INTERFACE by error(PositioningStrategy.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error() val PROPERTY_INITIALIZER_NO_BACKING_FIELD by error() diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index d5e745662b5..1b0d5d8c296 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -215,6 +215,9 @@ object FirErrors { val ABSTRACT_PROPERTY_WITH_INITIALIZER by error0() val PROPERTY_INITIALIZER_IN_INTERFACE by error0() val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val MUST_BE_INITIALIZED by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val BACKING_FIELD_IN_INTERFACE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error0() val PROPERTY_INITIALIZER_NO_BACKING_FIELD by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt index 6d8e5bed02c..d7540c7ab4d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt @@ -22,13 +22,25 @@ abstract class EventOccurrencesRangeInfo, K map: PersistentMap = persistentMapOf() ) : ControlFlowInfo(map) { - override fun merge(other: E): E { + override fun merge(other: E): E = + operation(other, EventOccurrencesRange::or) + + fun plus(other: E): E = + when { + isEmpty() -> other + other.isEmpty() -> + @Suppress("UNCHECKED_CAST") + this as E + else -> operation(other, EventOccurrencesRange::plus) + } + + private inline fun operation(other: E, op: (EventOccurrencesRange, EventOccurrencesRange) -> EventOccurrencesRange): E { @Suppress("UNCHECKED_CAST") var result = this as E for (symbol in keys.union(other.keys)) { val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO - result = result.put(symbol, kind1 or kind2) + result = result.put(symbol, op.invoke(kind1, kind2)) } return result } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index b7c3bad9213..8d2a9dfdee3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -19,9 +19,45 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.lexer.KtTokens +internal fun isInsideExpectClass(containingClass: FirRegularClass, context: CheckerContext): Boolean = + isInsideSpecificClass(containingClass, context) { klass -> klass.isExpect } + +internal fun isInsideExternalClass(containingClass: FirRegularClass, context: CheckerContext): Boolean = + isInsideSpecificClass(containingClass, context) { klass -> klass.isExternal } + // Note that the class that contains the currently visiting declaration will *not* be in the context's containing declarations *yet*. -internal fun isInsideExpectClass(containingDeclaration: FirRegularClass, context: CheckerContext): Boolean = - containingDeclaration.isExpect || context.containingDeclarations.asReversed().any { it is FirRegularClass && it.isExpect } +private inline fun isInsideSpecificClass( + containingClass: FirRegularClass, + context: CheckerContext, + specificStatus: (FirRegularClass) -> Boolean +): Boolean = + specificStatus.invoke(containingClass) || + context.containingDeclarations.asReversed().any { it is FirRegularClass && specificStatus.invoke(it) } + +internal fun FirMemberDeclaration.isEffectivelyExpect( + containingClass: FirRegularClass?, + modifierList: FirModifierList? = null, + context: CheckerContext, +): Boolean { + val isExpect = this.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true + if (isExpect) return true + + return containingClass != null && isInsideExpectClass(containingClass, context) +} + +internal fun FirMemberDeclaration.isEffectivelyExternal( + containingClass: FirRegularClass?, + modifierList: FirModifierList? = null, + context: CheckerContext, +): Boolean { + val isExternal = this.isExternal || modifierList?.modifiers?.any { it.token == KtTokens.EXTERNAL_KEYWORD } == true + if (isExternal) return true + + // NB: [MemberDescriptor.isEffectivelyExternal] checks property accessors for property and vice versa. + // But, raw FIR creation already did such upward/downward propagation of modifiers. + + return containingClass != null && isInsideExternalClass(containingClass, context) +} // TODO: check class too internal fun checkExpectDeclarationVisibilityAndBody( @@ -45,17 +81,19 @@ internal fun checkProperty( containingClass: FirRegularClass?, property: FirProperty, modifierList: FirModifierList?, + isInitialized: Boolean, reporter: DiagnosticReporter, context: CheckerContext ) { - checkPropertyInitializer(containingClass, modifierList, property, reporter, context) + checkPropertyInitializer(containingClass, property, modifierList, isInitialized, reporter, context) checkPropertyAccessors(property, reporter, context) } private fun checkPropertyInitializer( containingClass: FirRegularClass?, - modifierList: FirModifierList?, property: FirProperty, + modifierList: FirModifierList?, + isInitialized: Boolean, reporter: DiagnosticReporter, context: CheckerContext ) { @@ -78,7 +116,7 @@ private fun checkPropertyInitializer( } } - val isExpect = property.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true + val isExpect = property.isEffectivelyExpect(containingClass, modifierList, context) when { property.initializer != null -> { @@ -112,18 +150,16 @@ private fun checkPropertyInitializer( } } else -> { - val isExternal = property.isExternal || modifierList?.modifiers?.any { it.token == KtTokens.EXTERNAL_KEYWORD } == true - // TODO: need to analyze class anonymous initializer to see if the property is initialized there. - val isUninitialized = false - if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && isUninitialized && !isExternal) { + val isExternal = property.isEffectivelyExternal(containingClass, modifierList, context) + if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && !isInitialized && !isExternal) { property.source?.let { if (property.receiverTypeRef != null && !property.hasAccessorImplementation) { - // reporter.reportOn(it, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context) - } else { - if (containingClass != null || property.hasAccessorImplementation) { - // reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED, context) + reporter.reportOn(it, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context) + } else { // TODO: can be suppressed not to report diagnostics about no body + if (containingClass == null || property.hasAccessorImplementation) { + reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED, context) } else { - // reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context) + reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context) } } } @@ -148,5 +184,4 @@ private val FirProperty.hasAccessorImplementation: Boolean get() = (getter !is FirDefaultPropertyAccessor && getter?.hasBody == true) || (setter !is FirDefaultPropertyAccessor && setter?.hasBody == true) - internal val FirClass<*>.canHaveOpenMembers: Boolean get() = modality() != Modality.FINAL || classKind == ClassKind.ENUM_CLASS diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt index b9a8e47a7e2..0ec01e17696 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertyChecker.kt @@ -5,9 +5,13 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange +import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.analysis.cfa.PropertyInitializationInfo +import org.jetbrains.kotlin.fir.analysis.cfa.PropertyInitializationInfoCollector import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors @@ -15,22 +19,126 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.NormalPath +import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.lexer.KtTokens // See old FE's [DeclarationsChecker] object FirMemberPropertyChecker : FirRegularClassChecker() { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { - for (member in declaration.declarations) { - if (member is FirProperty) { - checkProperty(declaration, member, context, reporter) + val memberPropertySymbols = declaration.declarations.filterIsInstance().map { it.symbol }.toSet() + val initializedInConstructor = + mutableMapOf().withDefault { EventOccurrencesRange.ZERO } + val initializedInInitOrOtherProperty = + mutableMapOf().withDefault { EventOccurrencesRange.ZERO } + + // If all member properties have its own initializer, we don't need to collect property initialization info at all. + if (memberPropertySymbols.any { it.fir.initializer == null }) { + collectPropertyInitialization(declaration, memberPropertySymbols, initializedInConstructor, initializedInInitOrOtherProperty) + } + + for (propertySymbol in memberPropertySymbols) { + val property = propertySymbol.fir + val isInitialized = + property.initializer != null || + initializedInConstructor.getValue(propertySymbol).isDefinitelyVisited() || + initializedInInitOrOtherProperty.getValue(propertySymbol).isDefinitelyVisited() + checkProperty(declaration, property, isInitialized, context, reporter) + } + } + + private fun collectPropertyInitialization( + klass: FirRegularClass, + memberPropertySymbols: Set, + initializedInConstructor: MutableMap, + initializedInInitOrOtherProperty: MutableMap + ) { + // A property is known to be initialized only if it is initialized + // 1) with its own initializing expression; + // 2) at every class constructor; + // 3) at any of class's anonymous initializers; or + // 4) at other property's initializing expression + + // 2) Property can be initialized at constructors. Since it's unknown what constructor will be used, the property can be determined + // as initialized only if it is initialized at every constructor. We should consider a delegated constructor, e.g., + // constructor() { x = ... } + // constructor(...): this() { ... } // x will be initialized via this() delegation + // We need to topologically sort constructors so that we can process delegated ones before the use sites. + + // 3) Property can be initialized at any of class's anonymous initializers (all of initializers will be executed), e.g., + // init { x = ... } + // ... + // init { y = ... } + + // 4) Property can be initialized at other property's initializing expression too, e.g., + // val initX = inlineMe { x = ... } // where inlineMe returns the value of the last expression of the lambda + + // To handle the delegated constructor call, we need a cache from constructor to (analyzed) property init info. + val constructorToData = + mutableMapOf().withDefault { PropertyInitializationInfo.EMPTY } + + fun collectInfoFromGraph( + graph: ControlFlowGraph, + map: MutableMap, + acc: (EventOccurrencesRange, EventOccurrencesRange) -> EventOccurrencesRange, + delegatedConstructor: FirConstructor? = null, + ) { + val delegatedInfo = delegatedConstructor?.let { constructorToData.getValue(it) } ?: PropertyInitializationInfo.EMPTY + + val data = PropertyInitializationInfoCollector(memberPropertySymbols).getData(graph) + val infoAtExitNode = data[graph.exitNode]?.get(NormalPath) ?: PropertyInitializationInfo.EMPTY + + // NB: it's not [merge], which is conducted at merging points, such as loop condition or when conditions. + // Rather, delegated constructor call is the predecessor of the current constructor call, so we should accumulate. + val info = delegatedInfo.plus(infoAtExitNode) + + if (graph.declaration is FirConstructor) { + constructorToData.putIfAbsent(graph.declaration as FirConstructor, info) } + + for (propertySymbol in memberPropertySymbols) { + if (map.containsKey(propertySymbol)) { + // Accumulation: + // range join for class constructors, range plus for class's anonymous initializers and property initializations + map[propertySymbol] = acc.invoke(map[propertySymbol]!!, info[propertySymbol] ?: EventOccurrencesRange.ZERO) + } else { + // Initial assignment. + // NB: we should not use `acc` here to not weaken ranges. For example, if we visit one and only constructor where + // a property of interest is correctly initialized (a.k.a. [EXACTLY_ONCE]), and if `acc` is ...Range::or, + // merging with the default [ZERO] makes the result [AT_MOST_ONCE], which will be regarded as uninitialized. + map[propertySymbol] = info[propertySymbol] ?: EventOccurrencesRange.ZERO + } + } + } + + val constructorGraphs = klass.constructorsSortedByDelegation.mapNotNull { it.controlFlowGraphReference?.controlFlowGraph } + for (graph in constructorGraphs) { + collectInfoFromGraph( + graph, + initializedInConstructor, + EventOccurrencesRange::or, + (graph.declaration as? FirConstructor)?.delegatedThisConstructor + ) + } + + val initGraphs = klass.anonymousInitializers.mapNotNull { it.controlFlowGraphReference?.controlFlowGraph } + for (graph in initGraphs) { + collectInfoFromGraph(graph, initializedInInitOrOtherProperty, EventOccurrencesRange::plus) + } + + val propertyInitGraphs = memberPropertySymbols.mapNotNull { it.fir.controlFlowGraphReference?.controlFlowGraph } + for (graph in propertyInitGraphs) { + collectInfoFromGraph(graph, initializedInInitOrOtherProperty, EventOccurrencesRange::plus) } } private fun checkProperty( containingDeclaration: FirRegularClass, property: FirProperty, + isInitialized: Boolean, context: CheckerContext, reporter: DiagnosticReporter ) { @@ -40,7 +148,7 @@ object FirMemberPropertyChecker : FirRegularClassChecker() { // So, our source of truth should be the full modifier list retrieved from the source. val modifierList = with(FirModifierList) { property.source.getModifierList() } - checkProperty(containingDeclaration, property, modifierList, reporter, context) + checkProperty(containingDeclaration, property, modifierList, isInitialized, reporter, context) checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context) val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt index f360c89171f..e14077461f0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertyChecker.kt @@ -28,7 +28,7 @@ object FirTopLevelPropertyChecker : FirFileChecker() { // So, our source of truth should be the full modifier list retrieved from the source. val modifierList = with(FirModifierList) { source.getModifierList() } - checkProperty(null, property, modifierList, reporter, context) + checkProperty(null, property, modifierList, property.initializer != null, reporter, context) checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 68bb00f4095..b7d84be8c77 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -75,6 +75,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_SUPER_CLA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_SUPER_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPE_PARAMETER_BOUND +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME @@ -101,6 +102,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OB import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS @@ -471,16 +474,19 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(PRIVATE_PROPERTY_IN_INTERFACE, "Abstract property in an interface cannot be private") map.put(ABSTRACT_PROPERTY_WITH_INITIALIZER, "Property with initializer cannot be abstract") - - map.put(EXTENSION_PROPERTY_WITH_BACKING_FIELD, "Extension property cannot be initialized because it has no backing field") - map.put(PROPERTY_INITIALIZER_NO_BACKING_FIELD, "Initializer is not allowed here because this property has no backing field") - map.put(PROPERTY_INITIALIZER_IN_INTERFACE, "Property initializers are not allowed in interfaces") map.put( PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation, be initialized or be delegated" ) + + map.put(MUST_BE_INITIALIZED, "Property must be initialized") + map.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract") + map.put(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, "Extension property must have accessors or be abstract") + map.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field") + map.put(EXTENSION_PROPERTY_WITH_BACKING_FIELD, "Extension property cannot be initialized because it has no backing field") + map.put(PROPERTY_INITIALIZER_NO_BACKING_FIELD, "Initializer is not allowed here because this property has no backing field") map.put(ABSTRACT_DELEGATED_PROPERTY, "Delegated property cannot be abstract") map.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces") diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt index e6d0673c0fb..8c6fdaadfcf 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.FirRegularClassBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder import org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl import org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -117,8 +118,34 @@ val FirClassSymbol<*>.superConeTypes val FirClass<*>.superConeTypes get() = superTypeRefs.mapNotNull { it.coneTypeSafe() } +val FirClass<*>.anonymousInitializers: List + get() = declarations.filterIsInstance() + +val FirClass<*>.constructors: List + get() = declarations.filterIsInstance() + +val FirConstructor.delegatedThisConstructor: FirConstructor? + get() = delegatedConstructor?.takeIf { it.isThis } + ?.let { (it.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol?.fir as? FirConstructor } + +private object ConstructorDelegationComparator : Comparator { + override fun compare(p0: FirConstructor?, p1: FirConstructor?): Int { + if (p0 == null && p1 == null) return 0 + if (p0 == null) return -1 + if (p1 == null) return 1 + if (p0.delegatedThisConstructor == p1) return 1 + if (p1.delegatedThisConstructor == p0) return -1 + // If neither is a delegation to each other, the order doesn't matter. + // Here we return 0 to preserve the original order. + return 0 + } +} + +val FirClass<*>.constructorsSortedByDelegation: List + get() = constructors.sortedWith(ConstructorDelegationComparator) + fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? = - declarations.filterIsInstance().firstOrNull()?.takeIf { it.isPrimary } + constructors.firstOrNull()?.takeIf { it.isPrimary } fun FirRegularClass.collectEnumEntries(): Collection { assert(classKind == ClassKind.ENUM_CLASS) diff --git a/compiler/testData/cli/jvm/firError.out b/compiler/testData/cli/jvm/firError.out index e9c2373330d..21922f3d7fc 100644 --- a/compiler/testData/cli/jvm/firError.out +++ b/compiler/testData/cli/jvm/firError.out @@ -4,6 +4,9 @@ compiler/testData/cli/jvm/firError.kt:5:13: error: x must be initialized before compiler/testData/cli/jvm/firError.kt:10:16: error: public subclass exposes its private supertype 'Private' class Public : Private() { ^ +compiler/testData/cli/jvm/firError.kt:11:5: error: property must be initialized or be abstract + val x: Private + ^ compiler/testData/cli/jvm/firError.kt:11:9: error: public property exposes its private type 'Private' val x: Private ^ diff --git a/compiler/testData/diagnostics/tests/Abstract.fir.kt b/compiler/testData/diagnostics/tests/Abstract.fir.kt index 5582acd2514..f6db0ed7c51 100644 --- a/compiler/testData/diagnostics/tests/Abstract.fir.kt +++ b/compiler/testData/diagnostics/tests/Abstract.fir.kt @@ -1,17 +1,17 @@ // FILE: b.kt package MyPackage //properties - val a: Int + val a: Int val a1: Int = 1 abstract val a2: Int abstract val a3: Int = 1 - var b: Int private set + var b: Int private set var b1: Int = 0; private set abstract var b2: Int private set abstract var b3: Int = 0; private set - var c: Int set(v: Int) { field = v } + var c: Int set(v: Int) { field = v } var c1: Int = 0; set(v: Int) { field = v } abstract var c2: Int set(v: Int) { field = v } abstract var c3: Int = 0; set(v: Int) { field = v } @@ -28,19 +28,19 @@ package MyPackage abstract fun j() {} //property accessors - var i: Int abstract get abstract set + var i: Int abstract get abstract set var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set + var j: Int get() = i; abstract set var j1: Int = 0; get() = i; abstract set - var k: Int abstract set + var k: Int abstract set var k1: Int = 0; abstract set - var l: Int abstract get abstract set + var l: Int abstract get abstract set var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} // FILE: c.kt //creating an instance diff --git a/compiler/testData/diagnostics/tests/AbstractInAbstractClass.fir.kt b/compiler/testData/diagnostics/tests/AbstractInAbstractClass.fir.kt index c8969cdc372..d01739ce4a8 100644 --- a/compiler/testData/diagnostics/tests/AbstractInAbstractClass.fir.kt +++ b/compiler/testData/diagnostics/tests/AbstractInAbstractClass.fir.kt @@ -2,17 +2,17 @@ package abstract abstract class MyAbstractClass() { //properties - val a: Int + val a: Int val a1: Int = 1 abstract val a2: Int abstract val a3: Int = 1 - var b: Int private set + var b: Int private set var b1: Int = 0; private set abstract var b2: Int private set abstract var b3: Int = 0; private set - var c: Int set(v: Int) { field = v } + var c: Int set(v: Int) { field = v } var c1: Int = 0; set(v: Int) { field = v } abstract var c2: Int set(v: Int) { field = v } abstract var c3: Int = 0; set(v: Int) { field = v } @@ -29,17 +29,18 @@ abstract class MyAbstractClass() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set + var i: Int abstract get abstract set var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set - var j1: Int get() = i; abstract set + var j: Int get() = i; abstract set + var j1: Int get() = i; abstract set - var k: Int abstract set + var k: Int abstract set var k1: Int = 0; abstract set - var l: Int abstract get abstract set + var l: Int abstract get abstract set var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } + diff --git a/compiler/testData/diagnostics/tests/AbstractInClass.fir.kt b/compiler/testData/diagnostics/tests/AbstractInClass.fir.kt index d15460e0529..aeae285f020 100644 --- a/compiler/testData/diagnostics/tests/AbstractInClass.fir.kt +++ b/compiler/testData/diagnostics/tests/AbstractInClass.fir.kt @@ -2,17 +2,17 @@ package abstract class MyClass() { //properties - val a: Int + val a: Int val a1: Int = 1 abstract val a2: Int abstract val a3: Int = 1 - var b: Int private set + var b: Int private set var b1: Int = 0; private set abstract var b2: Int private set abstract var b3: Int = 0; private set - var c: Int set(v: Int) { field = v } + var c: Int set(v: Int) { field = v } var c1: Int = 0; set(v: Int) { field = v } abstract var c2: Int set(v: Int) { field = v } abstract var c3: Int = 0; set(v: Int) { field = v } @@ -29,17 +29,17 @@ class MyClass() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set + var i: Int abstract get abstract set var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set + var j: Int get() = i; abstract set var j1: Int = 0; get() = i; abstract set - var k: Int abstract set + var k: Int abstract set var k1: Int = 0; abstract set - var l: Int abstract get abstract set + var l: Int abstract get abstract set var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} + var n: Int abstract get abstract set(v: Int) {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/Constructors.fir.kt b/compiler/testData/diagnostics/tests/Constructors.fir.kt index b5b60357796..cddf4a45d93 100644 --- a/compiler/testData/diagnostics/tests/Constructors.fir.kt +++ b/compiler/testData/diagnostics/tests/Constructors.fir.kt @@ -19,7 +19,7 @@ class Foo() : WithPC0, this() { } class WithCPI_Dup(x : Int) { - var x : Int + var x : Int } class WithCPI(x : Int) { diff --git a/compiler/testData/diagnostics/tests/ExternalAccessors.fir.kt b/compiler/testData/diagnostics/tests/ExternalAccessors.fir.kt deleted file mode 100644 index 55bea112b91..00000000000 --- a/compiler/testData/diagnostics/tests/ExternalAccessors.fir.kt +++ /dev/null @@ -1,19 +0,0 @@ -// See KT-13997 - -class Foo { - var bar: Int // Ok - external get - external set -} - -class Bar { - val foo: Int // Ok - external get - - var baz: Int - external get - - var gav: Int - external set -} - diff --git a/compiler/testData/diagnostics/tests/ExternalAccessors.kt b/compiler/testData/diagnostics/tests/ExternalAccessors.kt index b88881b6c4e..89bab170a77 100644 --- a/compiler/testData/diagnostics/tests/ExternalAccessors.kt +++ b/compiler/testData/diagnostics/tests/ExternalAccessors.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // See KT-13997 class Foo { diff --git a/compiler/testData/diagnostics/tests/PrimaryConstructors.fir.kt b/compiler/testData/diagnostics/tests/PrimaryConstructors.fir.kt deleted file mode 100644 index d576493f416..00000000000 --- a/compiler/testData/diagnostics/tests/PrimaryConstructors.fir.kt +++ /dev/null @@ -1,29 +0,0 @@ -class X { - val x : Int -} - -open class Y() { - val x : Int = 2 -} - -class Y1 { - val x : Int get() = 1 -} - -class Z : Y() { -} - -//KT-650 Prohibit creating class without constructor. - -class MyIterable : Iterable -{ - override fun iterator(): Iterator = MyIterator() - - inner class MyIterator : Iterator - { - override fun hasNext(): Boolean = false - override fun next(): T { - throw UnsupportedOperationException() - } - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/PrimaryConstructors.kt b/compiler/testData/diagnostics/tests/PrimaryConstructors.kt index c83ebea6b85..95ebaec5e71 100644 --- a/compiler/testData/diagnostics/tests/PrimaryConstructors.kt +++ b/compiler/testData/diagnostics/tests/PrimaryConstructors.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class X { val x : Int } diff --git a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/diagnosticFileAnnotationInWrongPlace.fir.kt b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/diagnosticFileAnnotationInWrongPlace.fir.kt index 91147c0b82d..d876193a25c 100644 --- a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/diagnosticFileAnnotationInWrongPlace.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/diagnosticFileAnnotationInWrongPlace.fir.kt @@ -1,7 +1,7 @@ package bar -@file:foo -val prop +@file:foo +val prop @file:[bar baz] fun func() {} diff --git a/compiler/testData/diagnostics/tests/backingField/InitCustomSetter.fir.kt b/compiler/testData/diagnostics/tests/backingField/InitCustomSetter.fir.kt index b96daa2263e..c39035d89e1 100644 --- a/compiler/testData/diagnostics/tests/backingField/InitCustomSetter.fir.kt +++ b/compiler/testData/diagnostics/tests/backingField/InitCustomSetter.fir.kt @@ -6,7 +6,7 @@ class My(val v: Int) { var y: Int set(arg) { field = arg } - var z: Int + var z: Int set(arg) { field = arg } // Ok: initializer available diff --git a/compiler/testData/diagnostics/tests/backingField/InitOpenSetter.fir.kt b/compiler/testData/diagnostics/tests/backingField/InitOpenSetter.fir.kt index 6a8de3b254b..bbc5ecea2c8 100644 --- a/compiler/testData/diagnostics/tests/backingField/InitOpenSetter.fir.kt +++ b/compiler/testData/diagnostics/tests/backingField/InitOpenSetter.fir.kt @@ -4,7 +4,7 @@ abstract class My(val v: Int) { open var y: Int - open var z: Int + open var z: Int // Ok: initializer available open var w: Int = v diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.fir.kt index 7b1b9cb4de2..70f75894d78 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.fir.kt @@ -159,7 +159,7 @@ class AnonymousInitializers(var a: String, val b: String) { } } - val o: String + val o: String init { if (1 < 3) { o = "a" @@ -196,7 +196,7 @@ open class Open(a: Int, w: Int) {} class LocalValsVsProperties(val a: Int, w: Int) : Open(a, w) { val x : Int - val y : Int + val y : Int init { x = 1 val b = x @@ -279,7 +279,7 @@ fun foo() { } class TestObjectExpression() { - val a : Int + val a : Int fun foo() { val a = object { val x : Int @@ -306,7 +306,7 @@ class TestObjectExpression() { object TestObjectDeclaration { val x : Int - val y : Int + val y : Int init { x = 1 } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalClass.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalClass.fir.kt index 8e6c0e90ff4..07912a36765 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalClass.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLocalClass.fir.kt @@ -83,7 +83,7 @@ class My { } } -val top: Int +val top: Int fun init() { top = 1 diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt6788.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt6788.fir.kt index 82e506baf31..0fa9a05917e 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt6788.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt6788.fir.kt @@ -1,5 +1,5 @@ class A(val next: A? = null) { - val x: String + val x: String init { next?.x = "a" } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesInitWithOtherInstanceInner.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesInitWithOtherInstanceInner.fir.kt index 38e9e36656d..aac9cb95310 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesInitWithOtherInstanceInner.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesInitWithOtherInstanceInner.fir.kt @@ -1,5 +1,5 @@ class Outer { - val outerProp: String + val outerProp: String inner class Inner(inner: Inner, outer: Outer) { val innerProp: String init { diff --git a/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt b/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt index 9e15ed3230c..6f4251672c1 100644 --- a/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/AbstractInEnum.fir.kt @@ -4,17 +4,17 @@ package abstract enum class MyEnum() { INSTANCE; //properties - val a: Int + val a: Int val a1: Int = 1 abstract val a2: Int abstract val a3: Int = 1 - var b: Int private set + var b: Int private set var b1: Int = 0; private set abstract var b2: Int private set abstract var b3: Int = 0; private set - var c: Int set(v: Int) { field = v } + var c: Int set(v: Int) { field = v } var c1: Int = 0; set(v: Int) { field = v } abstract var c2: Int set(v: Int) { field = v } abstract var c3: Int = 0; set(v: Int) { field = v } @@ -31,17 +31,17 @@ enum class MyEnum() { abstract fun j() {} //property accessors - var i: Int abstract get abstract set + var i: Int abstract get abstract set var i1: Int = 0; abstract get abstract set - var j: Int get() = i; abstract set + var j: Int get() = i; abstract set var j1: Int = 0; get() = i; abstract set - var k: Int abstract set + var k: Int abstract set var k1: Int = 0; abstract set - var l: Int abstract get abstract set + var l: Int abstract get abstract set var l1: Int = 0; abstract get abstract set - var n: Int abstract get abstract set(v: Int) {} -} + var n: Int abstract get abstract set(v: Int) {} + diff --git a/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.fir.kt b/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.fir.kt index 26888c69552..d3f46fa3931 100644 --- a/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.fir.kt @@ -37,7 +37,7 @@ fun test() { val Int.abs : Int get() = if (this > 0) this else -this; -val T.foo : T +val T.foo : T fun Int.foo() = this diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.fir.kt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.fir.kt deleted file mode 100644 index 439724d5a0a..00000000000 --- a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -package h - -class Square() { - var size : Double = - set(value) { - $area = size * size - } - - var area : Double - private set -} - -fun main() { - val s = Square() - - s.size = 2.0 -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.kt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.kt index 40df42b7275..7d763c59ac3 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/checkBackingFieldException.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL package h class Square() { diff --git a/compiler/testData/diagnostics/tests/inference/kt11963.fir.kt b/compiler/testData/diagnostics/tests/inference/kt11963.fir.kt index 5bdf68a84a7..2bb0af2999b 100644 --- a/compiler/testData/diagnostics/tests/inference/kt11963.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/kt11963.fir.kt @@ -1 +1 @@ -val KClass.something> abc \ No newline at end of file +val KClass.something> abc diff --git a/compiler/testData/diagnostics/tests/infos/PropertiesWithBackingFields.fir.kt b/compiler/testData/diagnostics/tests/infos/PropertiesWithBackingFields.fir.kt index 193b402b51d..564a9198f01 100644 --- a/compiler/testData/diagnostics/tests/infos/PropertiesWithBackingFields.fir.kt +++ b/compiler/testData/diagnostics/tests/infos/PropertiesWithBackingFields.fir.kt @@ -3,8 +3,8 @@ abstract class Test() { abstract val x1 : Int get abstract val x2 : Int get() = 1 - val a : Int - val b : Int get + val a : Int + val b : Int get val c = 1 val c1 = 1 @@ -15,7 +15,7 @@ abstract class Test() { get() { return 1 } val c4 : Int get() = 1 - val c5 : Int + val c5 : Int get() = field + 1 abstract var y : Int @@ -26,19 +26,19 @@ abstract class Test() { abstract var y5 : Int set(x) {} get() = 1 abstract var y6 : Int set(x) {} - var v : Int - var v1 : Int get - var v2 : Int get set - var v3 : Int get() = 1; set + var v : Int + var v1 : Int get + var v2 : Int get set + var v3 : Int get() = 1; set var v4 : Int get() = 1; set(x){} - var v5 : Int get() = 1; set(x){field = x} - var v6 : Int get() = field + 1; set(x){} + var v5 : Int get() = 1; set(x){field = x} + var v6 : Int get() = field + 1; set(x){} abstract val v7 : Int get abstract var v8 : Int get set - var v9 : Int set - var v10 : Int get + var v9 : Int set + var v10 : Int get abstract val v11 : Int abstract get abstract var v12 : Int abstract get abstract set diff --git a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.fir.kt b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.fir.kt index bf5893bc6a8..1a11592382c 100644 --- a/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/IllegalModifiers.fir.kt @@ -6,7 +6,7 @@ abstract class A() { abstract open fun g() final open fun h() {} - open var r: String + open var r: String get abstract protected set } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.fir.kt new file mode 100644 index 00000000000..eb20620de6b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.fir.kt @@ -0,0 +1,69 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_PARAMETER +// MODULE: m1-common +// FILE: common.kt +import kotlin.reflect.KProperty + +fun lazy(initializer: () -> T): Lazy = TODO() +interface Lazy { + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = TODO() +} + +expect class OuterClass { + class NestedClass { + class DeepNested { + class Another { + fun f(s: String) + val p: Int + val c: Int = 1 + val a: Int by lazy { 1 } + } + } + } + + inner class InnerClass { + fun f(x: Int) + val p: String + } + + companion object +} + +expect class OuterClassWithNamedCompanion { + companion object Factory +} + +expect object OuterObject { + object NestedObject +} + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +actual class OuterClass { + actual class NestedClass { + actual class DeepNested { + actual class Another { + actual fun f(s: String) {} + actual val p: Int = 42 + actual val c: Int = 2 + actual val a: Int = 3 + } + } + } + + actual inner class InnerClass { + actual fun f(x: Int) {} + actual val p: String = "" + } + + actual companion object +} + +actual class OuterClassWithNamedCompanion { + actual companion object Factory +} + +actual object OuterObject { + actual object NestedObject +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.kt index db1817d5c6b..aac3f3a7c05 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.kt @@ -1,7 +1,13 @@ -// FIR_IDENTICAL // !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNUSED_PARAMETER // MODULE: m1-common // FILE: common.kt +import kotlin.reflect.KProperty + +fun lazy(initializer: () -> T): Lazy = TODO() +interface Lazy { + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = TODO() +} expect class OuterClass { class NestedClass { @@ -9,6 +15,8 @@ expect class OuterClass { class Another { fun f(s: String) val p: Int + val c: Int = 1 + val a: Int by lazy { 1 } } } } @@ -38,6 +46,8 @@ actual class OuterClass { actual class Another { actual fun f(s: String) {} actual val p: Int = 42 + actual val c: Int = 2 + actual val a: Int = 3 } } } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.txt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.txt index 773293a58ac..0b4474f1177 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClasses.txt @@ -1,6 +1,15 @@ // -- Module: -- package +public fun lazy(/*0*/ initializer: () -> T): Lazy + +public interface Lazy { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public final expect class OuterClass { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -31,6 +40,8 @@ public final expect class OuterClass { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final expect class Another { + public expect final val a: kotlin.Int + public expect final val c: kotlin.Int = 1 public expect final val p: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public final expect fun f(/*0*/ s: kotlin.String): kotlin.Unit @@ -68,6 +79,15 @@ public expect object OuterObject { // -- Module: -- package +public fun lazy(/*0*/ initializer: () -> T): Lazy + +public interface Lazy { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + public final actual class OuterClass { public constructor OuterClass() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -104,6 +124,8 @@ public final actual class OuterClass { public final actual class Another { public constructor Another() + public actual final val a: kotlin.Int = 3 + public actual final val c: kotlin.Int = 2 public actual final val p: kotlin.Int = 42 public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public final actual fun f(/*0*/ s: kotlin.String): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/override/NonGenerics.fir.kt b/compiler/testData/diagnostics/tests/override/NonGenerics.fir.kt index 7d9430c7527..4d62a6854ba 100644 --- a/compiler/testData/diagnostics/tests/override/NonGenerics.fir.kt +++ b/compiler/testData/diagnostics/tests/override/NonGenerics.fir.kt @@ -37,7 +37,7 @@ class MyIllegalClass3() : MyTrait, MyAbstractClass() { class MyIllegalClass4() : MyTrait, MyAbstractClass() { fun foo() {} - val pr : Unit + val pr : Unit override fun other() {} override val otherPr : Int = 1 } diff --git a/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.fir.kt b/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.fir.kt deleted file mode 100644 index 5dc414355bb..00000000000 --- a/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.fir.kt +++ /dev/null @@ -1,25 +0,0 @@ -val String.test1: Int -var String.test2: Int - -var String.test3: Int; public set - -class C { - val String.test1: Int - var String.test2: Int - var String.test3: Int; public set -} - -interface I { - val String.test1: Int - var String.test2: Int - var String.test3: Int; public set -} - -abstract class A { - val String.test1: Int - var String.test2: Int - var String.test3: Int; public set - - abstract val String.testA1: Int - abstract var String.testA2: Int -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.kt b/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.kt index e3e81475d4d..b3c02b0038e 100644 --- a/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.kt +++ b/compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL val String.test1: Int var String.test2: Int diff --git a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.fir.kt b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.fir.kt index 8b45beb2913..2b23646cc00 100644 --- a/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.fir.kt +++ b/compiler/testData/diagnostics/tests/properties/inferenceFromGetters/vars.fir.kt @@ -5,7 +5,7 @@ var x q checkType { _() } } -var noSetter +var noSetter get() = 1 diff --git a/compiler/testData/diagnostics/tests/regressions/kt10243a.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt10243a.fir.kt deleted file mode 100644 index e710a2b9cf8..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/kt10243a.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -var x: Int -fun foo(f: Boolean) { - try { - if (f) { - x = 0 - } - } - finally { - fun bar() {} - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt10243a.kt b/compiler/testData/diagnostics/tests/regressions/kt10243a.kt index 0cab799bdb5..8d726cf06f6 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt10243a.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt10243a.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL var x: Int fun foo(f: Boolean) { try { diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.fir.kt index 81e856b0233..f63590ed30f 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.fir.kt @@ -5,7 +5,7 @@ class A(val w: Char) { val z: Int val v = -1 - val uninitialized: Int + val uninitialized: Int val overinitialized: Int constructor(): this('a') { diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.fir.kt index b484ac7f7bb..9dcb548bd5a 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.fir.kt @@ -5,7 +5,7 @@ class A { val z: Int val v = -1 - val uninitialized: Int + val uninitialized: Int val overinitialized: Int constructor() { diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.fir.kt index 34d183bf40d..0fb0ff9b8cf 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.fir.kt @@ -1,5 +1,5 @@ class A0 { - val x: Int + val x: Int constructor() { if (1 == 1) { return @@ -12,7 +12,7 @@ class A0 { } class A1 { - val x: Int + val x: Int constructor() { if (1 == 1) { return diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.fir.kt index 17b476a0238..6d4a56af1dd 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.fir.kt @@ -8,7 +8,7 @@ class A(val w: Int) { val v = -1 val useInitialized = useUnitialized + v + w - val uninitialized: Int + val uninitialized: Int constructor(): this(1) { x + y + v + uninitialized + w diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.fir.kt index e99f7fa2722..60a66e4b4ef 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.fir.kt @@ -9,7 +9,11 @@ class A { val useInitialized = useUnitialized + v - val uninitialized: Int + val uninitialized: Int + + constructor(x: String): this() { + x + y + v + uninitialized + } constructor() { x = 1 @@ -30,10 +34,6 @@ class A { x + y + v + uninitialized } - constructor(x: String): this() { - x + y + v + uninitialized - } - //anonymous init { y diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt index ea2b64d48a1..e5a77fbb3a8 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt @@ -11,6 +11,10 @@ class A { val uninitialized: Int + constructor(x: String): this() { + x + y + v + uninitialized + } + constructor() { x = 1 y = 2 @@ -30,10 +34,6 @@ class A { x + y + v + uninitialized } - constructor(x: String): this() { - x + y + v + uninitialized - } - //anonymous init { y diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noMultiplatformProjects.fir.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noMultiplatformProjects.fir.kt index 54fa5bc124b..e5beb009775 100644 --- a/compiler/testData/diagnostics/tests/sourceCompatibility/noMultiplatformProjects.fir.kt +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noMultiplatformProjects.fir.kt @@ -3,5 +3,5 @@ expect val bar1 = 42 expect class Baz1 actual fun foo2() = 42 -actual val bar2: Int +actual val bar2: Int actual interface Baz2 diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valDefiniteInitialization.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valDefiniteInitialization.fir.kt index b5e2d6fab7e..8c455d59a2f 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valDefiniteInitialization.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valDefiniteInitialization.fir.kt @@ -83,7 +83,7 @@ fun unknownRun(block: () -> Unit) = block() class DefiniteInitializationInInitSection { val x: Int - val y: Int + val y: Int init { myRun { x = 42 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valIndefiniteInitialization.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valIndefiniteInitialization.fir.kt index ee888f657d7..de7b344033d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valIndefiniteInitialization.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/initialization/exactlyOnce/valIndefiniteInitialization.fir.kt @@ -60,7 +60,7 @@ fun nestedIndefiniteAssignment() { } class InitializationForbiddenInNonInitSection { - val x: Int + val x: Int fun setup() { myRun { x = 42 } diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/1.1.fir.kt index 2f37daf279b..b596dfedc4a 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-1/neg/1.1.fir.kt @@ -8,8 +8,8 @@ abstract class Base() { abstract fun foo() = {} fun boo() : Unit abstract val a = "" - val b - var d + val b + var d } class Impl : Base() { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/1.fir.kt index f7b700cd607..f685c32371a 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/1.fir.kt @@ -34,11 +34,11 @@ fun case_4() { // TESTCASE NUMBER: 5 class case_5 { - val value_1: Int - val value_2: Int + val value_1: Int + val value_2: Int val value_3: Int - var value_4: Int - var value_5: Int + var value_4: Int + var value_5: Int init { funWithAtMostOnceCallsInPlace { value_1 = 1 } funWithUnknownCallsInPlace { value_2 = 1 } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.fir.kt index 48ea8036dd0..e498cb4adbf 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/controlFlow/initialization/neg/3.fir.kt @@ -34,7 +34,7 @@ fun case_2(value_1: Any?) { // TESTCASE NUMBER: 3 class case_3(value_1: Any?) { - var value_2: Int + var value_2: Int init { if (value_1 is String) { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 934d379ee29..aa0a5dfff13 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -911,6 +911,24 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.MUST_BE_INITIALIZED) { firDiagnostic -> + MustBeInitializedImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT) { firDiagnostic -> + MustBeInitializedOrBeAbstractImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT) { firDiagnostic -> + ExtensionPropertyMustHaveAccessorsOrBeAbstractImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.BACKING_FIELD_IN_INTERFACE) { firDiagnostic -> BackingFieldInInterfaceImpl( firDiagnostic as FirPsiDiagnostic<*>, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index d55ce4b3050..6f27aad2509 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -645,6 +645,18 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = PropertyWithNoTypeNoInitializer::class } + abstract class MustBeInitialized : KtFirDiagnostic() { + override val diagnosticClass get() = MustBeInitialized::class + } + + abstract class MustBeInitializedOrBeAbstract : KtFirDiagnostic() { + override val diagnosticClass get() = MustBeInitializedOrBeAbstract::class + } + + abstract class ExtensionPropertyMustHaveAccessorsOrBeAbstract : KtFirDiagnostic() { + override val diagnosticClass get() = ExtensionPropertyMustHaveAccessorsOrBeAbstract::class + } + abstract class BackingFieldInInterface : KtFirDiagnostic() { override val diagnosticClass get() = BackingFieldInInterface::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index e5881e8d257..af820721c1e 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1036,6 +1036,27 @@ internal class PropertyWithNoTypeNoInitializerImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class MustBeInitializedImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.MustBeInitialized(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class MustBeInitializedOrBeAbstractImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.MustBeInitializedOrBeAbstract(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class ExtensionPropertyMustHaveAccessorsOrBeAbstractImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ExtensionPropertyMustHaveAccessorsOrBeAbstract(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class BackingFieldInInterfaceImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, diff --git a/idea/testData/checker/PrimaryConstructors.kt b/idea/testData/checker/PrimaryConstructors.kt index c38e9008be3..fe43f6fb40e 100644 --- a/idea/testData/checker/PrimaryConstructors.kt +++ b/idea/testData/checker/PrimaryConstructors.kt @@ -11,4 +11,5 @@ class Y1 { } class Z : Y() { -} \ No newline at end of file +} +// FIR_COMPARISON \ No newline at end of file diff --git a/idea/testData/checker/infos/PropertiesWithBackingFields.kt b/idea/testData/checker/infos/PropertiesWithBackingFields.kt index 6e5f10c55ed..ecc173d9ef0 100644 --- a/idea/testData/checker/infos/PropertiesWithBackingFields.kt +++ b/idea/testData/checker/infos/PropertiesWithBackingFields.kt @@ -52,4 +52,5 @@ class TestPCParameters(w : Int, x : Int, val y : Int, var z : fun foo() = x -} \ No newline at end of file +} +// FIR_COMPARISON \ No newline at end of file