Support synthetic accessors for constructors
This commit is contained in:
@@ -50,7 +50,7 @@ class JvmLower(val context: JvmBackendContext) {
|
|||||||
ObjectClassLowering(context).runOnFilePostfix(irFile)
|
ObjectClassLowering(context).runOnFilePostfix(irFile)
|
||||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||||
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
||||||
SyntheticAccessorLowering(context.state).lower(irFile)
|
SyntheticAccessorLowering(context).lower(irFile)
|
||||||
BridgeLowering(context.state).runOnFilePostfix(irFile)
|
BridgeLowering(context.state).runOnFilePostfix(irFile)
|
||||||
|
|
||||||
TailrecLowering(context).runOnFilePostfix(irFile)
|
TailrecLowering(context).runOnFilePostfix(irFile)
|
||||||
|
|||||||
+74
-25
@@ -17,18 +17,19 @@
|
|||||||
package org.jetbrains.kotlin.backend.jvm.lower
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
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.intrinsics.receiverAndArgs
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs
|
||||||
import org.jetbrains.kotlin.codegen.AccessorForCallableDescriptor
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.AccessorForPropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
|
||||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
|
||||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||||
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
|
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
@@ -36,13 +37,15 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
interface StubContext {
|
interface StubContext {
|
||||||
val irClassContext: IrClassContext
|
val irClassContext: IrClassContext
|
||||||
@@ -97,7 +100,11 @@ class ContextAnnotator(val state: GenerationState) : ClassLowerWithContext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass, IrElementTransformer<IrClassContext?> {
|
class SyntheticAccessorLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformer<IrClassContext?> {
|
||||||
|
|
||||||
|
private val state = context.state
|
||||||
|
|
||||||
|
var pendingTransformations = mutableListOf<Function0<Unit>>()
|
||||||
|
|
||||||
private val IrClassContext.codegenContext: CodegenContext<*>
|
private val IrClassContext.codegenContext: CodegenContext<*>
|
||||||
get() = contextAnnotator.context2Codegen[this]!!
|
get() = contextAnnotator.context2Codegen[this]!!
|
||||||
@@ -111,12 +118,14 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass,
|
|||||||
contextAnnotator = ContextAnnotator(state)
|
contextAnnotator = ContextAnnotator(state)
|
||||||
contextAnnotator.lower(irFile)
|
contextAnnotator.lower(irFile)
|
||||||
irFile.transform(this, null)
|
irFile.transform(this, null)
|
||||||
|
|
||||||
|
pendingTransformations.forEach { it() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass, data: IrClassContext?): IrStatement {
|
override fun visitClass(declaration: IrClass, data: IrClassContext?): IrStatement {
|
||||||
val classContext = (declaration.descriptor.codegenContext as StubContext).irClassContext
|
val classContext = (declaration.descriptor.codegenContext as StubContext).irClassContext
|
||||||
return super.visitClass(declaration, classContext).apply {
|
return super.visitClass(declaration, classContext).apply {
|
||||||
lower(classContext)
|
pendingTransformations.add { lower(classContext) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,24 +136,24 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass,
|
|||||||
(
|
(
|
||||||
accessors.filterIsInstance<FunctionDescriptor>() +
|
accessors.filterIsInstance<FunctionDescriptor>() +
|
||||||
accessors.filterIsInstance<AccessorForPropertyDescriptor>().flatMap {
|
accessors.filterIsInstance<AccessorForPropertyDescriptor>().flatMap {
|
||||||
listOf(if (it.isWithSyntheticGetterAccessor) it.getter else null, if (it.isWithSyntheticSetterAccessor) it.setter else null).filterNotNull()
|
listOfNotNull(if (it.isWithSyntheticGetterAccessor) it.getter else null, if (it.isWithSyntheticSetterAccessor) it.setter else null)
|
||||||
}
|
}
|
||||||
).filterIsInstance<AccessorForCallableDescriptor<*>>()
|
).filterIsInstance<AccessorForCallableDescriptor<*>>()
|
||||||
val irClassToAddAccessor = data.irClass
|
|
||||||
|
|
||||||
|
val irClassToAddAccessor = data.irClass
|
||||||
allAccessors.forEach { accessor ->
|
allAccessors.forEach { accessor ->
|
||||||
addAccessorToClass(accessor, irClassToAddAccessor, state.typeMapper)
|
addAccessorToClass(accessor, irClassToAddAccessor, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: IrClassContext?): IrElement {
|
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: IrClassContext?): IrElement {
|
||||||
val superResult = super.visitMemberAccess(expression, data)
|
val superResult = super.visitMemberAccess(expression, data)
|
||||||
return createSyntheticAccessorCallForFunction(superResult, expression, data?.codegenContext, state.typeMapper)
|
return createSyntheticAccessorCallForFunction(superResult, expression, data?.codegenContext, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createSyntheticAccessorCallForFunction(superResult: IrElement, expression: IrMemberAccessExpression, codegenContext: CodegenContext<*>?, typeMapper: KotlinTypeMapper): IrElement {
|
fun createSyntheticAccessorCallForFunction(superResult: IrElement, expression: IrMemberAccessExpression, codegenContext: CodegenContext<*>?, context: JvmBackendContext): IrElement {
|
||||||
|
|
||||||
val descriptor = expression.descriptor
|
val descriptor = expression.descriptor
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
@@ -152,31 +161,58 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass,
|
|||||||
val accessor = Companion.actualAccessor(descriptor, directAccessor)
|
val accessor = Companion.actualAccessor(descriptor, directAccessor)
|
||||||
|
|
||||||
if (accessor is AccessorForCallableDescriptor<*> && descriptor !is AccessorForCallableDescriptor<*>) {
|
if (accessor is AccessorForCallableDescriptor<*> && descriptor !is AccessorForCallableDescriptor<*>) {
|
||||||
|
val isConstructor = descriptor is ConstructorDescriptor
|
||||||
val accessorOwner = accessor.containingDeclaration as ClassOrPackageFragmentDescriptor
|
val accessorOwner = accessor.containingDeclaration as ClassOrPackageFragmentDescriptor
|
||||||
val staticAccessor = descriptor.toStatic(accessorOwner, Name.identifier(typeMapper.mapAsmMethod(accessor as FunctionDescriptor).name)) //TODO change call
|
val accessorForIr =
|
||||||
val call = IrCallImpl(expression.startOffset, expression.endOffset, staticAccessor, emptyMap(), expression.origin/*TODO super*/)
|
accessorToIrAccessor(isConstructor, accessor, context, descriptor, accessorOwner) //TODO change call
|
||||||
|
|
||||||
|
val call =
|
||||||
|
if (isConstructor && expression is IrDelegatingConstructorCall)
|
||||||
|
IrDelegatingConstructorCallImpl(expression.startOffset, expression.endOffset, accessorForIr as ClassConstructorDescriptor)
|
||||||
|
else IrCallImpl(expression.startOffset, expression.endOffset, accessorForIr, emptyMap(), expression.origin/*TODO super*/)
|
||||||
//copyAllArgsToValueParams(call, expression)
|
//copyAllArgsToValueParams(call, expression)
|
||||||
expression.receiverAndArgs().forEachIndexed { i, irExpression ->
|
val receiverAndArgs = expression.receiverAndArgs()
|
||||||
|
receiverAndArgs.forEachIndexed { i, irExpression ->
|
||||||
call.putValueArgument(i, irExpression)
|
call.putValueArgument(i, irExpression)
|
||||||
}
|
}
|
||||||
|
if (isConstructor) {
|
||||||
|
call.putValueArgument(receiverAndArgs.size, IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.ir.symbols.defaultConstructorMarker.descriptor.defaultType))
|
||||||
|
}
|
||||||
return call
|
return call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return superResult
|
return superResult
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAccessorToClass(accessor: AccessorForCallableDescriptor<*>, irClassToAddAccessor: IrClass, typeMapper: KotlinTypeMapper) {
|
private fun accessorToIrAccessor(isConstructor: Boolean, accessor: CallableMemberDescriptor, context: JvmBackendContext, descriptor: FunctionDescriptor, accessorOwner: ClassOrPackageFragmentDescriptor): FunctionDescriptor {
|
||||||
|
return if (isConstructor)
|
||||||
|
(accessor as AccessorForConstructorDescriptor).constructorDescriptorWithMarker(
|
||||||
|
context.ir.symbols.defaultConstructorMarker.descriptor.defaultType
|
||||||
|
)
|
||||||
|
else descriptor.toStatic(accessorOwner, Name.identifier(context.state.typeMapper.mapAsmMethod(accessor as FunctionDescriptor).name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addAccessorToClass(accessor: AccessorForCallableDescriptor<*>, irClassToAddAccessor: IrClass, context: JvmBackendContext) {
|
||||||
val accessorOwner = (accessor as FunctionDescriptor).containingDeclaration as ClassOrPackageFragmentDescriptor
|
val accessorOwner = (accessor as FunctionDescriptor).containingDeclaration as ClassOrPackageFragmentDescriptor
|
||||||
val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||||
val accessorDescriptor = accessor.toStatic(accessorOwner, Name.identifier(typeMapper.mapAsmMethod(accessor).name))
|
val isConstructor = accessor.calleeDescriptor is ConstructorDescriptor
|
||||||
|
val accessorForIr = accessorToIrAccessor(isConstructor, accessor, context, accessor.calleeDescriptor as FunctionDescriptor, accessorOwner)
|
||||||
val syntheticFunction = IrFunctionImpl(
|
val syntheticFunction = IrFunctionImpl(
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR,
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR,
|
||||||
accessorDescriptor, body
|
accessorForIr, body
|
||||||
)
|
)
|
||||||
val calleeDescriptor = accessor.calleeDescriptor as FunctionDescriptor
|
val calleeDescriptor = accessor.calleeDescriptor as FunctionDescriptor
|
||||||
val returnExpr = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, calleeDescriptor)
|
val delegationCall =
|
||||||
Companion.copyAllArgsToValueParams(returnExpr, accessorDescriptor)
|
if (!isConstructor)
|
||||||
body.statements.add(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor, returnExpr))
|
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, calleeDescriptor)
|
||||||
|
else IrDelegatingConstructorCallImpl(
|
||||||
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||||
|
createFunctionSymbol(accessor.calleeDescriptor) as IrConstructorSymbol,
|
||||||
|
accessor.calleeDescriptor as ClassConstructorDescriptor
|
||||||
|
)
|
||||||
|
copyAllArgsToValueParams(delegationCall, accessorForIr)
|
||||||
|
|
||||||
|
body.statements.add(if (isConstructor) delegationCall else IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor, delegationCall))
|
||||||
irClassToAddAccessor.declarations.add(syntheticFunction)
|
irClassToAddAccessor.declarations.add(syntheticFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +229,7 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass,
|
|||||||
return calculatedAccessor
|
return calculatedAccessor
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyAllArgsToValueParams(call: IrCallImpl, fromDescriptor: CallableMemberDescriptor) {
|
private fun copyAllArgsToValueParams(call: IrMemberAccessExpression, fromDescriptor: CallableMemberDescriptor) {
|
||||||
var offset = 0
|
var offset = 0
|
||||||
val newDescriptor = call.descriptor
|
val newDescriptor = call.descriptor
|
||||||
newDescriptor.dispatchReceiverParameter?.let {
|
newDescriptor.dispatchReceiverParameter?.let {
|
||||||
@@ -208,5 +244,18 @@ class SyntheticAccessorLowering(val state: GenerationState) : FileLoweringPass,
|
|||||||
call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, fromDescriptor.valueParameters[i + offset]))
|
call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, fromDescriptor.valueParameters[i + offset]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun AccessorForConstructorDescriptor.constructorDescriptorWithMarker(marker: KotlinType) =
|
||||||
|
ClassConstructorDescriptorImpl.createSynthesized(containingDeclaration, annotations, false, source).also {
|
||||||
|
it.initialize(
|
||||||
|
DescriptorUtils.getReceiverParameterType(extensionReceiverParameter),
|
||||||
|
dispatchReceiverParameter,
|
||||||
|
emptyList()/*TODO*/,
|
||||||
|
calleeDescriptor.valueParameters.map { it.copy(this, it.name, it.index) } + ValueParameterDescriptorImpl.createWithDestructuringDeclarations(it, null, calleeDescriptor.valueParameters.size, Annotations.EMPTY, Name.identifier("marker"), marker, false, false, false, null, SourceElement.NO_SOURCE, null),
|
||||||
|
calleeDescriptor.returnType,
|
||||||
|
Modality.FINAL,
|
||||||
|
Visibilities.LOCAL
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user