diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 575bc3b4d84..d9e28b1fbc3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -253,6 +253,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.INNER_ON_TOP_LEVEL_SCRIPT_CLASS.errorFactory) { firDiagnostic -> + InnerOnTopLevelScriptClassErrorImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } + add(FirErrors.INNER_ON_TOP_LEVEL_SCRIPT_CLASS.warningFactory) { firDiagnostic -> + InnerOnTopLevelScriptClassWarningImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic -> InvisibleReferenceImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a), 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 89ef0ce0e93..c10be060dfa 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 @@ -217,6 +217,14 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val callableId: CallableId } + interface InnerOnTopLevelScriptClassError : KtFirDiagnostic { + override val diagnosticClass get() = InnerOnTopLevelScriptClassError::class + } + + interface InnerOnTopLevelScriptClassWarning : KtFirDiagnostic { + override val diagnosticClass get() = InnerOnTopLevelScriptClassWarning::class + } + interface InvisibleReference : KtFirDiagnostic { override val diagnosticClass get() = InvisibleReference::class val reference: 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 75cbe0adf58..cf54946094e 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 @@ -246,6 +246,16 @@ internal class InvisibleSetterImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.InvisibleSetter +internal class InnerOnTopLevelScriptClassErrorImpl( + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassError + +internal class InnerOnTopLevelScriptClassWarningImpl( + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassWarning + internal class InvisibleReferenceImpl( override val reference: KtSymbol, override val visible: Visibility, diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 33adc17588d..a6874a9f147 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -29134,6 +29134,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/script/imports.kts"); } + @Test + @TestMetadata("innerClassError.kts") + public void testInnerClassError() throws Exception { + runTest("compiler/testData/diagnostics/tests/script/innerClassError.kts"); + } + + @Test + @TestMetadata("innerClassWarning.kts") + public void testInnerClassWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/script/innerClassWarning.kts"); + } + @Test @TestMetadata("LateInit.kts") public void testLateInit() throws Exception { 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 b394dacc64d..eabb446473c 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 @@ -99,6 +99,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("visibility") parameter("callableId") } + val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError(LanguageFeature.ProhibitScriptTopLevelInnerClasses) } val UNRESOLVED by object : DiagnosticGroup("Unresolved") { 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 be41781c06d..82d09ff151e 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageFeature.ProhibitCyclesInAnnotations import org.jetbrains.kotlin.config.LanguageFeature.ProhibitImplementingVarByInheritedVal import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments +import org.jetbrains.kotlin.config.LanguageFeature.ProhibitScriptTopLevelInnerClasses import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes import org.jetbrains.kotlin.config.LanguageFeature.RestrictRetentionForExpressionAnnotations import org.jetbrains.kotlin.config.LanguageFeature.RestrictionOfValReassignmentViaBackingField @@ -146,6 +147,7 @@ object FirErrors { val VAL_OR_VAR_ON_CATCH_PARAMETER by error1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) val INVISIBLE_SETTER by error3(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) + val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError0(ProhibitScriptTopLevelInnerClasses) // Unresolved val INVISIBLE_REFERENCE by error3, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt index 7aa2af2e2c6..f586443507a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt @@ -262,13 +262,17 @@ object FirModifierChecker : FirBasicDeclarationChecker() { val possibleParentPredicate = possibleParentTargetPredicateMap[modifierToken] ?: return true if (actualParents.any { possibleParentPredicate.isAllowed(it, context.session.languageVersionSettings) }) return true - reporter.reportOn( - modifierSource, - FirErrors.WRONG_MODIFIER_CONTAINING_DECLARATION, - modifierToken, - actualParents.firstOrThis(), - context - ) + if (modifierToken == KtTokens.INNER_KEYWORD && parent is FirScript) { + reporter.reportOn(modifierSource, FirErrors.INNER_ON_TOP_LEVEL_SCRIPT_CLASS, context) + } else { + reporter.reportOn( + modifierSource, + FirErrors.WRONG_MODIFIER_CONTAINING_DECLARATION, + modifierToken, + actualParents.firstOrThis(), + context + ) + } return false } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 518bbd1bd01..ad62b106a2b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -301,6 +301,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INLINE_SUSPEND_FU import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_CONSTRUCTOR_NO_RECEIVER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_INSIDE_VALUE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_ON_TOP_LEVEL_SCRIPT_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_AS_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS @@ -714,6 +715,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { VISIBILITY, NAME_OF_CONTAINING_DECLARATION_OR_FILE ) + map.put(INNER_ON_TOP_LEVEL_SCRIPT_CLASS, "Top level script class cannot be inner.") map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", NULLABLE_STRING) map.put(UNRESOLVED_IMPORT, "Unresolved reference: {0}", NULLABLE_STRING) // & map.put(UNRESOLVED_LABEL, "Unresolved label") diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt index b3cf3329bf5..555d2d6839f 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt @@ -1023,7 +1023,7 @@ open class PsiRawFirBuilder( val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply { isExpect = this@toFirConstructor?.hasExpectModifier() == true || this@PsiRawFirBuilder.context.containerIsExpect isActual = this@toFirConstructor?.hasActualModifier() == true - isInner = owner.hasModifier(INNER_KEYWORD) + isInner = owner.parent.parent !is KtScript && owner.hasModifier(INNER_KEYWORD) // a warning about inner script class is reported on the class itself isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private isFromEnumClass = owner.hasModifier(ENUM_KEYWORD) } @@ -1244,6 +1244,7 @@ open class PsiRawFirBuilder( // NB: enum entry nested classes are considered local by FIR design (see discussion in KT-45115) val isLocal = classOrObject.isLocal || classOrObject.getStrictParentOfType() != null val classIsExpect = classOrObject.hasExpectModifier() || context.containerIsExpect + val sourceElement = classOrObject.toFirSourceElement() return withChildClassName( classOrObject.nameAsSafeName, isExpect = classIsExpect, @@ -1265,7 +1266,7 @@ open class PsiRawFirBuilder( ).apply { isExpect = classIsExpect isActual = classOrObject.hasActualModifier() - isInner = classOrObject.hasModifier(INNER_KEYWORD) + isInner = classOrObject.hasModifier(INNER_KEYWORD) && classOrObject.parent.parent !is KtScript isCompanion = (classOrObject as? KtObjectDeclaration)?.isCompanion() == true isData = classOrObject.hasModifier(DATA_KEYWORD) isInline = classOrObject.hasModifier(INLINE_KEYWORD) || classOrObject.hasModifier(VALUE_KEYWORD) @@ -1273,10 +1274,10 @@ open class PsiRawFirBuilder( isExternal = classOrObject.hasModifier(EXTERNAL_KEYWORD) } - withCapturedTypeParameters(status.isInner || isLocal, classOrObject.toFirSourceElement(), listOf()) { + withCapturedTypeParameters(status.isInner || isLocal, sourceElement, listOf()) { var delegatedFieldsMap: Map? buildRegularClass { - source = classOrObject.toFirSourceElement() + source = sourceElement moduleData = baseModuleData origin = FirDeclarationOrigin.Source name = classOrObject.nameAsSafeName diff --git a/compiler/testData/diagnostics/tests/script/NestedInnerClass.fir.kts b/compiler/testData/diagnostics/tests/script/NestedInnerClass.fir.kts index d20c27c2f57..b96f8f27d0c 100644 --- a/compiler/testData/diagnostics/tests/script/NestedInnerClass.fir.kts +++ b/compiler/testData/diagnostics/tests/script/NestedInnerClass.fir.kts @@ -10,7 +10,7 @@ class Nested { } -inner class Inner { +inner class Inner { fun innerFun() = function() val innerProp = property fun innerThisFun() = this@NestedInnerClass.function() diff --git a/compiler/testData/diagnostics/tests/script/innerClassError.fir.kts b/compiler/testData/diagnostics/tests/script/innerClassError.fir.kts new file mode 100644 index 00000000000..bca175cb8e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/innerClassError.fir.kts @@ -0,0 +1,4 @@ +// TARGET_BACKEND: JVM_IR +// !LANGUAGE: +ProhibitScriptTopLevelInnerClasses + +inner class A diff --git a/compiler/testData/diagnostics/tests/script/innerClassError.kts b/compiler/testData/diagnostics/tests/script/innerClassError.kts new file mode 100644 index 00000000000..8fda5582bc0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/innerClassError.kts @@ -0,0 +1,3 @@ +// TARGET_BACKEND: JVM_IR + +inner class A diff --git a/compiler/testData/diagnostics/tests/script/innerClassWarning.fir.kts b/compiler/testData/diagnostics/tests/script/innerClassWarning.fir.kts new file mode 100644 index 00000000000..1afecf4192b --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/innerClassWarning.fir.kts @@ -0,0 +1,4 @@ +// TARGET_BACKEND: JVM_IR +// !LANGUAGE: -ProhibitScriptTopLevelInnerClasses + +inner class A diff --git a/compiler/testData/diagnostics/tests/script/innerClassWarning.kts b/compiler/testData/diagnostics/tests/script/innerClassWarning.kts new file mode 100644 index 00000000000..8fda5582bc0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/script/innerClassWarning.kts @@ -0,0 +1,3 @@ +// TARGET_BACKEND: JVM_IR + +inner class A diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index e2bb5a0e0a0..ed4e5132fa2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -29972,6 +29972,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/script/imports.kts"); } + @Test + @TestMetadata("innerClassError.kts") + public void testInnerClassError() throws Exception { + runTest("compiler/testData/diagnostics/tests/script/innerClassError.kts"); + } + + @Test + @TestMetadata("innerClassWarning.kts") + public void testInnerClassWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/script/innerClassWarning.kts"); + } + @Test @TestMetadata("LateInit.kts") public void testLateInit() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 7183dbd0748..55dec0c5c41 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -332,6 +332,11 @@ enum class LanguageFeature( // When this feature is enabled, no such errors are reported. NoAdditionalErrorsInK1DiagnosticReporter(sinceVersion = null, kind = OTHER), + // top-level script inner classes never made any sense, but used for some time to overcome the capturing logic limitations + // Now capturing logic works properly, therefore the warning is reported in K2 + // this feature will eventually switch this warning to an error + ProhibitScriptTopLevelInnerClasses(sinceVersion = null, kind = OTHER), + // Experimental features BreakContinueInInlineLambdas(null), // KT-1436