Skip to content

Commit db565fc

Browse files
committed
Generate replacement variables in cases where nullability smart-cast fails
1 parent 9060f60 commit db565fc

File tree

6 files changed

+98
-35
lines changed

6 files changed

+98
-35
lines changed

typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/DeclarationLowering.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ interface DeclarationLowering : TopLevelDeclarationLowering, DeclarationStatemen
5252
typeParameters = declaration.typeParameters.map { typeParameter ->
5353
typeParameter.copy(constraints = typeParameter.constraints.map { constraint -> lowerParameterValue(constraint, owner.wrap(declaration)) })
5454
},
55-
body = declaration.body?.let { lowerBlockStatement(it) }
55+
body = declaration.body?.let { lowerBlock(it) }
5656
)
5757
}
5858

@@ -107,7 +107,7 @@ interface DeclarationLowering : TopLevelDeclarationLowering, DeclarationStatemen
107107
typeParameter.copy(constraints = typeParameter.constraints.map { constraint -> lowerParameterValue(constraint, owner.wrap(declaration)) })
108108
},
109109
type = lowerParameterValue(declaration.type, owner.wrap(declaration)),
110-
body = declaration.body?.let { lowerBlockStatement(it) }
110+
body = declaration.body?.let { lowerBlock(it) }
111111
)
112112
}
113113

typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/DeclarationStatementLowering.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,4 @@ interface DeclarationStatementLowering : ExpressionLowering {
148148
}
149149
}
150150

151-
fun lowerBlockStatement(block: BlockDeclaration): BlockDeclaration {
152-
return BlockDeclaration(block.statements.map { lower(it) })
153-
}
154-
155151
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.jetbrains.dukat.tsLowerings
2+
3+
import org.jetbrains.dukat.astCommon.IdentifierEntity
4+
import org.jetbrains.dukat.astCommon.NameEntity
5+
import org.jetbrains.dukat.astCommon.QualifierEntity
6+
import org.jetbrains.dukat.tsmodel.expression.ExpressionDeclaration
7+
import org.jetbrains.dukat.tsmodel.expression.PropertyAccessExpressionDeclaration
8+
import org.jetbrains.dukat.tsmodel.expression.name.IdentifierExpressionDeclaration
9+
import org.jetbrains.dukat.tsmodel.expression.name.QualifierExpressionDeclaration
10+
11+
internal class ReplaceExpressionsLowering(private val replacements: Map<ExpressionDeclaration, IdentifierExpressionDeclaration>):
12+
DeclarationLowering {
13+
override fun lowerIdentifier(identifier: IdentifierEntity): IdentifierEntity {
14+
return replacements[IdentifierExpressionDeclaration(
15+
identifier
16+
)]?.identifier ?: identifier
17+
}
18+
19+
override fun lowerQualifier(qualifier: QualifierEntity): NameEntity {
20+
return replacements[QualifierExpressionDeclaration(
21+
qualifier
22+
)]?.identifier ?: super.lowerQualifier(qualifier)
23+
}
24+
25+
override fun lower(declaration: ExpressionDeclaration): ExpressionDeclaration {
26+
return when (declaration) {
27+
is PropertyAccessExpressionDeclaration -> {
28+
return replacements[declaration] ?: super.lower(declaration)
29+
}
30+
else -> super.lower(declaration)
31+
}
32+
}
33+
}

typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/StatementTypeContext.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import org.jetbrains.dukat.tsmodel.types.ParameterValueDeclaration
1919
import org.jetbrains.dukat.tsmodel.types.TypeDeclaration
2020

2121
private data class Scope(
22-
val variables: MutableMap<NameEntity, ParameterValueDeclaration> = mutableMapOf()
22+
val variables: MutableMap<NameEntity, ParameterValueDeclaration> = mutableMapOf(),
23+
val expressionsToReplace: MutableSet<ExpressionDeclaration> = mutableSetOf()
2324
)
2425

