Skip to content

Commit acd9256

Browse files
committed
Change variance and nullability of property type in parent
if needed to generate correct override
1 parent 649ec56 commit acd9256

File tree

6 files changed

+169
-15
lines changed

6 files changed

+169
-15
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// [test] variance.kt
2+
@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
3+
4+
import kotlin.js.*
5+
import kotlin.js.Json
6+
import org.khronos.webgl.*
7+
import org.w3c.dom.*
8+
import org.w3c.dom.events.*
9+
import org.w3c.dom.parsing.*
10+
import org.w3c.dom.svg.*
11+
import org.w3c.dom.url.*
12+
import org.w3c.fetch.*
13+
import org.w3c.files.*
14+
import org.w3c.notifications.*
15+
import org.w3c.performance.*
16+
import org.w3c.workers.*
17+
import org.w3c.xhr.*
18+
19+
external open class Observable<T> {
20+
open val source: Observable<out Any?>
21+
}
22+
23+
external open class ConnectableObservable<T> : Observable<T> {
24+
override val source: Observable<T>
25+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export declare class Observable<T> {
2+
source: Observable<any>
3+
}
4+
5+
export declare class ConnectableObservable<T> extends Observable<T> {
6+
source: Observable<T>
7+
}
Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ private fun PropertyModel.toVal(): PropertyModel {
2929
)
3030
}
3131

