JS: support bridges and copying of non-abstract methods of interfaces in new pipeline
This commit is contained in:
@@ -16,4 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.backend.ast
|
||||
|
||||
class JsClassModel(val name: JsName, val superName: JsName?)
|
||||
class JsClassModel(val name: JsName, val superName: JsName?) {
|
||||
val postDeclarationBlock = JsGlobalBlock()
|
||||
}
|
||||
|
||||
@@ -752,13 +752,4 @@ public final class StaticContext {
|
||||
String tag = Namer.getFunctionTag(descriptor);
|
||||
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
||||
}
|
||||
|
||||
/*public void postProcess() {
|
||||
addInterfaceDefaultMethods();
|
||||
rootFunction.getBody().getStatements().addAll(importStatements);
|
||||
addClassPrototypes();
|
||||
rootFunction.getBody().getStatements().addAll(declarationStatements);
|
||||
rootFunction.getBody().getStatements().addAll(exporter.getStatements());
|
||||
rootFunction.getBody().getStatements().addAll(topLevelStatements);
|
||||
}*/
|
||||
}
|
||||
|
||||
+15
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.js.translate.context;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -633,6 +635,19 @@ public class TranslationContext {
|
||||
staticContext.getDeclarationStatements().add(statement);
|
||||
}
|
||||
|
||||
private final Function1<JsStatement, Unit> declarationStatementConsumer = new Function1<JsStatement, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(JsStatement statement) {
|
||||
addDeclarationStatement(statement);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
public Function1<JsStatement, Unit> getDeclarationStatementConsumer() {
|
||||
return declarationStatementConsumer;
|
||||
}
|
||||
|
||||
public void addTopLevelStatement(@NotNull JsStatement statement) {
|
||||
staticContext.getTopLevelStatements().add(statement);
|
||||
}
|
||||
|
||||
+244
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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,15 +16,255 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsClassModel
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.prototypeOf
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.utils.identity
|
||||
|
||||
class ClassModelGenerator(val context: StaticContext) {
|
||||
fun generateClassModel(descriptor: ClassDescriptor): JsClassModel {
|
||||
val superName = descriptor.getSuperClassNotAny()?.let { context.getInnerNameForDescriptor(it) }
|
||||
val model = JsClassModel(context.getInnerNameForDescriptor(descriptor), superName)
|
||||
if (descriptor.kind != ClassKind.ANNOTATION_CLASS && !AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
copyDefaultMembers(descriptor, model)
|
||||
generateBridgeMethods(descriptor, model)
|
||||
}
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyDefaultMembers(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||
val members = descriptor.unsubstitutedMemberScope
|
||||
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
.mapNotNull { it as? CallableMemberDescriptor }
|
||||
|
||||
// Traverse fake non-abstract member. Current class does not provide their implementation,
|
||||
// it can be inherited from interface.
|
||||
for (member in members.filter { !it.kind.isReal && it.modality != Modality.ABSTRACT }) {
|
||||
if (member is FunctionDescriptor) {
|
||||
tryCopyWhenImplementingInterfaceWithDefaultArgs(member, model)
|
||||
}
|
||||
|
||||
copySimpleMember(descriptor, member, model)
|
||||
|
||||
// Copy *implementation* functions (i.e. those ones which end with `$default` suffix)
|
||||
// of Kotlin functions with optional parameters.
|
||||
if (member is FunctionDescriptor && !hasImplementationInPrototype(member)) {
|
||||
copyMemberWithOptionalArgs(descriptor, member, model, Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX)
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse non-fake non-abstract members. Current class provides their implementation, but the implementation
|
||||
// may override function with optional parameters. In this case we already copied *implementation* function
|
||||
// (with `$default` suffix) but we also need *dispatcher* function (without suffix).
|
||||
// Case of fake member is covered by previous loop.
|
||||
for (function in members.filterIsInstance<FunctionDescriptor>().filter { it.modality != Modality.ABSTRACT && it.kind.isReal }) {
|
||||
copyMemberWithOptionalArgs(descriptor, function, model, "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasImplementationInPrototype(member: CallableMemberDescriptor): Boolean {
|
||||
return member.overriddenDescriptors.any {
|
||||
it.modality != Modality.ABSTRACT && !DescriptorUtils.isInterface(it.containingDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
// Cover very special case. Consider
|
||||
//
|
||||
// open class B { fun foo(x: Int): Unit }
|
||||
// interface I { fun foo(x: Int = ...): Unit }
|
||||
// class D : B(), I
|
||||
//
|
||||
// Interface I provides dispatcher function, but no implementation function. It's expected that D
|
||||
// inherits dispatcher function from I (by copying it) and implementation function from B.
|
||||
// However, D inherits `foo` without suffix (i.e. it corresponds to I's dispatcher function).
|
||||
// We must copy B.foo to D.foo$default and then I.foo to D.foo
|
||||
private fun tryCopyWhenImplementingInterfaceWithDefaultArgs(member: FunctionDescriptor, model: JsClassModel) {
|
||||
val fromInterface = member.overriddenDescriptors.firstOrNull { it.hasOwnParametersWithDefaultValue() } ?: return
|
||||
if (!DescriptorUtils.isInterface(fromInterface.containingDeclaration)) return
|
||||
val fromClass = member.overriddenDescriptors.firstOrNull { !DescriptorUtils.isInterface(it.containingDeclaration) } ?: return
|
||||
|
||||
val targetClass = member.containingDeclaration as ClassDescriptor
|
||||
val fromInterfaceName = context.getNameForDescriptor(fromInterface).ident
|
||||
|
||||
copyMethod(context.getNameForDescriptor(fromClass).ident, fromInterfaceName + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX,
|
||||
fromClass.containingDeclaration as ClassDescriptor, targetClass, model.postDeclarationBlock)
|
||||
copyMethod(fromInterfaceName, context.getNameForDescriptor(member).ident,
|
||||
fromInterface.containingDeclaration as ClassDescriptor, targetClass,
|
||||
model.postDeclarationBlock)
|
||||
}
|
||||
|
||||
private fun copySimpleMember(descriptor: ClassDescriptor, member: CallableMemberDescriptor, model: JsClassModel) {
|
||||
// Special case: fake descriptor denotes (possible multiple) private members from different super interfaces
|
||||
if (member.visibility == Visibilities.INVISIBLE_FAKE) return copyInvisibleFakeMember(descriptor, member, model)
|
||||
|
||||
val memberToCopy = findMemberToCopy(member) ?: return
|
||||
val classToCopyFrom = memberToCopy.containingDeclaration as ClassDescriptor
|
||||
if (classToCopyFrom.kind != ClassKind.INTERFACE || AnnotationsUtils.isNativeObject(classToCopyFrom)) return
|
||||
|
||||
val name = context.getNameForDescriptor(member).ident
|
||||
when (member) {
|
||||
is FunctionDescriptor -> {
|
||||
copyMethod(name, name, classToCopyFrom, descriptor, model.postDeclarationBlock)
|
||||
}
|
||||
is PropertyDescriptor -> copyProperty(name, classToCopyFrom, descriptor, model.postDeclarationBlock)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyInvisibleFakeMember(descriptor: ClassDescriptor, member: CallableMemberDescriptor, model: JsClassModel) {
|
||||
for (overriddenMember in member.overriddenDescriptors) {
|
||||
val memberToCopy = if (overriddenMember.kind.isReal) overriddenMember else findMemberToCopy(overriddenMember) ?: continue
|
||||
val classToCopyFrom = memberToCopy.containingDeclaration as ClassDescriptor
|
||||
if (classToCopyFrom.kind != ClassKind.INTERFACE) continue
|
||||
|
||||
val name = context.getNameForDescriptor(memberToCopy).ident
|
||||
when (member) {
|
||||
is FunctionDescriptor -> {
|
||||
copyMethod(name, name, classToCopyFrom, descriptor, model.postDeclarationBlock)
|
||||
}
|
||||
is PropertyDescriptor -> copyProperty(name, classToCopyFrom, descriptor, model.postDeclarationBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyMemberWithOptionalArgs(descriptor: ClassDescriptor, member: FunctionDescriptor, model: JsClassModel, suffix: String) {
|
||||
val memberToCopy = findOptionalArgsMemberToCopy(member) ?: return
|
||||
val classToCopyFrom = memberToCopy.containingDeclaration as ClassDescriptor
|
||||
if (classToCopyFrom.kind != ClassKind.INTERFACE || AnnotationsUtils.isNativeObject(classToCopyFrom)) return
|
||||
|
||||
val name = context.getNameForDescriptor(member).ident + suffix
|
||||
copyMethod(name, name, classToCopyFrom, descriptor, model.postDeclarationBlock)
|
||||
}
|
||||
|
||||
private fun findMemberToCopy(member: CallableMemberDescriptor): CallableMemberDescriptor? {
|
||||
// If one of overridden members is non-abstract, copy it.
|
||||
// When none found, we have nothing to copy, ignore.
|
||||
// When multiple found, our current class should provide implementation, ignore.
|
||||
val memberToCopy = member.overriddenDescriptors
|
||||
.filter { it.modality != Modality.ABSTRACT }
|
||||
.singleOrNull() ?: return null
|
||||
|
||||
// If found member is not from interface, we don't need to copy it, it's already in prototype
|
||||
if ((memberToCopy.containingDeclaration as ClassDescriptor).kind != ClassKind.INTERFACE) return null
|
||||
|
||||
// If found member is fake itself, repeat search for it, until we find actual implementation
|
||||
return if (!memberToCopy.kind.isReal) findMemberToCopy(memberToCopy) else memberToCopy
|
||||
}
|
||||
|
||||
private fun findOptionalArgsMemberToCopy(member: FunctionDescriptor): FunctionDescriptor? {
|
||||
// If one of overridden members has parameters with default value, copy it.
|
||||
// When non found, we have nothing to copy, ignore.
|
||||
// When multiple found, our current class should provide implementation, ignore.
|
||||
val memberToCopy = member.overriddenDescriptors
|
||||
.filter { it.hasOrInheritsParametersWithDefaultValue() }
|
||||
.singleOrNull() ?: return null
|
||||
|
||||
// If found member is not from interface, we don't need to copy it, it's already in prototype
|
||||
if ((memberToCopy.containingDeclaration as ClassDescriptor).kind != ClassKind.INTERFACE) return null
|
||||
|
||||
// If found member is fake itself, repeat search for it, until we find actual implementation
|
||||
return if (!memberToCopy.kind.isReal) findOptionalArgsMemberToCopy(memberToCopy) else memberToCopy
|
||||
}
|
||||
|
||||
private fun generateBridgeMethods(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||
generateBridgesToTraitImpl(descriptor, model)
|
||||
generateOtherBridges(descriptor, model)
|
||||
}
|
||||
|
||||
private fun generateBridgesToTraitImpl(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||
val translationContext = TranslationContext.rootContext(context)
|
||||
for ((key, value) in CodegenUtil.getNonPrivateTraitMethods(descriptor)) {
|
||||
val sourceName = context.getNameForDescriptor(key).ident
|
||||
val targetName = context.getNameForDescriptor(value).ident
|
||||
if (sourceName != targetName) {
|
||||
generateDelegateCall(descriptor, key, value, JsLiteral.THIS, translationContext) {
|
||||
model.postDeclarationBlock.statements += it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateOtherBridges(descriptor: ClassDescriptor, model: JsClassModel) {
|
||||
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
val bridgesToGenerate = generateBridgesForFunctionDescriptor(memberDescriptor, identity()) {
|
||||
//There is no DefaultImpls in js backend so if method non-abstract it should be recognized as non-abstract on bridges calculation
|
||||
false
|
||||
}
|
||||
|
||||
for (bridge in bridgesToGenerate) {
|
||||
generateBridge(descriptor, model, bridge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateBridge(descriptor: ClassDescriptor, model: JsClassModel, bridge: Bridge<FunctionDescriptor>) {
|
||||
val fromDescriptor = bridge.from
|
||||
val toDescriptor = bridge.to
|
||||
|
||||
if (toDescriptor.visibility == Visibilities.INVISIBLE_FAKE) return
|
||||
|
||||
val sourceName = context.getNameForDescriptor(fromDescriptor).ident
|
||||
val targetName = context.getNameForDescriptor(toDescriptor).ident
|
||||
if (sourceName == targetName) return
|
||||
|
||||
if ((fromDescriptor.containingDeclaration as ClassDescriptor).kind != ClassKind.INTERFACE) {
|
||||
if (fromDescriptor.kind.isReal && fromDescriptor.modality != Modality.ABSTRACT && !toDescriptor.kind.isReal) return
|
||||
}
|
||||
|
||||
val translationContext = TranslationContext.rootContext(context)
|
||||
generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS, translationContext) {
|
||||
model.postDeclarationBlock.statements += it
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyMethod(
|
||||
sourceName: String,
|
||||
targetName: String,
|
||||
sourceDescriptor: ClassDescriptor,
|
||||
targetDescriptor: ClassDescriptor,
|
||||
block: JsBlock
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val targetFunction = JsNameRef(targetName, targetPrototype)
|
||||
val sourceFunction = JsNameRef(sourceName, sourcePrototype)
|
||||
block.statements += JsAstUtils.assignment(targetFunction, sourceFunction).makeStmt()
|
||||
}
|
||||
|
||||
private fun copyProperty(
|
||||
name: String,
|
||||
sourceDescriptor: ClassDescriptor,
|
||||
targetDescriptor: ClassDescriptor,
|
||||
block: JsBlock
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val nameLiteral = context.program.getStringLiteral(name)
|
||||
|
||||
val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), sourcePrototype, nameLiteral)
|
||||
val defineProperty = JsAstUtils.defineProperty(targetPrototype, name, getPropertyDescriptor, context.program)
|
||||
|
||||
block.statements += defineProperty.makeStmt()
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -50,7 +47,6 @@ import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclasses
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.identity
|
||||
|
||||
/**
|
||||
* Generates a definition of a single class.
|
||||
@@ -70,8 +66,6 @@ class ClassTranslator private constructor(
|
||||
|
||||
private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
|
||||
|
||||
private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS
|
||||
|
||||
private fun translate() {
|
||||
val scope = context().getScopeForDescriptor(descriptor)
|
||||
val context = context().newDeclaration(descriptor)
|
||||
@@ -105,8 +99,6 @@ class ClassTranslator private constructor(
|
||||
addSuperclassReferences()
|
||||
classDeclaration.secondaryConstructors.forEach { generateSecondaryConstructor(context, it) }
|
||||
|
||||
generatedBridgeMethods()
|
||||
|
||||
if (descriptor.isData) {
|
||||
JsDataClassGenerator(classDeclaration, context).generate()
|
||||
}
|
||||
@@ -491,54 +483,6 @@ class ClassTranslator private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun generatedBridgeMethods() {
|
||||
if (isAnnotation()) return
|
||||
|
||||
generateBridgesToTraitImpl()
|
||||
|
||||
generateOtherBridges()
|
||||
}
|
||||
|
||||
private fun generateBridgesToTraitImpl() {
|
||||
for ((key, value) in CodegenUtil.getNonPrivateTraitMethods(descriptor)) {
|
||||
if (!areNamesEqual(key, value)) {
|
||||
generateDelegateCall(descriptor, value, key, JsLiteral.THIS, context())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateOtherBridges() {
|
||||
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
val bridgesToGenerate = generateBridgesForFunctionDescriptor(memberDescriptor, identity()) {
|
||||
//There is no DefaultImpls in js backend so if method non-abstract it should be recognized as non-abstract on bridges calculation
|
||||
false
|
||||
}
|
||||
|
||||
for (bridge in bridgesToGenerate) {
|
||||
generateBridge(bridge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateBridge(bridge: Bridge<FunctionDescriptor>) {
|
||||
val fromDescriptor = bridge.from
|
||||
val toDescriptor = bridge.to
|
||||
if (areNamesEqual(fromDescriptor, toDescriptor)) return
|
||||
|
||||
if (fromDescriptor.kind.isReal && fromDescriptor.modality != Modality.ABSTRACT && !toDescriptor.kind.isReal)
|
||||
return
|
||||
|
||||
generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS, context())
|
||||
}
|
||||
|
||||
private fun areNamesEqual(first: FunctionDescriptor, second: FunctionDescriptor): Boolean {
|
||||
val firstName = context().getNameForDescriptor(first)
|
||||
val secondName = context().getNameForDescriptor(second)
|
||||
return firstName.ident == secondName.ident
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext, enumInitializerName: JsName?) {
|
||||
return ClassTranslator(classDeclaration, context, enumInitializerName, null).translate()
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@ class DeclarationBodyVisitor(
|
||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?) {
|
||||
if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) {
|
||||
if (expression != null) {
|
||||
context.addFunctionToPrototype(containingClass, descriptor, expression)
|
||||
context.addFunctionToPrototype(containingClass, descriptor, expression, context.declarationStatementConsumer)
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -139,7 +139,7 @@ class DeclarationBodyVisitor(
|
||||
}
|
||||
caller.body.statements += statement
|
||||
|
||||
context.addFunctionToPrototype(containingClass, descriptor, caller)
|
||||
context.addFunctionToPrototype(containingClass, descriptor, caller, context.declarationStatementConsumer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -89,7 +89,7 @@ class DelegationTranslator(
|
||||
}
|
||||
|
||||
private fun getSuperClass(specifier: KtSuperTypeListEntry): ClassDescriptor =
|
||||
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
|
||||
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
|
||||
|
||||
private fun generateDelegates(toClass: ClassDescriptor, field: Field) {
|
||||
for ((descriptor, overriddenDescriptor) in DelegationResolver.getDelegates(classDescriptor, toClass)) {
|
||||
@@ -174,10 +174,12 @@ class DelegationTranslator(
|
||||
// TODO: same logic as in AbstractDeclarationVisitor
|
||||
if (descriptor.isExtensionProperty || TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
||||
val getter = descriptor.getter!!
|
||||
context().addFunctionToPrototype(classDescriptor, getter, generateDelegateGetterFunction(getter))
|
||||
context().addFunctionToPrototype(classDescriptor, getter, generateDelegateGetterFunction(getter),
|
||||
context().declarationStatementConsumer)
|
||||
if (descriptor.isVar) {
|
||||
val setter = descriptor.setter!!
|
||||
context().addFunctionToPrototype(classDescriptor, setter, generateDelegateSetterFunction(setter))
|
||||
context().addFunctionToPrototype(classDescriptor, setter, generateDelegateSetterFunction(setter),
|
||||
context().declarationStatementConsumer)
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -194,6 +196,7 @@ class DelegationTranslator(
|
||||
delegateName: JsName
|
||||
) {
|
||||
val delegateRef = JsNameRef(delegateName, JsLiteral.THIS)
|
||||
generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context())
|
||||
generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context(),
|
||||
context().declarationStatementConsumer)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -192,7 +192,8 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
|
||||
private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
JsFunction functionObject = context.createRootScopedFunction(functionDescriptor);
|
||||
ClassDescriptor containingClass = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
|
||||
UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject);
|
||||
UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject,
|
||||
context.getDeclarationStatementConsumer());
|
||||
return functionObject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,13 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
declarationBlock.statements += fragment.declarationBlock
|
||||
initializerBlock.statements += fragment.initializerBlock
|
||||
exportBlock.statements += fragment.exportBlock
|
||||
|
||||
classes += fragment.classes.values.map { cls ->
|
||||
val name = nameMap.rename(cls.name)
|
||||
name to JsClassModel(name, cls.superName?.let { nameMap.rename(it) }).also { copy ->
|
||||
copy.postDeclarationBlock.statements += cls.postDeclarationBlock.statements.map { nameMap.rename(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val importedModules: List<JsImportedModule>
|
||||
@@ -116,6 +123,7 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
addClassPrototypes(this)
|
||||
this += declarationBlock.statements
|
||||
this += exportBlock.statements
|
||||
addClassPostDeclarations(this)
|
||||
this += initializerBlock.statements
|
||||
}
|
||||
}
|
||||
@@ -149,4 +157,25 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
||||
val constructorRef = JsNameRef("constructor", prototype.deepCopy())
|
||||
statements += JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt()
|
||||
}
|
||||
|
||||
private fun addClassPostDeclarations(statements: MutableList<JsStatement>) {
|
||||
val visited = mutableSetOf<JsName>()
|
||||
for (cls in classes.keys) {
|
||||
addClassPostDeclarations(cls, visited, statements)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addClassPostDeclarations(
|
||||
name: JsName,
|
||||
visited: MutableSet<JsName>,
|
||||
statements: MutableList<JsStatement>
|
||||
) {
|
||||
if (!visited.add(name)) return
|
||||
val cls = classes[name] ?: return
|
||||
val superName = cls.superName
|
||||
if (superName != null) {
|
||||
addClassPostDeclarations(superName, visited, statements)
|
||||
}
|
||||
statements += cls.postDeclarationBlock.statements
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,8 @@ fun generateDelegateCall(
|
||||
fromDescriptor: FunctionDescriptor,
|
||||
toDescriptor: FunctionDescriptor,
|
||||
thisObject: JsExpression,
|
||||
context: TranslationContext
|
||||
context: TranslationContext,
|
||||
consumer: (JsStatement) -> Unit
|
||||
) {
|
||||
val overriddenMemberFunctionName = context.getNameForDescriptor(toDescriptor)
|
||||
val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject)
|
||||
@@ -75,7 +76,7 @@ fun generateDelegateCall(
|
||||
val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation)
|
||||
functionObject.parameters.addAll(parameters)
|
||||
|
||||
context.addFunctionToPrototype(classDescriptor, fromDescriptor, functionObject)
|
||||
context.addFunctionToPrototype(classDescriptor, fromDescriptor, functionObject, consumer)
|
||||
}
|
||||
|
||||
fun <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
|
||||
@@ -120,10 +121,15 @@ fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsExpr
|
||||
return referenceToJsClass
|
||||
}
|
||||
|
||||
fun TranslationContext.addFunctionToPrototype(classDescriptor: ClassDescriptor, descriptor: FunctionDescriptor, function: JsExpression) {
|
||||
fun TranslationContext.addFunctionToPrototype(
|
||||
classDescriptor: ClassDescriptor,
|
||||
descriptor: FunctionDescriptor,
|
||||
function: JsExpression,
|
||||
consumer: (JsStatement) -> Unit
|
||||
) {
|
||||
val prototypeRef = JsAstUtils.prototypeOf(getInnerReference(classDescriptor))
|
||||
val functionRef = JsNameRef(getNameForDescriptor(descriptor), prototypeRef)
|
||||
addDeclarationStatement(JsAstUtils.assignment(functionRef, function).makeStmt())
|
||||
consumer(JsAstUtils.assignment(functionRef, function).makeStmt())
|
||||
}
|
||||
|
||||
fun TranslationContext.addAccessorsToPrototype(
|
||||
|
||||
Reference in New Issue
Block a user