From 36ae8790a14fb6a00e6cba74f2abfe88694dfa34 Mon Sep 17 00:00:00 2001 From: dnpetrov Date: Wed, 17 Jun 2015 14:08:45 +0300 Subject: [PATCH] KT-8011 Compiler crashes on attempt to create local class inside lambda - use StackValue from upper-level context if local lookup fails #KT-8011 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 5 ++ .../kotlin/codegen/context/LocalLookup.java | 15 ++++-- .../testData/codegen/box/classes/kt8011a.kt | 52 +++++++++++++++++++ .../codegen/boxWithStdlib/classes/kt8011.kt | 17 ++++++ .../BlackBoxCodegenTestGenerated.java | 6 +++ ...lackBoxWithStdlibCodegenTestGenerated.java | 6 +++ 6 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/classes/kt8011a.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index fa3e304681b..7d92295fc77 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2022,6 +2022,11 @@ public class ExpressionCodegen extends JetVisitor implem return stackValueForLocal(descriptor, index); } + return findCapturedValue(descriptor); + } + + @Nullable + public StackValue findCapturedValue(@NotNull DeclarationDescriptor descriptor) { if (context instanceof ConstructorContext) { return lookupCapturedValueInConstructorParameters(descriptor); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java index eba8b060b5e..7ece0709a11 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java @@ -159,10 +159,17 @@ public interface LocalLookup { @NotNull public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) { - int idx = codegen.lookupLocalIndex(d.getDescriptor()); - assert idx != -1; - - return StackValue.local(idx, d.getType()); + DeclarationDescriptor declarationDescriptor = d.getDescriptor(); + int idx = codegen.lookupLocalIndex(declarationDescriptor); + if (idx >= 0) { + return StackValue.local(idx, d.getType()); + } + else { + assert declarationDescriptor != null : "No declaration descriptor for " + d; + StackValue capturedValue = codegen.findCapturedValue(declarationDescriptor); + assert capturedValue != null : "Unresolved captured value for " + d; + return capturedValue; + } } } } diff --git a/compiler/testData/codegen/box/classes/kt8011a.kt b/compiler/testData/codegen/box/classes/kt8011a.kt new file mode 100644 index 00000000000..9a8fa24c6d9 --- /dev/null +++ b/compiler/testData/codegen/box/classes/kt8011a.kt @@ -0,0 +1,52 @@ +fun testFun1(str: String): String { + val capture = str + + class A { + val x = capture + } + + return A().x +} + + +fun testFun2(str: String): String { + class A { + val x = str + } + fun bar() = A() + return bar().x +} + + +class TestClass(val str: String) { + var xx: String? = null + + init { + class A { + val x = str + } + + xx = A().x + } +} + +fun testFun3(str: String): String = TestClass(str).xx!! + + +fun String.testFun4(): String { + class A { + val x = this@testFun4 + } + return A().x +} + + +fun box(): String { + return when { + testFun1("test1") != "test1" -> "Fail #1 (local class with capture)" + testFun2("test2") != "test2" -> "Fail #2 (local class with capture ctor in another context)" + testFun3("test3") != "test3" -> "Fail #3 (local class with capture ctor in init{ ... })" + "test4".testFun4() != "test4" -> "Fail #4 (local class with extension receiver)" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt b/compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt new file mode 100644 index 00000000000..b98989525ea --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt @@ -0,0 +1,17 @@ +fun testFun1(str: String): String { + val local = str + + class Local { + fun foo() = str + } + + val list = listOf(0).map { Local() } + return list[0].foo() +} + +fun box(): String { + return when { + testFun1("test1") != "test1" -> "Fail #1" + else -> "OK" + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 72b0d92d41a..b4fad7abca5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1414,6 +1414,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt8011a.kt") + public void testKt8011a() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/kt8011a.kt"); + doTest(fileName); + } + @TestMetadata("kt903.kt") public void testKt903() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/kt903.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 7fb19d4a06d..f8b759ec6ca 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -909,6 +909,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/classes/kt633.kt"); doTestWithStdlib(fileName); } + + @TestMetadata("kt8011.kt") + public void testKt8011() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/classes/kt8011.kt"); + doTestWithStdlib(fileName); + } } @TestMetadata("compiler/testData/codegen/boxWithStdlib/dataClasses")