32-
private class VarOverrideResolver(
32+
private class OverrideConflictResolver(
3333
private val modelContext: ModelContext,
3434
private val inheritanceContext: InheritanceContext
3535
) : ModelWithOwnerTypeLowering {
3636

3737
val propertiesToChangeToVal: MutableSet<NameEntity> = mutableSetOf()
38+
val propertiesToChangeType: MutableMap<NameEntity, TypeModel> = mutableMapOf()
3839

3940
private fun findConflictingProperties(
4041
parentMembers: Map<NameEntity?, List<MemberData>>,
@@ -71,6 +72,25 @@ private class VarOverrideResolver(
7172
return null
7273
}
7374

75+
private fun processParentPropertiesNeededToChangeType(
76+
member: PropertyModel,
77+
parentMembers: Map<NameEntity?, List<MemberData>>,
78+
typeChecker: OverrideTypeChecker
79+
) {
80+
val parentProperty = parentMembers[member.name]?.firstOrNull { it.memberModel is PropertyModel }
81+
if (parentProperty != null) {
82+
val parentType = (parentProperty.memberModel as PropertyModel).type
83+
val childType = member.type
84+
val newType = parentType
85+
.changeVarianceToMatchChild(childType, typeChecker)
86+
.changeNullabilityToMatchChild(childType)
87+
val fqName = parentProperty.fqName?.appendLeft(member.name)
88+
if (newType != parentType && fqName != null) {
89+
propertiesToChangeType[fqName] = newType
90+
}
91+
}
92+
}
93+
7494
private fun findSuperType(types: List<TypeModel>, typeChecker: OverrideTypeChecker): TypeModel? {
7595
var superType: TypeModel? = types[0]
7696
types.forEach { type ->
@@ -109,7 +129,7 @@ private class VarOverrideResolver(
109129

110130
val propertiesToAdd = allConflictingProperties.mapNotNull { createPropertyToAdd(it, classLike) }
111131

112-
return classLike.members.mapNotNull { member ->
132+
return classLike.members.map { member ->
113133
if (member is PropertyModel) {
114134
when {
115135
allConflictingProperties.any { properties ->
@@ -143,14 +163,24 @@ private class VarOverrideResolver(
143163
OverrideTypeChecker(modelContext, inheritanceContext, classLike, null)
144164
)
145165

146-
val varPropertiesWithSpecifiedType = classLike.members.filterIsInstance<PropertyModel>().mapNotNull {
166+
val properties = classLike.members.filterIsInstance<PropertyModel>()
167+
168+
val varPropertiesWithSpecifiedType = properties.mapNotNull {
147169
findVarPropertiesWithSpecifiedType(
148170
it,
149171
parentMembers,
150172
OverrideTypeChecker(modelContext, inheritanceContext, classLike, null)
151173
)
152174
}
153175

176+
properties.forEach {
177+
processParentPropertiesNeededToChangeType(
178+
it,
179+
parentMembers,
180+
OverrideTypeChecker(modelContext, inheritanceContext, classLike, null)
181+
)
182+
}
183+
154184
(allConflictingProperties + listOf(varPropertiesWithSpecifiedType)).forEach { propertiesToChangeToVal += it.mapNotNull { memberData ->
155185
(memberData.memberModel as? PropertyModel)?.let { property ->
156186
memberData.fqName?.appendLeft(property.name)
@@ -167,17 +197,24 @@ private class VarOverrideResolver(
167197
}
168198
}
169199

170-
private class VarToValResolver(private val propertiesToChangeToVal: Set<NameEntity>) : ModelWithOwnerTypeLowering {
200+
private class ParentPropertyChanger(
201+
private val propertiesToChangeToVal: Set<NameEntity>,
202+
private val propertiesToChangeType: MutableMap<NameEntity, TypeModel>
203+
) : ModelWithOwnerTypeLowering {
171204

172205
private var currentFqName: NameEntity = IdentifierEntity("")
173206

174207
override fun lowerPropertyModel(ownerContext: NodeOwner<PropertyModel>): PropertyModel {
175208
val property = ownerContext.node
209+
val propertyFqName = currentFqName.appendLeft(property.name)
176210

177-
return if (propertiesToChangeToVal.contains(currentFqName.appendLeft(property.name))) {
178-
property.toVal()
211+
val newType = propertiesToChangeType[propertyFqName] ?: property.type
212+
val newProperty = property.copy(type = newType)
213+
214+
return if (propertiesToChangeToVal.contains(propertyFqName)) {
215+
newProperty.toVal()
179216
} else {
180-
property
217+
newProperty
181218
}
182219
}
183220

@@ -197,22 +234,24 @@ private class VarToValResolver(private val propertiesToChangeToVal: Set<NameEnti
197234
}
198235
}
199236

200-
class VarConflictResolveLowering : ModelLowering {
237+
class OverrideConflictResolveLowering : ModelLowering {
201238

202239
override fun lower(source: SourceSetModel): SourceSetModel {
203240
val modelContext = ModelContext(source)
204241
val inheritanceContext = InheritanceContext(modelContext.buildInheritanceGraph())
205-
val varOverrideResolver = VarOverrideResolver(modelContext, inheritanceContext)
242+
val overrideConflictResolver = OverrideConflictResolver(modelContext, inheritanceContext)
206243
val newSourceSet = source.copy(
207244
sources = source.sources.map {
208-
it.copy(root = varOverrideResolver.lowerRoot(it.root, NodeOwner(it.root, null)))
245+
it.copy(root = overrideConflictResolver.lowerRoot(it.root, NodeOwner(it.root, null)))
209246
}
210247
)
211-
val varToValResolver =
212-
VarToValResolver(varOverrideResolver.propertiesToChangeToVal)
248+
val parentPropertyChanger = ParentPropertyChanger(
249+
overrideConflictResolver.propertiesToChangeToVal,
250+
overrideConflictResolver.propertiesToChangeType
251+
)
213252
return newSourceSet.copy(
214253
sources = newSourceSet.sources.map {
215-
it.copy(root = varToValResolver.lowerRoot(it.root, NodeOwner(it.root, null)))
254+
it.copy(root = parentPropertyChanger.lowerRoot(it.root, NodeOwner(it.root, null)))
216255
}
217256
)
218257
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.jetbrains.dukat.model.commonLowerings.overrides
2+
3+
import org.jetbrains.dukat.astCommon.IdentifierEntity
4+
import org.jetbrains.dukat.astModel.TypeModel
5+
import org.jetbrains.dukat.astModel.TypeParameterReferenceModel
6+
import org.jetbrains.dukat.astModel.TypeValueModel
7+
8+
internal fun TypeModel.changeNullabilityToMatchChild(
9+
childType: TypeModel
10+
): TypeModel {
11+
return when {
12+
this !is TypeValueModel -> {
13+
this
14+
}
15+
childType is TypeParameterReferenceModel -> {
16+
if (this.value == IdentifierEntity("Any")) {
17+
this.copy(nullable = true)
18+
} else {
19+
this
20+
}
21+
}
22+
childType is TypeValueModel -> {
23+
if (params.size != childType.params.size) {
24+
this
25+
} else {
26+
val newParams = params.zip(childType.params).map { (parentParam, childParam) ->
27+
parentParam.type.changeNullabilityToMatchChild(childParam.type)
28+
}
29+
copy(params = newParams.mapIndexed { index, newParam ->
30+
params[index].copy(type = newParam)
31+
})
32+
}
33+
}
34+
else -> this
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.jetbrains.dukat.model.commonLowerings.overrides
2+
3+
import org.jetbrains.dukat.astCommon.IdentifierEntity
4+
import org.jetbrains.dukat.astModel.FunctionTypeModel
5+
import org.jetbrains.dukat.astModel.TypeModel
6+
import org.jetbrains.dukat.astModel.TypeParameterModel
7+
import org.jetbrains.dukat.astModel.TypeParameterReferenceModel
8+
import org.jetbrains.dukat.astModel.TypeValueModel
9+
import org.jetbrains.dukat.astModel.Variance
10+
import org.jetbrains.dukat.model.commonLowerings.OverrideTypeChecker
11+
12+
private fun TypeParameterModel.toCovariant(): TypeParameterModel {
13+
return copy(variance = Variance.COVARIANT)
14+
}
15+
16+
private fun TypeValueModel.toCovariant(indexes: Set<Int>): TypeValueModel {
17+
return copy(params = params.mapIndexed { index, typeParameterModel ->
18+
if (index in indexes) {
19+
typeParameterModel.toCovariant()
20+
} else {
21+
typeParameterModel
22+
}
23+
})
24+
}
25+
26+
internal fun TypeModel.changeVarianceToMatchChild(
27+
childType: TypeModel,
28+
typeChecker: OverrideTypeChecker
29+
): TypeModel {
30+
if (childType !is TypeValueModel || this !is TypeValueModel) {
31+
return this
32+
}
33+
if (params.size != childType.params.size) {
34+
return this
35+
}
36+
val indexesToChange = params.zip(childType.params).mapIndexedNotNull { index, (parentParam, childParam) ->
37+
if (with(typeChecker) { childParam.type.isOverridingReturnType(parentParam.type) && !childParam.type.isEquivalent(parentParam.type) }) {
38+
index
39+
} else {
40+
null
41+
}
42+
}.toSet()
43+
if (indexesToChange.isEmpty()) {
44+
return this
45+
}
46+
return toCovariant(indexesToChange)
47+
}

typescript/ts-translator/src/org/jetbrains/dukat/ts/translator/TypescriptLowerer.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import org.jetbrains.dukat.model.commonLowerings.RemoveConflictingOverloads
2323
import org.jetbrains.dukat.model.commonLowerings.RemoveKotlinBuiltIns
2424
import org.jetbrains.dukat.model.commonLowerings.RemoveRedundantTypeParams
2525
import org.jetbrains.dukat.model.commonLowerings.lower
26-
import org.jetbrains.dukat.model.commonLowerings.overrides.VarConflictResolveLowering
26+
import org.jetbrains.dukat.model.commonLowerings.overrides.OverrideConflictResolveLowering
2727
import org.jetbrains.dukat.moduleNameResolver.ModuleNameResolver
2828
import org.jetbrains.dukat.nodeIntroduction.IntroduceNodes
2929
import org.jetbrains.dukat.nodeIntroduction.ResolveModuleAnnotations
@@ -120,7 +120,7 @@ open class TypescriptLowerer(
120120
.lower { context, inheritanceContext ->
121121
LowerOverrides(context, inheritanceContext)
122122
},
123-
VarConflictResolveLowering(),
123+
OverrideConflictResolveLowering(),
124124
AddExplicitGettersAndSetters(),
125125
AnyfyUnresolvedTypes(),
126126
RemoveKotlinBuiltIns(),

0 commit comments

Comments
 (0)