Skip to content

Commit

Permalink
Merge conflicting functions and preserve corresponding metadata
Browse files Browse the repository at this point in the history
see #174
  • Loading branch information
Schahen committed Jun 4, 2020
1 parent a111778 commit 9b6a720
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ external interface Ping {
fun ping(a: Boolean)
}

external fun addListener(event: String, listener: (worker: Ping) -> Unit): Message
external fun addListener(event: String /* "disconnect" | "online" */, listener: (worker: Ping) -> Unit): Message /* */
4 changes: 1 addition & 3 deletions compiler/test/data/typescript/misc/literalType.d.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import org.w3c.performance.*
import org.w3c.workers.*
import org.w3c.xhr.*

external fun foo(s: String /* "number" */): Number

external fun foo(s: String /* "string" */): String
external fun foo(s: String /* "number" | "string" */): dynamic /* Number | String */

external interface I {
fun bar(s: String /* "number" */): Number
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jetbrains.dukat.model.commonLowerings

import org.jetbrains.dukat.astCommon.IdentifierEntity
import org.jetbrains.dukat.astCommon.NameEntity
import org.jetbrains.dukat.astCommon.rightMost
import org.jetbrains.dukat.astModel.ClassModel
import org.jetbrains.dukat.astModel.FunctionModel
import org.jetbrains.dukat.astModel.InterfaceModel
Expand Down Expand Up @@ -33,13 +36,6 @@ private fun MemberModel.normalize(): MemberModel {
}
}

private fun TopLevelModel.normalize(): TopLevelModel {
return when (this) {
is FunctionModel -> copy(parameters = parameters.map { it.withoutMeta() })
else -> this
}
}

private fun filterOutConflictingOverloads(members: List<MemberModel>): List<MemberModel> {
return members.groupBy { it.normalize() }.map { (_, bucketMembers) ->
if (bucketMembers.size > 1) {
Expand All @@ -50,26 +46,71 @@ private fun filterOutConflictingOverloads(members: List<MemberModel>): List<Memb
}
}

private class ConflictingOverloads() : ModelWithOwnerTypeLowering {
private class ConflictingOverloads : TopLevelModelLowering {

override fun lowerInterfaceModel(ownerContext: NodeOwner<InterfaceModel>, parentModule: ModuleModel): InterfaceModel {
override fun lowerInterfaceModel(ownerContext: NodeOwner<InterfaceModel>, parentModule: ModuleModel): InterfaceModel? {
val node = ownerContext.node.copy(members = filterOutConflictingOverloads(ownerContext.node.members))
return super.lowerInterfaceModel(ownerContext.copy(node = node), parentModule)
}

override fun lowerClassModel(ownerContext: NodeOwner<ClassModel>, parentModule: ModuleModel): ClassModel {
override fun lowerClassModel(ownerContext: NodeOwner<ClassModel>, parentModule: ModuleModel): ClassModel? {
val node = ownerContext.node.copy(members = filterOutConflictingOverloads(ownerContext.node.members))
return super.lowerClassModel(ownerContext.copy(node = node), parentModule)
}
}

private fun mergeTypeModels(a: TypeModel, b: TypeModel): TypeModel {
return if ((a is TypeValueModel) && (b is TypeValueModel)) {
a.copy(metaDescription = listOfNotNull(a.metaDescription, b.metaDescription).joinToString(" | "))
} else {
a
}
}

private fun mergeTypeModelsAsReturn(a: TypeModel, b: TypeModel): TypeModel {
return if ((a is TypeValueModel) && (b is TypeValueModel)) {
a.copy(metaDescription = listOfNotNull(a.metaDescription, b.metaDescription).joinToString(" | "))
if (a.withoutMeta() == b.withoutMeta()) {
mergeTypeModels(a, b)
} else {
TypeValueModel(IdentifierEntity("dynamic"), listOf(), listOfNotNull(a.fqName?.rightMost(), b.fqName?.rightMost()).joinToString(" | ") { it.toString() }, null)
}
} else {
TypeValueModel(IdentifierEntity("dynamic"), listOf(), null, null)
}
}


private fun mergeFunctionModels(a: FunctionModel, b: FunctionModel): FunctionModel {
val paramsMerged = a.parameters.zip(b.parameters).map { (paramA, paramB) ->
paramA.copy(type = mergeTypeModels(paramA.type, paramB.type))
}

return a.copy(parameters = paramsMerged, type = mergeTypeModelsAsReturn(a.type, b.type))
}

typealias FunctionModelKey = Triple<NameEntity, List<TypeModel>, List<TypeModel>>

private fun FunctionModel.getKey(): FunctionModelKey {
return Triple(name, parameters.map { it.type.withoutMeta() }, typeParameters.map { it.type.withoutMeta() })
}

class RemoveConflictingOverloads : ModelLowering {
override fun lower(module: ModuleModel): ModuleModel {
val declarationsResolved = module.declarations.groupBy { it.normalize() }.map { (_, bucketMembers) ->
if (bucketMembers.size > 1) {
bucketMembers.first().normalize()
} else {
bucketMembers.first()
val keyCache = mutableMapOf<FunctionModel, FunctionModelKey>()

val functionsBucket = module.declarations.filterIsInstance(FunctionModel::class.java).groupBy { functionModel ->
val key = functionModel.getKey()
keyCache.put(functionModel, key)
key
}.toMutableMap()

val declarationsResolved = module.declarations.mapNotNull { topLevelModel ->
when (topLevelModel) {
is FunctionModel -> {
functionsBucket.remove(keyCache[topLevelModel])?.reduce { a, b -> mergeFunctionModels(a, b) }
}
else -> topLevelModel
}
}

Expand Down

0 comments on commit 9b6a720

Please sign in to comment.