diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index bd644180533..01551fc971b 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 94c678db14a..b9ef597b7c9 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -224,7 +224,7 @@ private fun IrTypeParameter.copySuperTypesFrom(source: IrTypeParameter, srcToDst val target = this val sourceParent = source.parent as IrTypeParametersContainer val targetParent = target.parent as IrTypeParametersContainer - target.superTypes += source.superTypes.map { + target.superTypes = source.superTypes.map { it.remapTypeParameters(sourceParent, targetParent, srcToDstParameterMap) } } @@ -596,6 +596,12 @@ private fun IrSimpleFunction.copyAndRenameConflictingTypeParametersFrom( }) } + val zipped = contextParameters.zip(newParameters) + val parameterMap = zipped.toMap() + for ((oldParameter, newParameter) in zipped) { + newParameter.copySuperTypesFrom(oldParameter, parameterMap) + } + typeParameters = typeParameters + newParameters return newParameters diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt index 7924df0f263..970636aebff 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ClosureAnnotator.kt @@ -223,6 +223,12 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) { includeInParent(closureBuilder) } + override fun visitTypeParameter(declaration: IrTypeParameter, data: ClosureBuilder?) { + for (superType in declaration.superTypes) { + data?.seeType(superType) + } + } + override fun visitValueAccess(expression: IrValueAccessExpression, data: ClosureBuilder?) { data?.seeVariable(expression.symbol) super.visitValueAccess(expression, data) 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 c7ea08a09de..cae36db6bee 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 @@ -22,14 +22,9 @@ 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 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.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -195,28 +190,7 @@ class LocalDeclarationsLowering( } - private fun LocalContext.remapType(type: IrType): IrType { - if (type !is IrSimpleType) return type - val classifier = (type.classifier as? IrTypeParameterSymbol)?.let { capturedTypeParameterToTypeParameter[it.owner]?.symbol } - ?: type.classifier - val arguments = type.arguments.map { remapTypeArgument(it) } - return IrSimpleTypeImpl( - classifier, type.hasQuestionMark, arguments, type.annotations, - type.abbreviation?.let { remapTypeAbbreviation(it) } - ) - } - - private fun LocalContext.remapTypeArgument(argument: IrTypeArgument) = - (argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) } - ?: argument - - private fun LocalContext.remapTypeAbbreviation(abbreviation: IrTypeAbbreviation): IrTypeAbbreviation = - IrTypeAbbreviationImpl( - abbreviation.typeAlias, // TODO: if/when the language gets local or nested type aliases, this will need remapping. - abbreviation.hasQuestionMark, - abbreviation.arguments.map { remapTypeArgument(it) }, - abbreviation.annotations - ) + private fun LocalContext.remapType(type: IrType): IrType = typeRemapper.remapType(type) @OptIn(ObsoleteDescriptorBasedAPI::class) private inner class LocalDeclarationsTransformer( @@ -252,14 +226,13 @@ 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) + this.body?.remapTypes(it.typeRemapper) original.valueParameters.filter { v -> v.defaultValue != null }.forEach { argument -> val body = argument.defaultValue!! - body.remapTypes(typeRemapper) + body.remapTypes(it.typeRemapper) oldParameterToNew[argument]!!.defaultValue = body } acceptChildren(SetDeclarationsParentVisitor, this) @@ -930,45 +903,5 @@ class LocalDeclarationsLowering( } } -class TypeParameterAdjustmentTypeRemapper(val typeParameterMap: Map) : 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 diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/declarations/IrTypeParameterBuilder.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/declarations/IrTypeParameterBuilder.kt index 6816d1db896..6194ced66c9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/declarations/IrTypeParameterBuilder.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/declarations/IrTypeParameterBuilder.kt @@ -21,6 +21,6 @@ class IrTypeParameterBuilder : IrDeclarationBuilder() { index = from.index variance = from.variance isReified = from.isReified - superTypes.addAll(from.superTypes) + // Do not copy superTypes. You typically want a remapping for a group of type parameters at a time, see IrTypeParameterRemapper. } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeParameterRemapper.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeParameterRemapper.kt new file mode 100644 index 00000000000..527fa0da1d7 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeParameterRemapper.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.util + +import org.jetbrains.kotlin.ir.declarations.IrTypeParameter +import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +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 + +/* After moving an IrElement, some type parameter references within it may become out of scope. + This remapper restores validity by redirecting those references to new type parameters. + */ +class IrTypeParameterRemapper( + val typeParameterMap: Map +) : 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@IrTypeParameterRemapper) } + } + + 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@IrTypeParameterRemapper) } + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RemapTypes.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RemapTypes.kt index e8ba63b8cde..0ab1320695f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RemapTypes.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RemapTypes.kt @@ -24,9 +24,9 @@ private class RemapTypesHelper(private val typeRemapper: TypeRemapper) : IrEleme element.acceptChildrenVoid(this) } - override fun visitExpression(expression: IrExpression) { - expression.type = typeRemapper.remapType(expression.type) - super.visitExpression(expression) + override fun visitClass(declaration: IrClass) { + declaration.superTypes = declaration.superTypes.map { typeRemapper.remapType(it) } + super.visitClass(declaration) } override fun visitValueParameter(declaration: IrValueParameter) { @@ -34,6 +34,11 @@ private class RemapTypesHelper(private val typeRemapper: TypeRemapper) : IrEleme super.visitValueParameter(declaration) } + override fun visitTypeParameter(declaration: IrTypeParameter) { + declaration.superTypes = declaration.superTypes.map { typeRemapper.remapType(it) } + super.visitTypeParameter(declaration) + } + override fun visitVariable(declaration: IrVariable) { declaration.type = typeRemapper.remapType(declaration.type) super.visitVariable(declaration) @@ -59,6 +64,11 @@ private class RemapTypesHelper(private val typeRemapper: TypeRemapper) : IrEleme super.visitTypeAlias(declaration) } + override fun visitExpression(expression: IrExpression) { + expression.type = typeRemapper.remapType(expression.type) + super.visitExpression(expression) + } + override fun visitTypeOperator(expression: IrTypeOperatorCall) { expression.typeOperand = typeRemapper.remapType(expression.typeOperand) super.visitTypeOperator(expression) diff --git a/compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt b/compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt new file mode 100644 index 00000000000..0d6485ac0de --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt @@ -0,0 +1,21 @@ +interface I { + fun id(x: TT) = x +} + +fun forClass(x: T): T { + fun g(z: T): T { + class C : I + + return C().id(z) + } + + return g(x) +} + +fun forTypeParameter(x: T): T { + fun h(z: S) = z + + return h(x) +} + +fun box() = forClass("O") + forTypeParameter("K") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 649b2a045fc..c6400860082 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a4549e776ea..c409fd54958 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 5d80362aec6..ae27f941867 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 0243f81a7d8..af1dfa9ee92 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index c1a492956c1..d50fa81ad64 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 6a2ba46fbaf..9a2078aed2a 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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("boundTypeParameterInSupertype.kt") + public void testBoundTypeParameterInSupertype() throws Exception { + runTest("compiler/testData/codegen/box/functions/localFunctions/boundTypeParameterInSupertype.kt"); + } + @TestMetadata("callBetweenLocalFunctions.kt") public void testCallBetweenLocalFunctions() throws Exception { runTest("compiler/testData/codegen/box/functions/localFunctions/callBetweenLocalFunctions.kt");