K2 Scripting: deprecate top level script inner classes

no LT support yet
This commit is contained in:
Ilya Chernikov
2023-06-07 14:36:40 +02:00
committed by Space Team
parent 7484ccb9ee
commit 70d2fcd9c4
16 changed files with 95 additions and 12 deletions
@@ -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),
@@ -217,6 +217,14 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val callableId: CallableId
}
interface InnerOnTopLevelScriptClassError : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = InnerOnTopLevelScriptClassError::class
}
interface InnerOnTopLevelScriptClassWarning : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = InnerOnTopLevelScriptClassWarning::class
}
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = InvisibleReference::class
val reference: KtSymbol
@@ -246,6 +246,16 @@ internal class InvisibleSetterImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InvisibleSetter
internal class InnerOnTopLevelScriptClassErrorImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassError
internal class InnerOnTopLevelScriptClassWarningImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassWarning
internal class InvisibleReferenceImpl(
override val reference: KtSymbol,
override val visible: Visibility,
@@ -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 {
@@ -99,6 +99,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<Visibility>("visibility")
parameter<CallableId>("callableId")
}
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError<PsiElement>(LanguageFeature.ProhibitScriptTopLevelInnerClasses)
}
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
@@ -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<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError0<PsiElement>(ProhibitScriptTopLevelInnerClasses)
// Unresolved
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -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
}
@@ -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")
@@ -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<KtEnumEntry>() != 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<Int, FirFieldSymbol>?
buildRegularClass {
source = classOrObject.toFirSourceElement()
source = sourceElement
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
name = classOrObject.nameAsSafeName
@@ -10,7 +10,7 @@ class Nested {
}
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>inner<!> class Inner {
<!INNER_ON_TOP_LEVEL_SCRIPT_CLASS_WARNING!>inner<!> class Inner {
fun innerFun() = function()
val innerProp = property
fun innerThisFun() = this<!UNRESOLVED_LABEL!>@NestedInnerClass<!>.function()
@@ -0,0 +1,4 @@
// TARGET_BACKEND: JVM_IR
// !LANGUAGE: +ProhibitScriptTopLevelInnerClasses
<!INNER_ON_TOP_LEVEL_SCRIPT_CLASS_ERROR!>inner<!> class A
@@ -0,0 +1,3 @@
// TARGET_BACKEND: JVM_IR
inner class A
@@ -0,0 +1,4 @@
// TARGET_BACKEND: JVM_IR
// !LANGUAGE: -ProhibitScriptTopLevelInnerClasses
<!INNER_ON_TOP_LEVEL_SCRIPT_CLASS_WARNING!>inner<!> class A
@@ -0,0 +1,3 @@
// TARGET_BACKEND: JVM_IR
inner class A
@@ -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 {
@@ -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