diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 4368c1b7702..5da73bc9d5a 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -40135,6 +40135,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testClassReference() throws Exception { runTest("compiler/testData/codegen/box/script/classReference.kt"); } + + @Test + @TestMetadata("localCaptureTests.kt") + public void testLocalCaptureTests() throws Exception { + runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); + } } @Nested diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt index 2c518fab5af..1789f3b6927 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt @@ -17,12 +17,9 @@ package org.jetbrains.kotlin.backend.common import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrStatementContainer -import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformSubsetFlat import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -64,6 +61,12 @@ interface BodyLoweringPass : FileLoweringPass { override fun lower(irFile: IrFile) = runOnFilePostfix(irFile) } +interface BodyAndScriptBodyLoweringPass : BodyLoweringPass { + fun lowerScriptBody(irDeclarationContainer: IrDeclarationContainer, container: IrDeclaration) + + override fun lower(irFile: IrFile) = runOnFilePostfix(irFile) +} + fun FileLoweringPass.lower(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { lower(it) } fun ClassLoweringPass.runOnFilePostfix(irFile: IrFile) { @@ -129,7 +132,17 @@ fun BodyLoweringPass.runOnFilePostfix( } } -private class BodyLoweringVisitor( +fun BodyAndScriptBodyLoweringPass.runOnFilePostfix( + irFile: IrFile, + allowDeclarationModification: Boolean = false +) { + val visitor = ScriptBodyLoweringVisitor(this, allowDeclarationModification) + for (declaration in ArrayList(irFile.declarations)) { + declaration.accept(visitor, null) + } +} + +private open class BodyLoweringVisitor( private val loweringPass: BodyLoweringPass, private val withLocalDeclarations: Boolean, private val allowDeclarationModification: Boolean, @@ -168,6 +181,30 @@ private class BodyLoweringVisitor( } } +private class ScriptBodyLoweringVisitor( + private val loweringPass: BodyAndScriptBodyLoweringPass, + private val allowDeclarationModification: Boolean +) : BodyLoweringVisitor(loweringPass, false, allowDeclarationModification) { + + override fun visitClass(declaration: IrClass, data: IrDeclaration?) { + declaration.thisReceiver?.accept(this, declaration) + declaration.typeParameters.forEach { it.accept(this, declaration) } + ArrayList(declaration.declarations).forEach { it.accept(this, declaration) } + if (declaration.origin == IrDeclarationOrigin.SCRIPT_CLASS) { + val stageController = declaration.factory.stageController + stageController.restrictTo(declaration) { + if (allowDeclarationModification) { + loweringPass.lowerScriptBody(declaration, declaration) + } else { + stageController.bodyLowering { + loweringPass.lowerScriptBody(declaration, declaration) + } + } + } + } + } +} + interface DeclarationTransformer : FileLoweringPass { fun transformFlat(declaration: IrDeclaration): List? diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 1b90d5696c5..16dc1452fbe 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -5,11 +5,12 @@ package org.jetbrains.kotlin.backend.common.lower -import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.BodyAndScriptBodyLoweringPass import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.runOnFilePostfix +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibility @@ -79,7 +80,7 @@ class LocalDeclarationsLowering( val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT, val suggestUniqueNames: Boolean = true, // When `true` appends a `-#index` suffix to lifted declaration names ) : - BodyLoweringPass { + BodyAndScriptBodyLoweringPass { override fun lower(irFile: IrFile) { runOnFilePostfix(irFile, allowDeclarationModification = true) @@ -92,11 +93,16 @@ class LocalDeclarationsLowering( IrDeclarationOriginImpl("FIELD_FOR_CROSSINLINE_CAPTURED_VALUE", isSynthetic = true) override fun lower(irBody: IrBody, container: IrDeclaration) { - LocalDeclarationsTransformer(irBody, container, null).lowerLocalDeclarations() + LocalDeclarationsTransformer(irBody, container, null, false).lowerLocalDeclarations() } + override fun lowerScriptBody(irDeclarationContainer: IrDeclarationContainer, container: IrDeclaration) { + LocalDeclarationsTransformer(irDeclarationContainer, container, null, true).lowerLocalDeclarations() + } + + fun lower(irElement: IrElement, container: IrDeclaration, classesToLower: Set) { - LocalDeclarationsTransformer(irElement, container, classesToLower).lowerLocalDeclarations() + LocalDeclarationsTransformer(irElement, container, classesToLower, false).lowerLocalDeclarations() } internal class ScopeWithCounter(val irElement: IrElement) { @@ -199,7 +205,7 @@ class LocalDeclarationsLowering( } private inner class LocalDeclarationsTransformer( - val irElement: IrElement, val container: IrDeclaration, val classesToLower: Set? + val irElement: IrElement, val container: IrDeclaration, val classesToLower: Set?, val isScriptMode: Boolean ) { val localFunctions: MutableMap = LinkedHashMap() val localClasses: MutableMap = LinkedHashMap() @@ -461,6 +467,8 @@ class LocalDeclarationsLowering( irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext)) + if (isScriptMode && constructors.isEmpty()) return + val constructorsCallingSuper = constructors .asSequence() .map { localClassConstructors[it]!! } @@ -928,7 +936,9 @@ class LocalDeclarationsLowering( override fun visitConstructor(declaration: IrConstructor, data: Data) { super.visitConstructor(declaration, data) - if (!declaration.constructedClass.isLocalNotInner()) return + if (!isScriptMode && !declaration.constructedClass.isLocalNotInner()) return + // LDL doesn't work on the enums because local enums are not allowed, so skipping them in scripts too + if (isScriptMode && declaration.constructedClass.kind == ClassKind.ENUM_CLASS) return localClassConstructors[declaration] = LocalClassConstructorContext(declaration, data.inInlineFunctionScope) } @@ -937,7 +947,9 @@ class LocalDeclarationsLowering( if (classesToLower?.contains(declaration) == false) return super.visitClass(declaration, data.withCurrentClass(declaration)) - if (!declaration.isLocalNotInner()) return + if (!isScriptMode && !declaration.isLocalNotInner()) return + // LDL doesn't work on the enums because local enums are not allowed, so skipping them in scripts too + if (isScriptMode && declaration.kind == ClassKind.ENUM_CLASS) return localClasses[declaration] = LocalClassContext(declaration, data.inInlineFunctionScope) } diff --git a/compiler/testData/codegen/box/script/localCaptureTests.kt b/compiler/testData/codegen/box/script/localCaptureTests.kt new file mode 100644 index 00000000000..08f8caf1934 --- /dev/null +++ b/compiler/testData/codegen/box/script/localCaptureTests.kt @@ -0,0 +1,31 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_LIGHT_ANALYSIS +// WITH_RUNTIME +// FILE: test.kt + +fun box(): String = + Script.Build.Debug.run { "${c0()}${c1()}" } + +// FILE: script.kts + +interface Base { + val v: String + + fun c0(): Char { + fun getC0() = v[0] + return getC0() + } +} + +enum class Build(override val v: String): Base { + Debug("OK"), + Release("NO"); + + fun c1(): Char { + val g = object { + val c1 = v[1] + } + return g.c1 + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/script/kt48025.kts b/compiler/testData/codegen/script/kt48025.kts new file mode 100644 index 00000000000..044f54a0e82 --- /dev/null +++ b/compiler/testData/codegen/script/kt48025.kts @@ -0,0 +1,14 @@ + +val p = 0 + +class ReducedFraction() { + fun plus1() = reducedFractionOf(p) + val y = 1 +} + +fun reducedFractionOf(a: Int) { +} + +val c = ReducedFraction() +val x = c.y +// expected: x: 1 diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 9cfae406a24..be5ceb5f7a2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -39961,6 +39961,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testClassReference() throws Exception { runTest("compiler/testData/codegen/box/script/classReference.kt"); } + + @Test + @TestMetadata("localCaptureTests.kt") + public void testLocalCaptureTests() throws Exception { + runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index f84b547ea3a..a8cc0147f59 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -40135,6 +40135,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testClassReference() throws Exception { runTest("compiler/testData/codegen/box/script/classReference.kt"); } + + @Test + @TestMetadata("localCaptureTests.kt") + public void testLocalCaptureTests() throws Exception { + runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); + } } @Nested diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 5985432e290..28aad6aeb42 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -32025,6 +32025,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testClassReference() throws Exception { runTest("compiler/testData/codegen/box/script/classReference.kt"); } + + @TestMetadata("localCaptureTests.kt") + public void testLocalCaptureTests() throws Exception { + runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); + } } @TestMetadata("compiler/testData/codegen/box/sealed") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java index de4697e1704..946e6f41e4e 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java @@ -74,6 +74,11 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest { runTest("compiler/testData/codegen/script/kt22029.kts"); } + @TestMetadata("kt48025.kts") + public void testKt48025() throws Exception { + runTest("compiler/testData/codegen/script/kt48025.kts"); + } + @TestMetadata("localDelegatedProperty.kts") public void testLocalDelegatedProperty() throws Exception { runTest("compiler/testData/codegen/script/localDelegatedProperty.kts"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java index 9b01908d5b4..c2b72d7b38a 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java @@ -75,6 +75,11 @@ public class IrScriptCodegenTestGenerated extends AbstractIrScriptCodegenTest { runTest("compiler/testData/codegen/script/kt22029.kts"); } + @TestMetadata("kt48025.kts") + public void testKt48025() throws Exception { + runTest("compiler/testData/codegen/script/kt48025.kts"); + } + @TestMetadata("localDelegatedProperty.kts") public void testLocalDelegatedProperty() throws Exception { runTest("compiler/testData/codegen/script/localDelegatedProperty.kts");