JS: fix generation of bridge methods for non-abstract methods inherited from interfaces

This commit is contained in:
Alexey Andreev
2016-10-19 17:53:19 +03:00
parent bb57eaef96
commit bec1e526a1
@@ -503,25 +503,28 @@ class ClassTranslator private constructor(
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
.mapNotNull { it as? CallableMemberDescriptor } .mapNotNull { it as? CallableMemberDescriptor }
for (member in members) { 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 if (member.modality == Modality.ABSTRACT || member.overriddenDescriptors.size != 1) continue
val overriddenFunction = generateSequence(member) { it.overriddenDescriptors.firstOrNull() } val overriddenMember = generateSequence(member) { it.overriddenDescriptors.firstOrNull() }
.drop(1) .drop(1)
.dropWhile { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && .dropWhile { !it.kind.isReal && DescriptorUtils.isInterface(it.containingDeclaration) }
DescriptorUtils.isInterface(it.containingDeclaration) } .firstOrNull() ?: continue
.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 if (interfaceDescriptor.kind != ClassKind.INTERFACE) continue
val directContainer = member.overriddenDescriptors.first().containingDeclaration as ClassDescriptor val directContainer = member.overriddenDescriptors.first().containingDeclaration as ClassDescriptor
when (member) { when (overriddenMember) {
is FunctionDescriptor -> addDefaultMethodFromInterface(member, directContainer, descriptor, context) is FunctionDescriptor -> {
is PropertyDescriptor -> addDefaultPropertyFromInterface(member, directContainer, descriptor, context) addDefaultMethodFromInterface(overriddenMember, directContainer, descriptor,context)
}
is PropertyDescriptor -> {
addDefaultPropertyFromInterface(overriddenMember, directContainer, descriptor, context)
}
} }
} }
} }
@@ -532,12 +535,13 @@ class ClassTranslator private constructor(
descriptor: ClassDescriptor, descriptor: ClassDescriptor,
context: StaticContext context: StaticContext
) { ) {
val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) for (name in generateAllNames(function, context)) {
val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null))
val functionName = context.getNameForDescriptor(function) val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null))
val classFunction = JsNameRef(functionName, classPrototype) val classFunction = JsNameRef(name, classPrototype)
val interfaceFunction = JsNameRef(functionName, interfacePrototype) val interfaceFunction = JsNameRef(name, interfacePrototype)
context.declarationStatements += JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt() context.declarationStatements += JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt()
}
} }
private fun addDefaultPropertyFromInterface( private fun addDefaultPropertyFromInterface(
@@ -546,15 +550,35 @@ class ClassTranslator private constructor(
descriptor: ClassDescriptor, descriptor: ClassDescriptor,
context: StaticContext context: StaticContext
) { ) {
val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) for (name in generateAllNames(property, context)) {
val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null))
val functionName = context.getNameForDescriptor(property) val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null))
val nameLiteral = context.program.getStringLiteral(functionName.ident) val nameLiteral = context.program.getStringLiteral(name.ident)
val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral) val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral)
val defineProperty = JsAstUtils.defineProperty(classPrototype, functionName.ident, getPropertyDescriptor, context.program) 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<JsName> {
return (generateBridges(member) + member)
.map { context.getNameForDescriptor(it) }
.distinctBy { it.ident }
}
private fun generateBridges(member: CallableMemberDescriptor): Sequence<CallableMemberDescriptor> = 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")
} }
} }