Skip to content

Commit a4fb236

Browse files
committed
Merge conflicting methods and preserve corresponding metadata
1 parent 9b6a720 commit a4fb236

File tree

4 files changed

+49
-42
lines changed

4 files changed

+49
-42
lines changed

compiler/test/data/typescript/class/override/conflictingOverloads.d.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import org.w3c.workers.*
1616
import org.w3c.xhr.*
1717

1818
external open class Message {
19-
open fun once(event: String, listener: () -> Unit): Message /* this */
19+
open fun once(event: String /* 'abort' | 'timeout' | 'close' | 'drain' | "cancel" | "submit" | "start" | 'end' | 'finish' | 'basta' */, listener: () -> Unit): Message /* this */
2020
open fun once(event: Any, listener: () -> Unit): Message /* this */
2121
}
2222

@@ -26,4 +26,4 @@ external interface Ping {
2626
fun ping(a: Boolean)
2727
}
2828

29-
external fun addListener(event: String /* "disconnect" | "online" */, listener: (worker: Ping) -> Unit): Message /* */
29+
external fun addListener(event: String /* "disconnect" | "online" */, listener: (worker: Ping) -> Unit): Message

compiler/test/data/typescript/extendExternalDeclarations/resolveClashingNames/resolveClashingNames.d.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ external interface API {
3939
fun ping(): Boolean
4040
fun pong(a: String): Boolean
4141
fun foo(a: String)
42-
fun pong(b: String): Boolean
4342
fun pong(c: Number): Boolean
4443
fun foo(a: String, b: Boolean = definedExternally)
4544
fun foo(a: Number, b: Boolean = definedExternally)

compiler/test/data/typescript/misc/literalType.d.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ import org.w3c.xhr.*
1818
external fun foo(s: String /* "number" | "string" */): dynamic /* Number | String */
1919

2020
external interface I {
21-
fun bar(s: String /* "number" */): Number
22-
fun bar(s: String /* "string" */): String
21+
fun bar(s: String /* "number" | "string" */): dynamic /* Number | String */
2322
}
2423

2524
external open class C {
26-
open fun baz(s: String /* "number" */): Number
27-
open fun baz(s: String /* "string" */): String
25+
open fun baz(s: String /* "number" | "string" */): dynamic /* Number | String */
2826
}
2927

3028
external interface Foo {

model-lowerings-common/src/org/jetbrains/dukat/model/commonLowerings/removeConflictingOverloads.kt

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ package org.jetbrains.dukat.model.commonLowerings
33
import org.jetbrains.dukat.astCommon.IdentifierEntity
44
import org.jetbrains.dukat.astCommon.NameEntity
55
import org.jetbrains.dukat.astCommon.rightMost
6+
import org.jetbrains.dukat.astModel.ClassLikeModel
67
import org.jetbrains.dukat.astModel.ClassModel
78
import org.jetbrains.dukat.astModel.FunctionModel
89
import org.jetbrains.dukat.astModel.InterfaceModel
910
import org.jetbrains.dukat.astModel.MemberModel
1011
import org.jetbrains.dukat.astModel.MethodModel
1112
import org.jetbrains.dukat.astModel.ModuleModel
12-
import org.jetbrains.dukat.astModel.ParameterModel
13-
import org.jetbrains.dukat.astModel.TopLevelModel
1413
import org.jetbrains.dukat.astModel.TypeModel
1514
import org.jetbrains.dukat.astModel.TypeValueModel
1615
import org.jetbrains.dukat.ownerContext.NodeOwner
@@ -22,54 +21,35 @@ private fun TypeModel.withoutMeta(): TypeModel {
2221
}
2322
}
2423

25-
private fun ParameterModel.withoutMeta(): ParameterModel {
26-
return copy(type = type.withoutMeta())
27-
}
28-
29-
private fun MemberModel.normalize(): MemberModel {
30-
return when (this) {
31-
is MethodModel -> copy(
32-
parameters = parameters.map { it.withoutMeta() },
33-
override = null
34-
)
35-
else -> this
36-
}
37-
}
38-
39-
private fun filterOutConflictingOverloads(members: List<MemberModel>): List<MemberModel> {
40-
return members.groupBy { it.normalize() }.map { (_, bucketMembers) ->
41-
if (bucketMembers.size > 1) {
42-
bucketMembers.first().normalize()
43-
} else {
44-
bucketMembers.first()
45-
}
46-
}
47-
}
48-
4924
private class ConflictingOverloads : TopLevelModelLowering {
50-
5125
override fun lowerInterfaceModel(ownerContext: NodeOwner<InterfaceModel>, parentModule: ModuleModel): InterfaceModel? {
52-
val node = ownerContext.node.copy(members = filterOutConflictingOverloads(ownerContext.node.members))
26+
val node = ownerContext.node.copy(members = ownerContext.node.resolveMembers())
5327
return super.lowerInterfaceModel(ownerContext.copy(node = node), parentModule)
5428
}
5529

5630
override fun lowerClassModel(ownerContext: NodeOwner<ClassModel>, parentModule: ModuleModel): ClassModel? {
57-
val node = ownerContext.node.copy(members = filterOutConflictingOverloads(ownerContext.node.members))
31+
val node = ownerContext.node.copy(members = ownerContext.node.resolveMembers())
5832
return super.lowerClassModel(ownerContext.copy(node = node), parentModule)
5933
}
6034
}
6135

6236
private fun mergeTypeModels(a: TypeModel, b: TypeModel): TypeModel {
6337
return if ((a is TypeValueModel) && (b is TypeValueModel)) {
64-
a.copy(metaDescription = listOfNotNull(a.metaDescription, b.metaDescription).joinToString(" | "))
38+
val metaDescription = listOfNotNull(a.metaDescription, b.metaDescription).distinct().let {
39+
if (it.isEmpty()) {
40+
null
41+
} else {
42+
it.joinToString(" | ")
43+
}
44+
}
45+
a.copy(metaDescription = metaDescription)
6546
} else {
6647
a
6748
}
6849
}
6950

7051
private fun mergeTypeModelsAsReturn(a: TypeModel, b: TypeModel): TypeModel {
7152
return if ((a is TypeValueModel) && (b is TypeValueModel)) {
72-
a.copy(metaDescription = listOfNotNull(a.metaDescription, b.metaDescription).joinToString(" | "))
7353
if (a.withoutMeta() == b.withoutMeta()) {
7454
mergeTypeModels(a, b)
7555
} else {
@@ -80,6 +60,13 @@ private fun mergeTypeModelsAsReturn(a: TypeModel, b: TypeModel): TypeModel {
8060
}
8161
}
8262

63+
private fun mergeMethodModels(a: MethodModel, b: MethodModel): MethodModel {
64+
val paramsMerged = a.parameters.zip(b.parameters).map { (paramA, paramB) ->
65+
paramA.copy(type = mergeTypeModels(paramA.type, paramB.type))
66+
}
67+
68+
return a.copy(parameters = paramsMerged, type = mergeTypeModelsAsReturn(a.type, b.type))
69+
}
8370

8471
private fun mergeFunctionModels(a: FunctionModel, b: FunctionModel): FunctionModel {
8572
val paramsMerged = a.parameters.zip(b.parameters).map { (paramA, paramB) ->
@@ -89,21 +76,44 @@ private fun mergeFunctionModels(a: FunctionModel, b: FunctionModel): FunctionMod
8976
return a.copy(parameters = paramsMerged, type = mergeTypeModelsAsReturn(a.type, b.type))
9077
}
9178

92-
typealias FunctionModelKey = Triple<NameEntity, List<TypeModel>, List<TypeModel>>
79+
typealias CallableKey = Triple<NameEntity, List<TypeModel>, List<TypeModel>>
80+
81+
private fun ClassLikeModel.resolveMembers(): List<MemberModel> {
82+
val keyCache = mutableMapOf<MethodModel, CallableKey>()
83+
84+
val methodsBucket = members.filterIsInstance(MethodModel::class.java).groupBy { methodModel ->
85+
val key = methodModel.getKey()
86+
keyCache.put(methodModel, key)
87+
key
88+
}.toMutableMap()
89+
90+
return members.mapNotNull { memberModel ->
91+
when (memberModel) {
92+
is MethodModel -> {
93+
methodsBucket.remove(keyCache[memberModel])?.reduce { a, b -> mergeMethodModels(a, b) }
94+
}
95+
else -> memberModel
96+
}
97+
}
98+
}
99+
100+
private fun FunctionModel.getKey(): CallableKey {
101+
return Triple(name, parameters.map { it.type.withoutMeta() }, typeParameters.map { it.type.withoutMeta() })
102+
}
93103

94-
private fun FunctionModel.getKey(): FunctionModelKey {
104+
private fun MethodModel.getKey(): CallableKey {
95105
return Triple(name, parameters.map { it.type.withoutMeta() }, typeParameters.map { it.type.withoutMeta() })
96106
}
97107

98108
class RemoveConflictingOverloads : ModelLowering {
99109
override fun lower(module: ModuleModel): ModuleModel {
100-
val keyCache = mutableMapOf<FunctionModel, FunctionModelKey>()
110+
val keyCache = mutableMapOf<FunctionModel, CallableKey>()
101111

102112
val functionsBucket = module.declarations.filterIsInstance(FunctionModel::class.java).groupBy { functionModel ->
103113
val key = functionModel.getKey()
104114
keyCache.put(functionModel, key)
105115
key
106-
}.toMutableMap()
116+
}.toMutableMap()
107117

108118
val declarationsResolved = module.declarations.mapNotNull { topLevelModel ->
109119
when (topLevelModel) {

0 commit comments

Comments
 (0)