KJS: fix non-local return inside catch block
This commit is contained in:
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
inline fun foo(a: Int) {
|
||||||
|
bar(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun bar(a: Int) {
|
||||||
|
try {
|
||||||
|
if (a > 0) throw Exception()
|
||||||
|
log("foo($a) #1")
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
myRun {
|
||||||
|
log("foo($a) #2")
|
||||||
|
if (a > 1) return
|
||||||
|
log("foo($a) #3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log("foo($a) #4")
|
||||||
|
}
|
||||||
|
|
||||||
|
var LOG: String = ""
|
||||||
|
|
||||||
|
fun log(s: String): String {
|
||||||
|
LOG += s + ";"
|
||||||
|
return LOG
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun myRun(f: () -> Unit) = f()
|
||||||
|
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import utils.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
foo(0)
|
||||||
|
if (LOG != "foo(0) #1;foo(0) #4;") return "fail1: $LOG"
|
||||||
|
LOG = ""
|
||||||
|
|
||||||
|
foo(1)
|
||||||
|
if (LOG != "foo(1) #2;foo(1) #3;foo(1) #4;") return "fail2: $LOG"
|
||||||
|
LOG = ""
|
||||||
|
|
||||||
|
foo(2)
|
||||||
|
if (LOG != "foo(2) #2;") return "fail3: $LOG"
|
||||||
|
LOG = ""
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+51
@@ -0,0 +1,51 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
inline fun foo(a: Int) {
|
||||||
|
try {
|
||||||
|
if (a > 0) throw Exception()
|
||||||
|
log("foo($a)")
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
bar(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun bar(a: Int) {
|
||||||
|
myRun {
|
||||||
|
log("bar($a) #1")
|
||||||
|
if (a == 2) return
|
||||||
|
log("bar($a) #2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var LOG: String = ""
|
||||||
|
|
||||||
|
fun log(s: String): String {
|
||||||
|
LOG += s + ";"
|
||||||
|
return LOG
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun myRun(f: () -> Unit) = f()
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import utils.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
foo(0)
|
||||||
|
if (LOG != "foo(0);") return "fail1: $LOG"
|
||||||
|
LOG = ""
|
||||||
|
|
||||||
|
foo(1)
|
||||||
|
if (LOG != "bar(1) #1;bar(1) #2;") return "fail2: $LOG"
|
||||||
|
LOG = ""
|
||||||
|
|
||||||
|
foo(2)
|
||||||
|
if (LOG != "bar(2) #1;") return "fail3: $LOG"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1387,12 +1387,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnFromCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnFromCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
||||||
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnToCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnToCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+12
@@ -1387,12 +1387,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnFromCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnFromCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
||||||
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnToCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnToCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+3
-3
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.generators.tests
|
package org.jetbrains.kotlin.generators.tests
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsFunctionScope
|
|
||||||
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
|
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsDeclarationScope
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.renderer.KeywordStringsGenerated
|
import org.jetbrains.kotlin.renderer.KeywordStringsGenerated
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -366,8 +366,8 @@ val testNotRenamedByRef = testNotRenamed("$KEYWORD_MARKER()")
|
|||||||
|
|
||||||
// KEYWORDS
|
// KEYWORDS
|
||||||
|
|
||||||
val SHOULD_BE_ESCAPED = JsFunctionScope.RESERVED_WORDS.filter { it in KeywordStringsGenerated.KEYWORDS }.sorted()
|
val SHOULD_BE_ESCAPED = JsDeclarationScope.RESERVED_WORDS.filter { it in KeywordStringsGenerated.KEYWORDS }.sorted()
|
||||||
val SHOULD_NOT_BE_ESCAPED = JsFunctionScope.RESERVED_WORDS.filter { it !in SHOULD_BE_ESCAPED }.sorted()
|
val SHOULD_NOT_BE_ESCAPED = JsDeclarationScope.RESERVED_WORDS.filter { it !in SHOULD_BE_ESCAPED }.sorted()
|
||||||
|
|
||||||
// all keywords by portions
|
// all keywords by portions
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* A special scope used only for catch blocks. It only holds a single symbol:
|
* A special scope used only for catch blocks. It only holds a single symbol:
|
||||||
* the catch argument's name.
|
* the catch argument's name.
|
||||||
*/
|
*/
|
||||||
public class JsCatchScope extends JsScope {
|
public class JsCatchScope extends JsDeclarationScope {
|
||||||
private final JsName name;
|
private final JsName name;
|
||||||
|
|
||||||
public JsCatchScope(JsScope parent, @NotNull String ident) {
|
public JsCatchScope(JsScope parent, @NotNull String ident) {
|
||||||
super(parent, "Catch scope");
|
super(parent, "Catch scope", true);
|
||||||
name = new JsName(this, ident, false);
|
name = new JsName(this, ident, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.backend.ast
|
package org.jetbrains.kotlin.js.backend.ast
|
||||||
|
|
||||||
import java.util.Stack
|
import java.util.*
|
||||||
|
|
||||||
class JsObjectScope(parent: JsScope, description: String) : JsScope(parent, description)
|
class JsObjectScope(parent: JsScope, description: String) : JsScope(parent, description)
|
||||||
|
|
||||||
@@ -24,15 +24,18 @@ object JsDynamicScope : JsScope(null, "Scope for dynamic declarations") {
|
|||||||
override fun doCreateName(name: String) = JsName(this, name, false)
|
override fun doCreateName(name: String) = JsName(this, name, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class JsFunctionScope(parent: JsScope, description: String) : JsScope(parent, description) {
|
open class JsFunctionScope(parent: JsScope, description: String) : JsDeclarationScope(parent, description) {
|
||||||
|
|
||||||
private val labelScopes = Stack<LabelScope>()
|
|
||||||
private val topLabelScope: LabelScope?
|
|
||||||
get() = if (labelScopes.isNotEmpty()) labelScopes.peek() else null
|
|
||||||
|
|
||||||
override fun hasOwnName(name: String): Boolean = RESERVED_WORDS.contains(name) || super.hasOwnName(name)
|
override fun hasOwnName(name: String): Boolean = RESERVED_WORDS.contains(name) || super.hasOwnName(name)
|
||||||
|
|
||||||
open fun declareNameUnsafe(identifier: String): JsName = super.declareName(identifier)
|
open fun declareNameUnsafe(identifier: String): JsName = super.declareName(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class JsDeclarationScope(parent: JsScope, description: String, useParentScopeStack: Boolean = false) : JsScope(parent, description) {
|
||||||
|
private val labelScopes: Stack<LabelScope> =
|
||||||
|
if (parent is JsDeclarationScope && useParentScopeStack) parent.labelScopes else Stack<LabelScope>()
|
||||||
|
|
||||||
|
private val topLabelScope
|
||||||
|
get() = if (labelScopes.isNotEmpty()) labelScopes.peek() else null
|
||||||
|
|
||||||
open fun enterLabel(label: String): JsName {
|
open fun enterLabel(label: String): JsName {
|
||||||
val scope = LabelScope(topLabelScope, label)
|
val scope = LabelScope(topLabelScope, label)
|
||||||
@@ -58,7 +61,7 @@ open class JsFunctionScope(parent: JsScope, description: String) : JsScope(paren
|
|||||||
else -> ident
|
else -> ident
|
||||||
}
|
}
|
||||||
|
|
||||||
labelName = JsName(this@JsFunctionScope, freshIdent, false)
|
labelName = JsName(this@JsDeclarationScope, freshIdent, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findOwnName(name: String): JsName? =
|
override fun findOwnName(name: String): JsName? =
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
package com.google.gwt.dev.js
|
package com.google.gwt.dev.js
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import java.util.*
|
||||||
import java.util.Stack
|
|
||||||
|
|
||||||
class ScopeContext(scope: JsScope) {
|
class ScopeContext(scope: JsScope) {
|
||||||
private val rootScope = generateSequence(scope) { it.parent }.first { it is JsRootScope }
|
private val rootScope = generateSequence(scope) { it.parent }.first { it is JsRootScope }
|
||||||
@@ -35,7 +34,7 @@ class ScopeContext(scope: JsScope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun exitFunction() {
|
fun exitFunction() {
|
||||||
assert(currentScope is JsFunctionScope)
|
assert(currentScope is JsDeclarationScope)
|
||||||
exitScope()
|
exitScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,13 +50,13 @@ class ScopeContext(scope: JsScope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun enterLabel(ident: String): JsName =
|
fun enterLabel(ident: String): JsName =
|
||||||
(currentScope as JsFunctionScope).enterLabel(ident)
|
(currentScope as JsDeclarationScope).enterLabel(ident)
|
||||||
|
|
||||||
fun exitLabel() =
|
fun exitLabel() =
|
||||||
(currentScope as JsFunctionScope).exitLabel()
|
(currentScope as JsDeclarationScope).exitLabel()
|
||||||
|
|
||||||
fun labelFor(ident: String): JsName? =
|
fun labelFor(ident: String): JsName? =
|
||||||
(currentScope as JsFunctionScope).findLabel(ident)
|
(currentScope as JsDeclarationScope).findLabel(ident)
|
||||||
|
|
||||||
fun globalNameFor(ident: String): JsName =
|
fun globalNameFor(ident: String): JsName =
|
||||||
currentScope.findName(ident) ?: rootScope.declareName(ident)
|
currentScope.findName(ident) ?: rootScope.declareName(ident)
|
||||||
|
|||||||
+12
@@ -155,12 +155,24 @@ public class NonLocalReturnsTestGenerated extends AbstractNonLocalReturnsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnFromCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnFromCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
@TestMetadata("nonLocalReturnFromOuterLambda.kt")
|
||||||
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
public void testNonLocalReturnFromOuterLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnFromOuterLambda.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonLocalReturnToCatchBlock.kt")
|
||||||
|
public void testNonLocalReturnToCatchBlock() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/nonLocalReturnToCatchBlock.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user