IR: remap types in LocalDeclarationsLowering
This commit is contained in:
Generated
+5
@@ -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");
|
||||
|
||||
+53
-6
@@ -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
|
||||
|
||||
+19
@@ -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")
|
||||
}
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user