Support sealed class inheritors in the same file

#KT-11573 Fixed
This commit is contained in:
Stanislav Erokhin
2016-05-17 19:23:32 +03:00
parent 26be254fbe
commit 7332032bb6
22 changed files with 343 additions and 72 deletions
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
public class PackageCodegen { public class PackageCodegen {
private final GenerationState state; 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) { private void generateFile(@NotNull KtFile file) {
JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file); JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file);
@@ -88,6 +96,8 @@ public class PackageCodegen {
boolean generatePackagePart = false; boolean generatePackagePart = false;
List<KtClassOrObject> classOrObjects = new ArrayList<KtClassOrObject>();
for (KtDeclaration declaration : file.getDeclarations()) { for (KtDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) { if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) {
generatePackagePart = true; generatePackagePart = true;
@@ -95,7 +105,7 @@ public class PackageCodegen {
else if (declaration instanceof KtClassOrObject) { else if (declaration instanceof KtClassOrObject) {
KtClassOrObject classOrObject = (KtClassOrObject) declaration; KtClassOrObject classOrObject = (KtClassOrObject) declaration;
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) { if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
generateClassOrObject(classOrObject, packagePartContext); classOrObjects.add(classOrObject);
} }
} }
else if (declaration instanceof KtScript) { else if (declaration instanceof KtScript) {
@@ -106,6 +116,7 @@ public class PackageCodegen {
} }
} }
} }
generateClassesAndObjectsInFile(classOrObjects, packagePartContext);
if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,21 +18,27 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext 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.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils 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.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.*
fun generateIsCheck( fun generateIsCheck(
v: InstructionAdapter, v: InstructionAdapter,
@@ -126,3 +132,47 @@ 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 @NotNull
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { public ClassContext intoClass(@NotNull ClassDescriptor descriptor, @NotNull OwnerKind kind, @NotNull GenerationState state) {
if (descriptor.isCompanionObject()) { if (shouldAddChild(descriptor)) {
CodegenContext companionContext = this.findChildContext(descriptor); CodegenContext savedContext = this.findChildContext(descriptor);
if (companionContext != null) { if (savedContext != null) {
assert companionContext.getContextKind() == kind : "Kinds should be same, but: " + assert savedContext.getContextKind() == kind : "Kinds should be same, but: " +
companionContext.getContextKind() + "!= " + kind; savedContext.getContextKind() + "!= " + kind;
return (ClassContext) companionContext; return (ClassContext) savedContext;
} }
} }
ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null); ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
if (descriptor.getCompanionObjectDescriptor() != null) { if (descriptor.getCompanionObjectDescriptor() != null) {
@@ -571,6 +572,17 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this); 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) { if (descriptorContext == null) {
return descriptor; return descriptor;
} }
@@ -630,7 +642,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
private void addChild(@NotNull CodegenContext child) { private void addChild(@NotNull CodegenContext child) {
if (shouldAddChild(child)) { if (shouldAddChild(child.contextDescriptor)) {
if (childContexts == null) { if (childContexts == null) {
childContexts = new HashMap<DeclarationDescriptor, CodegenContext>(); childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
} }
@@ -639,8 +651,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
} }
protected boolean shouldAddChild(@NotNull CodegenContext child) { private static boolean shouldAddChild(@NotNull DeclarationDescriptor childContextDescriptor) {
return DescriptorUtils.isCompanionObject(child.contextDescriptor); return DescriptorUtils.isCompanionObject(childContextDescriptor) || DescriptorUtils.isSealedClass(childContextDescriptor);
} }
@Nullable @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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,29 +16,30 @@
package org.jetbrains.kotlin.cfg package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.psi.*
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind 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.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils 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.isEnumClass
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator 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.* import java.util.*
interface WhenMissingCase { interface WhenMissingCase {
@@ -229,9 +230,8 @@ private object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChec
subjectDescriptor: ClassDescriptor?, subjectDescriptor: ClassDescriptor?,
nullable: Boolean nullable: Boolean
): List<WhenMissingCase> { ): List<WhenMissingCase> {
assert(subjectDescriptor != null) { "isWhenOnSealedClassExhaustive should be called with not-null subject class descriptor" } assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
assert(subjectDescriptor!!.modality === Modality.SEALED) { "isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor"
} }
val memberClassDescriptors = LinkedHashSet<ClassDescriptor>() val memberClassDescriptors = LinkedHashSet<ClassDescriptor>()
collectNestedSubclasses(subjectDescriptor!!, subjectDescriptor, memberClassDescriptors) collectNestedSubclasses(subjectDescriptor!!, subjectDescriptor, memberClassDescriptors)
@@ -241,21 +241,27 @@ private object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChec
} }
override fun isApplicable(subjectType: KotlinType): Boolean { override fun isApplicable(subjectType: KotlinType): Boolean {
return TypeUtils.getClassDescriptor(subjectType)?.modality == Modality.SEALED return DescriptorUtils.isSealedClass(TypeUtils.getClassDescriptor(subjectType))
} }
private fun collectNestedSubclasses( private fun collectNestedSubclasses(
baseDescriptor: ClassDescriptor, baseDescriptor: ClassDescriptor,
currentDescriptor: ClassDescriptor, currentDescriptor: ClassDescriptor,
subclasses: MutableSet<ClassDescriptor>) { subclasses: MutableSet<ClassDescriptor>
for (descriptor in DescriptorUtils.getAllDescriptors(currentDescriptor.unsubstitutedInnerClassesScope)) { ) {
if (descriptor is ClassDescriptor) { fun collectSubclasses(scope: MemberScope, collectNested: Boolean) {
if (DescriptorUtils.isDirectSubclass(descriptor, baseDescriptor)) { for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) {
subclasses.add(descriptor) 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; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class BodyResolver { public class BodyResolver {
private static final boolean ALLOW_TOP_LEVEL_SEALED_INHERITANCE = true;
@NotNull private final AnnotationChecker annotationChecker; @NotNull private final AnnotationChecker annotationChecker;
@NotNull private final ExpressionTypingServices expressionTypingServices; @NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final CallResolver callResolver; @NotNull private final CallResolver callResolver;
@@ -384,18 +386,26 @@ public class BodyResolver {
@NotNull @NotNull
private static Set<TypeConstructor> getAllowedFinalSupertypes( private static Set<TypeConstructor> getAllowedFinalSupertypes(
@NotNull ClassDescriptor descriptor, @NotNull ClassDescriptor descriptor,
@NotNull KtClassOrObject jetClass @NotNull Map<KtTypeReference, KotlinType> supertypes,
@NotNull KtClassOrObject ktClassOrObject
) { ) {
Set<TypeConstructor> parentEnumOrSealed; Set<TypeConstructor> parentEnumOrSealed = Collections.emptySet();
if (jetClass instanceof KtEnumEntry) { if (ktClassOrObject instanceof KtEnumEntry) {
parentEnumOrSealed = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration()).getTypeConstructor()); 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 { else {
parentEnumOrSealed = Collections.emptySet();
ClassDescriptor currentDescriptor = descriptor; ClassDescriptor currentDescriptor = descriptor;
while (currentDescriptor.getContainingDeclaration() instanceof ClassDescriptor) { while (currentDescriptor.getContainingDeclaration() instanceof ClassDescriptor) {
currentDescriptor = (ClassDescriptor) currentDescriptor.getContainingDeclaration(); currentDescriptor = (ClassDescriptor) currentDescriptor.getContainingDeclaration();
if (currentDescriptor.getModality() == Modality.SEALED) { if (DescriptorUtils.isSealedClass(currentDescriptor)) {
if (parentEnumOrSealed.isEmpty()) { if (parentEnumOrSealed.isEmpty()) {
parentEnumOrSealed = new HashSet<TypeConstructor>(); parentEnumOrSealed = new HashSet<TypeConstructor>();
} }
@@ -418,9 +428,9 @@ public class BodyResolver {
private void checkSupertypeList( private void checkSupertypeList(
@NotNull ClassDescriptor supertypeOwner, @NotNull ClassDescriptor supertypeOwner,
@NotNull Map<KtTypeReference, KotlinType> supertypes, @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(); Set<TypeConstructor> typeConstructors = Sets.newHashSet();
boolean classAppeared = false; boolean classAppeared = false;
for (Map.Entry<KtTypeReference, KotlinType> entry : supertypes.entrySet()) { for (Map.Entry<KtTypeReference, KotlinType> entry : supertypes.entrySet()) {
@@ -458,13 +468,13 @@ public class BodyResolver {
trace.report(INTERFACE_WITH_SUPERCLASS.on(typeReference)); trace.report(INTERFACE_WITH_SUPERCLASS.on(typeReference));
addSupertype = false; 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)); trace.report(DATA_CLASS_CANNOT_HAVE_CLASS_SUPERTYPES.on(typeReference));
addSupertype = false; addSupertype = false;
} }
else if (DescriptorUtils.isSubclass(classDescriptor, builtIns.getThrowable()) && else if (DescriptorUtils.isSubclass(classDescriptor, builtIns.getThrowable()) &&
!supertypeOwner.getDeclaredTypeParameters().isEmpty()) { !supertypeOwner.getDeclaredTypeParameters().isEmpty()) {
trace.report(GENERIC_THROWABLE_SUBCLASS.on(jetClass.getTypeParameterList())); trace.report(GENERIC_THROWABLE_SUBCLASS.on(ktClassOrObject.getTypeParameterList()));
addSupertype = false; addSupertype = false;
} }
@@ -492,7 +502,7 @@ public class BodyResolver {
} }
} }
else if (!allowedFinalSupertypes.contains(constructor)) { else if (!allowedFinalSupertypes.contains(constructor)) {
if (classDescriptor.getModality() == Modality.SEALED) { if (DescriptorUtils.isSealedClass(classDescriptor)) {
DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration(); DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration();
while (containingDescriptor != null && containingDescriptor != classDescriptor) { while (containingDescriptor != null && containingDescriptor != classDescriptor) {
containingDescriptor = containingDescriptor.getContainingDeclaration(); containingDescriptor = containingDescriptor.getContainingDeclaration();
@@ -20,7 +20,9 @@ import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns 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.diagnostics.Errors.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -214,7 +216,7 @@ class CallExpressionResolver(
if (DescriptorUtils.isEnumClass(containingDescriptor)) { if (DescriptorUtils.isEnumClass(containingDescriptor)) {
context.trace.report(ENUM_CLASS_CONSTRUCTOR_CALL.on(callExpression)) 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)) 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<!>()
}
@@ -1,5 +1,7 @@
package package
public fun test(): kotlin.Unit
public sealed class Base { public sealed class Base {
private constructor 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 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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String 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); 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") @TestMetadata("DoubleInner.kt")
public void testDoubleInner() throws Exception { public void testDoubleInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/DoubleInner.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/DoubleInner.kt");
@@ -15735,9 +15741,9 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("NeverDerived.kt") @TestMetadata("NeverDerivedFromNested.kt")
public void testNeverDerived() throws Exception { public void testNeverDerivedFromNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/NeverDerived.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sealed/NeverDerivedFromNested.kt");
doTest(fileName); doTest(fileName);
} }
@@ -19584,6 +19590,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); 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") @TestMetadata("When.kt")
public void testWhen() throws Exception { public void testWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt");
@@ -2902,6 +2902,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); 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") @TestMetadata("selfcreate.kt")
public void testSelfcreate() throws Exception { public void testSelfcreate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/selfcreate.kt"); 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -36,12 +36,28 @@ public class Visibilities {
return true; 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 @Override
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) { public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
if (DescriptorUtils.isTopLevelDeclaration(what)) { if (DescriptorUtils.isTopLevelDeclaration(what)) {
SourceFile fromContainingFile = DescriptorUtils.getContainingSourceFile(from); return inSameFile(what, from);
if (fromContainingFile != SourceFile.NO_SOURCE_FILE) { }
return fromContainingFile.equals(DescriptorUtils.getContainingSourceFile(what));
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); return getFqNameFromTopLevelClass(containingDeclaration).child(name);
} }
public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) { public static boolean isTopLevelDeclaration(@Nullable DeclarationDescriptor descriptor) {
return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor; return descriptor != null && descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
} }
public static boolean isExtension(@NotNull CallableDescriptor descriptor) { public static boolean isExtension(@NotNull CallableDescriptor descriptor) {
@@ -276,6 +276,10 @@ public class DescriptorUtils {
return isKindOf(descriptor, ClassKind.OBJECT) && ((ClassDescriptor) descriptor).isCompanionObject(); 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) { public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED); return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
} }
@@ -369,7 +373,7 @@ public class DescriptorUtils {
@NotNull @NotNull
public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) { public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
ClassKind classKind = classDescriptor.getKind(); 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; return Visibilities.PRIVATE;
} }
if (isAnonymousObject(classDescriptor)) { if (isAnonymousObject(classDescriptor)) {
@@ -456,7 +460,7 @@ public class DescriptorUtils {
public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) { public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
return classDescriptor.getModality() == Modality.ABSTRACT return classDescriptor.getModality() == Modality.ABSTRACT
|| classDescriptor.getModality() == Modality.SEALED || isSealedClass(classDescriptor)
|| classDescriptor.getKind() == ClassKind.ENUM_CLASS; || classDescriptor.getKind() == ClassKind.ENUM_CLASS;
} }
@@ -683,6 +683,12 @@ public class ClassesTestGenerated extends AbstractClassesTest {
doTest(fileName); 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") @TestMetadata("selfcreate.kt")
public void testSelfcreate() throws Exception { public void testSelfcreate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/selfcreate.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/selfcreate.kt");
@@ -7,12 +7,12 @@ c 1 0/Ann1
d 0/Ann2 d 0/Ann2
c 0 0/Ann2 c 0 0/Ann2
c 1 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/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
@@ -4,8 +4,8 @@ a java.lang.annotation.Inherited 0
c 0 0/Ann c 0 0/Ann
a java.lang.annotation.Retention 1 a java.lang.annotation.Retention 1
c 1 0/Ann c 1 0/Ann
d 0/B
d 0/A d 0/A
a org.test.Ann 2 a org.test.Ann 2
c 2 0/A c 2 0/A
d 0/A$DefaultImpls d 0/A$DefaultImpls
d 0/B
@@ -2,7 +2,7 @@ a java.lang.annotation.Retention 0
p org.test 0 p org.test 0
c 0 0/Ann c 0 0/Ann
a org.test.Ann 1 a org.test.Ann 1
m 1 0/Parent overridenWithoutAnnotation
m 1 0/Parent notOverriden
m 1 0/Child overridenWithAnnotation m 1 0/Child overridenWithAnnotation
m 1 0/Child childMethod m 1 0/Child childMethod
m 1 0/Parent overridenWithoutAnnotation
m 1 0/Parent notOverriden