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
|
||||
|
||||
Reference in New Issue
Block a user