IR: remap types in LocalDeclarationsLowering

This commit is contained in:
Georgy Bronnikov
2020-09-04 12:34:28 +03:00
parent 1f3d344835
commit 33a2c69122
9 changed files with 107 additions and 6 deletions
@@ -12476,6 +12476,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
@@ -29,10 +30,7 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrTypeAbbreviationImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -127,6 +125,8 @@ class LocalDeclarationsLowering(
private abstract class LocalContext {
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
// By the time typeRemapper is used, the map will be already filled
val typeRemapper = IrTypeParameterRemapper(capturedTypeParameterToTypeParameter)
/**
* @return the expression to get the value for given declaration, or `null` if [IrGetValue] should be used.
@@ -252,10 +252,14 @@ class LocalDeclarationsLowering(
localFunctions.values.forEach {
it.transformedDeclaration.apply {
val original = it.declaration
val typeRemapper = TypeParameterAdjustmentTypeRemapper(it.capturedTypeParameterToTypeParameter)
this.body = original.body
this.body?.remapTypes(typeRemapper)
original.valueParameters.filter { v -> v.defaultValue != null }.forEach { argument ->
val body = argument.defaultValue!!
body.remapTypes(typeRemapper)
oldParameterToNew[argument]!!.defaultValue = body
}
acceptChildren(SetDeclarationsParentVisitor, this)
@@ -511,7 +515,7 @@ class LocalDeclarationsLowering(
private fun createNewCall(oldCall: IrCall, newCallee: IrSimpleFunction) =
IrCallImpl(
oldCall.startOffset, oldCall.endOffset,
newCallee.returnType,
oldCall.type,
newCallee.symbol,
typeArgumentsCount = newCallee.typeParameters.size,
valueArgumentsCount = newCallee.valueParameters.size,
@@ -525,7 +529,7 @@ class LocalDeclarationsLowering(
private fun createNewCall(oldCall: IrConstructorCall, newCallee: IrConstructor) =
IrConstructorCallImpl.fromSymbolOwner(
oldCall.startOffset, oldCall.endOffset,
newCallee.returnType,
oldCall.type,
newCallee.symbol,
newCallee.parentAsClass.typeParameters.size,
oldCall.origin
@@ -608,6 +612,9 @@ class LocalDeclarationsLowering(
capturedTypeParameters.zip(newTypeParameters)
)
newDeclaration.copyTypeParametersFrom(oldDeclaration, parameterMap = localFunctionContext.capturedTypeParameterToTypeParameter)
localFunctionContext.capturedTypeParameterToTypeParameter.putAll(
oldDeclaration.typeParameters.zip(newDeclaration.typeParameters.drop(newTypeParameters.size))
)
// Type parameters of oldDeclaration may depend on captured type parameters, so deal with that after copying.
newDeclaration.typeParameters.drop(newTypeParameters.size).forEach { tp ->
tp.superTypes = tp.superTypes.map { localFunctionContext.remapType(it) }
@@ -923,5 +930,45 @@ class LocalDeclarationsLowering(
}
}
class TypeParameterAdjustmentTypeRemapper(val typeParameterMap: Map<IrTypeParameter, IrTypeParameter>) : TypeRemapper {
override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) {}
override fun leaveScope() {}
override fun remapType(type: IrType): IrType =
if (type !is IrSimpleType)
type
else
IrSimpleTypeImpl(
null,
type.classifier.remap(),
type.hasQuestionMark,
type.arguments.map { it.remap() },
type.annotations,
type.abbreviation?.remap()
).apply {
annotations.forEach { it.remapTypes(this@TypeParameterAdjustmentTypeRemapper) }
}
private fun IrClassifierSymbol.remap() =
(owner as? IrTypeParameter)?.let { typeParameterMap[it]?.symbol }
?: this
private fun IrTypeArgument.remap() =
if (this is IrTypeProjection)
makeTypeProjection(remapType(type), variance)
else
this
private fun IrTypeAbbreviation.remap() =
IrTypeAbbreviationImpl(
typeAlias,
hasQuestionMark,
arguments.map { it.remap() },
annotations
).apply {
annotations.forEach { it.remapTypes(this@TypeParameterAdjustmentTypeRemapper) }
}
}
// Local inner classes capture anything through outer
internal fun IrClass.isLocalNotInner(): Boolean = visibility == DescriptorVisibilities.LOCAL && !isInner
@@ -0,0 +1,19 @@
fun box(): String {
var a = 0
fun <T> local(xx: T): T {
class A {
val b = 0
fun id(x: T): T {
a = b
return x
}
}
fun local2() : T {
return A().id(xx)
}
return local2()
}
return local("OK")
}
@@ -13871,6 +13871,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -13871,6 +13871,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -12476,6 +12476,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -10731,6 +10731,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -10731,6 +10731,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
@@ -10731,6 +10731,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/functions/localFunctions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("callBetweenLocalFunctions.kt")
public void testCallBetweenLocalFunctions() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");
}
@TestMetadata("callInlineLocalInLambda.kt")
public void testCallInlineLocalInLambda() throws Exception {
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");