IR: copy type parameters for local functions in LocalDeclarationLowering
Local functions raised in LocalDeclarationLowering continue to refer to type parameters that are no longer visible to them. This commit only adds new type parameters to their declarations, which makes JVM accept those declarations. The generated IR is still semantically incorrect (needs further fix), but code generation seems to proceed nevertheless.
This commit is contained in:
+58
-6
@@ -23,17 +23,18 @@ import org.jetbrains.kotlin.backend.common.push
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
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.isLocal
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
class Closure(val capturedValues: List<IrValueSymbol> = emptyList())
|
data class Closure(val capturedValues: List<IrValueSymbol>, val capturedTypeParameters: List<IrTypeParameter>)
|
||||||
|
|
||||||
class ClosureAnnotator(irFile: IrFile) {
|
class ClosureAnnotator(irFile: IrFile) {
|
||||||
private val closureBuilders = mutableMapOf<IrDeclaration, ClosureBuilder>()
|
private val closureBuilders = mutableMapOf<IrDeclaration, ClosureBuilder>()
|
||||||
@@ -58,6 +59,9 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
private val declaredValues = mutableSetOf<IrValueDeclaration>()
|
private val declaredValues = mutableSetOf<IrValueDeclaration>()
|
||||||
private val includes = mutableSetOf<ClosureBuilder>()
|
private val includes = mutableSetOf<ClosureBuilder>()
|
||||||
|
|
||||||
|
private val potentiallyCapturedTypeParameters = mutableSetOf<IrTypeParameter>()
|
||||||
|
private val capturedTypeParameters = mutableSetOf<IrTypeParameter>()
|
||||||
|
|
||||||
var processed = false
|
var processed = false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -74,7 +78,7 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: We can save the closure and reuse it.
|
// TODO: We can save the closure and reuse it.
|
||||||
return Closure(result.toList())
|
return Closure(result.toList(), capturedTypeParameters.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -95,6 +99,31 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
fun isExternal(valueDeclaration: IrValueDeclaration): Boolean {
|
fun isExternal(valueDeclaration: IrValueDeclaration): Boolean {
|
||||||
return !declaredValues.contains(valueDeclaration)
|
return !declaredValues.contains(valueDeclaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isExternal(typeParameter: IrTypeParameter): Boolean {
|
||||||
|
return potentiallyCapturedTypeParameters.contains(typeParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addPotentiallyCapturedTypeParameter(param: IrTypeParameter) {
|
||||||
|
potentiallyCapturedTypeParameters.add(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun seeType(type: IrType) {
|
||||||
|
if (type !is IrSimpleType) return
|
||||||
|
(type.classifier as? IrTypeParameterSymbol)?.let { typeParameterSymbol ->
|
||||||
|
val typeParameter = typeParameterSymbol.owner
|
||||||
|
if (isExternal(typeParameter))
|
||||||
|
capturedTypeParameters.add(typeParameter)
|
||||||
|
}
|
||||||
|
for (arg in type.arguments) {
|
||||||
|
(arg as? IrTypeProjection)?.let { seeType(arg.type) }
|
||||||
|
}
|
||||||
|
type.abbreviation?.let { abbreviation ->
|
||||||
|
for (arg in abbreviation.arguments) {
|
||||||
|
(arg as? IrTypeProjection)?.let { seeType(arg.type) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
|
private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
|
||||||
@@ -129,6 +158,8 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
constructor.valueParameters.forEach { v -> closureBuilder.declareVariable(v) }
|
constructor.valueParameters.forEach { v -> closureBuilder.declareVariable(v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectPotentiallyCapturedTypeParameters(closureBuilder)
|
||||||
|
|
||||||
closuresStack.push(closureBuilder)
|
closuresStack.push(closureBuilder)
|
||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
closuresStack.pop()
|
closuresStack.pop()
|
||||||
@@ -154,6 +185,7 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectPotentiallyCapturedTypeParameters(closureBuilder)
|
||||||
|
|
||||||
closuresStack.push(closureBuilder)
|
closuresStack.push(closureBuilder)
|
||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
@@ -188,6 +220,16 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
expression.setter?.let { processMemberAccess(it.owner) }
|
expression.setter?.let { processMemberAccess(it.owner) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitExpression(expression: IrExpression) {
|
||||||
|
super.visitExpression(expression)
|
||||||
|
val typeParameterContainerScopeBuilder = closuresStack.peek()?.let {
|
||||||
|
if (it.owner is IrConstructor) {
|
||||||
|
closuresStack[closuresStack.size - 2]
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
typeParameterContainerScopeBuilder?.seeType(expression.type)
|
||||||
|
}
|
||||||
|
|
||||||
private fun processMemberAccess(declaration: IrDeclaration) {
|
private fun processMemberAccess(declaration: IrDeclaration) {
|
||||||
if (declaration.isLocal) {
|
if (declaration.isLocal) {
|
||||||
if (declaration is IrSimpleFunction && declaration.visibility != Visibilities.LOCAL) {
|
if (declaration is IrSimpleFunction && declaration.visibility != Visibilities.LOCAL) {
|
||||||
@@ -200,5 +242,15 @@ class ClosureAnnotator(irFile: IrFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun collectPotentiallyCapturedTypeParameters(closureBuilder: ClosureBuilder) {
|
||||||
|
closuresStack.takeLastWhile { it.owner !is IrClass }.forEach {
|
||||||
|
(it.owner as? IrTypeParametersContainer)?.let { container ->
|
||||||
|
for (tp in container.typeParameters) {
|
||||||
|
closureBuilder.addPotentiallyCapturedTypeParameter(tp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+79
-16
@@ -30,12 +30,17 @@ import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||||
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.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.IrUninitializedType
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
@@ -77,6 +82,14 @@ object BOUND_VALUE_PARAMETER : IrDeclarationOriginImpl("BOUND_VALUE_PARAMETER")
|
|||||||
|
|
||||||
object BOUND_RECEIVER_PARAMETER : IrDeclarationOriginImpl("BOUND_RECEIVER_PARAMETER")
|
object BOUND_RECEIVER_PARAMETER : IrDeclarationOriginImpl("BOUND_RECEIVER_PARAMETER")
|
||||||
|
|
||||||
|
/*
|
||||||
|
Local functions raised in LocalDeclarationLowering continue to refer to
|
||||||
|
type parameters no longer visible to them.
|
||||||
|
We add new type parameters to their declarations, which
|
||||||
|
makes JVM accept those declarations. The generated IR is still
|
||||||
|
semantically incorrect (TODO: needs further fix), but code generation seems
|
||||||
|
to proceed nevertheless.
|
||||||
|
*/
|
||||||
class LocalDeclarationsLowering(
|
class LocalDeclarationsLowering(
|
||||||
val context: BackendContext,
|
val context: BackendContext,
|
||||||
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
|
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
|
||||||
@@ -98,6 +111,8 @@ class LocalDeclarationsLowering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private abstract class LocalContext {
|
private abstract class LocalContext {
|
||||||
|
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
@@ -165,6 +180,29 @@ 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 inner class LocalDeclarationsTransformer(val irFile: IrFile) {
|
private inner class LocalDeclarationsTransformer(val irFile: IrFile) {
|
||||||
val localFunctions: MutableMap<IrFunction, LocalFunctionContext> = LinkedHashMap()
|
val localFunctions: MutableMap<IrFunction, LocalFunctionContext> = LinkedHashMap()
|
||||||
val localClasses: MutableMap<IrClass, LocalClassContext> = LinkedHashMap()
|
val localClasses: MutableMap<IrClass, LocalClassContext> = LinkedHashMap()
|
||||||
@@ -349,11 +387,12 @@ class LocalDeclarationsLowering(
|
|||||||
expression.startOffset, expression.endOffset,
|
expression.startOffset, expression.endOffset,
|
||||||
expression.type, // TODO functional type for transformed descriptor
|
expression.type, // TODO functional type for transformed descriptor
|
||||||
newCallee.symbol,
|
newCallee.symbol,
|
||||||
expression.typeArgumentsCount,
|
newCallee.typeParameters.size,
|
||||||
expression.origin
|
expression.origin
|
||||||
).also {
|
).also {
|
||||||
it.fillArguments2(expression, newCallee)
|
it.fillArguments2(expression, newCallee)
|
||||||
it.copyTypeArgumentsFrom(expression)
|
it.setLocalTypeArguments(oldCallee)
|
||||||
|
it.copyTypeArgumentsFrom(expression, shift = newCallee.typeParameters.size - expression.typeArgumentsCount)
|
||||||
it.copyAttributes(expression)
|
it.copyAttributes(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,11 +486,12 @@ class LocalDeclarationsLowering(
|
|||||||
oldCall.startOffset, oldCall.endOffset,
|
oldCall.startOffset, oldCall.endOffset,
|
||||||
newCallee.returnType,
|
newCallee.returnType,
|
||||||
newCallee.symbol,
|
newCallee.symbol,
|
||||||
oldCall.typeArgumentsCount,
|
newCallee.typeParameters.size,
|
||||||
oldCall.origin,
|
oldCall.origin,
|
||||||
oldCall.superQualifierSymbol
|
oldCall.superQualifierSymbol
|
||||||
).also {
|
).also {
|
||||||
it.copyTypeArgumentsFrom(oldCall)
|
it.setLocalTypeArguments(oldCall.symbol.owner)
|
||||||
|
it.copyTypeArgumentsFrom(oldCall, shift = newCallee.typeParameters.size - oldCall.typeArgumentsCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNewCall(oldCall: IrConstructorCall, newCallee: IrConstructor) =
|
private fun createNewCall(oldCall: IrConstructorCall, newCallee: IrConstructor) =
|
||||||
@@ -465,6 +505,13 @@ class LocalDeclarationsLowering(
|
|||||||
it.copyTypeArgumentsFrom(oldCall)
|
it.copyTypeArgumentsFrom(oldCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrMemberAccessExpression.setLocalTypeArguments(callee: IrFunction) {
|
||||||
|
val context = localFunctions[callee] ?: return
|
||||||
|
for ((outerTypeParameter, innerTypeParameter) in context.capturedTypeParameterToTypeParameter) {
|
||||||
|
putTypeArgument(innerTypeParameter.index, outerTypeParameter.defaultType) // TODO: remap default type!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun transformDeclarations() {
|
private fun transformDeclarations() {
|
||||||
localFunctions.values.forEach {
|
localFunctions.values.forEach {
|
||||||
createLiftedDeclaration(it)
|
createLiftedDeclaration(it)
|
||||||
@@ -502,6 +549,7 @@ class LocalDeclarationsLowering(
|
|||||||
|
|
||||||
private fun createLiftedDeclaration(localFunctionContext: LocalFunctionContext) {
|
private fun createLiftedDeclaration(localFunctionContext: LocalFunctionContext) {
|
||||||
val oldDeclaration = localFunctionContext.declaration
|
val oldDeclaration = localFunctionContext.declaration
|
||||||
|
assert(oldDeclaration.dispatchReceiverParameter == null)
|
||||||
|
|
||||||
val memberOwner = localFunctionContext.ownerForLoweredDeclaration
|
val memberOwner = localFunctionContext.ownerForLoweredDeclaration
|
||||||
val newDescriptor = WrappedSimpleFunctionDescriptor(oldDeclaration.descriptor)
|
val newDescriptor = WrappedSimpleFunctionDescriptor(oldDeclaration.descriptor)
|
||||||
@@ -512,10 +560,8 @@ class LocalDeclarationsLowering(
|
|||||||
throw AssertionError("local functions must not have dispatch receiver")
|
throw AssertionError("local functions must not have dispatch receiver")
|
||||||
}
|
}
|
||||||
|
|
||||||
val newDispatchReceiverParameter = null
|
|
||||||
|
|
||||||
// TODO: consider using fields to access the closure of enclosing class.
|
// TODO: consider using fields to access the closure of enclosing class.
|
||||||
val capturedValues = localFunctionContext.closure.capturedValues
|
val (capturedValues, capturedTypeParameters) = localFunctionContext.closure
|
||||||
|
|
||||||
val newDeclaration = IrFunctionImpl(
|
val newDeclaration = IrFunctionImpl(
|
||||||
oldDeclaration.startOffset,
|
oldDeclaration.startOffset,
|
||||||
@@ -525,7 +571,7 @@ class LocalDeclarationsLowering(
|
|||||||
newName,
|
newName,
|
||||||
Visibilities.PRIVATE,
|
Visibilities.PRIVATE,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
oldDeclaration.returnType,
|
returnType = IrUninitializedType,
|
||||||
isInline = oldDeclaration.isInline,
|
isInline = oldDeclaration.isInline,
|
||||||
isExternal = oldDeclaration.isExternal,
|
isExternal = oldDeclaration.isExternal,
|
||||||
isTailrec = oldDeclaration.isTailrec,
|
isTailrec = oldDeclaration.isTailrec,
|
||||||
@@ -538,17 +584,29 @@ class LocalDeclarationsLowering(
|
|||||||
|
|
||||||
localFunctionContext.transformedDeclaration = newDeclaration
|
localFunctionContext.transformedDeclaration = newDeclaration
|
||||||
|
|
||||||
newDeclaration.parent = memberOwner
|
val newTypeParameters = newDeclaration.copyTypeParameters(capturedTypeParameters)
|
||||||
|
localFunctionContext.capturedTypeParameterToTypeParameter.putAll(
|
||||||
|
capturedTypeParameters.zip(newTypeParameters)
|
||||||
|
)
|
||||||
newDeclaration.copyTypeParametersFrom(oldDeclaration)
|
newDeclaration.copyTypeParametersFrom(oldDeclaration)
|
||||||
newDeclaration.dispatchReceiverParameter = newDispatchReceiverParameter
|
// 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.replaceAll { localFunctionContext.remapType(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
newDeclaration.parent = memberOwner
|
||||||
|
newDeclaration.returnType = localFunctionContext.remapType(oldDeclaration.returnType)
|
||||||
|
newDeclaration.dispatchReceiverParameter = null
|
||||||
newDeclaration.extensionReceiverParameter = oldDeclaration.extensionReceiverParameter?.run {
|
newDeclaration.extensionReceiverParameter = oldDeclaration.extensionReceiverParameter?.run {
|
||||||
copyTo(newDeclaration).also {
|
copyTo(newDeclaration, type = localFunctionContext.remapType(this.type)).also {
|
||||||
newParameterToOld.putAbsentOrSame(it, this)
|
newParameterToOld.putAbsentOrSame(it, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newDeclaration.copyAttributes(oldDeclaration)
|
newDeclaration.copyAttributes(oldDeclaration)
|
||||||
|
|
||||||
newDeclaration.valueParameters += createTransformedValueParameters(capturedValues, oldDeclaration, newDeclaration)
|
newDeclaration.valueParameters += createTransformedValueParameters(
|
||||||
|
capturedValues, localFunctionContext, oldDeclaration, newDeclaration
|
||||||
|
)
|
||||||
newDeclaration.recordTransformedValueParameters(localFunctionContext)
|
newDeclaration.recordTransformedValueParameters(localFunctionContext)
|
||||||
|
|
||||||
newDeclaration.annotations.addAll(oldDeclaration.annotations)
|
newDeclaration.annotations.addAll(oldDeclaration.annotations)
|
||||||
@@ -558,6 +616,7 @@ class LocalDeclarationsLowering(
|
|||||||
|
|
||||||
private fun createTransformedValueParameters(
|
private fun createTransformedValueParameters(
|
||||||
capturedValues: List<IrValueSymbol>,
|
capturedValues: List<IrValueSymbol>,
|
||||||
|
localFunctionContext: LocalContext,
|
||||||
oldDeclaration: IrFunction,
|
oldDeclaration: IrFunction,
|
||||||
newDeclaration: IrFunction
|
newDeclaration: IrFunction
|
||||||
) = ArrayList<IrValueParameter>(capturedValues.size + oldDeclaration.valueParameters.size).apply {
|
) = ArrayList<IrValueParameter>(capturedValues.size + oldDeclaration.valueParameters.size).apply {
|
||||||
@@ -573,7 +632,7 @@ class LocalDeclarationsLowering(
|
|||||||
IrValueParameterSymbolImpl(parameterDescriptor),
|
IrValueParameterSymbolImpl(parameterDescriptor),
|
||||||
suggestNameForCapturedValue(p, generatedNames),
|
suggestNameForCapturedValue(p, generatedNames),
|
||||||
i,
|
i,
|
||||||
p.type,
|
localFunctionContext.remapType(p.type),
|
||||||
null,
|
null,
|
||||||
isCrossinline = false,
|
isCrossinline = false,
|
||||||
isNoinline = false
|
isNoinline = false
|
||||||
@@ -585,7 +644,11 @@ class LocalDeclarationsLowering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldDeclaration.valueParameters.mapTo(this) { v ->
|
oldDeclaration.valueParameters.mapTo(this) { v ->
|
||||||
v.copyTo(newDeclaration, index = v.index + capturedValues.size).also {
|
v.copyTo(
|
||||||
|
newDeclaration,
|
||||||
|
index = v.index + capturedValues.size,
|
||||||
|
type = localFunctionContext.remapType(v.type)
|
||||||
|
).also {
|
||||||
newParameterToOld.putAbsentOrSame(it, v)
|
newParameterToOld.putAbsentOrSame(it, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,7 +707,7 @@ class LocalDeclarationsLowering(
|
|||||||
throw AssertionError("Local class constructor can't have extension receiver: ${ir2string(oldDeclaration)}")
|
throw AssertionError("Local class constructor can't have extension receiver: ${ir2string(oldDeclaration)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
newDeclaration.valueParameters += createTransformedValueParameters(capturedValues, oldDeclaration, newDeclaration)
|
newDeclaration.valueParameters += createTransformedValueParameters(capturedValues, localClassContext, oldDeclaration, newDeclaration)
|
||||||
newDeclaration.recordTransformedValueParameters(constructorContext)
|
newDeclaration.recordTransformedValueParameters(constructorContext)
|
||||||
|
|
||||||
newDeclaration.metadata = oldDeclaration.metadata
|
newDeclaration.metadata = oldDeclaration.metadata
|
||||||
|
|||||||
+7
-8
@@ -78,8 +78,8 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
|||||||
"Inconsistency between callable reference to suspend lambda and the corresponding continuation"
|
"Inconsistency between callable reference to suspend lambda and the corresponding continuation"
|
||||||
}
|
}
|
||||||
+irCall(constructor.symbol).apply {
|
+irCall(constructor.symbol).apply {
|
||||||
for (tp in info.constructor.parentAsClass.typeParameters) {
|
for (typeParameter in info.constructor.parentAsClass.typeParameters) {
|
||||||
putTypeArgument(tp.index, expression.getTypeArgument(tp.index))
|
putTypeArgument(typeParameter.index, expression.getTypeArgument(typeParameter.index))
|
||||||
}
|
}
|
||||||
expressionArguments.forEachIndexed { index, argument ->
|
expressionArguments.forEachIndexed { index, argument ->
|
||||||
putValueArgument(index, argument)
|
putValueArgument(index, argument)
|
||||||
@@ -134,7 +134,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
|||||||
if (info.arity <= 1) {
|
if (info.arity <= 1) {
|
||||||
val singleParameterField = receiverField ?: parametersWithoutArguments.singleOrNull()
|
val singleParameterField = receiverField ?: parametersWithoutArguments.singleOrNull()
|
||||||
val create = addCreate(constructor, suspendLambda, info, parametersWithArguments, singleParameterField)
|
val create = addCreate(constructor, suspendLambda, info, parametersWithArguments, singleParameterField)
|
||||||
addInvokeCallingCreate(info.function, create, invokeSuspend, invokeToOverride, singleParameterField)
|
addInvokeCallingCreate(create, invokeSuspend, invokeToOverride, singleParameterField)
|
||||||
} else {
|
} else {
|
||||||
addInvokeCallingConstructor(
|
addInvokeCallingConstructor(
|
||||||
constructor,
|
constructor,
|
||||||
@@ -242,7 +242,6 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
|||||||
// 2) starting newly created coroutine by calling `invokeSuspend`.
|
// 2) starting newly created coroutine by calling `invokeSuspend`.
|
||||||
// Thus, it creates a clone of suspend lambda and starts it.
|
// Thus, it creates a clone of suspend lambda and starts it.
|
||||||
private fun IrClass.addInvokeCallingCreate(
|
private fun IrClass.addInvokeCallingCreate(
|
||||||
suspendLambdaFunction: IrFunction,
|
|
||||||
create: IrFunction,
|
create: IrFunction,
|
||||||
invokeSuspend: IrFunction,
|
invokeSuspend: IrFunction,
|
||||||
invokeToOverride: IrSimpleFunctionSymbol,
|
invokeToOverride: IrSimpleFunctionSymbol,
|
||||||
@@ -289,8 +288,8 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
|||||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||||
// Create a copy
|
// Create a copy
|
||||||
val newlyCreatedObject = irTemporary(irCall(constructor).also { constructorCall ->
|
val newlyCreatedObject = irTemporary(irCall(constructor).also { constructorCall ->
|
||||||
for (tp in typeParameters) {
|
for (typeParameter in typeParameters) {
|
||||||
constructorCall.putTypeArgument(tp.index, tp.defaultType)
|
constructorCall.putTypeArgument(typeParameter.index, typeParameter.defaultType)
|
||||||
}
|
}
|
||||||
for ((index, field) in parametersWithArguments.withIndex()) {
|
for ((index, field) in parametersWithArguments.withIndex()) {
|
||||||
constructorCall.putValueArgument(index, irGetField(irGet(function.dispatchReceiverParameter!!), field))
|
constructorCall.putValueArgument(index, irGetField(irGet(function.dispatchReceiverParameter!!), field))
|
||||||
@@ -328,8 +327,8 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
|||||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||||
var index = 0
|
var index = 0
|
||||||
val constructorCall = irCall(constructor).also {
|
val constructorCall = irCall(constructor).also {
|
||||||
for (tp in typeParameters) {
|
for (typeParameter in typeParameters) {
|
||||||
it.putTypeArgument(tp.index, tp.defaultType)
|
it.putTypeArgument(typeParameter.index, typeParameter.defaultType)
|
||||||
}
|
}
|
||||||
for ((i, field) in parametersWithArguments.withIndex()) {
|
for ((i, field) in parametersWithArguments.withIndex()) {
|
||||||
if (info.reference.getValueArgument(i) == null) continue
|
if (info.reference.getValueArgument(i) == null) continue
|
||||||
|
|||||||
+5
-5
@@ -36,12 +36,12 @@ interface IrMemberAccessExpression : IrExpression, IrDeclarationReference {
|
|||||||
fun IrMemberAccessExpression.getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): IrType? =
|
fun IrMemberAccessExpression.getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): IrType? =
|
||||||
getTypeArgument(typeParameterDescriptor.index)
|
getTypeArgument(typeParameterDescriptor.index)
|
||||||
|
|
||||||
fun IrMemberAccessExpression.copyTypeArgumentsFrom(other: IrMemberAccessExpression) {
|
fun IrMemberAccessExpression.copyTypeArgumentsFrom(other: IrMemberAccessExpression, shift: Int = 0) {
|
||||||
assert(typeArgumentsCount == other.typeArgumentsCount) {
|
assert(typeArgumentsCount == other.typeArgumentsCount + shift) {
|
||||||
"Mismatching type arguments: $typeArgumentsCount vs ${other.typeArgumentsCount} "
|
"Mismatching type arguments: $typeArgumentsCount vs ${other.typeArgumentsCount} + $shift"
|
||||||
}
|
}
|
||||||
for (i in 0 until typeArgumentsCount) {
|
for (i in 0 until other.typeArgumentsCount) {
|
||||||
putTypeArgument(i, other.getTypeArgument(i))
|
putTypeArgument(i + shift, other.getTypeArgument(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
class TypeParamInInner {
|
||||||
|
void check() {
|
||||||
|
TypeParamInInnerKt.outer("OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class outerClass<T>(val t: T) {
|
||||||
|
inner class innerClass {
|
||||||
|
fun getT() = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> outer(arg: T): T {
|
||||||
|
class localClass(val v: T) {
|
||||||
|
init {
|
||||||
|
fun innerFunInLocalClass() = v
|
||||||
|
|
||||||
|
val vv = innerFunInLocalClass()
|
||||||
|
}
|
||||||
|
fun member() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fun innerFun(): T {
|
||||||
|
class localClassInLocalFunction {
|
||||||
|
val v = arg
|
||||||
|
}
|
||||||
|
|
||||||
|
return localClass(arg).member()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <X> innerFunWithOwnTypeParam(x: X) = x
|
||||||
|
|
||||||
|
innerFunWithOwnTypeParam(arg)
|
||||||
|
return innerFun()
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
public fun </*0*/ T> outer(/*0*/ T): T
|
||||||
|
|
||||||
|
public/*package*/ open class TypeParamInInner {
|
||||||
|
public/*package*/ constructor TypeParamInInner()
|
||||||
|
public/*package*/ open fun check(): kotlin.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class outerClass</*0*/ T> {
|
||||||
|
public constructor outerClass</*0*/ T>(/*0*/ T)
|
||||||
|
public final val t: T
|
||||||
|
|
||||||
|
public final inner class innerClass /*captured type parameters: /*0*/ T*/ {
|
||||||
|
public constructor innerClass()
|
||||||
|
public final fun getT(): T
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+10
@@ -313,6 +313,11 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TypeParamInInner.kt")
|
||||||
|
public void testTypeParamInInner() throws Exception {
|
||||||
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TypeParamInInner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Vararg.kt")
|
@TestMetadata("Vararg.kt")
|
||||||
public void testVararg() throws Exception {
|
public void testVararg() throws Exception {
|
||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
||||||
@@ -956,6 +961,11 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TypeParamInInner.kt")
|
||||||
|
public void testTypeParamInInner() throws Exception {
|
||||||
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TypeParamInInner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Vararg.kt")
|
@TestMetadata("Vararg.kt")
|
||||||
public void testVararg() throws Exception {
|
public void testVararg() throws Exception {
|
||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
||||||
|
|||||||
Generated
+5
@@ -311,6 +311,11 @@ public class IrCompileJavaAgainstKotlinTestGenerated extends AbstractIrCompileJa
|
|||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TypeParamInInner.kt")
|
||||||
|
public void testTypeParamInInner() throws Exception {
|
||||||
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/TypeParamInInner.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Vararg.kt")
|
@TestMetadata("Vararg.kt")
|
||||||
public void testVararg() throws Exception {
|
public void testVararg() throws Exception {
|
||||||
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
runTest("compiler/testData/compileJavaAgainstKotlin/method/Vararg.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user