[FE] Support sealed classes and interfaces from java
KT-43551 KT-41215
This commit is contained in:
committed by
TeamCityServer
parent
bdfb71b149
commit
7897bb6adb
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
// ISSUE: KT-41215, KT-43551
|
||||
|
||||
// FILE: Base.java
|
||||
public sealed class Base permits A, B {}
|
||||
|
||||
// FILE: A.java
|
||||
public final class A extends Base {}
|
||||
|
||||
// FILE: B.java
|
||||
public sealed class B extends Base permits B.C, B.D {
|
||||
public static final class C implements B {}
|
||||
|
||||
public static non-sealed class D extends B {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
fun test_ok_1(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B -> 2
|
||||
}
|
||||
}
|
||||
|
||||
fun test_ok_2(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B.C -> 2
|
||||
is B.D -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_error_1(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
}
|
||||
}
|
||||
|
||||
fun test_error_2(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
is B.C -> 2
|
||||
}
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
package
|
||||
|
||||
public fun test_error_1(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_error_2(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_ok_1(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_ok_2(/*0*/ base: Base): kotlin.Unit
|
||||
|
||||
public final class A : Base {
|
||||
public constructor A()
|
||||
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 {
|
||||
public 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 C : B {
|
||||
public constructor C()
|
||||
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 open class D : B {
|
||||
public 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
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Base {
|
||||
public constructor 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
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
// ISSUE: KT-41215, KT-43551
|
||||
|
||||
// FILE: Base.java
|
||||
public sealed interface Base permits A, B, E {}
|
||||
|
||||
// FILE: A.java
|
||||
public non-sealed interface A extends Base {}
|
||||
|
||||
// FILE: B.java
|
||||
public sealed interface B extends Base permits B.C, B.D {
|
||||
public static final class C implements B {}
|
||||
|
||||
public static non-sealed interface D extends B {}
|
||||
}
|
||||
|
||||
// FILE: E.java
|
||||
public enum E implements Base {
|
||||
First, Second
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
fun test_ok_1(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B -> 2
|
||||
is E -> 3
|
||||
}
|
||||
}
|
||||
|
||||
fun test_ok_2(base: Base) {
|
||||
val x = when (base) {
|
||||
is A -> 1
|
||||
is B.C -> 2
|
||||
is B.D -> 3
|
||||
E.First -> 4
|
||||
E.Second -> 5
|
||||
}
|
||||
}
|
||||
|
||||
fun test_error_1(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
is B -> 2
|
||||
}
|
||||
}
|
||||
|
||||
fun test_error_2(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
is B.C -> 2
|
||||
is B.D -> 3
|
||||
E.Second -> 5
|
||||
}
|
||||
}
|
||||
|
||||
fun test_error_3(base: Base) {
|
||||
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
|
||||
is A -> 1
|
||||
is B.C -> 2
|
||||
E.First -> 4
|
||||
E.Second -> 5
|
||||
}
|
||||
}
|
||||
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
package
|
||||
|
||||
public fun test_error_1(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_error_2(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_error_3(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_ok_1(/*0*/ base: Base): kotlin.Unit
|
||||
public fun test_ok_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 interface B : 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 class C : B {
|
||||
public constructor C()
|
||||
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 interface D : 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 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 E : kotlin.Enum<E!>, Base {
|
||||
enum entry First
|
||||
|
||||
enum entry Second
|
||||
|
||||
public constructor E()
|
||||
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: E!): kotlin.Int
|
||||
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public final override /*1*/ /*fake_override*/ fun describeConstable(): java.util.Optional<java.lang.Enum.EnumDesc<E!>!>!
|
||||
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<E!>!
|
||||
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): E
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<E>
|
||||
}
|
||||
+33
@@ -70,4 +70,37 @@ public class DiagnosticsWithJdk15TestGenerated extends AbstractDiagnosticsWithJd
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/supertypesCheck.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithJava15/sealedClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SealedClasses extends AbstractDiagnosticsWithJdk15Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSealedClasses() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJava15/sealedClasses"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("javaSealedClassExhaustiveness.kt")
|
||||
public void testJavaSealedClassExhaustiveness() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/sealedClasses/javaSealedClassExhaustiveness.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaSealedInterfaceExhaustiveness.kt")
|
||||
public void testJavaSealedInterfaceExhaustiveness() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/sealedClasses/javaSealedInterfaceExhaustiveness.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinInheritsJavaClass.kt")
|
||||
public void testKotlinInheritsJavaClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/sealedClasses/kotlinInheritsJavaClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinInheritsJavaInterface.kt")
|
||||
public void testKotlinInheritsJavaInterface() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/sealedClasses/kotlinInheritsJavaInterface.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@ enum class Modality {
|
||||
ABSTRACT;
|
||||
|
||||
companion object {
|
||||
|
||||
// NB: never returns SEALED
|
||||
fun convertFromFlags(abstract: Boolean, open: Boolean): Modality {
|
||||
if (abstract) return ABSTRACT
|
||||
if (open) return OPEN
|
||||
return FINAL
|
||||
fun convertFromFlags(sealed: Boolean, abstract: Boolean, open: Boolean): Modality {
|
||||
return when {
|
||||
sealed -> SEALED
|
||||
abstract -> ABSTRACT
|
||||
open -> OPEN
|
||||
else -> FINAL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -76,7 +76,7 @@ class LazyJavaClassDescriptor(
|
||||
|
||||
private val modality =
|
||||
if (jClass.isAnnotationType || jClass.isEnum) Modality.FINAL
|
||||
else Modality.convertFromFlags(jClass.isAbstract || jClass.isInterface, !jClass.isFinal)
|
||||
else Modality.convertFromFlags(jClass.isSealed, jClass.isAbstract || jClass.isInterface, !jClass.isFinal)
|
||||
|
||||
private val visibility = jClass.visibility
|
||||
private val isInner = jClass.outerClass != null && !jClass.isStatic
|
||||
@@ -180,7 +180,14 @@ class LazyJavaClassDescriptor(
|
||||
fun wasScopeContentRequested() =
|
||||
getUnsubstitutedMemberScope().wasContentRequested() || staticScope.wasContentRequested()
|
||||
|
||||
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||
override fun getSealedSubclasses(): Collection<ClassDescriptor> = if (modality == Modality.SEALED) {
|
||||
val attributes = TypeUsage.COMMON.toAttributes()
|
||||
jClass.permittedTypes.mapNotNull {
|
||||
c.typeResolver.transformJavaType(it, attributes).constructor.declarationDescriptor as? ClassDescriptor
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
|
||||
|
||||
|
||||
+1
-1
@@ -515,7 +515,7 @@ class LazyJavaClassMemberScope(
|
||||
returnType,
|
||||
// Those functions are generated as open in bytecode
|
||||
// Actually, it should not be important because the class is final anyway, but leaving them open is convenient for consistency
|
||||
Modality.convertFromFlags(abstract = false, open = true),
|
||||
Modality.convertFromFlags(sealed = false, abstract = false, open = true),
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
null,
|
||||
)
|
||||
|
||||
+1
-1
@@ -181,7 +181,7 @@ abstract class LazyJavaScope(
|
||||
effectiveSignature.typeParameters,
|
||||
effectiveSignature.valueParameters,
|
||||
effectiveSignature.returnType,
|
||||
Modality.convertFromFlags(method.isAbstract, !method.isFinal),
|
||||
Modality.convertFromFlags(sealed = false, method.isAbstract, !method.isFinal),
|
||||
method.visibility.toDescriptorVisibility(),
|
||||
if (effectiveSignature.receiverType != null)
|
||||
mapOf(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER to valueParameters.descriptors.first())
|
||||
|
||||
Reference in New Issue
Block a user