From 75015f6bfaddb078501dcde61018364f28ce5684 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 28 Apr 2016 15:12:01 +0300 Subject: [PATCH] JS/RTTI: fix compiler crashing when translating expressions like `(continue as T)` --- .../test/semantics/EvaluationOrderTest.java | 4 + .../expression/PatternTranslator.java | 5 + .../cases/castWithBreakContinueReturn.kt | 120 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 js/js.translator/testData/expression/evaluationOrder/cases/castWithBreakContinueReturn.kt diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java index 8fe15651b06..f41811107c0 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EvaluationOrderTest.java @@ -132,4 +132,8 @@ public class EvaluationOrderTest extends AbstractExpressionTest { public void testLoopWithBreakContinueReturnInCondition() throws Exception { checkFooBoxIsOk(); } + + public void testCastWithBreakContinueReturn() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java index 1767a0b5b85..c8b553affef 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.js.translate.utils.BindingUtils; +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS; @@ -73,6 +74,8 @@ public final class PatternTranslator extends AbstractTranslator { assert isCastExpression(expression): "Expected cast expression, got " + expression; KtExpression left = expression.getLeft(); JsExpression expressionToCast = Translation.translateAsExpression(left, context()); + if (JsAstUtils.isEmptyExpression(expressionToCast)) return expressionToCast; + TemporaryVariable temporary = context().declareTemporary(expressionToCast); KtTypeReference typeReference = expression.getRight(); @@ -105,6 +108,8 @@ public final class PatternTranslator extends AbstractTranslator { @NotNull public JsExpression translateIsCheck(@NotNull JsExpression subject, @NotNull KtTypeReference typeReference) { + if (JsAstUtils.isEmptyExpression(subject)) return subject; + KotlinType type = BindingUtils.getTypeByReference(bindingContext(), typeReference); JsExpression checkFunReference = doGetIsTypeCheckCallable(type); boolean isReifiedType = isReifiedTypeParameter(type); diff --git a/js/js.translator/testData/expression/evaluationOrder/cases/castWithBreakContinueReturn.kt b/js/js.translator/testData/expression/evaluationOrder/cases/castWithBreakContinueReturn.kt new file mode 100644 index 00000000000..9f756af7ad9 --- /dev/null +++ b/js/js.translator/testData/expression/evaluationOrder/cases/castWithBreakContinueReturn.kt @@ -0,0 +1,120 @@ +package foo + +fun castWithReturn(): Int { + return (return 23) as Int +} + +fun safeCastWithReturn(): Int? { + return (return 23) as Int? +} + +fun isWithReturn(): Int { + return if ((return 23) is Int) 2 else 3 +} + +fun castWithBreak(): Int { + var result = 23 + while (result < 40) { + if ((break as Int) == 0) result += 2 else result += 3 + } + return result +} + +fun safeCastWithBreak(): Int { + var result = 23 + while (result < 40) { + if ((break as Int) == 0) result += 2 else result += 3 + } + return result +} + +fun isWithBreak(): Int { + var result = 23 + while (result < 40) { + if (break is Int) result += 2 else result += 3 + } + return result +} + +fun castWithContinue(): Int { + var result = 25 + while (result in 24..30) { + --result + if ((continue as Int) == 0) result += 2 else result += 3 + } + return result +} + +fun castNullableWithContinue(): Int { + var result = 25 + while (result in 24..30) { + --result + if ((continue as Int?) == 0) result += 2 else result += 3 + } + return result +} + +fun safeCastWithContinue(): Int { + var result = 25 + while (result in 24..30) { + --result + if ((continue as? Int) == 0) result += 2 else result += 3 + } + return result +} + +fun safeCastNullableWithContinue(): Int { + var result = 25 + while (result in 24..30) { + --result + if ((continue as? Int?) == 0) result += 2 else result += 3 + } + return result +} + +fun isWithContinue(): Int { + var result = 25 + while (result in 24..30) { + --result + if (continue is Int) result += 2 else result += 3 + } + return result +} + +fun isNullableWithContinue(): Int { + var result = 23 + while (result in 24..30) { + --result + if (continue is Int?) result += 2 else result += 3 + } + return result +} + +fun whenWithReturn(): Int { + return when ((return 23) as Int) { + is Int -> 24 + else -> 25 + } +} + +fun box(): String { + assertEquals(23, castWithReturn()) + assertEquals(23, safeCastWithReturn()) + assertEquals(23, isWithReturn()) + + assertEquals(23, castWithBreak()) + assertEquals(23, safeCastWithBreak()) + assertEquals(23, isWithBreak()) + + assertEquals(23, castWithContinue()) + assertEquals(23, safeCastWithContinue()) + assertEquals(23, isWithContinue()) + + assertEquals(23, castNullableWithContinue()) + assertEquals(23, safeCastNullableWithContinue()) + assertEquals(23, isNullableWithContinue()) + + assertEquals(23, whenWithReturn()) + + return "OK" +} \ No newline at end of file