diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 3e580f1f97c..cf3d1b37016 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2313,7 +2313,7 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val parameter: KtSymbol } - abstract class UninitializedEnumEntry : KtFirDiagnostic() { + abstract class UninitializedEnumEntry : KtFirDiagnostic() { override val diagnosticClass get() = UninitializedEnumEntry::class abstract val enumEntry: KtSymbol } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 8f1a8878cd1..c1b0caf42b1 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2793,7 +2793,7 @@ internal class UninitializedEnumEntryImpl( override val enumEntry: KtSymbol, override val firDiagnostic: KtPsiDiagnostic, override val token: KtLifetimeToken, -) : KtFirDiagnostic.UninitializedEnumEntry(), KtAbstractFirDiagnostic +) : KtFirDiagnostic.UninitializedEnumEntry(), KtAbstractFirDiagnostic internal class UninitializedEnumCompanionImpl( override val enumClass: KtClassLikeSymbol, 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 63d85df2915..7fa9ced1b7f 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 @@ -1133,7 +1133,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val UNINITIALIZED_PARAMETER by error { parameter("parameter") } - val UNINITIALIZED_ENUM_ENTRY by error { + val UNINITIALIZED_ENUM_ENTRY by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("enumEntry") } val UNINITIALIZED_ENUM_COMPANION by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { 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 8b3cddbbddd..231297d7809 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 @@ -607,7 +607,7 @@ object FirErrors { // Control flow diagnostics val UNINITIALIZED_VARIABLE by error1() val UNINITIALIZED_PARAMETER by error1() - val UNINITIALIZED_ENUM_ENTRY by error1() + val UNINITIALIZED_ENUM_ENTRY by error1(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val UNINITIALIZED_ENUM_COMPANION by error1(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val VAL_REASSIGNMENT by error1>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError1(RestrictionOfValReassignmentViaBackingField, SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index f8dee7a34a2..07b7f2e9365 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -131,6 +131,7 @@ fun FirTypeRef.toRegularClassSymbol(session: FirSession): FirRegularClassSymbol? fun FirBasedSymbol<*>.getContainingClassSymbol(session: FirSession): FirClassLikeSymbol<*>? = when (this) { is FirCallableSymbol<*> -> containingClassLookupTag()?.toSymbol(session) is FirClassLikeSymbol<*> -> getContainingClassLookupTag()?.toSymbol(session) + is FirAnonymousInitializerSymbol -> dispatchReceiverType?.toSymbol(session) as? FirClassLikeSymbol<*> else -> null } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt index 3a994c30fa7..d751bc3510b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt @@ -83,12 +83,6 @@ internal fun FirMemberDeclaration.isEffectivelyExternal( internal val FirClass.canHaveOpenMembers: Boolean get() = modality() != Modality.FINAL || classKind == ClassKind.ENUM_CLASS -internal val FirDeclaration.isEnumEntryInitializer: Boolean - get() { - if (this !is FirConstructor || !this.isPrimary) return false - return (containingClassForStaticMemberAttr as? ConeClassLookupTagWithFixedSymbol)?.symbol?.classKind == ClassKind.ENUM_ENTRY - } - // contract: returns(true) implies (this is FirMemberDeclaration<*>) val FirDeclaration.isLocalMember: Boolean get() = symbol.isLocalMember diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUninitializedEnumChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUninitializedEnumChecker.kt index e2a879f1e9f..eafc44ea727 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUninitializedEnumChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUninitializedEnumChecker.kt @@ -6,25 +6,27 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.classKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isEnumEntryInitializer import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.analysis.checkers.outerClassSymbol import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals -import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.utils.addToStdlib.flatAssociateBy object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { // Initialization order: member property initializers, enum entries, companion object (including members in it). @@ -44,8 +46,8 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { // } // // Note that, when initializing enum entries, now we call the enum class's constructor, a.k.a. , to initialize non-final - // instance members. Therefore, if there is a member property in the enum class, and if that member has an access to enum entries, - // that is an illegal access since enum entries are not yet initialized: + // instance members. Therefore, if there is a member property in the enum class, and if that member has access to enum entries, + // that is illegal access since enum entries are not yet initialized: // enum class E(...) { // E1, E2, ... // val m1 = E1 @@ -99,19 +101,28 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { // companion object is not initialized for both member properties. The former has the property itself as the last containing // declaration, whereas the latter has an anonymous function instead. For both cases, we're looking for member properties as an // accessed context. + val isInsideCorrespondingEnum = context.containingDeclarations.any { + it.getContainingClassSymbol(context.session) == enumClassSymbol + } + if (!isInsideCorrespondingEnum) return + + val declarationSymbols = enumClassSymbol.declarationSymbols + val enumMemberProperties = declarationSymbols.filterIsInstance() + val enumInitBlocks = declarationSymbols.filterIsInstance() + val enumEntries = declarationSymbols.filterIsInstance() + val enumEntriesInitBlocks = enumEntries.flatAssociateBy { + it.initializerObjectSymbol?.declarationSymbols?.filterIsInstance().orEmpty() + } + val accessedContext = context.containingDeclarations.lastOrNull { - // To not raise an error for an access from another enum class, e.g., + // To not raise an error for access from another enum class, e.g., // enum class EnumCompanion4(...) { // INSTANCE(EnumCompanion2.foo()) // } // find an accessed context within the same enum class. - it.getContainingClassSymbol(context.session) == enumClassSymbol + it.getContainingClassSymbol(context.session) == enumClassSymbol || it.symbol in enumEntriesInitBlocks }?.symbol ?: return - val declarationSymbols = enumClassSymbol.declarationSymbols - val enumMemberProperties = declarationSymbols.filterIsInstance() - val enumEntries = declarationSymbols.filterIsInstance() - // When checking enum member properties, accesses to enum entries in lazy delegation is legitimate, e.g., // enum JvmTarget(...) { // JVM_1_6, ... @@ -120,9 +131,10 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { // JVM_1_6 -> ... // } // } + val containingDeclarationForAccess = context.containingDeclarations.lastOrNull() if (accessedContext in enumMemberProperties) { val lazyDelegation = (accessedContext as FirPropertySymbol).lazyDelegation - if (lazyDelegation != null && lazyDelegation == context.containingDeclarations.lastOrNull()) { + if (lazyDelegation != null && lazyDelegation == containingDeclarationForAccess) { return } } @@ -137,7 +149,7 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { // fun foo() = ... // } // } - if (accessedContext in enumEntries && context.containingDeclarations.lastOrNull()?.isEnumEntryInitializer != true) { + if (accessedContext in enumEntries && containingDeclarationForAccess?.isEnumEntryInitializer(context.session) != true) { return } @@ -163,36 +175,74 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { if (calleeSymbol in enumEntries) { val calleeEnumEntry = calleeSymbol as FirEnumEntrySymbol // Uninitialized from the point of view of members of that enum class - if (accessedContext in enumMemberProperties) { - // From KT-6054 - // enum class MyEnum { - // A, B; - // val x = when(this) { - // A -> ... - // B -> ... - // } - // } - reporter.reportOn(source, FirErrors.UNINITIALIZED_ENUM_ENTRY, calleeEnumEntry, context) - } - // enum class A(...) { - // A1(A2), - // A2(...), - // A3(A3) - // } - if (accessedContext in enumEntries) { + + fun reportIllegalAccessInEnumEntry(correspondingEnumEntry: FirEnumEntrySymbol) { // Technically, this is equal to `enumEntries.indexOf(accessedContext) <= enumEntries.indexOf(calleeDeclaration)`. // Instead of double `indexOf`, we can iterate entries just once until either one appears. var precedingEntry: FirEnumEntrySymbol? = null - enumEntries.forEach { - if (precedingEntry != null) return@forEach - if (it == calleeEnumEntry || it == accessedContext) { + for (it in enumEntries) { + if (it == calleeEnumEntry || it == correspondingEnumEntry) { precedingEntry = it + break } } - if (precedingEntry == accessedContext) { + if (precedingEntry == correspondingEnumEntry) { reporter.reportOn(source, FirErrors.UNINITIALIZED_ENUM_ENTRY, calleeEnumEntry, context) } } + + when (accessedContext) { + in enumMemberProperties, + in enumInitBlocks -> { + /* From KT-6054 + * enum class MyEnum { + * A, B; + * val x = when(this) { + * A -> ... + * B -> ... + * } + * } + */ + reporter.reportOn(source, FirErrors.UNINITIALIZED_ENUM_ENTRY, calleeEnumEntry, context) + } + + in enumEntries -> { + /* + * enum class A(...) { + * A1(A2), + * A2(...), + * A3(A3) + * } + */ + reportIllegalAccessInEnumEntry(accessedContext as FirEnumEntrySymbol) + } + + in enumEntriesInitBlocks -> { + /* + * enum class MyEnum { + * A { + * init { A } + * }, + * B; + * } + */ + val entrySymbol = enumEntriesInitBlocks.getValue(accessedContext as FirAnonymousInitializerSymbol) + /* + * In init block of entry this entry already initialized, so it's safe to access it + * enum class MyEnum { + * A { + * init { + * A // safe + * B // unsafe + * } + * }, + * B + * } + */ + if (entrySymbol == calleeSymbol) return + reportIllegalAccessInEnumEntry(entrySymbol) + } + } } } @@ -208,4 +258,18 @@ object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() { val lazyCallArgument = delegateCall.argumentList.arguments.singleOrNull() as? FirLambdaArgumentExpression ?: return null return (lazyCallArgument.expression as? FirAnonymousFunctionExpression)?.anonymousFunction } + + private fun FirDeclaration.isEnumEntryInitializer(session: FirSession): Boolean { + val containingClassSymbol = when (this) { + is FirConstructor -> { + if (!isPrimary) return false + (containingClassForStaticMemberAttr as? ConeClassLookupTagWithFixedSymbol)?.symbol + } + is FirAnonymousInitializer -> { + dispatchReceiverType?.toSymbol(session) + } + else -> null + } ?: return false + return containingClassSymbol.classKind == ClassKind.ENUM_ENTRY + } } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousInitializer.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousInitializer.kt index e50b63a4d5d..8f0771cdda8 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousInitializer.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousInitializer.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousInitializerSymbol -import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType +import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.visitors.* /* @@ -30,7 +30,7 @@ abstract class FirAnonymousInitializer : FirDeclaration(), FirControlFlowGraphOw abstract override val controlFlowGraphReference: FirControlFlowGraphReference? abstract val body: FirBlock? abstract override val symbol: FirAnonymousInitializerSymbol - abstract val dispatchReceiverType: ConeSimpleKotlinType? + abstract val dispatchReceiverType: ConeClassLikeType? override fun accept(visitor: FirVisitor, data: D): R = visitor.visitAnonymousInitializer(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousInitializerBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousInitializerBuilder.kt index aa18a5374b0..5a691177d3b 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousInitializerBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousInitializerBuilder.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousInitializerSymbol -import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType +import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.visitors.* /* @@ -40,7 +40,7 @@ class FirAnonymousInitializerBuilder : FirDeclarationBuilder, FirAnnotationConta override var attributes: FirDeclarationAttributes = FirDeclarationAttributes() var body: FirBlock? = null var symbol: FirAnonymousInitializerSymbol = FirAnonymousInitializerSymbol() - var dispatchReceiverType: ConeSimpleKotlinType? = null + var dispatchReceiverType: ConeClassLikeType? = null override fun build(): FirAnonymousInitializer { return FirAnonymousInitializerImpl( diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousInitializerImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousInitializerImpl.kt index 0a81e8d47cf..9d16c0ed8f7 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousInitializerImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousInitializerImpl.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousInitializerSymbol -import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType +import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.visitors.* import org.jetbrains.kotlin.fir.MutableOrEmptyList import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty @@ -36,7 +36,7 @@ internal class FirAnonymousInitializerImpl( override val attributes: FirDeclarationAttributes, override var body: FirBlock?, override val symbol: FirAnonymousInitializerSymbol, - override val dispatchReceiverType: ConeSimpleKotlinType?, + override val dispatchReceiverType: ConeClassLikeType?, ) : FirAnonymousInitializer() { override val annotations: List get() = emptyList() override var controlFlowGraphReference: FirControlFlowGraphReference? = null diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAnonymousInitializerSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAnonymousInitializerSymbol.kt index 57dd59b73fd..ca1ce55f262 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAnonymousInitializerSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirAnonymousInitializerSymbol.kt @@ -7,7 +7,11 @@ package org.jetbrains.kotlin.fir.symbols.impl import org.jetbrains.kotlin.fir.declarations.FirAnonymousInitializer import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType class FirAnonymousInitializerSymbol : FirBasedSymbol() { override fun toString(): String = "${this::class.simpleName} " + + val dispatchReceiverType: ConeSimpleKotlinType? + get() = fir.dispatchReceiverType } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt index 816956eb460..957bf7294d6 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.symbols.impl import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase @@ -94,7 +95,10 @@ class FirFieldSymbol(callableId: CallableId) : FirVariableSymbol(calla get() = fir.isVar } -class FirEnumEntrySymbol(callableId: CallableId) : FirVariableSymbol(callableId) +class FirEnumEntrySymbol(callableId: CallableId) : FirVariableSymbol(callableId) { + val initializerObjectSymbol: FirAnonymousObjectSymbol? + get() = (fir.initializer as? FirAnonymousObjectExpression)?.anonymousObject?.symbol +} class FirValueParameterSymbol(name: Name) : FirVariableSymbol(CallableId(name)) { val hasDefaultValue: Boolean diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index ddcdb7af929..0ef60cf998f 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -453,7 +453,7 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild anonymousInitializer.configure { +body(nullable = true, withReplace = true) +symbol("FirAnonymousInitializerSymbol") - +field("dispatchReceiverType", coneSimpleKotlinTypeType, nullable = true) + +field("dispatchReceiverType", coneClassLikeTypeType, nullable = true) } danglingModifierList.configure { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt index 1485d5b5e3f..580377e4506 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.tree.generator.context.generatedType import org.jetbrains.kotlin.fir.tree.generator.context.type +import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType import org.jetbrains.kotlin.name.ClassId @@ -44,6 +45,7 @@ val annotationUseSiteTargetType = type(AnnotationUseSiteTarget::class) val operationKindType = type("fir.expressions", "LogicOperationKind") val coneKotlinTypeType = type(ConeKotlinType::class) val coneSimpleKotlinTypeType = type(ConeSimpleKotlinType::class) +val coneClassLikeTypeType = type(ConeClassLikeType::class) val whenRefType = generatedType("", "FirExpressionRef") val referenceToSimpleExpressionType = generatedType("", "FirExpressionRef") diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.fir.kt deleted file mode 100644 index 06c90466cef..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.fir.kt +++ /dev/null @@ -1,55 +0,0 @@ -// LANGUAGE: +ProhibitQualifiedAccessToUninitializedEnumEntry -// ISSUE: KT-41124 - -enum class SomeEnum11(var x: Int) { - A(1), - B(2); - - init { - A.x = 10 // Error - } -} - -enum class SomeEnum12(var x: Int) { - A(1), - B(2); - - init { - SomeEnum12.A.x = 10 // Error - } -} - -enum class SomeEnum21(var x: Int) { - A(1) { - init { - A.x = 10 // OK - SomeEnum21.A.x = 10 // OK - B.x = 10 // Error - } - }, - B(2) -} - -enum class SomeEnum22(var x: Int) { - A(1) { - init { - A.x = 10 // OK - SomeEnum22.A.x = 10 // OK - SomeEnum22.B.x = 10 // Migration error - } - }, - B(2) -} - - -enum class SomeEnum3(var x: Int) { - A(1), - B(2) { - init { - A.x = 10 // OK - SomeEnum3.A.x = 10 // OK - B.x = 10 // OK - SomeEnum3.B.x = 10 // OK - } - }; -} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.kt index 6002cce1a2b..440ba0bc4bb 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedQualifiedEnumEntry.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // LANGUAGE: +ProhibitQualifiedAccessToUninitializedEnumEntry // ISSUE: KT-41124 diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt index 29fc1688c6c..1958cd32b49 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt @@ -292,6 +292,16 @@ inline fun List.flatGroupBy( return result } +inline fun List.flatAssociateBy(selector: (T) -> Collection): Map { + return buildMap { + for (value in this@flatAssociateBy) { + for (key in selector(value)) { + put(key, value) + } + } + } +} + fun MutableList.popLast(): E = removeAt(lastIndex) fun , V> enumMapOf(vararg pairs: Pair): EnumMap = EnumMap(mapOf(*pairs))