Support sealed class inheritors in the same file
#KT-11573 Fixed
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,7 +34,9 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class PackageCodegen {
|
||||
private final GenerationState state;
|
||||
@@ -76,6 +78,12 @@ public class PackageCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateClassesAndObjectsInFile(@NotNull List<KtClassOrObject> classOrObjects, @NotNull PackageContext packagePartContext) {
|
||||
for (KtClassOrObject classOrObject : CodegenUtilKt.sortTopLevelClassesAndPrepareContextForSealedClasses(classOrObjects, packagePartContext, state)) {
|
||||
generateClassOrObject(classOrObject, packagePartContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFile(@NotNull KtFile file) {
|
||||
JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file);
|
||||
|
||||
@@ -88,6 +96,8 @@ public class PackageCodegen {
|
||||
|
||||
boolean generatePackagePart = false;
|
||||
|
||||
List<KtClassOrObject> classOrObjects = new ArrayList<KtClassOrObject>();
|
||||
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) {
|
||||
generatePackagePart = true;
|
||||
@@ -95,7 +105,7 @@ public class PackageCodegen {
|
||||
else if (declaration instanceof KtClassOrObject) {
|
||||
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
|
||||
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
|
||||
generateClassOrObject(classOrObject, packagePartContext);
|
||||
classOrObjects.add(classOrObject);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtScript) {
|
||||
@@ -106,6 +116,7 @@ public class PackageCodegen {
|
||||
}
|
||||
}
|
||||
}
|
||||
generateClassesAndObjectsInFile(classOrObjects, packagePartContext);
|
||||
|
||||
if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,21 +18,27 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import java.util.*
|
||||
|
||||
fun generateIsCheck(
|
||||
v: InstructionAdapter,
|
||||
@@ -125,4 +131,48 @@ fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(companion: KtObject
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Top level subclasses of a sealed class should be generated before that sealed class,
|
||||
// so that we'd generate the necessary accessor for its constructor afterwards
|
||||
fun sortTopLevelClassesAndPrepareContextForSealedClasses(
|
||||
classOrObjects: List<KtClassOrObject>,
|
||||
packagePartContext: PackageContext,
|
||||
state: GenerationState
|
||||
): List<KtClassOrObject> {
|
||||
fun prepareContextIfNeeded(descriptor: ClassDescriptor?) {
|
||||
if (DescriptorUtils.isSealedClass(descriptor)) {
|
||||
// save context for sealed class
|
||||
packagePartContext.intoClass(descriptor!!, OwnerKind.IMPLEMENTATION, state)
|
||||
}
|
||||
}
|
||||
|
||||
// optimization
|
||||
when (classOrObjects.size) {
|
||||
0 -> return emptyList()
|
||||
1 -> {
|
||||
prepareContextIfNeeded(state.bindingContext.get(BindingContext.CLASS, classOrObjects.first()))
|
||||
return classOrObjects
|
||||
}
|
||||
}
|
||||
|
||||
val result = ArrayList<KtClassOrObject>(classOrObjects.size)
|
||||
val descriptorToPsi = LinkedHashMap<ClassDescriptor, KtClassOrObject>()
|
||||
for (classOrObject in classOrObjects) {
|
||||
val descriptor = state.bindingContext.get(BindingContext.CLASS, classOrObject)
|
||||
if (descriptor == null) {
|
||||
result.add(classOrObject)
|
||||
}
|
||||
else {
|
||||
prepareContextIfNeeded(descriptor)
|
||||
descriptorToPsi[descriptor] = classOrObject
|
||||
}
|
||||
}
|
||||
|
||||
// topologicalOrder(listOf(1, 2, 3)) { emptyList() } = listOf(3, 2, 1). Because of this used keys.reversed().
|
||||
val sortedDescriptors = DFS.topologicalOrder(descriptorToPsi.keys.reversed()) {
|
||||
it.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as? ClassDescriptor }.filter { it in descriptorToPsi.keys }
|
||||
}
|
||||
sortedDescriptors.mapTo(result) { descriptorToPsi[it]!! }
|
||||
return result
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -274,15 +274,16 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
||||
if (descriptor.isCompanionObject()) {
|
||||
CodegenContext companionContext = this.findChildContext(descriptor);
|
||||
if (companionContext != null) {
|
||||
assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
|
||||
companionContext.getContextKind() + "!= " + kind;
|
||||
return (ClassContext) companionContext;
|
||||
public ClassContext intoClass(@NotNull ClassDescriptor descriptor, @NotNull OwnerKind kind, @NotNull GenerationState state) {
|
||||
if (shouldAddChild(descriptor)) {
|
||||
CodegenContext savedContext = this.findChildContext(descriptor);
|
||||
if (savedContext != null) {
|
||||
assert savedContext.getContextKind() == kind : "Kinds should be same, but: " +
|
||||
savedContext.getContextKind() + "!= " + kind;
|
||||
return (ClassContext) savedContext;
|
||||
}
|
||||
}
|
||||
|
||||
ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
|
||||
|
||||
if (descriptor.getCompanionObjectDescriptor() != null) {
|
||||
@@ -571,6 +572,17 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
|
||||
}
|
||||
|
||||
if (descriptorContext == null && descriptor instanceof ConstructorDescriptor) {
|
||||
ClassDescriptor classDescriptor = ((ConstructorDescriptor) descriptor).getContainingDeclaration();
|
||||
if (DescriptorUtils.isSealedClass(classDescriptor)) {
|
||||
CodegenContext parentContextForClass = findParentContextWithDescriptor(classDescriptor.getContainingDeclaration());
|
||||
if (parentContextForClass != null) {
|
||||
//generate super constructor calls for top-level sealed classes from top level child
|
||||
descriptorContext = parentContextForClass.findChildContext(classDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptorContext == null) {
|
||||
return descriptor;
|
||||
}
|
||||
@@ -630,7 +642,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
private void addChild(@NotNull CodegenContext child) {
|
||||
if (shouldAddChild(child)) {
|
||||
if (shouldAddChild(child.contextDescriptor)) {
|
||||
if (childContexts == null) {
|
||||
childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
|
||||
}
|
||||
@@ -639,8 +651,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldAddChild(@NotNull CodegenContext child) {
|
||||
return DescriptorUtils.isCompanionObject(child.contextDescriptor);
|
||||
private static boolean shouldAddChild(@NotNull DeclarationDescriptor childContextDescriptor) {
|
||||
return DescriptorUtils.isCompanionObject(childContextDescriptor) || DescriptorUtils.isSealedClass(childContextDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,29 +16,30 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg
|
||||
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import java.util.*
|
||||
|
||||
interface WhenMissingCase {
|
||||
@@ -229,9 +230,8 @@ private object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChec
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
): List<WhenMissingCase> {
|
||||
assert(subjectDescriptor != null) { "isWhenOnSealedClassExhaustive should be called with not-null subject class descriptor" }
|
||||
assert(subjectDescriptor!!.modality === Modality.SEALED) {
|
||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor"
|
||||
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
||||
}
|
||||
val memberClassDescriptors = LinkedHashSet<ClassDescriptor>()
|
||||
collectNestedSubclasses(subjectDescriptor!!, subjectDescriptor, memberClassDescriptors)
|
||||
@@ -241,21 +241,27 @@ private object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChec
|
||||
}
|
||||
|
||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||
return TypeUtils.getClassDescriptor(subjectType)?.modality == Modality.SEALED
|
||||
return DescriptorUtils.isSealedClass(TypeUtils.getClassDescriptor(subjectType))
|
||||
}
|
||||
|
||||
private fun collectNestedSubclasses(
|
||||
baseDescriptor: ClassDescriptor,
|
||||
currentDescriptor: ClassDescriptor,
|
||||
subclasses: MutableSet<ClassDescriptor>) {
|
||||
for (descriptor in DescriptorUtils.getAllDescriptors(currentDescriptor.unsubstitutedInnerClassesScope)) {
|
||||
if (descriptor is ClassDescriptor) {
|
||||
if (DescriptorUtils.isDirectSubclass(descriptor, baseDescriptor)) {
|
||||
subclasses.add(descriptor)
|
||||
subclasses: MutableSet<ClassDescriptor>
|
||||
) {
|
||||
fun collectSubclasses(scope: MemberScope, collectNested: Boolean) {
|
||||
for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) {
|
||||
if (descriptor is ClassDescriptor) {
|
||||
if (DescriptorUtils.isDirectSubclass(descriptor, baseDescriptor)) subclasses.add(descriptor)
|
||||
|
||||
if (collectNested) collectNestedSubclasses(baseDescriptor, descriptor, subclasses)
|
||||
}
|
||||
collectNestedSubclasses(baseDescriptor, descriptor, subclasses)
|
||||
}
|
||||
}
|
||||
if (currentDescriptor == baseDescriptor && DescriptorUtils.isTopLevelDeclaration(currentDescriptor)) {
|
||||
collectSubclasses((currentDescriptor.containingDeclaration as PackageFragmentDescriptor).getMemberScope(), collectNested = false)
|
||||
}
|
||||
collectSubclasses(currentDescriptor.unsubstitutedInnerClassesScope, collectNested = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
|
||||
public class BodyResolver {
|
||||
private static final boolean ALLOW_TOP_LEVEL_SEALED_INHERITANCE = true;
|
||||
|
||||
@NotNull private final AnnotationChecker annotationChecker;
|
||||
@NotNull private final ExpressionTypingServices expressionTypingServices;
|
||||
@NotNull private final CallResolver callResolver;
|
||||
@@ -384,18 +386,26 @@ public class BodyResolver {
|
||||
@NotNull
|
||||
private static Set<TypeConstructor> getAllowedFinalSupertypes(
|
||||
@NotNull ClassDescriptor descriptor,
|
||||
@NotNull KtClassOrObject jetClass
|
||||
@NotNull Map<KtTypeReference, KotlinType> supertypes,
|
||||
@NotNull KtClassOrObject ktClassOrObject
|
||||
) {
|
||||
Set<TypeConstructor> parentEnumOrSealed;
|
||||
if (jetClass instanceof KtEnumEntry) {
|
||||
Set<TypeConstructor> parentEnumOrSealed = Collections.emptySet();
|
||||
if (ktClassOrObject instanceof KtEnumEntry) {
|
||||
parentEnumOrSealed = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration()).getTypeConstructor());
|
||||
}
|
||||
else if (ALLOW_TOP_LEVEL_SEALED_INHERITANCE && DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
for (KotlinType superType : supertypes.values()) {
|
||||
ClassifierDescriptor classifierDescriptor = superType.getConstructor().getDeclarationDescriptor();
|
||||
if (DescriptorUtils.isSealedClass(classifierDescriptor) && DescriptorUtils.isTopLevelDeclaration(classifierDescriptor)) {
|
||||
parentEnumOrSealed = Collections.singleton(classifierDescriptor.getTypeConstructor());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
parentEnumOrSealed = Collections.emptySet();
|
||||
ClassDescriptor currentDescriptor = descriptor;
|
||||
while (currentDescriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
currentDescriptor = (ClassDescriptor) currentDescriptor.getContainingDeclaration();
|
||||
if (currentDescriptor.getModality() == Modality.SEALED) {
|
||||
if (DescriptorUtils.isSealedClass(currentDescriptor)) {
|
||||
if (parentEnumOrSealed.isEmpty()) {
|
||||
parentEnumOrSealed = new HashSet<TypeConstructor>();
|
||||
}
|
||||
@@ -418,9 +428,9 @@ public class BodyResolver {
|
||||
private void checkSupertypeList(
|
||||
@NotNull ClassDescriptor supertypeOwner,
|
||||
@NotNull Map<KtTypeReference, KotlinType> supertypes,
|
||||
@NotNull KtClassOrObject jetClass
|
||||
@NotNull KtClassOrObject ktClassOrObject
|
||||
) {
|
||||
Set<TypeConstructor> allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, jetClass);
|
||||
Set<TypeConstructor> allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, supertypes, ktClassOrObject);
|
||||
Set<TypeConstructor> typeConstructors = Sets.newHashSet();
|
||||
boolean classAppeared = false;
|
||||
for (Map.Entry<KtTypeReference, KotlinType> entry : supertypes.entrySet()) {
|
||||
@@ -458,13 +468,13 @@ public class BodyResolver {
|
||||
trace.report(INTERFACE_WITH_SUPERCLASS.on(typeReference));
|
||||
addSupertype = false;
|
||||
}
|
||||
else if (jetClass.hasModifier(KtTokens.DATA_KEYWORD)) {
|
||||
else if (ktClassOrObject.hasModifier(KtTokens.DATA_KEYWORD)) {
|
||||
trace.report(DATA_CLASS_CANNOT_HAVE_CLASS_SUPERTYPES.on(typeReference));
|
||||
addSupertype = false;
|
||||
}
|
||||
else if (DescriptorUtils.isSubclass(classDescriptor, builtIns.getThrowable()) &&
|
||||
!supertypeOwner.getDeclaredTypeParameters().isEmpty()) {
|
||||
trace.report(GENERIC_THROWABLE_SUBCLASS.on(jetClass.getTypeParameterList()));
|
||||
trace.report(GENERIC_THROWABLE_SUBCLASS.on(ktClassOrObject.getTypeParameterList()));
|
||||
addSupertype = false;
|
||||
}
|
||||
|
||||
@@ -492,7 +502,7 @@ public class BodyResolver {
|
||||
}
|
||||
}
|
||||
else if (!allowedFinalSupertypes.contains(constructor)) {
|
||||
if (classDescriptor.getModality() == Modality.SEALED) {
|
||||
if (DescriptorUtils.isSealedClass(classDescriptor)) {
|
||||
DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration();
|
||||
while (containingDescriptor != null && containingDescriptor != classDescriptor) {
|
||||
containingDescriptor = containingDescriptor.getContainingDeclaration();
|
||||
|
||||
@@ -20,7 +20,9 @@ import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
@@ -214,7 +216,7 @@ class CallExpressionResolver(
|
||||
if (DescriptorUtils.isEnumClass(containingDescriptor)) {
|
||||
context.trace.report(ENUM_CLASS_CONSTRUCTOR_CALL.on(callExpression))
|
||||
}
|
||||
if (containingDescriptor is ClassDescriptor && containingDescriptor.modality === Modality.SEALED) {
|
||||
if (DescriptorUtils.isSealedClass(containingDescriptor)) {
|
||||
context.trace.report(SEALED_CLASS_CONSTRUCTOR_CALL.on(callExpression))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
class B : A()
|
||||
|
||||
sealed class A() {
|
||||
constructor(i: Int): this()
|
||||
|
||||
class C: A()
|
||||
}
|
||||
|
||||
object T : Y()
|
||||
|
||||
class D : A(4)
|
||||
|
||||
class E : A {
|
||||
constructor(i: Int): super(i)
|
||||
constructor(): super()
|
||||
}
|
||||
|
||||
object S : Z()
|
||||
|
||||
sealed class Y : X()
|
||||
|
||||
sealed class Z : Y()
|
||||
|
||||
sealed class X : A()
|
||||
|
||||
class Q : Y()
|
||||
|
||||
fun box() : String {
|
||||
B()
|
||||
A.C()
|
||||
D()
|
||||
E()
|
||||
E(4)
|
||||
T
|
||||
S
|
||||
Q()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
sealed class Base
|
||||
|
||||
class Derived: Base() {
|
||||
class Derived2: <!INVISIBLE_MEMBER, SEALED_SUPERTYPE!>Base<!>()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
class Local: <!INVISIBLE_MEMBER, SEALED_SUPERTYPE!>Base<!>()
|
||||
}
|
||||
|
||||
+9
@@ -1,5 +1,7 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public sealed class Base {
|
||||
private constructor Base()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
@@ -12,4 +14,11 @@ public final class Derived : 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 Derived2 : Base {
|
||||
public constructor Derived2()
|
||||
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,7 +0,0 @@
|
||||
sealed class Base {
|
||||
|
||||
}
|
||||
|
||||
class Derived: <!INVISIBLE_MEMBER, SEALED_SUPERTYPE!>Base<!>() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class A {
|
||||
sealed class Base
|
||||
}
|
||||
|
||||
class Derived : <!INVISIBLE_MEMBER, SEALED_SUPERTYPE!>A.Base<!>()
|
||||
|
||||
fun test() {
|
||||
class DerivedLocal : <!INVISIBLE_MEMBER, SEALED_SUPERTYPE!>A.Base<!>()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
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 Base {
|
||||
private 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 Derived : A.Base {
|
||||
public constructor Derived()
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
sealed class A {
|
||||
class B: A() {
|
||||
class C: A()
|
||||
}
|
||||
}
|
||||
|
||||
class D: A()
|
||||
|
||||
fun test(a: A) {
|
||||
val nonExhaustive = <!NO_ELSE_IN_WHEN!>when<!> (a) {
|
||||
is A.B -> "B"
|
||||
is A.B.C -> "C"
|
||||
}
|
||||
|
||||
val exhaustive = when (a) {
|
||||
is A.B -> "B"
|
||||
is A.B.C -> "C"
|
||||
is D -> "D"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public sealed class A {
|
||||
private 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 B : A {
|
||||
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 : A {
|
||||
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 D : A {
|
||||
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
|
||||
}
|
||||
@@ -15657,6 +15657,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("DerivedTopLevel.kt")
|
||||
public void testDerivedTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/DerivedTopLevel.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DoubleInner.kt")
|
||||
public void testDoubleInner() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/DoubleInner.kt");
|
||||
@@ -15735,9 +15741,9 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NeverDerived.kt")
|
||||
public void testNeverDerived() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/NeverDerived.kt");
|
||||
@TestMetadata("NeverDerivedFromNested.kt")
|
||||
public void testNeverDerivedFromNested() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/NeverDerivedFromNested.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@@ -19584,6 +19590,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TopLevelSealed.kt")
|
||||
public void testTopLevelSealed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/TopLevelSealed.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("When.kt")
|
||||
public void testWhen() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt");
|
||||
|
||||
@@ -2902,6 +2902,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInSameFile.kt")
|
||||
public void testSealedInSameFile() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/sealedInSameFile.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("selfcreate.kt")
|
||||
public void testSelfcreate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/selfcreate.kt");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,12 +36,28 @@ public class Visibilities {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean inSameFile(@NotNull DeclarationDescriptor what, @NotNull DeclarationDescriptor from) {
|
||||
SourceFile fromContainingFile = DescriptorUtils.getContainingSourceFile(from);
|
||||
if (fromContainingFile != SourceFile.NO_SOURCE_FILE) {
|
||||
return fromContainingFile.equals(DescriptorUtils.getContainingSourceFile(what));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
|
||||
if (DescriptorUtils.isTopLevelDeclaration(what)) {
|
||||
SourceFile fromContainingFile = DescriptorUtils.getContainingSourceFile(from);
|
||||
if (fromContainingFile != SourceFile.NO_SOURCE_FILE) {
|
||||
return fromContainingFile.equals(DescriptorUtils.getContainingSourceFile(what));
|
||||
return inSameFile(what, from);
|
||||
}
|
||||
|
||||
if (what instanceof ConstructorDescriptor) {
|
||||
ClassDescriptor classDescriptor = ((ConstructorDescriptor) what).getContainingDeclaration();
|
||||
if (DescriptorUtils.isSealedClass(classDescriptor)
|
||||
&& DescriptorUtils.isTopLevelDeclaration(classDescriptor)
|
||||
&& from instanceof ConstructorDescriptor
|
||||
&& DescriptorUtils.isTopLevelDeclaration(from.getContainingDeclaration())
|
||||
&& inSameFile(what, from)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,8 +129,8 @@ public class DescriptorUtils {
|
||||
return getFqNameFromTopLevelClass(containingDeclaration).child(name);
|
||||
}
|
||||
|
||||
public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
|
||||
return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
|
||||
public static boolean isTopLevelDeclaration(@Nullable DeclarationDescriptor descriptor) {
|
||||
return descriptor != null && descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
|
||||
}
|
||||
|
||||
public static boolean isExtension(@NotNull CallableDescriptor descriptor) {
|
||||
@@ -276,6 +276,10 @@ public class DescriptorUtils {
|
||||
return isKindOf(descriptor, ClassKind.OBJECT) && ((ClassDescriptor) descriptor).isCompanionObject();
|
||||
}
|
||||
|
||||
public static boolean isSealedClass(@Nullable DeclarationDescriptor descriptor) {
|
||||
return isKindOf(descriptor, ClassKind.CLASS) && ((ClassDescriptor) descriptor).getModality() == Modality.SEALED;
|
||||
}
|
||||
|
||||
public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
|
||||
}
|
||||
@@ -369,7 +373,7 @@ public class DescriptorUtils {
|
||||
@NotNull
|
||||
public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
|
||||
ClassKind classKind = classDescriptor.getKind();
|
||||
if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || classDescriptor.getModality() == Modality.SEALED) {
|
||||
if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isSealedClass(classDescriptor)) {
|
||||
return Visibilities.PRIVATE;
|
||||
}
|
||||
if (isAnonymousObject(classDescriptor)) {
|
||||
@@ -456,7 +460,7 @@ public class DescriptorUtils {
|
||||
|
||||
public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
|
||||
return classDescriptor.getModality() == Modality.ABSTRACT
|
||||
|| classDescriptor.getModality() == Modality.SEALED
|
||||
|| isSealedClass(classDescriptor)
|
||||
|| classDescriptor.getKind() == ClassKind.ENUM_CLASS;
|
||||
}
|
||||
|
||||
|
||||
@@ -683,6 +683,12 @@ public class ClassesTestGenerated extends AbstractClassesTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInSameFile.kt")
|
||||
public void testSealedInSameFile() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/sealedInSameFile.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("selfcreate.kt")
|
||||
public void testSelfcreate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/selfcreate.kt");
|
||||
|
||||
+8
-8
@@ -7,12 +7,12 @@ c 1 0/Ann1
|
||||
d 0/Ann2
|
||||
c 0 0/Ann2
|
||||
c 1 0/Ann2
|
||||
d 0/A
|
||||
a org.test.Ann1 2
|
||||
c 2 0/A
|
||||
d 0/A$DefaultImpls
|
||||
d 0/B
|
||||
a org.test.Ann2 3
|
||||
c 3 0/B
|
||||
d 0/C
|
||||
d 0/D
|
||||
d 0/C
|
||||
d 0/B
|
||||
a org.test.Ann2 2
|
||||
c 2 0/B
|
||||
d 0/A
|
||||
a org.test.Ann1 3
|
||||
c 3 0/A
|
||||
d 0/A$DefaultImpls
|
||||
|
||||
+1
-1
@@ -4,8 +4,8 @@ a java.lang.annotation.Inherited 0
|
||||
c 0 0/Ann
|
||||
a java.lang.annotation.Retention 1
|
||||
c 1 0/Ann
|
||||
d 0/B
|
||||
d 0/A
|
||||
a org.test.Ann 2
|
||||
c 2 0/A
|
||||
d 0/A$DefaultImpls
|
||||
d 0/B
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ a java.lang.annotation.Retention 0
|
||||
p org.test 0
|
||||
c 0 0/Ann
|
||||
a org.test.Ann 1
|
||||
m 1 0/Parent overridenWithoutAnnotation
|
||||
m 1 0/Parent notOverriden
|
||||
m 1 0/Child overridenWithAnnotation
|
||||
m 1 0/Child childMethod
|
||||
m 1 0/Parent overridenWithoutAnnotation
|
||||
m 1 0/Parent notOverriden
|
||||
|
||||
Reference in New Issue
Block a user