Implement default interface members
This commit is contained in:
committed by
Roman Artemev
parent
d861fb498f
commit
cf31e544eb
@@ -114,18 +114,18 @@ fun IrMemberAccessExpression.addArguments(args: Map<ParameterDescriptor, IrExpre
|
||||
}
|
||||
|
||||
fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) =
|
||||
this.addArguments(args.toMap())
|
||||
this.addArguments(args.toMap())
|
||||
|
||||
fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
|
||||
|
||||
fun IrMemberAccessExpression.usesDefaultArguments(): Boolean =
|
||||
this.descriptor.valueParameters.any { this.getValueArgument(it) == null}
|
||||
this.descriptor.valueParameters.any { this.getValueArgument(it) == null }
|
||||
|
||||
fun IrFunction.createParameterDeclarations() {
|
||||
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
|
||||
innerStartOffset(this), innerEndOffset(this),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
this
|
||||
innerStartOffset(this), innerEndOffset(this),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
this
|
||||
).also {
|
||||
it.parent = this@createParameterDeclarations
|
||||
}
|
||||
@@ -139,9 +139,9 @@ fun IrFunction.createParameterDeclarations() {
|
||||
assert(typeParameters.isEmpty())
|
||||
descriptor.typeParameters.mapTo(typeParameters) {
|
||||
IrTypeParameterImpl(
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
it
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
it
|
||||
).also { typeParameter ->
|
||||
typeParameter.parent = this
|
||||
}
|
||||
@@ -151,18 +151,18 @@ fun IrFunction.createParameterDeclarations() {
|
||||
fun IrClass.createParameterDeclarations() {
|
||||
descriptor.thisAsReceiverParameter.let {
|
||||
thisReceiver = IrValueParameterImpl(
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||
it
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||
it
|
||||
)
|
||||
}
|
||||
|
||||
assert(typeParameters.isEmpty())
|
||||
descriptor.declaredTypeParameters.mapTo(typeParameters) {
|
||||
IrTypeParameterImpl(
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
it
|
||||
innerStartOffset(it), innerEndOffset(it),
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -173,34 +173,34 @@ fun IrClass.addFakeOverrides() {
|
||||
val endOffset = this.endOffset
|
||||
|
||||
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
|
||||
startOffset, endOffset,
|
||||
IrDeclarationOrigin.FAKE_OVERRIDE, this
|
||||
startOffset, endOffset,
|
||||
IrDeclarationOrigin.FAKE_OVERRIDE, this
|
||||
).apply {
|
||||
createParameterDeclarations()
|
||||
}
|
||||
|
||||
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
||||
.mapTo(this.declarations) {
|
||||
when (it) {
|
||||
is FunctionDescriptor -> it.createFunction()
|
||||
is PropertyDescriptor ->
|
||||
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
|
||||
// TODO: add field if getter is missing?
|
||||
getter = it.getter?.createFunction()
|
||||
setter = it.setter?.createFunction()
|
||||
}
|
||||
else -> TODO(it.toString())
|
||||
}
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
||||
.mapTo(this.declarations) {
|
||||
when (it) {
|
||||
is FunctionDescriptor -> it.createFunction()
|
||||
is PropertyDescriptor ->
|
||||
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
|
||||
// TODO: add field if getter is missing?
|
||||
getter = it.getter?.createFunction()
|
||||
setter = it.setter?.createFunction()
|
||||
}
|
||||
else -> TODO(it.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
||||
descriptor.startOffset ?: this.startOffset
|
||||
descriptor.startOffset ?: this.startOffset
|
||||
|
||||
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
||||
descriptor.endOffset ?: this.endOffset
|
||||
descriptor.endOffset ?: this.endOffset
|
||||
|
||||
val DeclarationDescriptorWithSource.startOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.startOffset
|
||||
val DeclarationDescriptorWithSource.endOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.endOffset
|
||||
@@ -215,14 +215,14 @@ val IrClassSymbol.constructors: Sequence<IrConstructorSymbol>
|
||||
get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol }
|
||||
|
||||
private fun IrClassSymbol.getPropertyDeclaration(name: String) =
|
||||
this.owner.declarations.filterIsInstance<IrProperty>()
|
||||
.atMostOne { it.descriptor.name == Name.identifier(name) }
|
||||
this.owner.declarations.filterIsInstance<IrProperty>()
|
||||
.atMostOne { it.descriptor.name == Name.identifier(name) }
|
||||
|
||||
fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
|
||||
this.getPropertyDeclaration(name)?.getter?.symbol
|
||||
this.getPropertyDeclaration(name)?.getter?.symbol
|
||||
|
||||
fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
|
||||
this.getPropertyDeclaration(name)?.setter?.symbol
|
||||
this.getPropertyDeclaration(name)?.setter?.symbol
|
||||
|
||||
val IrFunction.explicitParameters: List<IrValueParameterSymbol>
|
||||
get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
|
||||
@@ -232,3 +232,39 @@ val IrValueParameter.type: KotlinType
|
||||
|
||||
val IrClass.defaultType: KotlinType
|
||||
get() = this.descriptor.defaultType
|
||||
|
||||
val IrSimpleFunction.isReal: Boolean get() = descriptor.kind.isReal
|
||||
|
||||
fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction? {
|
||||
|
||||
if (isReal) return this
|
||||
|
||||
val visited = mutableSetOf<IrSimpleFunction>()
|
||||
val realOverrides = mutableSetOf<IrSimpleFunction>()
|
||||
|
||||
fun collectRealOverrides(func: IrSimpleFunction) {
|
||||
if (!visited.add(func)) return
|
||||
|
||||
if (func.isReal) {
|
||||
realOverrides += func
|
||||
} else {
|
||||
func.overriddenSymbols.forEach { collectRealOverrides(it.owner) }
|
||||
}
|
||||
}
|
||||
|
||||
overriddenSymbols.forEach { collectRealOverrides(it.owner) }
|
||||
|
||||
fun excludeRepeated(func: IrSimpleFunction) {
|
||||
if (!visited.add(func)) return
|
||||
|
||||
func.overriddenSymbols.forEach {
|
||||
realOverrides.remove(it.owner)
|
||||
excludeRepeated(it.owner)
|
||||
}
|
||||
}
|
||||
|
||||
visited.clear()
|
||||
realOverrides.asSequence().forEach { excludeRepeated(it) }
|
||||
|
||||
return realOverrides.singleOrNull { it.modality != Modality.ABSTRACT }
|
||||
}
|
||||
+28
-3
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
||||
@@ -21,6 +19,33 @@ class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrEl
|
||||
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
||||
}
|
||||
|
||||
// sort member forwarding code
|
||||
addPostDeclarations(rootContext)
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
|
||||
private fun addPostDeclarations(context: JsGenerationContext) {
|
||||
val staticContext = context.staticContext
|
||||
val program = context.currentScope.program
|
||||
val block = program.globalBlock
|
||||
|
||||
val visited = mutableSetOf<JsName>()
|
||||
|
||||
for (name in staticContext.classModels.keys) {
|
||||
addPostDeclaration(name, visited, block.statements, staticContext.classModels)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addPostDeclaration(name: JsName, visited: MutableSet<JsName>, statements: MutableList<JsStatement>, classModels: Map<JsName, JsClassModel>) {
|
||||
if (visited.add(name)) {
|
||||
classModels[name]?.run {
|
||||
superName?.let { addPostDeclaration(it, visited, statements, classModels) }
|
||||
interfaces.forEach { addPostDeclaration(it, visited, statements, classModels) }
|
||||
|
||||
statements += postDeclarationBlock.statements
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-25
@@ -6,22 +6,27 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.onlyIf
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.isReal
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
|
||||
private val className = context.getNameForSymbol(irClass.symbol)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val baseClass = irClass.superClasses.firstOrNull { it.kind != ClassKind.INTERFACE }
|
||||
private val baseClassName = baseClass?.let { context.getNameForSymbol(it) }
|
||||
private val classPrototypeRef = prototypeOf(classNameRef)
|
||||
private val classBlock = JsBlock()
|
||||
private val classModel = JsClassModel(className, baseClassName)
|
||||
|
||||
fun generate(): JsStatement {
|
||||
|
||||
@@ -29,34 +34,62 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val transformer = IrFunctionToJsTransformer()
|
||||
|
||||
for (declaration in irClass.declarations) {
|
||||
if (declaration is IrConstructor) {
|
||||
classBlock.statements += declaration.accept(transformer, context).makeStmt()
|
||||
classBlock.statements += generateInheritanceCode()
|
||||
} else if (declaration is IrFunction) {
|
||||
if (declaration.symbol.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||
declaration.symbol.modality != Modality.ABSTRACT
|
||||
) {
|
||||
classBlock.statements += declaration.accept(transformer, context).let {
|
||||
if (declaration.isStatic) {
|
||||
it.makeStmt()
|
||||
} else {
|
||||
val memberName = context.getNameForSymbol(declaration.symbol)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
jsAssignment(memberRef, it).makeStmt()
|
||||
}
|
||||
}
|
||||
when (declaration) {
|
||||
is IrConstructor -> {
|
||||
classBlock.statements += declaration.accept(transformer, context).makeStmt()
|
||||
classBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
is IrSimpleFunction -> {
|
||||
generateMemberFunction(declaration)?.let { classBlock.statements += it }
|
||||
}
|
||||
is IrClass -> {
|
||||
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
} else if (declaration is IrClass) {
|
||||
//TODO: redesign inner classes generation
|
||||
classBlock.statements += JsClassGenerator(declaration, context).generate()
|
||||
}
|
||||
}
|
||||
|
||||
classBlock.statements += generateClassMetadata()
|
||||
irClass.onlyIf({ kind == ClassKind.OBJECT }) { classBlock.statements += maybeGenerateObjectInstance() }
|
||||
context.staticContext.classModels[className] = classModel
|
||||
return classBlock
|
||||
}
|
||||
|
||||
private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? {
|
||||
|
||||
val translatedFunction = declaration.run { if (isReal) accept(IrFunctionToJsTransformer(), context) else null }
|
||||
if (declaration.isStatic) {
|
||||
return translatedFunction!!.makeStmt()
|
||||
}
|
||||
|
||||
val memberName = context.getNameForSymbol(declaration.symbol)
|
||||
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||
|
||||
translatedFunction?.let { return jsAssignment(memberRef, it).makeStmt() }
|
||||
|
||||
// do not generate code like
|
||||
// interface I { foo() = "OK" }
|
||||
// interface II : I
|
||||
// II.prototype.foo = I.prototype.foo
|
||||
if (irClass.kind != ClassKind.INTERFACE) {
|
||||
declaration.resolveFakeOverride()?.let {
|
||||
val implClassDesc = it.descriptor.containingDeclaration as ClassDescriptor
|
||||
if (!KotlinBuiltIns.isAny(implClassDesc)) {
|
||||
val implMethodName = context.getNameForSymbol(it.symbol)
|
||||
val implClassName = context.getNameForSymbol(IrClassSymbolImpl(implClassDesc))
|
||||
|
||||
val implClassPrototype = prototypeOf(implClassName.makeRef())
|
||||
val implMemberRef = JsNameRef(implMethodName, implClassPrototype)
|
||||
|
||||
classModel.postDeclarationBlock.statements += jsAssignment(memberRef, implMemberRef).makeStmt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun maybeGenerateObjectInstance(): List<JsStatement> {
|
||||
val instanceVarName = "${className.ident}_instance"
|
||||
val getInstanceFunName = "${className.ident}_getInstance"
|
||||
@@ -90,8 +123,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
private fun generateInheritanceCode(): List<JsStatement> {
|
||||
val baseClass = irClass.superClasses.first { it.kind != ClassKind.INTERFACE }
|
||||
if (baseClass.isAny) {
|
||||
if (baseClass == null || baseClass.isAny) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsClassModel
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||
|
||||
|
||||
@@ -19,6 +21,7 @@ class JsStaticContext(
|
||||
backendContext: JsIrBackendContext
|
||||
) {
|
||||
val intrinsics = JsIntrinsicTransformers(backendContext)
|
||||
val classModels = mutableMapOf<JsName, JsClassModel>()
|
||||
|
||||
fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context)
|
||||
}
|
||||
Reference in New Issue
Block a user