From bec1e526a14023bc8f009b7c885f29c78b0b1830 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 19 Oct 2016 17:53:19 +0300 Subject: [PATCH] JS: fix generation of bridge methods for non-abstract methods inherited from interfaces --- .../translate/declaration/ClassTranslator.kt | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index 8bf6b9b268f..4f491d36b34 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -503,25 +503,28 @@ class ClassTranslator private constructor( .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) .mapNotNull { it as? CallableMemberDescriptor } for (member in members) { - if (member.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue + if (member.kind.isReal) continue if (member.modality == Modality.ABSTRACT || member.overriddenDescriptors.size != 1) continue - val overriddenFunction = generateSequence(member) { it.overriddenDescriptors.firstOrNull() } - .drop(1) - .dropWhile { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && - DescriptorUtils.isInterface(it.containingDeclaration) } - .firstOrNull() ?: continue + val overriddenMember = generateSequence(member) { it.overriddenDescriptors.firstOrNull() } + .drop(1) + .dropWhile { !it.kind.isReal && DescriptorUtils.isInterface(it.containingDeclaration) } + .firstOrNull() ?: continue - if (overriddenFunction.modality == Modality.ABSTRACT) continue + if (overriddenMember.modality == Modality.ABSTRACT) continue - val interfaceDescriptor = overriddenFunction.containingDeclaration as ClassDescriptor + val interfaceDescriptor = overriddenMember.containingDeclaration as ClassDescriptor if (interfaceDescriptor.kind != ClassKind.INTERFACE) continue val directContainer = member.overriddenDescriptors.first().containingDeclaration as ClassDescriptor - when (member) { - is FunctionDescriptor -> addDefaultMethodFromInterface(member, directContainer, descriptor, context) - is PropertyDescriptor -> addDefaultPropertyFromInterface(member, directContainer, descriptor, context) + when (overriddenMember) { + is FunctionDescriptor -> { + addDefaultMethodFromInterface(overriddenMember, directContainer, descriptor,context) + } + is PropertyDescriptor -> { + addDefaultPropertyFromInterface(overriddenMember, directContainer, descriptor, context) + } } } } @@ -532,12 +535,13 @@ class ClassTranslator private constructor( descriptor: ClassDescriptor, context: StaticContext ) { - val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) - val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) - val functionName = context.getNameForDescriptor(function) - val classFunction = JsNameRef(functionName, classPrototype) - val interfaceFunction = JsNameRef(functionName, interfacePrototype) - context.declarationStatements += JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt() + for (name in generateAllNames(function, context)) { + val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) + val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) + val classFunction = JsNameRef(name, classPrototype) + val interfaceFunction = JsNameRef(name, interfacePrototype) + context.declarationStatements += JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt() + } } private fun addDefaultPropertyFromInterface( @@ -546,15 +550,35 @@ class ClassTranslator private constructor( descriptor: ClassDescriptor, context: StaticContext ) { - val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) - val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) - val functionName = context.getNameForDescriptor(property) - val nameLiteral = context.program.getStringLiteral(functionName.ident) + for (name in generateAllNames(property, context)) { + val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) + val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) + val nameLiteral = context.program.getStringLiteral(name.ident) - val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral) - val defineProperty = JsAstUtils.defineProperty(classPrototype, functionName.ident, getPropertyDescriptor, context.program) + val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral) + val defineProperty = JsAstUtils.defineProperty(classPrototype, name.ident, getPropertyDescriptor, context.program) - context.declarationStatements += defineProperty.makeStmt() + context.declarationStatements += defineProperty.makeStmt() + } + } + + private fun generateAllNames(member: CallableMemberDescriptor, context: StaticContext): Sequence { + return (generateBridges(member) + member) + .map { context.getNameForDescriptor(it) } + .distinctBy { it.ident } + } + + private fun generateBridges(member: CallableMemberDescriptor): Sequence = when (member) { + is FunctionDescriptor -> { + generateBridgesForFunctionDescriptor(member, identity()) { false } + .map { it.from } + .asSequence() + } + is PropertyDescriptor -> generateBridgesForFunctionDescriptor(member.getter!!, identity()) { false } + .map { it.from } + .map { (it as PropertyAccessorDescriptor).correspondingProperty } + .asSequence() + else -> error("Expected either be function or property: $member") } }