2526
internal class StatementTypeContext : DeclarationLowering {
@@ -78,6 +79,16 @@ internal class StatementTypeContext : DeclarationLowering {
7879
scopes.removeLast()
7980
}
8081

82+
fun addExpressionToReplace(expression: ExpressionDeclaration) {
83+
scopes.last().expressionsToReplace += expression
84+
}
85+
86+
fun getRelevantExpressionsToReplace(): Set<ExpressionDeclaration> {
87+
val expressions = scopes.last().expressionsToReplace.toSet()
88+
scopes.last().expressionsToReplace.clear()
89+
return expressions
90+
}
91+
8192
override fun lowerClassLikeDeclaration(
8293
declaration: ClassLikeDeclaration,
8394
owner: NodeOwner<ModuleDeclaration>?

typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/processNullabilityChecks.kt

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.jetbrains.dukat.tsmodel.FunctionDeclaration
77
import org.jetbrains.dukat.tsmodel.FunctionOwnerDeclaration
88
import org.jetbrains.dukat.tsmodel.IfStatementDeclaration
99
import org.jetbrains.dukat.tsmodel.SourceSetDeclaration
10+
import org.jetbrains.dukat.tsmodel.StatementDeclaration
1011
import org.jetbrains.dukat.tsmodel.VariableDeclaration
1112
import org.jetbrains.dukat.tsmodel.WhileStatementDeclaration
1213
import org.jetbrains.dukat.tsmodel.expression.BinaryExpressionDeclaration
@@ -15,12 +16,33 @@ import org.jetbrains.dukat.tsmodel.expression.ExpressionDeclaration
1516
import org.jetbrains.dukat.tsmodel.expression.ParenthesizedExpressionDeclaration
1617
import org.jetbrains.dukat.tsmodel.expression.UnaryExpressionDeclaration
1718
import org.jetbrains.dukat.tsmodel.expression.UnknownExpressionDeclaration
19+
import org.jetbrains.dukat.tsmodel.expression.name.IdentifierExpressionDeclaration
20+
import org.jetbrains.dukat.tsmodel.types.TypeDeclaration
21+
import java.util.*
1822

1923
private class ProcessNullabilityChecksLowering(private val typeContext: StatementTypeContext) : DeclarationLowering {
2024

2125
private val booleanUnaryOperators = listOf("!")
2226
private val booleanBinaryOperators = listOf("&&", "||")
2327

28+
private var counter = 1;
29+
30+
private fun generateVariableName(): String {
31+
return "_vn${counter++}"
32+
}
33+
34+
private fun createReplacementVariable(expression: ExpressionDeclaration): VariableDeclaration {
35+
return VariableDeclaration(
36+
name = generateVariableName(),
37+
type = TypeDeclaration(IdentifierEntity("Any"), emptyList()),
38+
modifiers = setOf(),
39+
initializer = expression,
40+
definitionsInfo = listOf(),
41+
uid = "",
42+
explicitlyDeclaredType = false
43+
)
44+
}
45+
2446
private fun ExpressionDeclaration.convertToNonNullCheck(): ExpressionDeclaration {
2547
return BinaryExpressionDeclaration(
2648
left = this,
@@ -39,13 +61,19 @@ private class ProcessNullabilityChecksLowering(private val typeContext: Statemen
3961

4062
private fun processConditionNonNull(condition: ExpressionDeclaration): ExpressionDeclaration {
4163
if (!typeContext.hasBooleanType(condition)) {
64+
if (condition !is IdentifierExpressionDeclaration) {
65+
typeContext.addExpressionToReplace(condition)
66+
}
4267
return ParenthesizedExpressionDeclaration(condition.convertToNonNullCheck())
4368
}
4469
return condition
4570
}
4671

4772
private fun processEqualsNull(condition: UnaryExpressionDeclaration): ExpressionDeclaration {
4873
if (!typeContext.hasBooleanType(condition.operand)) {
74+
if (condition.operand !is IdentifierExpressionDeclaration) {
75+
typeContext.addExpressionToReplace(condition.operand)
76+
}
4977
return ParenthesizedExpressionDeclaration(condition.operand.convertToEqualsNullCheck())
5078
}
5179
return condition
@@ -91,11 +119,31 @@ private class ProcessNullabilityChecksLowering(private val typeContext: Statemen
91119
)
92120
}
93121

94-
override fun lowerBlockStatement(block: BlockDeclaration): BlockDeclaration {
122+
override fun lowerBlock(statement: BlockDeclaration): BlockDeclaration {
95123
typeContext.startScope()
96-
val newBlock = super.lowerBlockStatement(block)
124+
val newStatements = mutableListOf<StatementDeclaration>()
125+
var statementsToProcess = ArrayDeque(statement.statements)
126+
while (statementsToProcess.isNotEmpty()) {
127+
val nextStatement = super.lower(statementsToProcess.removeFirst())
128+
val expressionsToReplace = typeContext.getRelevantExpressionsToReplace()
129+
if (expressionsToReplace.isNotEmpty()) {
130+
val replacementVariables = expressionsToReplace.map { createReplacementVariable(it) }
131+
val replacementLowering = ReplaceExpressionsLowering(
132+
replacementVariables.map { variable ->
133+
variable.initializer!! to IdentifierExpressionDeclaration(IdentifierEntity(variable.name))
134+
}.toMap()
135+
)
136+
137+
statementsToProcess = ArrayDeque(statementsToProcess.map {
138+
replacementLowering.lower(it)
139+
})
140+
newStatements += replacementVariables + replacementLowering.lower(nextStatement)
141+
} else {
142+
newStatements += nextStatement
143+
}
144+
}
97145
typeContext.endScope()
98-
return newBlock
146+
return BlockDeclaration(newStatements)
99147
}
100148

101149
override fun lowerVariableDeclaration(declaration: VariableDeclaration): VariableDeclaration {

typescript/ts-lowerings/src/org/jetbrains/dukat/tsLowerings/processTypePredicates.kt

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package org.jetbrains.dukat.tsLowerings
22

33
import org.jetbrains.dukat.astCommon.IdentifierEntity
4-
import org.jetbrains.dukat.astCommon.NameEntity
54
import org.jetbrains.dukat.astCommon.QualifierEntity
6-
import org.jetbrains.dukat.astCommon.appendLeft
7-
import org.jetbrains.dukat.astCommon.appendRight
8-
import org.jetbrains.dukat.astCommon.rightMost
9-
import org.jetbrains.dukat.astCommon.shiftLeft
10-
import org.jetbrains.dukat.astCommon.shiftRight
115
import org.jetbrains.dukat.ownerContext.NodeOwner
126
import org.jetbrains.dukat.tsmodel.BlockDeclaration
137
import org.jetbrains.dukat.tsmodel.ExpressionStatementDeclaration
@@ -96,25 +90,6 @@ private class TypePredicateExpressionLowering(private val context: TypePredicate
9690
}
9791
}
9892

99-
private class ReplaceExpressionsLowering(val replacements: Map<ExpressionDeclaration, IdentifierExpressionDeclaration>): DeclarationLowering {
100-
override fun lowerIdentifier(identifier: IdentifierEntity): IdentifierEntity {
101-
return replacements[IdentifierExpressionDeclaration(identifier)]?.identifier ?: identifier
102-
}
103-
104-
override fun lowerQualifier(qualifier: QualifierEntity): NameEntity {
105-
return replacements[QualifierExpressionDeclaration(qualifier)]?.identifier ?: super.lowerQualifier(qualifier)
106-
}
107-
108-
override fun lower(declaration: ExpressionDeclaration): ExpressionDeclaration {
109-
return when (declaration) {
110-
is PropertyAccessExpressionDeclaration -> {
111-
return replacements[declaration] ?: super.lower(declaration)
112-
}
113-
else -> super.lower(declaration)
114-
}
115-
}
116-
}
117-
11893
private class TypePredicateLowering(private val context: TypePredicateCollector) : DeclarationLowering {
11994

12095
private var counter = 1

0 commit comments

Comments
 (0)