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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
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.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
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.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrTypeAbbreviationImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrTypeAbbreviationImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
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.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
@@ -127,6 +125,8 @@ class LocalDeclarationsLowering(
|
|||||||
|
|
||||||
private abstract class LocalContext {
|
private abstract class LocalContext {
|
||||||
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
|
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.
|
* @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 {
|
localFunctions.values.forEach {
|
||||||
it.transformedDeclaration.apply {
|
it.transformedDeclaration.apply {
|
||||||
val original = it.declaration
|
val original = it.declaration
|
||||||
|
val typeRemapper = TypeParameterAdjustmentTypeRemapper(it.capturedTypeParameterToTypeParameter)
|
||||||
|
|
||||||
this.body = original.body
|
this.body = original.body
|
||||||
|
this.body?.remapTypes(typeRemapper)
|
||||||
|
|
||||||
original.valueParameters.filter { v -> v.defaultValue != null }.forEach { argument ->
|
original.valueParameters.filter { v -> v.defaultValue != null }.forEach { argument ->
|
||||||
val body = argument.defaultValue!!
|
val body = argument.defaultValue!!
|
||||||
|
body.remapTypes(typeRemapper)
|
||||||
oldParameterToNew[argument]!!.defaultValue = body
|
oldParameterToNew[argument]!!.defaultValue = body
|
||||||
}
|
}
|
||||||
acceptChildren(SetDeclarationsParentVisitor, this)
|
acceptChildren(SetDeclarationsParentVisitor, this)
|
||||||
@@ -511,7 +515,7 @@ class LocalDeclarationsLowering(
|
|||||||
private fun createNewCall(oldCall: IrCall, newCallee: IrSimpleFunction) =
|
private fun createNewCall(oldCall: IrCall, newCallee: IrSimpleFunction) =
|
||||||
IrCallImpl(
|
IrCallImpl(
|
||||||
oldCall.startOffset, oldCall.endOffset,
|
oldCall.startOffset, oldCall.endOffset,
|
||||||
newCallee.returnType,
|
oldCall.type,
|
||||||
newCallee.symbol,
|
newCallee.symbol,
|
||||||
typeArgumentsCount = newCallee.typeParameters.size,
|
typeArgumentsCount = newCallee.typeParameters.size,
|
||||||
valueArgumentsCount = newCallee.valueParameters.size,
|
valueArgumentsCount = newCallee.valueParameters.size,
|
||||||
@@ -525,7 +529,7 @@ class LocalDeclarationsLowering(
|
|||||||
private fun createNewCall(oldCall: IrConstructorCall, newCallee: IrConstructor) =
|
private fun createNewCall(oldCall: IrConstructorCall, newCallee: IrConstructor) =
|
||||||
IrConstructorCallImpl.fromSymbolOwner(
|
IrConstructorCallImpl.fromSymbolOwner(
|
||||||
oldCall.startOffset, oldCall.endOffset,
|
oldCall.startOffset, oldCall.endOffset,
|
||||||
newCallee.returnType,
|
oldCall.type,
|
||||||
newCallee.symbol,
|
newCallee.symbol,
|
||||||
newCallee.parentAsClass.typeParameters.size,
|
newCallee.parentAsClass.typeParameters.size,
|
||||||
oldCall.origin
|
oldCall.origin
|
||||||
@@ -608,6 +612,9 @@ class LocalDeclarationsLowering(
|
|||||||
capturedTypeParameters.zip(newTypeParameters)
|
capturedTypeParameters.zip(newTypeParameters)
|
||||||
)
|
)
|
||||||
newDeclaration.copyTypeParametersFrom(oldDeclaration, parameterMap = localFunctionContext.capturedTypeParameterToTypeParameter)
|
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.
|
// Type parameters of oldDeclaration may depend on captured type parameters, so deal with that after copying.
|
||||||
newDeclaration.typeParameters.drop(newTypeParameters.size).forEach { tp ->
|
newDeclaration.typeParameters.drop(newTypeParameters.size).forEach { tp ->
|
||||||
tp.superTypes = tp.superTypes.map { localFunctionContext.remapType(it) }
|
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
|
// Local inner classes capture anything through outer
|
||||||
internal fun IrClass.isLocalNotInner(): Boolean = visibility == DescriptorVisibilities.LOCAL && !isInner
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
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);
|
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")
|
@TestMetadata("callInlineLocalInLambda.kt")
|
||||||
public void testCallInlineLocalInLambda() throws Exception {
|
public void testCallInlineLocalInLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
runTest("compiler/testData/codegen/box/functions/localFunctions/callInlineLocalInLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user