[JVM_IR] Propagate Type Parameters to DefaultImpls
This ensures correct generation of generic signatures in the resulting byte code, but it _is_ a work in progress: the actual type *arguments* passed for these parameters during compilation are dummy `Any?` types. Sites that need more work are indicated with TODO's. - copy type parameters of interfaces to methods moved to DefaultImpls - implement type parameter renaming scheme from JVM, with proper renaming and substitution. - adjust call sites in bridges in classes->DefaultImpls - adjust call sites in bridges from DefaultImpls->Interface - adjust call sites in bridges from DefaultImpls->DefaultImpls - adjust super calls ->DefaultImpls - adjust calls in code of Interfaces->DefaultImpls
This commit is contained in:
committed by
Georgy Bronnikov
parent
3606a4104b
commit
4dd794c2d2
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.Scope
|
import org.jetbrains.kotlin.ir.builders.Scope
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.IrTypeParameterBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.build
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
@@ -31,12 +33,12 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
|||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeBuilder
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
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.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
@@ -121,7 +123,7 @@ val IrClass.isFinalClass: Boolean
|
|||||||
fun IrCall.getAnnotationClass(): IrClass {
|
fun IrCall.getAnnotationClass(): IrClass {
|
||||||
val callable = symbol.owner
|
val callable = symbol.owner
|
||||||
assert(callable is IrConstructor) { "Constructor call expected, got ${ir2string(this)}" }
|
assert(callable is IrConstructor) { "Constructor call expected, got ${ir2string(this)}" }
|
||||||
val annotationClass = callable.parentAsClass
|
val annotationClass = callable.parentAsClass
|
||||||
assert(annotationClass.isAnnotationClass) { "Annotation class expected, got ${ir2string(annotationClass)}" }
|
assert(annotationClass.isAnnotationClass) { "Annotation class expected, got ${ir2string(annotationClass)}" }
|
||||||
return annotationClass
|
return annotationClass
|
||||||
}
|
}
|
||||||
@@ -135,9 +137,11 @@ fun IrValueParameter.copyTo(
|
|||||||
startOffset: Int = this.startOffset,
|
startOffset: Int = this.startOffset,
|
||||||
endOffset: Int = this.endOffset,
|
endOffset: Int = this.endOffset,
|
||||||
name: Name = this.name,
|
name: Name = this.name,
|
||||||
|
remapTypeMap: Map<IrTypeParameter, IrTypeParameter> = mapOf(),
|
||||||
type: IrType = this.type.remapTypeParameters(
|
type: IrType = this.type.remapTypeParameters(
|
||||||
(parent as IrTypeParametersContainer).classIfConstructor,
|
(parent as IrTypeParametersContainer).classIfConstructor,
|
||||||
irFunction.classIfConstructor
|
irFunction.classIfConstructor,
|
||||||
|
remapTypeMap
|
||||||
),
|
),
|
||||||
varargElementType: IrType? = this.varargElementType, // TODO: remapTypeParameters here as well
|
varargElementType: IrType? = this.varargElementType, // TODO: remapTypeParameters here as well
|
||||||
defaultValue: IrExpressionBody? = this.defaultValue,
|
defaultValue: IrExpressionBody? = this.defaultValue,
|
||||||
@@ -395,7 +399,8 @@ fun Scope.createTemporaryVariableWithWrappedDescriptor(
|
|||||||
irExpression: IrExpression,
|
irExpression: IrExpression,
|
||||||
nameHint: String? = null,
|
nameHint: String? = null,
|
||||||
isMutable: Boolean = false,
|
isMutable: Boolean = false,
|
||||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE): IrVariable {
|
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
|
): IrVariable {
|
||||||
|
|
||||||
val descriptor = WrappedVariableDescriptor()
|
val descriptor = WrappedVariableDescriptor()
|
||||||
return createTemporaryVariableWithGivenDescriptor(
|
return createTemporaryVariableWithGivenDescriptor(
|
||||||
@@ -440,7 +445,7 @@ fun IrClass.simpleFunctions() = declarations.flatMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun IrClass.createParameterDeclarations() {
|
fun IrClass.createParameterDeclarations() {
|
||||||
assert (thisReceiver == null)
|
assert(thisReceiver == null)
|
||||||
|
|
||||||
thisReceiver = WrappedReceiverParameterDescriptor().let {
|
thisReceiver = WrappedReceiverParameterDescriptor().let {
|
||||||
IrValueParameterImpl(
|
IrValueParameterImpl(
|
||||||
@@ -480,8 +485,9 @@ fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = nu
|
|||||||
|
|
||||||
val IrFunction.allParameters: List<IrValueParameter>
|
val IrFunction.allParameters: List<IrValueParameter>
|
||||||
get() = if (this is IrConstructor) {
|
get() = if (this is IrConstructor) {
|
||||||
listOf(this.constructedClass.thisReceiver
|
listOf(
|
||||||
?: error(this.descriptor)
|
this.constructedClass.thisReceiver
|
||||||
|
?: error(this.descriptor)
|
||||||
) + explicitParameters
|
) + explicitParameters
|
||||||
} else {
|
} else {
|
||||||
explicitParameters
|
explicitParameters
|
||||||
@@ -556,7 +562,8 @@ fun createStaticFunctionWithReceivers(
|
|||||||
origin: IrDeclarationOrigin = oldFunction.origin,
|
origin: IrDeclarationOrigin = oldFunction.origin,
|
||||||
modality: Modality = Modality.FINAL,
|
modality: Modality = Modality.FINAL,
|
||||||
visibility: Visibility = oldFunction.visibility,
|
visibility: Visibility = oldFunction.visibility,
|
||||||
copyMetadata: Boolean = true
|
copyMetadata: Boolean = true,
|
||||||
|
typeParametersFromContext: List<IrTypeParameter> = listOf()
|
||||||
): IrSimpleFunction {
|
): IrSimpleFunction {
|
||||||
val descriptor = (oldFunction.descriptor as? DescriptorWithContainerSource)?.let {
|
val descriptor = (oldFunction.descriptor as? DescriptorWithContainerSource)?.let {
|
||||||
WrappedFunctionDescriptorWithContainerSource(it.containerSource)
|
WrappedFunctionDescriptorWithContainerSource(it.containerSource)
|
||||||
@@ -580,7 +587,19 @@ fun createStaticFunctionWithReceivers(
|
|||||||
descriptor.bind(this)
|
descriptor.bind(this)
|
||||||
parent = irParent
|
parent = irParent
|
||||||
|
|
||||||
copyTypeParametersFrom(oldFunction)
|
val newTypeParametersFromContext = copyAndRenameConflictingTypeParametersFrom(
|
||||||
|
typeParametersFromContext,
|
||||||
|
oldFunction.typeParameters
|
||||||
|
)
|
||||||
|
val newTypeParametersFromFunction = copyTypeParametersFrom(oldFunction)
|
||||||
|
val typeParameterMap =
|
||||||
|
(typeParametersFromContext + oldFunction.typeParameters)
|
||||||
|
.zip(newTypeParametersFromContext + newTypeParametersFromFunction).toMap()
|
||||||
|
|
||||||
|
fun remap(type: IrType): IrType =
|
||||||
|
type.remapTypeParameters(oldFunction, this, typeParameterMap)
|
||||||
|
|
||||||
|
typeParameters.forEach { it.superTypes.replaceAll { remap(it) } }
|
||||||
|
|
||||||
annotations.addAll(oldFunction.annotations)
|
annotations.addAll(oldFunction.annotations)
|
||||||
|
|
||||||
@@ -589,22 +608,74 @@ fun createStaticFunctionWithReceivers(
|
|||||||
this,
|
this,
|
||||||
name = Name.identifier("this"),
|
name = Name.identifier("this"),
|
||||||
index = offset++,
|
index = offset++,
|
||||||
type = dispatchReceiverType!!,
|
type = remap(dispatchReceiverType!!),
|
||||||
origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
|
origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
|
||||||
)
|
)
|
||||||
val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo(
|
val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo(
|
||||||
this,
|
this,
|
||||||
name = Name.identifier("receiver"),
|
name = Name.identifier("receiver"),
|
||||||
index = offset++,
|
index = offset++,
|
||||||
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER,
|
||||||
|
remapTypeMap = typeParameterMap
|
||||||
)
|
)
|
||||||
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
|
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
|
||||||
oldFunction.valueParameters.map { it.copyTo(this, index = it.index + offset) }
|
oldFunction.valueParameters.map {
|
||||||
|
it.copyTo(
|
||||||
|
this,
|
||||||
|
index = it.index + offset,
|
||||||
|
remapTypeMap = typeParameterMap
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (copyMetadata) metadata = oldFunction.metadata
|
if (copyMetadata) metadata = oldFunction.metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the parameters in [contextParameters] to the type parameters of
|
||||||
|
* [this] function, renaming those that may clash with a provided collection of
|
||||||
|
* [existingParameters] (e.g. type parameters of the function itself, when
|
||||||
|
* creating DefaultImpls).
|
||||||
|
*
|
||||||
|
* @returns List of newly created, possibly renamed, copies of type parameters
|
||||||
|
* in order of the corresponding parameters in [context].
|
||||||
|
*/
|
||||||
|
private fun IrSimpleFunction.copyAndRenameConflictingTypeParametersFrom(
|
||||||
|
contextParameters: List<IrTypeParameter>,
|
||||||
|
existingParameters: Collection<IrTypeParameter>
|
||||||
|
): List<IrTypeParameter> {
|
||||||
|
val newParameters = mutableListOf<IrTypeParameter>()
|
||||||
|
|
||||||
|
val existingNames =
|
||||||
|
(contextParameters.map { it.name.asString() } + existingParameters.map { it.name.asString() }).toMutableSet()
|
||||||
|
|
||||||
|
contextParameters.forEach { contextType ->
|
||||||
|
val newName = if (existingParameters.any { it.name.asString() == contextType.name.asString() }) {
|
||||||
|
val newNamePrefix = contextType.name.asString() + "_I"
|
||||||
|
val newName = newNamePrefix + generateSequence(1) { x -> x + 1 }.first { n ->
|
||||||
|
(newNamePrefix + n) !in existingNames
|
||||||
|
}
|
||||||
|
existingNames.add(newName)
|
||||||
|
newName
|
||||||
|
} else {
|
||||||
|
contextType.name.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val newTypeParameter = IrTypeParameterBuilder().run {
|
||||||
|
updateFrom(contextType)
|
||||||
|
name = Name.identifier(newName)
|
||||||
|
build()
|
||||||
|
}.also {
|
||||||
|
it.parent = this
|
||||||
|
}
|
||||||
|
|
||||||
|
typeParameters.add(newTypeParameter)
|
||||||
|
newParameters.add(newTypeParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newParameters
|
||||||
|
}
|
||||||
|
|
||||||
val IrSymbol.isSuspend: Boolean
|
val IrSymbol.isSuspend: Boolean
|
||||||
get() = this is IrSimpleFunctionSymbol && owner.isSuspend
|
get() = this is IrSimpleFunctionSymbol && owner.isSuspend
|
||||||
|
|||||||
+4
-1
@@ -210,11 +210,14 @@ class JvmDeclarationFactory(
|
|||||||
},
|
},
|
||||||
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
|
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
|
||||||
modality = Modality.OPEN,
|
modality = Modality.OPEN,
|
||||||
|
|
||||||
// Interface functions are always public, with one exception: clone in Cloneable, which is protected. However, Cloneable
|
// Interface functions are always public, with one exception: clone in Cloneable, which is protected. However, Cloneable
|
||||||
// has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend. We should rather not generate
|
// has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend. We should rather not generate
|
||||||
// a bridge to clone when interface inherits from Cloneable at all. Below, we force everything, including those bridges,
|
// a bridge to clone when interface inherits from Cloneable at all. Below, we force everything, including those bridges,
|
||||||
// to be public so that we won't try to generate synthetic accessor for them.
|
// to be public so that we won't try to generate synthetic accessor for them.
|
||||||
visibility = Visibilities.PUBLIC
|
visibility = Visibilities.PUBLIC,
|
||||||
|
|
||||||
|
typeParametersFromContext = parent.typeParameters
|
||||||
).also { it.copyAttributes(interfaceFun) }
|
).also { it.copyAttributes(interfaceFun) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,3 +209,51 @@ fun IrBody.replaceThisByStaticReference(
|
|||||||
return super.visitGetValue(expression)
|
return super.visitGetValue(expression)
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Interface Parameters
|
||||||
|
//
|
||||||
|
// The call sites using this function share that they are calling an
|
||||||
|
// interface method that has been moved to a DefaultImpls class. In that
|
||||||
|
// process, the type parameters of the interface are introduced as the first
|
||||||
|
// parameters to the method. When rewriting calls to point to the new method,
|
||||||
|
// the instantiation `S,T` of the interface type `I<S,T>` for the _calling_
|
||||||
|
// class `C` gives the proper instantiation fo arguments.
|
||||||
|
//
|
||||||
|
// We essentially want to answer the type query:
|
||||||
|
//
|
||||||
|
// C <: I<?S,?T>
|
||||||
|
//
|
||||||
|
// And put that instantiation as the first type parameters to the call, filling
|
||||||
|
// in whatever type arguments are provided at call the call site for the rest.
|
||||||
|
// The front-end type checking guarantees this is well-formed.
|
||||||
|
//
|
||||||
|
// For now, we put `Any?`.
|
||||||
|
fun createPlaceholderAnyNType(irBuiltIns: IrBuiltIns): IrType =
|
||||||
|
irBuiltIns.anyNType
|
||||||
|
|
||||||
|
fun createDelegatingCallWithPlaceholderTypeArguments(existingCall: IrCall, redirectTarget: IrFunction, irBuiltIns: IrBuiltIns): IrCall =
|
||||||
|
IrCallImpl(
|
||||||
|
existingCall.startOffset,
|
||||||
|
existingCall.endOffset,
|
||||||
|
existingCall.type,
|
||||||
|
redirectTarget.symbol,
|
||||||
|
typeArgumentsCount = redirectTarget.typeParameters.size,
|
||||||
|
valueArgumentsCount = redirectTarget.valueParameters.size,
|
||||||
|
origin = existingCall.origin
|
||||||
|
).apply {
|
||||||
|
copyValueArgumentsFrom(
|
||||||
|
existingCall,
|
||||||
|
existingCall.symbol.owner,
|
||||||
|
this.symbol.owner,
|
||||||
|
receiversAsArguments = true,
|
||||||
|
argumentsAsReceivers = false
|
||||||
|
)
|
||||||
|
var offset = 0
|
||||||
|
existingCall.symbol.owner.parentAsClass.typeParameters.forEach { _ ->
|
||||||
|
putTypeArgument(offset++, createPlaceholderAnyNType(irBuiltIns))
|
||||||
|
}
|
||||||
|
for (i in 0 until (existingCall.typeArgumentsCount)) {
|
||||||
|
putTypeArgument(i + offset, existingCall.getTypeArgument(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-8
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createDelegatingCallWithPlaceholderTypeArguments
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createPlaceholderAnyNType
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
@@ -49,11 +51,11 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
|||||||
element.acceptChildrenVoid(this)
|
element.acceptChildrenVoid(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lower(declaration: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (!declaration.isJvmInterface)
|
if (!irClass.isJvmInterface)
|
||||||
generateInterfaceMethods(declaration)
|
generateInterfaceMethods(irClass)
|
||||||
|
|
||||||
super.visitClass(declaration)
|
super.visitClass(irClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateInterfaceMethods(irClass: IrClass) {
|
private fun generateInterfaceMethods(irClass: IrClass) {
|
||||||
@@ -87,8 +89,12 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
|||||||
irFunction.body = irBlockBody {
|
irFunction.body = irBlockBody {
|
||||||
+irReturn(
|
+irReturn(
|
||||||
irCall(defaultImplFun.symbol, irFunction.returnType).apply {
|
irCall(defaultImplFun.symbol, irFunction.returnType).apply {
|
||||||
|
interfaceImplementation.parentAsClass.typeParameters.forEachIndexed { index, _ ->
|
||||||
|
putTypeArgument(index, createPlaceholderAnyNType(context.irBuiltIns))
|
||||||
|
}
|
||||||
|
passTypeArgumentsFrom(irFunction, offset = interfaceImplementation.parentAsClass.typeParameters.size)
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
passTypeArgumentsFrom(irFunction)
|
|
||||||
irFunction.dispatchReceiverParameter?.let { putValueArgument(offset++, irGet(it)) }
|
irFunction.dispatchReceiverParameter?.let { putValueArgument(offset++, irGet(it)) }
|
||||||
irFunction.extensionReceiverParameter?.let { putValueArgument(offset++, irGet(it)) }
|
irFunction.extensionReceiverParameter?.let { putValueArgument(offset++, irGet(it)) }
|
||||||
irFunction.valueParameters.mapIndexed { i, parameter -> putValueArgument(i + offset, irGet(parameter)) }
|
irFunction.valueParameters.mapIndexed { i, parameter -> putValueArgument(i + offset, irGet(parameter)) }
|
||||||
@@ -118,12 +124,14 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl
|
|||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This is too eagerly resolving the fake override statically. It
|
||||||
|
// should cf the old backend call precisely <supertype>.foo, not
|
||||||
|
// resolve foo to its implementation.
|
||||||
val superCallee = (expression.symbol.owner as IrSimpleFunction).resolveFakeOverride()!!
|
val superCallee = (expression.symbol.owner as IrSimpleFunction).resolveFakeOverride()!!
|
||||||
if (superCallee.isDefinitelyNotDefaultImplsMethod() || superCallee.hasJvmDefault()) return super.visitCall(expression)
|
if (superCallee.isDefinitelyNotDefaultImplsMethod() || superCallee.hasJvmDefault()) return super.visitCall(expression)
|
||||||
|
|
||||||
val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee)
|
val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee)
|
||||||
val newCall = irCall(expression, redirectTarget, receiversAsArguments = true)
|
val newCall = createDelegatingCallWithPlaceholderTypeArguments(expression, redirectTarget, context.irBuiltIns)
|
||||||
|
|
||||||
return super.visitCall(newCall)
|
return super.visitCall(newCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +165,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
|
|||||||
// gets redirected to call itself.
|
// gets redirected to call itself.
|
||||||
if (redirectTarget == currentFunction?.irElement) return super.visitCall(expression)
|
if (redirectTarget == currentFunction?.irElement) return super.visitCall(expression)
|
||||||
|
|
||||||
val newCall = irCall(expression, redirectTarget, receiversAsArguments = true)
|
val newCall = createDelegatingCallWithPlaceholderTypeArguments(expression, redirectTarget, context.irBuiltIns)
|
||||||
|
|
||||||
return super.visitCall(newCall)
|
return super.visitCall(newCall)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-5
@@ -8,10 +8,11 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
|||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||||
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
|
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
|
||||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createDelegatingCallWithPlaceholderTypeArguments
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createPlaceholderAnyNType
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
|
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
@@ -187,11 +189,15 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
|||||||
newFunction.parentAsClass.declarations.add(newFunction)
|
newFunction.parentAsClass.declarations.add(newFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bridge from static to static method - simply fill the arguments to the parameters.
|
// Bridge from static to static method - simply fill the function arguments to the parameters.
|
||||||
// By nature of the generation of both source and target of bridge, they line up.
|
// By nature of the generation of both source and target of bridge, they line up.
|
||||||
private fun IrFunction.bridgeToStatic(callTarget: IrFunction) {
|
private fun IrFunction.bridgeToStatic(callTarget: IrFunction) {
|
||||||
body = IrExpressionBodyImpl(IrCallImpl(startOffset, endOffset, returnType, callTarget.symbol).also { call ->
|
body = IrExpressionBodyImpl(IrCallImpl(startOffset, endOffset, returnType, callTarget.symbol).also { call ->
|
||||||
call.passTypeArgumentsFrom(this)
|
|
||||||
|
callTarget.typeParameters.forEachIndexed { i, _ ->
|
||||||
|
call.putTypeArgument(i, createPlaceholderAnyNType(context.irBuiltIns))
|
||||||
|
}
|
||||||
|
|
||||||
valueParameters.forEachIndexed { i, it ->
|
valueParameters.forEachIndexed { i, it ->
|
||||||
call.putValueArgument(i, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
call.putValueArgument(i, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
||||||
}
|
}
|
||||||
@@ -209,7 +215,9 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
|||||||
callTarget.symbol,
|
callTarget.symbol,
|
||||||
superQualifierSymbol = callTarget.parentAsClass.symbol
|
superQualifierSymbol = callTarget.parentAsClass.symbol
|
||||||
).also { call ->
|
).also { call ->
|
||||||
call.passTypeArgumentsFrom(this)
|
this.typeParameters.drop(callTarget.parentAsClass.typeParameters.size).forEachIndexed { i, typeParameter ->
|
||||||
|
call.putTypeArgument(i, typeParameter.defaultType)
|
||||||
|
}
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
callTarget.dispatchReceiverParameter?.let {
|
callTarget.dispatchReceiverParameter?.let {
|
||||||
@@ -243,7 +251,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
|||||||
val newFunction = removedFunctions[expression.symbol]?.owner
|
val newFunction = removedFunctions[expression.symbol]?.owner
|
||||||
return super.visitCall(
|
return super.visitCall(
|
||||||
if (newFunction != null) {
|
if (newFunction != null) {
|
||||||
irCall(expression, newFunction, receiversAsArguments = true)
|
createDelegatingCallWithPlaceholderTypeArguments(expression, newFunction, context.irBuiltIns)
|
||||||
} else {
|
} else {
|
||||||
expression
|
expression
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.builders.declarations
|
package org.jetbrains.kotlin.ir.builders.declarations
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
@@ -14,4 +15,12 @@ class IrTypeParameterBuilder : IrDeclarationBuilder() {
|
|||||||
var variance: Variance = Variance.INVARIANT
|
var variance: Variance = Variance.INVARIANT
|
||||||
var isReified: Boolean = false
|
var isReified: Boolean = false
|
||||||
val superTypes: MutableList<IrType> = SmartList()
|
val superTypes: MutableList<IrType> = SmartList()
|
||||||
|
|
||||||
|
fun updateFrom(from: IrTypeParameter) {
|
||||||
|
super.updateFrom(from)
|
||||||
|
index = from.index
|
||||||
|
variance = from.variance
|
||||||
|
isReified = from.isReified
|
||||||
|
superTypes.addAll(from.superTypes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -583,7 +583,16 @@ private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
|
|||||||
argumentsAsReceivers: Boolean = false
|
argumentsAsReceivers: Boolean = false
|
||||||
) {
|
) {
|
||||||
copyTypeArgumentsFrom(src)
|
copyTypeArgumentsFrom(src)
|
||||||
|
copyValueArgumentsFrom(src, srcFunction, destFunction, receiversAsArguments, argumentsAsReceivers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrMemberAccessExpression.copyValueArgumentsFrom(
|
||||||
|
src: IrMemberAccessExpression,
|
||||||
|
srcFunction: IrFunction,
|
||||||
|
destFunction: IrFunction,
|
||||||
|
receiversAsArguments: Boolean = false,
|
||||||
|
argumentsAsReceivers: Boolean = false
|
||||||
|
) {
|
||||||
var destValueArgumentIndex = 0
|
var destValueArgumentIndex = 0
|
||||||
var srcValueArgumentIndex = 0
|
var srcValueArgumentIndex = 0
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
class B<M>
|
class B<M>
|
||||||
|
|
||||||
interface A<T, Y : B<T>> {
|
interface A<T, Y : B<T>> {
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
class B<M>
|
class B<M>
|
||||||
|
|
||||||
interface A<T, Y : B<T>, T_I1: T> {
|
interface A<T, Y : B<T>, T_I1: T> {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
|
|
||||||
class B<M>
|
class B<M>
|
||||||
|
|
||||||
interface A<T, Y : B<T>> {
|
interface A<T, Y : B<T>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user