Fix translation of labels with non-identifier names in JS BE
See KT-18027
This commit is contained in:
@@ -37,8 +37,8 @@ open class JsDeclarationScope(parent: JsScope, description: String, useParentSco
|
||||
private val topLabelScope
|
||||
get() = if (labelScopes.isNotEmpty()) labelScopes.peek() else null
|
||||
|
||||
open fun enterLabel(label: String): JsName {
|
||||
val scope = LabelScope(topLabelScope, label)
|
||||
open fun enterLabel(label: String, outputName: String): JsName {
|
||||
val scope = LabelScope(topLabelScope, label, outputName)
|
||||
labelScopes.push(scope)
|
||||
return scope.labelName
|
||||
}
|
||||
@@ -51,18 +51,8 @@ open class JsDeclarationScope(parent: JsScope, description: String, useParentSco
|
||||
open fun findLabel(label: String): JsName? =
|
||||
topLabelScope?.findName(label)
|
||||
|
||||
private inner class LabelScope(parent: LabelScope?, val ident: String) : JsScope(parent, "Label scope for $ident") {
|
||||
val labelName: JsName
|
||||
|
||||
init {
|
||||
val freshIdent = when {
|
||||
ident in RESERVED_WORDS -> getFreshIdent(ident)
|
||||
parent != null -> parent.getFreshIdent(ident)
|
||||
else -> ident
|
||||
}
|
||||
|
||||
labelName = JsName(freshIdent, false)
|
||||
}
|
||||
private inner class LabelScope(parent: LabelScope?, val ident: String, outputIdent: String) : JsScope(parent, "Label scope for $ident") {
|
||||
val labelName: JsName = JsName(outputIdent, true)
|
||||
|
||||
override fun findOwnName(name: String): JsName? =
|
||||
if (name == ident) labelName else null
|
||||
@@ -130,8 +120,8 @@ class DelegatingJsFunctionScopeWithTemporaryParent(
|
||||
override fun declareFreshName(suggestedName: String): JsName =
|
||||
delegatingScope.declareFreshName(suggestedName)
|
||||
|
||||
override fun enterLabel(label: String): JsName =
|
||||
delegatingScope.enterLabel(label)
|
||||
override fun enterLabel(label: String, outputName: String): JsName =
|
||||
delegatingScope.enterLabel(label, outputName)
|
||||
|
||||
override fun exitLabel() =
|
||||
delegatingScope.exitLabel()
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ class LabelNameRefreshingVisitor(val functionScope: JsFunctionScope) : JsVisitor
|
||||
|
||||
override fun visit(x: JsLabel, ctx: JsContext<JsNode>): Boolean {
|
||||
val labelName = x.name
|
||||
val freshName = functionScope.enterLabel(labelName.ident)
|
||||
val freshName = functionScope.enterLabel(labelName.ident, labelName.ident)
|
||||
substitutions.getOrPut(labelName) { ArrayDeque() }.push(freshName)
|
||||
|
||||
return super.visit(x, ctx)
|
||||
@@ -57,5 +57,5 @@ class LabelNameRefreshingVisitor(val functionScope: JsFunctionScope) : JsVisitor
|
||||
super.endVisit(x, ctx)
|
||||
}
|
||||
|
||||
private fun getSubstitution(name: JsName) = substitutions[name]?.let { it.peek() } ?: name
|
||||
private fun getSubstitution(name: JsName) = substitutions[name]?.peek() ?: name
|
||||
}
|
||||
|
||||
@@ -665,7 +665,7 @@ public class JsAstMapper {
|
||||
private JsLabel mapLabel(Node labelNode) throws JsParserException {
|
||||
String fromName = labelNode.getFirstChild().getString();
|
||||
|
||||
JsName toName = scopeContext.enterLabel(fromName);
|
||||
JsName toName = scopeContext.enterLabel(fromName, fromName);
|
||||
|
||||
Node fromStmt = labelNode.getFirstChild().getNext();
|
||||
JsLabel toLabel = new JsLabel(toName);
|
||||
|
||||
@@ -49,8 +49,8 @@ class ScopeContext(scope: JsScope) {
|
||||
exitScope()
|
||||
}
|
||||
|
||||
fun enterLabel(ident: String): JsName =
|
||||
(currentScope as JsDeclarationScope).enterLabel(ident)
|
||||
fun enterLabel(ident: String, outputName: String): JsName =
|
||||
(currentScope as JsDeclarationScope).enterLabel(ident, outputName)
|
||||
|
||||
fun exitLabel() =
|
||||
(currentScope as JsDeclarationScope).exitLabel()
|
||||
|
||||
@@ -5450,6 +5450,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("peculiarNames.kt")
|
||||
public void testPeculiarNames() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/labels/peculiarNames.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("siblingLabels.kt")
|
||||
public void testSiblingLabels() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/labels/siblingLabels.kt");
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.PropertyTranslatorKt;
|
||||
@@ -363,7 +364,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
|
||||
String labelIdent = getReferencedName(expression.getTargetLabel());
|
||||
|
||||
JsName labelName = functionScope.enterLabel(labelIdent);
|
||||
JsName labelName = functionScope.enterLabel(labelIdent, NameSuggestion.sanitizeName(labelIdent));
|
||||
JsStatement baseStatement = Translation.translateAsStatement(baseExpression, context);
|
||||
functionScope.exitLabel();
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// EXPECTED_REACHABLE_NODES: 487
|
||||
fun box(): String {
|
||||
var log = ""
|
||||
|
||||
var i = 0
|
||||
`!`@while (true) {
|
||||
log += "i=$i;"
|
||||
for (j in 1..3) {
|
||||
log += "j=$j;"
|
||||
if (i++ + j > 5) break@`!`
|
||||
log += "!"
|
||||
}
|
||||
}
|
||||
|
||||
if (log != "i=0;j=1;!j=2;!j=3;!i=3;j=1;!j=2;") return "fail: $log"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user