[FE] Collect inheritors of sealed classes from new places in computeSealedSubclasses

#KT-13495
This commit is contained in:
Dmitriy Novozhilov
2020-11-16 12:20:15 +03:00
committed by TeamCityServer
parent 70c61be1ef
commit e76acc8ee0
17 changed files with 374 additions and 39 deletions
@@ -20768,6 +20768,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenWithElse.kt");
}
@TestMetadata("ExhaustiveWithFreedom.kt")
public void testExhaustiveWithFreedom() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
}
@TestMetadata("Local.kt")
public void testLocal() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
@@ -20788,6 +20793,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealed.kt");
}
@TestMetadata("NestedSealedWithoutRestrictions.kt")
public void testNestedSealedWithoutRestrictions() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealedWithoutRestrictions.kt");
}
@TestMetadata("NeverConstructed.kt")
public void testNeverConstructed() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NeverConstructed.kt");
@@ -271,7 +271,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
);
// TODO: only consider classes from the same file, not the whole package fragment
this.sealedSubclasses = storageManager.createLazyValue(() -> DescriptorUtilsKt.computeSealedSubclasses(this));
boolean freedomForSealedInterfacesSupported = c.getLanguageVersionSettings().supportsFeature(LanguageFeature.FreedomForSealedClasses);
this.sealedSubclasses = storageManager.createLazyValue(() -> DescriptorUtilsKt.computeSealedSubclasses(this, freedomForSealedInterfacesSupported));
}
private static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) {
@@ -2,23 +2,40 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !LANGUAGE: +FreedomForSealedClasses
// FILE: a.kt
// FILE: Base.kt
sealed class Base {
class A : Base()
}
// FILE: b.kt
// FILE: B.kt
class B : Base()
// FILE: c.kt
// FILE: Container.kt
fun getLetter(base: Base): String = when (base) {
is Base.A -> "O"
is B -> "K"
class Containter {
class C : Base()
inner class D : Base()
val d = D()
}
// FILE: main.kt
fun getValue(base: Base): Int = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
fun box(): String {
return getLetter(Base.A()) + getLetter(B())
var res = 0
res += getValue(Base.A())
res += getValue(B())
res += getValue(Containter.C())
res += getValue(Containter().d)
return if (res == 10) "OK" else "Fail"
}
@@ -0,0 +1,64 @@
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +FreedomForSealedClasses
// FILE: Base.kt
sealed class Base {
class A : Base()
}
// FILE: B.kt
class B : <!HIDDEN!>Base<!>()
// FILE: Container.kt
class Containter {
class C : <!HIDDEN, SEALED_SUPERTYPE!>Base<!>()
inner class D : <!HIDDEN, SEALED_SUPERTYPE!>Base<!>()
}
// FILE: main.kt
fun test_OK(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_1(base: Base) {
val x = when (base) {
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_2(base: Base) {
val x = when (base) {
is Base.A -> 1
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_3(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.D -> 4
}
}
fun test_error_4(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
}
}
@@ -0,0 +1,64 @@
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +FreedomForSealedClasses
// FILE: Base.kt
sealed class Base {
class A : Base()
}
// FILE: B.kt
class B : Base()
// FILE: Container.kt
class Containter {
class C : Base()
inner class D : Base()
}
// FILE: main.kt
fun test_OK(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_1(base: Base) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is B -> 2
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_2(base: Base) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is Base.A -> 1
is Containter.C -> 3
is Containter.D -> 4
}
}
fun test_error_3(base: Base) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is Base.A -> 1
is B -> 2
is Containter.D -> 4
}
}
fun test_error_4(base: Base) {
val x = <!NO_ELSE_IN_WHEN!>when<!> (base) {
is Base.A -> 1
is B -> 2
is Containter.C -> 3
}
}
@@ -0,0 +1,49 @@
package
public fun test_OK(/*0*/ base: Base): kotlin.Unit
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_error_4(/*0*/ base: Base): kotlin.Unit
public final 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 sealed class Base {
internal 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
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 final class Containter {
public constructor Containter()
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 : Base {
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 final inner class D : Base {
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
}
}
@@ -1,5 +1,4 @@
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +FreedomForSealedClasses
// FILE: a.kt
@@ -25,14 +24,3 @@ class Container {
class LocalClass : <!HIDDEN, SEALED_SUPERTYPE_IN_LOCAL_CLASS!>Base<!>() {} // Should be an error
}
}
// FILE: d.kt
fun test(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Container.C -> 3
is Container.D -> 4
}
}
@@ -1,5 +1,4 @@
// ISSUE: KT-13495
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !LANGUAGE: +FreedomForSealedClasses
// FILE: a.kt
@@ -25,14 +24,3 @@ class Container {
class LocalClass : <!SEALED_SUPERTYPE!>Base<!>() {} // Should be an error
}
}
// FILE: d.kt
fun test(base: Base) {
val x = when (base) {
is Base.A -> 1
is B -> 2
is Container.C -> 3
is Container.D -> 4
}
}
@@ -1,7 +1,5 @@
package
public fun test(/*0*/ base: Base): kotlin.Unit
public final class B : Base {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -0,0 +1,39 @@
// ISSUE: KT-13495
// !LANGUAGE: +FreedomForSealedClasses
// !DIAGNOSTICS: -UNUSED_VARIABLE
// FILE: base.kt
package foo
class Container {
sealed class Base
}
// FILE: a.kt
package foo
class A : <!HIDDEN, SEALED_SUPERTYPE!>Container.Base<!>()
// FILE: b.kt
package foo
class BContainer {
class B : <!HIDDEN, SEALED_SUPERTYPE!>Container.Base<!>()
inner class C : <!HIDDEN, SEALED_SUPERTYPE!>Container.Base<!>()
}
// FILE: test.kt
package foo
fun test(base: Container.Base) {
val x = when (base) {
is A -> 1
is BContainer.B -> 2
is BContainer.C -> 3
}
}
@@ -0,0 +1,39 @@
// ISSUE: KT-13495
// !LANGUAGE: +FreedomForSealedClasses
// !DIAGNOSTICS: -UNUSED_VARIABLE
// FILE: base.kt
package foo
class Container {
sealed class Base
}
// FILE: a.kt
package foo
class A : Container.Base()
// FILE: b.kt
package foo
class BContainer {
class B : Container.Base()
inner class C : Container.Base()
}
// FILE: test.kt
package foo
fun test(base: Container.Base) {
val x = when (base) {
is A -> 1
is BContainer.B -> 2
is BContainer.C -> 3
}
}
@@ -0,0 +1,47 @@
package
package foo {
public fun test(/*0*/ base: foo.Container.Base): kotlin.Unit
public final class A : foo.Container.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 final class BContainer {
public constructor BContainer()
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 B : foo.Container.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 inner class C : foo.Container.Base {
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 final class Container {
public constructor Container()
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 {
internal 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
}
}
}
@@ -20845,6 +20845,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenWithElse.kt");
}
@TestMetadata("ExhaustiveWithFreedom.kt")
public void testExhaustiveWithFreedom() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
}
@TestMetadata("Local.kt")
public void testLocal() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
@@ -20865,6 +20870,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealed.kt");
}
@TestMetadata("NestedSealedWithoutRestrictions.kt")
public void testNestedSealedWithoutRestrictions() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealedWithoutRestrictions.kt");
}
@TestMetadata("NeverConstructed.kt")
public void testNeverConstructed() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NeverConstructed.kt");
@@ -20770,6 +20770,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenWithElse.kt");
}
@TestMetadata("ExhaustiveWithFreedom.kt")
public void testExhaustiveWithFreedom() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
}
@TestMetadata("Local.kt")
public void testLocal() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
@@ -20790,6 +20795,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealed.kt");
}
@TestMetadata("NestedSealedWithoutRestrictions.kt")
public void testNestedSealedWithoutRestrictions() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NestedSealedWithoutRestrictions.kt");
}
@TestMetadata("NeverConstructed.kt")
public void testNeverConstructed() throws Exception {
runTest("compiler/testData/diagnostics/tests/sealed/NeverConstructed.kt");
@@ -377,7 +377,7 @@ fun ClassifierDescriptor.getAllSuperClassifiers(): Sequence<ClassifierDescriptor
// Note this is a generic and slow implementation which would work almost for any subclass of ClassDescriptor.
// Please avoid using it in new code.
// TODO: do something more clever instead at call sites of this function
fun computeSealedSubclasses(sealedClass: ClassDescriptor): Collection<ClassDescriptor> {
fun computeSealedSubclasses(sealedClass: ClassDescriptor, freedomForSealedInterfacesSupported: Boolean): Collection<ClassDescriptor> {
if (sealedClass.modality != Modality.SEALED) return emptyList()
val result = linkedSetOf<ClassDescriptor>()
@@ -396,9 +396,16 @@ fun computeSealedSubclasses(sealedClass: ClassDescriptor): Collection<ClassDescr
}
}
val container = sealedClass.containingDeclaration
val container = if (!freedomForSealedInterfacesSupported) {
sealedClass.containingDeclaration
} else {
sealedClass.parents.firstOrNull { it is PackageFragmentDescriptor }
}
if (container is PackageFragmentDescriptor) {
collectSubclasses(container.getMemberScope(), collectNested = false)
collectSubclasses(
container.getMemberScope(),
collectNested = freedomForSealedInterfacesSupported
)
}
collectSubclasses(sealedClass.unsubstitutedInnerClassesScope, collectNested = true)
return result
@@ -165,7 +165,7 @@ class DeserializedClassDescriptor(
}
// This is needed because classes compiled with Kotlin 1.0 did not contain the sealed_subclass_fq_name field
return computeSealedSubclasses(this)
return computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false)
}
override fun getSealedSubclasses() = sealedSubclasses()
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.builder
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
@@ -51,7 +52,10 @@ class CommonizedClassDescriptor(
MemberScope.Empty
private val typeConstructor = CommonizedClassTypeConstructor(targetComponents, cirSupertypes)
private val sealedSubclasses = targetComponents.storageManager.createLazyValue { computeSealedSubclasses(this) }
private val sealedSubclasses = targetComponents.storageManager.createLazyValue {
// TODO: pass proper language version settings
computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false)
}
private val declaredTypeParametersAndTypeParameterResolver = targetComponents.storageManager.createLazyValue {
val parent = if (isInner) (containingDeclaration as? ClassDescriptor)?.getTypeParameterResolver() else null