IR KT-47840 fix-point solution for closure conversion

This commit is contained in:
Dmitry Petrov
2021-07-22 20:01:32 +03:00
committed by teamcityserver
parent e9f2d574d5
commit 34f5b85ae5
10 changed files with 111 additions and 13 deletions
@@ -5606,6 +5606,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/closures/kt47120a.kt");
}
@Test
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@Test
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.util.isLocal
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
data class Closure(val capturedValues: List<IrValueSymbol>, val capturedTypeParameters: List<IrTypeParameter>)
@@ -43,7 +44,6 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
fun getClassClosure(declaration: IrClass) = getClosure(declaration)
private fun getClosure(declaration: IrDeclaration): Closure {
closureBuilders.values.forEach { it.processed = false }
return closureBuilders
.getOrElse(declaration) { throw AssertionError("No closure builder for passed declaration ${ir2string(declaration)}.") }
.buildClosure()
@@ -57,24 +57,63 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
private val potentiallyCapturedTypeParameters = mutableSetOf<IrTypeParameter>()
private val capturedTypeParameters = mutableSetOf<IrTypeParameter>()
var processed = false
private var closure: Closure? = null
/*
* Node's closure = variables captured by the node +
* closure of all included nodes -
* variables declared in the node.
* This will solve a system of equations for each dependent closure:
*
* closure[V] = captured(V) + { closure[U] | U <- included(V) } - declared(V)
*
*/
fun buildClosure(): Closure {
includes.forEach { builder ->
if (!builder.processed) {
builder.processed = true
val subClosure = builder.buildClosure()
subClosure.capturedValues.filterTo(capturedValues) { isExternal(it.owner) }
subClosure.capturedTypeParameters.filterTo(capturedTypeParameters) { isExternal(it) }
closure?.let { return it }
val work = collectConnectedClosures()
do {
var changes = false
for (c in work) {
if (c.updateFromIncluded()) {
changes = true
}
}
} while (changes)
for (c in work) {
c.closure = Closure(c.capturedValues.toList(), c.capturedTypeParameters.toList())
}
return closure
?: throw AssertionError("Closure should have been built for ${owner.render()}")
}
private fun collectConnectedClosures(): List<ClosureBuilder> {
val connected = LinkedHashSet<ClosureBuilder>()
fun collectRec(current: ClosureBuilder) {
for (included in current.includes) {
if (included.closure == null && connected.add(included)) {
collectRec(included)
}
}
}
// TODO: We can save the closure and reuse it.
return Closure(capturedValues.toList(), capturedTypeParameters.toList())
connected.add(this)
collectRec(this)
return connected.toList().asReversed()
}
private fun updateFromIncluded(): Boolean {
if (closure != null)
throw AssertionError("Closure has already been built for ${owner.render()}")
val capturedValuesBefore = capturedValues.size
val capturedTypeParametersBefore = capturedTypeParameters.size
for (subClosure in includes) {
subClosure.capturedValues.filterTo(capturedValues) { isExternal(it.owner) }
subClosure.capturedTypeParameters.filterTo(capturedTypeParameters) { isExternal(it) }
}
return capturedValues.size != capturedValuesBefore ||
capturedTypeParameters.size != capturedTypeParametersBefore
}
+16
View File
@@ -0,0 +1,16 @@
fun box(): String {
var t = ""
fun foo(x: String) {
fun bar() {
fun a() {
foo("")
bar()
}
t = x
}
bar()
}
foo("OK")
return t
}
@@ -5546,6 +5546,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/closures/kt47120a.kt");
}
@Test
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@Test
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
@@ -5606,6 +5606,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/closures/kt47120a.kt");
}
@Test
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@Test
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
@@ -4836,6 +4836,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/closures/kt47120a.kt");
}
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt5589.kt");
@@ -3776,6 +3776,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/closures/kt4137.kt");
}
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt5589.kt");
@@ -3776,6 +3776,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/closures/kt4137.kt");
}
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt5589.kt");
@@ -3776,6 +3776,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/closures/kt4137.kt");
}
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt5589.kt");
@@ -2657,6 +2657,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/closures/kt4137.kt");
}
@TestMetadata("kt47840.kt")
public void testKt47840() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt47840.kt");
}
@TestMetadata("kt5589.kt")
public void testKt5589() throws Exception {
runTest("compiler/testData/codegen/box/closures/kt5589.kt");