[FE] Allow using sealed modifier on interface and compute sealed modality for them
#KT-20423
This commit is contained in:
committed by
TeamCityServer
parent
d605c7e491
commit
9609954560
+23
@@ -20897,6 +20897,29 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
public void testWithInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/WithInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/sealed/interfaces")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Interfaces extends AbstractFirOldFrontendDiagnosticsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInterfaces() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleSealedInterface.kt")
|
||||
public void testSimpleSealedInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/simpleSealedInterface.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors")
|
||||
|
||||
@@ -52,7 +52,7 @@ object ModifierCheckerCore {
|
||||
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY, INTERFACE),
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||
|
||||
@@ -42,6 +42,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
ContractDescriptionBlockChecker,
|
||||
PrivateInlineFunctionsReturningAnonymousObjectsChecker,
|
||||
SealedInheritorInSamePackageChecker,
|
||||
SealedInterfaceAllowedChecker,
|
||||
)
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
|
||||
object SealedInterfaceAllowedChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.SealedInterfaces)) return
|
||||
if (descriptor !is ClassDescriptor) return
|
||||
if (descriptor.kind != ClassKind.INTERFACE) return
|
||||
val keyword = declaration.modifierList?.getModifier(KtTokens.SEALED_KEYWORD) ?: return
|
||||
context.trace.report(Errors.WRONG_MODIFIER_TARGET.on(keyword, KtTokens.SEALED_KEYWORD, KotlinTarget.INTERFACE.description))
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// ISSUE: KT-20423
|
||||
// !LANGUAGE: -SealedInterfaces
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
sealed interface Base
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// ISSUE: KT-20423
|
||||
// !LANGUAGE: -SealedInterfaces
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
<!WRONG_MODIFIER_TARGET!>sealed<!> interface Base
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package
|
||||
|
||||
public sealed interface Base {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// ISSUE: KT-20423
|
||||
// !LANGUAGE: +FreedomForSealedClasses +SealedInterfaces
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
sealed interface Base
|
||||
|
||||
interface A : Base
|
||||
|
||||
sealed class B : Base {
|
||||
class First : B()
|
||||
class Second : B()
|
||||
}
|
||||
|
||||
enum class C : Base {
|
||||
SomeValue, AnotherValue
|
||||
}
|
||||
|
||||
object D : Base
|
||||
|
||||
fun test_1(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B -> 2
|
||||
is C -> 3
|
||||
is D -> 4
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B.First -> 2
|
||||
is B.Second -> 3
|
||||
C.SomeValue -> 4
|
||||
C.AnotherValue -> 5
|
||||
D -> 6
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// ISSUE: KT-20423
|
||||
// !LANGUAGE: +FreedomForSealedClasses +SealedInterfaces
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
sealed interface Base
|
||||
|
||||
interface A : Base
|
||||
|
||||
sealed class B : Base {
|
||||
class First : B()
|
||||
class Second : B()
|
||||
}
|
||||
|
||||
enum class C : Base {
|
||||
SomeValue, AnotherValue
|
||||
}
|
||||
|
||||
object D : Base
|
||||
|
||||
fun test_1(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B -> 2
|
||||
is C -> 3
|
||||
is D -> 4
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
is B.First -> 2
|
||||
is B.Second -> 3
|
||||
C.SomeValue -> 4
|
||||
C.AnotherValue -> 5
|
||||
D -> 6
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package
|
||||
|
||||
public fun test_1(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_2(/*0*/ base: Base): kotlin.Unit
|
||||
|
||||
public interface A : Base {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public sealed class B : Base {
|
||||
internal constructor B()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public final class First : B {
|
||||
public constructor First()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Second : B {
|
||||
public constructor Second()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
public sealed interface Base {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final enum class C : kotlin.Enum<C>, Base {
|
||||
enum entry SomeValue
|
||||
|
||||
enum entry AnotherValue
|
||||
|
||||
private constructor C()
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: C): kotlin.Int
|
||||
public final override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
|
||||
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<C!>!
|
||||
public final override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): C
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<C>
|
||||
}
|
||||
|
||||
public object D : Base {
|
||||
private constructor D()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+23
@@ -20974,6 +20974,29 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
public void testWithInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/WithInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/sealed/interfaces")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Interfaces extends AbstractDiagnosticsTestWithFirValidation {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInterfaces() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleSealedInterface.kt")
|
||||
public void testSimpleSealedInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/simpleSealedInterface.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors")
|
||||
|
||||
Generated
+23
@@ -20899,6 +20899,29 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
public void testWithInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/WithInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/sealed/interfaces")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Interfaces extends AbstractDiagnosticsUsingJavacTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInterfaces() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleSealedInterface.kt")
|
||||
public void testSimpleSealedInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/simpleSealedInterface.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors")
|
||||
|
||||
@@ -144,6 +144,7 @@ enum class LanguageFeature(
|
||||
JvmRecordSupport(KOTLIN_1_5),
|
||||
|
||||
FreedomForSealedClasses(KOTLIN_1_5),
|
||||
SealedInterfaces(KOTLIN_1_5),
|
||||
|
||||
// Temporarily disabled, see KT-27084/KT-22379
|
||||
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
|
||||
|
||||
@@ -270,7 +270,7 @@ public class DescriptorUtils {
|
||||
}
|
||||
|
||||
public static boolean isSealedClass(@Nullable DeclarationDescriptor descriptor) {
|
||||
return isKindOf(descriptor, ClassKind.CLASS) && ((ClassDescriptor) descriptor).getModality() == Modality.SEALED;
|
||||
return (isKindOf(descriptor, ClassKind.CLASS) || isKindOf(descriptor, ClassKind.INTERFACE)) && ((ClassDescriptor) descriptor).getModality() == Modality.SEALED;
|
||||
}
|
||||
|
||||
public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
|
||||
Reference in New Issue
Block a user