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
|
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);
|
String tag = Namer.getFunctionTag(descriptor);
|
||||||
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(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;
|
package org.jetbrains.kotlin.js.translate.context;
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import kotlin.Unit;
|
||||||
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
@@ -633,6 +635,19 @@ public class TranslationContext {
|
|||||||
staticContext.getDeclarationStatements().add(statement);
|
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) {
|
public void addTopLevelStatement(@NotNull JsStatement statement) {
|
||||||
staticContext.getTopLevelStatements().add(statement);
|
staticContext.getTopLevelStatements().add(statement);
|
||||||
}
|
}
|
||||||
|
|||||||
+243
-3
@@ -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");
|
* 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,15 +16,255 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.declaration
|
package org.jetbrains.kotlin.js.translate.declaration
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsClassModel
|
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.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.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) {
|
class ClassModelGenerator(val context: StaticContext) {
|
||||||
fun generateClassModel(descriptor: ClassDescriptor): JsClassModel {
|
fun generateClassModel(descriptor: ClassDescriptor): JsClassModel {
|
||||||
val superName = descriptor.getSuperClassNotAny()?.let { context.getInnerNameForDescriptor(it) }
|
val superName = descriptor.getSuperClassNotAny()?.let { context.getInnerNameForDescriptor(it) }
|
||||||
val model = JsClassModel(context.getInnerNameForDescriptor(descriptor), superName)
|
val model = JsClassModel(context.getInnerNameForDescriptor(descriptor), superName)
|
||||||
|
if (descriptor.kind != ClassKind.ANNOTATION_CLASS && !AnnotationsUtils.isNativeObject(descriptor)) {
|
||||||
|
copyDefaultMembers(descriptor, model)
|
||||||
|
generateBridgeMethods(descriptor, model)
|
||||||
|
}
|
||||||
return 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
|
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.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
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.SimpleType
|
||||||
import org.jetbrains.kotlin.types.TypeConstructor
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
import org.jetbrains.kotlin.utils.identity
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a definition of a single class.
|
* 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 isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
|
||||||
|
|
||||||
private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS
|
|
||||||
|
|
||||||
private fun translate() {
|
private fun translate() {
|
||||||
val scope = context().getScopeForDescriptor(descriptor)
|
val scope = context().getScopeForDescriptor(descriptor)
|
||||||
val context = context().newDeclaration(descriptor)
|
val context = context().newDeclaration(descriptor)
|
||||||
@@ -105,8 +99,6 @@ class ClassTranslator private constructor(
|
|||||||
addSuperclassReferences()
|
addSuperclassReferences()
|
||||||
classDeclaration.secondaryConstructors.forEach { generateSecondaryConstructor(context, it) }
|
classDeclaration.secondaryConstructors.forEach { generateSecondaryConstructor(context, it) }
|
||||||
|
|
||||||
generatedBridgeMethods()
|
|
||||||
|
|
||||||
if (descriptor.isData) {
|
if (descriptor.isData) {
|
||||||
JsDataClassGenerator(classDeclaration, context).generate()
|
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 {
|
companion object {
|
||||||
@JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext, enumInitializerName: JsName?) {
|
@JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext, enumInitializerName: JsName?) {
|
||||||
return ClassTranslator(classDeclaration, context, enumInitializerName, null).translate()
|
return ClassTranslator(classDeclaration, context, enumInitializerName, null).translate()
|
||||||
|
|||||||
+2
-2
@@ -99,7 +99,7 @@ class DeclarationBodyVisitor(
|
|||||||
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?) {
|
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?) {
|
||||||
if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) {
|
if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) {
|
||||||
if (expression != null) {
|
if (expression != null) {
|
||||||
context.addFunctionToPrototype(containingClass, descriptor, expression)
|
context.addFunctionToPrototype(containingClass, descriptor, expression, context.declarationStatementConsumer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -139,7 +139,7 @@ class DeclarationBodyVisitor(
|
|||||||
}
|
}
|
||||||
caller.body.statements += statement
|
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 =
|
private fun getSuperClass(specifier: KtSuperTypeListEntry): ClassDescriptor =
|
||||||
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
|
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
|
||||||
|
|
||||||
private fun generateDelegates(toClass: ClassDescriptor, field: Field) {
|
private fun generateDelegates(toClass: ClassDescriptor, field: Field) {
|
||||||
for ((descriptor, overriddenDescriptor) in DelegationResolver.getDelegates(classDescriptor, toClass)) {
|
for ((descriptor, overriddenDescriptor) in DelegationResolver.getDelegates(classDescriptor, toClass)) {
|
||||||
@@ -174,10 +174,12 @@ class DelegationTranslator(
|
|||||||
// TODO: same logic as in AbstractDeclarationVisitor
|
// TODO: same logic as in AbstractDeclarationVisitor
|
||||||
if (descriptor.isExtensionProperty || TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
if (descriptor.isExtensionProperty || TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
||||||
val getter = descriptor.getter!!
|
val getter = descriptor.getter!!
|
||||||
context().addFunctionToPrototype(classDescriptor, getter, generateDelegateGetterFunction(getter))
|
context().addFunctionToPrototype(classDescriptor, getter, generateDelegateGetterFunction(getter),
|
||||||
|
context().declarationStatementConsumer)
|
||||||
if (descriptor.isVar) {
|
if (descriptor.isVar) {
|
||||||
val setter = descriptor.setter!!
|
val setter = descriptor.setter!!
|
||||||
context().addFunctionToPrototype(classDescriptor, setter, generateDelegateSetterFunction(setter))
|
context().addFunctionToPrototype(classDescriptor, setter, generateDelegateSetterFunction(setter),
|
||||||
|
context().declarationStatementConsumer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -194,6 +196,7 @@ class DelegationTranslator(
|
|||||||
delegateName: JsName
|
delegateName: JsName
|
||||||
) {
|
) {
|
||||||
val delegateRef = JsNameRef(delegateName, JsLiteral.THIS)
|
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) {
|
private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||||
JsFunction functionObject = context.createRootScopedFunction(functionDescriptor);
|
JsFunction functionObject = context.createRootScopedFunction(functionDescriptor);
|
||||||
ClassDescriptor containingClass = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
|
ClassDescriptor containingClass = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
|
||||||
UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject);
|
UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject,
|
||||||
|
context.getDeclarationStatementConsumer());
|
||||||
return functionObject;
|
return functionObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
|||||||
declarationBlock.statements += fragment.declarationBlock
|
declarationBlock.statements += fragment.declarationBlock
|
||||||
initializerBlock.statements += fragment.initializerBlock
|
initializerBlock.statements += fragment.initializerBlock
|
||||||
exportBlock.statements += fragment.exportBlock
|
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>
|
val importedModules: List<JsImportedModule>
|
||||||
@@ -116,6 +123,7 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
|||||||
addClassPrototypes(this)
|
addClassPrototypes(this)
|
||||||
this += declarationBlock.statements
|
this += declarationBlock.statements
|
||||||
this += exportBlock.statements
|
this += exportBlock.statements
|
||||||
|
addClassPostDeclarations(this)
|
||||||
this += initializerBlock.statements
|
this += initializerBlock.statements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,4 +157,25 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
|
|||||||
val constructorRef = JsNameRef("constructor", prototype.deepCopy())
|
val constructorRef = JsNameRef("constructor", prototype.deepCopy())
|
||||||
statements += JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt()
|
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,
|
fromDescriptor: FunctionDescriptor,
|
||||||
toDescriptor: FunctionDescriptor,
|
toDescriptor: FunctionDescriptor,
|
||||||
thisObject: JsExpression,
|
thisObject: JsExpression,
|
||||||
context: TranslationContext
|
context: TranslationContext,
|
||||||
|
consumer: (JsStatement) -> Unit
|
||||||
) {
|
) {
|
||||||
val overriddenMemberFunctionName = context.getNameForDescriptor(toDescriptor)
|
val overriddenMemberFunctionName = context.getNameForDescriptor(toDescriptor)
|
||||||
val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject)
|
val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject)
|
||||||
@@ -75,7 +76,7 @@ fun generateDelegateCall(
|
|||||||
val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation)
|
val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), invocation)
|
||||||
functionObject.parameters.addAll(parameters)
|
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>> {
|
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
|
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 prototypeRef = JsAstUtils.prototypeOf(getInnerReference(classDescriptor))
|
||||||
val functionRef = JsNameRef(getNameForDescriptor(descriptor), prototypeRef)
|
val functionRef = JsNameRef(getNameForDescriptor(descriptor), prototypeRef)
|
||||||
addDeclarationStatement(JsAstUtils.assignment(functionRef, function).makeStmt())
|
consumer(JsAstUtils.assignment(functionRef, function).makeStmt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TranslationContext.addAccessorsToPrototype(
|
fun TranslationContext.addAccessorsToPrototype(
|
||||||
|
|||||||
Reference in New Issue
Block a user