Update compiler to IR with symbols, part 2 (#581)

The symbols produced by first lowering phases are now bound
This commit is contained in:
SvyatoslavScherbina
2017-05-18 17:54:53 +03:00
committed by GitHub
parent 3000b1ec41
commit c9d7f976a5
29 changed files with 1332 additions and 494 deletions
@@ -20,14 +20,26 @@ import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetVariableImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.DeepCopySymbolsRemapper
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
/**
* Copies IR tree with descriptors of all declarations inside;
* updates the references to these declarations.
*/
@Deprecated("Creates unbound symbols")
open class DeepCopyIrTreeWithDeclarations : DeepCopyIrTree() {
private fun DeclarationDescriptor.notSupported(): Nothing = TODO("${this}")
@@ -95,4 +107,69 @@ open class DeepCopyIrTreeWithDeclarations : DeepCopyIrTree() {
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop
}
}
}
fun IrElement.deepCopyWithVariablesImpl(): IrElement {
// FIXME: support non-transformed loops
val remapper = DeepCopySymbolsRemapper()
acceptVoid(remapper)
val variableDescriptorReplacer = object : IrElementTransformerVoid() {
val copiedVariables = mutableMapOf<IrVariableSymbol, IrVariableSymbol>()
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid()
val descriptor = declaration.descriptor
val newDescriptor = LocalVariableDescriptor(
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ descriptor.annotations,
/* name = */ descriptor.name,
/* type = */ descriptor.type,
/* mutable = */ descriptor.isVar,
/* isDelegated = */ false,
/* source = */ descriptor.source
)
val newSymbol = IrVariableSymbolImpl(newDescriptor)
copiedVariables[declaration.symbol] = newSymbol
return with(declaration) {
IrVariableImpl(startOffset, endOffset, origin, newSymbol).also {
it.initializer = initializer
}
}
}
override fun visitValueAccess(expression: IrValueAccessExpression): IrExpression {
assert(expression.symbol !in copiedVariables)
return super.visitValueAccess(expression)
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newSymbol = copiedVariables[expression.symbol] ?: return super.visitGetValue(expression)
expression.transformChildrenVoid()
return with(expression) {
IrGetValueImpl(startOffset, endOffset, newSymbol, origin)
}
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
val newSymbol = copiedVariables[expression.symbol] ?: return super.visitSetVariable(expression)
expression.transformChildrenVoid()
return with(expression) {
IrSetVariableImpl(startOffset, endOffset, newSymbol, value, origin)
}
}
}
return this.transform(DeepCopyIrTreeWithSymbols(remapper), null).transform(variableDescriptorReplacer, null)
}
inline fun <reified T : IrElement> T.deepCopyWithVariables(): T =
this.deepCopyWithVariablesImpl() as T
@@ -38,7 +38,7 @@ abstract internal class IrElementTransformerVoidWithContext : IrElementTransform
}
override final fun visitClass(declaration: IrClass): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitClassNew(declaration)
scopeStack.pop()
return result
@@ -52,14 +52,14 @@ abstract internal class IrElementTransformerVoidWithContext : IrElementTransform
}
override final fun visitField(declaration: IrField): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitFieldNew(declaration)
scopeStack.pop()
return result
}
override final fun visitFunction(declaration: IrFunction): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitFunctionNew(declaration)
scopeStack.pop()
return result
@@ -102,13 +102,13 @@ abstract internal class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
private val scopeStack = mutableListOf<ScopeWithIr>()
override final fun visitFile(declaration: IrFile) {
scopeStack.push(ScopeWithIr(Scope(declaration.packageFragmentDescriptor), declaration))
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
visitFileNew(declaration)
scopeStack.pop()
}
override final fun visitClass(declaration: IrClass) {
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
visitClassNew(declaration)
scopeStack.pop()
}
@@ -121,7 +121,7 @@ abstract internal class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
override final fun visitField(declaration: IrField) {
val isDelegated = declaration.descriptor.isDelegated
if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
visitFieldNew(declaration)
if (isDelegated) scopeStack.pop()
}
@@ -203,7 +203,7 @@ private class IrValidator(val context: BackendContext, performHeavyValidations:
private fun recordDeclaration(declaration: IrDeclaration) {
if (foundDeclarations.isAlreadyDeclared(declaration)) {
if (declaration.descriptor !is ReceiverParameterDescriptor && declaration !is IrTypeParameter) {
if (declaration !is IrValueParameter && declaration !is IrTypeParameter) {
// TODO: remove the check.
error(declaration, "redeclaration")
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCatch
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -30,7 +31,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
// TODO: synchronize with JVM BE
// TODO: rename the file.
class Closure(val capturedValues: List<ValueDescriptor> = emptyList())
class Closure(val capturedValues: List<IrValueSymbol> = emptyList())
class ClosureAnnotator {
private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>()
@@ -51,7 +52,7 @@ class ClosureAnnotator {
}
private class ClosureBuilder(val owner: DeclarationDescriptor) {
val capturedValues = mutableSetOf<ValueDescriptor>()
val capturedValues = mutableSetOf<IrValueSymbol>()
private val declaredValues = mutableSetOf<ValueDescriptor>()
private val includes = mutableSetOf<ClosureBuilder>()
@@ -63,11 +64,11 @@ class ClosureAnnotator {
* variables declared in the node.
*/
fun buildClosure(): Closure {
val result = mutableSetOf<ValueDescriptor>().apply { addAll(capturedValues) }
val result = mutableSetOf<IrValueSymbol>().apply { addAll(capturedValues) }
includes.forEach {
if (!it.processed) {
it.processed = true
it.buildClosure().capturedValues.filterTo(result) { isExternal(it) }
it.buildClosure().capturedValues.filterTo(result) { isExternal(it.descriptor) }
}
}
// TODO: We can save the closure and reuse it.
@@ -84,9 +85,9 @@ class ClosureAnnotator {
declaredValues.add(valueDescriptor)
}
fun seeVariable(valueDescriptor: ValueDescriptor) {
if (isExternal(valueDescriptor))
capturedValues.add(valueDescriptor)
fun seeVariable(value: IrValueSymbol) {
if (isExternal(value.descriptor))
capturedValues.add(value)
}
fun isExternal(valueDescriptor: ValueDescriptor): Boolean {
@@ -159,7 +160,7 @@ class ClosureAnnotator {
}
override fun visitVariableAccess(expression: IrValueAccessExpression) {
closuresStack.peek()?.seeVariable(expression.descriptor)
closuresStack.peek()?.seeVariable(expression.symbol)
super.visitVariableAccess(expression)
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
@@ -78,13 +79,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
get() = declaration.descriptor
abstract val transformedDescriptor: FunctionDescriptor
abstract val transformedDeclaration: IrFunction
val capturedValueToParameter: MutableMap<ValueDescriptor, ValueParameterDescriptor> = HashMap()
val capturedValueToParameter: MutableMap<ValueDescriptor, IrValueParameterSymbol> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val newDescriptor = capturedValueToParameter[descriptor] ?: return null
val newSymbol = capturedValueToParameter[descriptor] ?: return null
return IrGetValueImpl(startOffset, endOffset, newDescriptor)
return IrGetValueImpl(startOffset, endOffset, newSymbol)
}
}
@@ -92,6 +94,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
lateinit var closure: Closure
override lateinit var transformedDescriptor: FunctionDescriptor
override lateinit var transformedDeclaration: IrSimpleFunction
var index: Int = -1
@@ -104,6 +107,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
get() = declaration.descriptor
override lateinit var transformedDescriptor: ClassConstructorDescriptor
override lateinit var transformedDeclaration: IrConstructor
override fun toString(): String =
"LocalClassConstructorContext for $descriptor"
@@ -115,13 +119,13 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
lateinit var closure: Closure
val capturedValueToField: MutableMap<ValueDescriptor, PropertyDescriptor> = HashMap()
val capturedValueToField: MutableMap<ValueDescriptor, IrField> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val fieldDescriptor = capturedValueToField[descriptor] ?: return null
val field = capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor,
receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter)
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
receiver = IrGetValueImpl(startOffset, endOffset, declaration.thisReceiver!!.symbol)
)
}
@@ -134,14 +138,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
val transformedDescriptors = mutableMapOf<DeclarationDescriptor, DeclarationDescriptor>()
val transformedDeclarations = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val FunctionDescriptor.transformed: FunctionDescriptor?
get() = transformedDescriptors[this] as FunctionDescriptor?
val FunctionDescriptor.transformed: IrFunctionSymbol?
get() = transformedDeclarations[this] as IrFunctionSymbol?
val oldParameterToNew: MutableMap<ParameterDescriptor, ParameterDescriptor> = HashMap()
val oldParameterToNew: MutableMap<ParameterDescriptor, IrValueParameterSymbol> = HashMap()
val newParameterToOld: MutableMap<ParameterDescriptor, ParameterDescriptor> = HashMap()
val newParameterToCaptured: MutableMap<ValueParameterDescriptor, ValueDescriptor> = HashMap()
val newParameterToCaptured: MutableMap<ValueParameterDescriptor, IrValueSymbol> = HashMap()
fun lowerLocalDeclarations(): List<IrDeclaration>? {
collectLocalDeclarations()
@@ -163,16 +167,12 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
localFunctions.values.mapTo(this) {
val original = it.declaration
IrFunctionImpl(
original.startOffset, original.endOffset, original.origin,
it.transformedDescriptor,
original.body
).apply {
createParameterDeclarations()
it.transformedDeclaration.apply {
this.body = original.body
original.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = original.getDefault(argument)!!
this.putDefault(oldParameterToNew[argument] as ValueParameterDescriptor, body)
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
}
@@ -205,16 +205,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
override fun visitConstructor(declaration: IrConstructor): IrStatement {
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
val transformedDescriptor = localClassConstructors[declaration.descriptor]?.transformedDescriptor
if (transformedDescriptor != null) {
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
transformedDescriptor, declaration.body!!).apply {
createParameterDeclarations()
val constructorContext = localClassConstructors[declaration.descriptor]
if (constructorContext != null) {
return constructorContext.transformedDeclaration.apply {
this.body = declaration.body!!
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = declaration.getDefault(argument)!!
this.putDefault(oldParameterToNew[argument] as ValueParameterDescriptor, body)
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
} else {
@@ -251,12 +249,13 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = transformedDescriptors[oldCallee] as ClassConstructorDescriptor? ?: return expression
val newCallee = transformedDeclarations[oldCallee] as IrConstructorSymbol? ?: return expression
val newExpression = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset,
newCallee,
remapTypeArguments(expression, newCallee)
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor)
).fillArguments(expression)
return newExpression
@@ -271,17 +270,18 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
oldExpression.getValueArgument(oldParameter as ValueParameterDescriptor)
} else {
// The callee expects captured value as argument.
val capturedValueDescriptor =
val capturedValueSymbol =
newParameterToCaptured[newValueParameterDescriptor] ?:
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
val capturedValueDescriptor = capturedValueSymbol.descriptor
localContext?.irGet(
oldExpression.startOffset, oldExpression.endOffset,
capturedValueDescriptor
) ?:
// Captured value is directly available for the caller.
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
oldParameterToNew[capturedValueDescriptor] ?: capturedValueDescriptor)
oldParameterToNew[capturedValueDescriptor] ?: capturedValueSymbol)
}
}
@@ -302,7 +302,8 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
expression.startOffset, expression.endOffset,
expression.type, // TODO functional type for transformed descriptor
newCallee,
remapTypeArguments(expression, newCallee),
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor),
expression.origin
).fillArguments(expression)
@@ -319,14 +320,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
}
override fun visitDeclarationReference(expression: IrDeclarationReference): IrExpression {
if (expression.descriptor in transformedDescriptors) {
if (expression.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclarationReference(expression)
}
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
if (declaration.descriptor in transformedDescriptors) {
if (declaration.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclaration(declaration)
@@ -352,24 +353,18 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
.filter { it.declaration.callsSuper() }
assert(constructorsCallingSuper.any(), { "Expected at least one constructor calling super; class: $classDescriptor" })
localClassContext.capturedValueToField.forEach { capturedValue, fieldDescriptor ->
localClassContext.capturedValueToField.forEach { capturedValue, field ->
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
irClass.declarations.add(
IrFieldImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
fieldDescriptor
)
)
irClass.declarations.add(field)
for (constructorContext in constructorsCallingSuper) {
val blockBody = constructorContext.declaration.body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}")
val capturedValueExpression = constructorContext.irGet(startOffset, endOffset, capturedValue)!!
blockBody.statements.add(0,
IrSetFieldImpl(startOffset, endOffset, fieldDescriptor,
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
IrSetFieldImpl(startOffset, endOffset, field.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE))
}
}
@@ -391,15 +386,16 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
rewriteFunctionBody(memberDeclaration, null)
}
private fun createNewCall(oldCall: IrCall, newCallee: FunctionDescriptor) =
private fun createNewCall(oldCall: IrCall, newCallee: IrFunctionSymbol) =
if (oldCall is IrCallWithShallowCopy)
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifier)
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifierSymbol)
else
IrCallImpl(
oldCall.startOffset, oldCall.endOffset,
newCallee,
remapTypeArguments(oldCall, newCallee),
oldCall.origin, oldCall.superQualifier
newCallee.descriptor,
remapTypeArguments(oldCall, newCallee.descriptor),
oldCall.origin, oldCall.superQualifierSymbol
)
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
@@ -463,7 +459,6 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
}
localFunctionContext.transformedDescriptor = newDescriptor
transformedDescriptors[oldDescriptor] = newDescriptor
if (oldDescriptor.dispatchReceiverParameter != null) {
throw AssertionError("local functions must not have dispatch receiver")
@@ -490,12 +485,20 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
)
oldDescriptor.extensionReceiverParameter?.let {
recordRemappedParameter(it, newDescriptor.extensionReceiverParameter!!)
newParameterToOld.putAbsentOrSame(newDescriptor.extensionReceiverParameter!!, it)
}
localFunctionContext.transformedDeclaration = with(localFunctionContext.declaration) {
IrFunctionImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(localFunctionContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createTransformedValueParameters(localContext: LocalContextWithClosureAsParameters,
capturedValues: List<ValueDescriptor>)
capturedValues: List<IrValueSymbol>)
: List<ValueParameterDescriptor> {
val oldDescriptor = localContext.descriptor
@@ -505,21 +508,39 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
val newValueParameters = ArrayList<ValueParameterDescriptor>(newValueParametersCount).apply {
capturedValues.mapIndexedTo(this) { i, capturedValueDescriptor ->
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValueDescriptor, i).apply {
localContext.recordCapturedAsParameter(capturedValueDescriptor, this)
capturedValues.mapIndexedTo(this) { i, capturedValue ->
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValue.descriptor, i).apply {
newParameterToCaptured[this] = capturedValue
}
}
oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
recordRemappedParameter(oldValueParameterDescriptor, this)
newParameterToOld.putAbsentOrSame(this, oldValueParameterDescriptor)
}
}
}
return newValueParameters
}
private fun IrFunction.recordTransformedValueParameters(localContext: LocalContextWithClosureAsParameters) {
valueParameters.forEach {
val capturedValue = newParameterToCaptured[it.descriptor]
if (capturedValue != null) {
localContext.capturedValueToParameter[capturedValue.descriptor] = it.symbol
}
}
(listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).forEach {
val oldParameter = newParameterToOld[it.descriptor]
if (oldParameter != null) {
oldParameterToNew.putAbsentOrSame(oldParameter, it.symbol)
}
}
}
private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
val oldDescriptor = constructorContext.descriptor
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
@@ -528,7 +549,6 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
constructorContext.transformedDescriptor = newDescriptor
transformedDescriptors[oldDescriptor] = newDescriptor
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
@@ -545,12 +565,20 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
newDescriptor.returnType = oldDescriptor.returnType
oldDescriptor.dispatchReceiverParameter?.let {
recordRemappedParameter(it, newDescriptor.dispatchReceiverParameter!!)
newParameterToOld.putAbsentOrSame(newDescriptor.dispatchReceiverParameter!!, it)
}
oldDescriptor.extensionReceiverParameter?.let {
throw AssertionError("constructors can't have extension receiver")
}
constructorContext.transformedDeclaration = with(constructorContext.declaration) {
IrConstructorImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(constructorContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
@@ -563,7 +591,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
Modality.FINAL,
Visibilities.PRIVATE,
/* isVar = */ false,
suggestNameForCapturedValue(capturedValue),
suggestNameForCapturedValue(capturedValue.descriptor),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
@@ -578,25 +606,19 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
val extensionReceiverParameter: ReceiverParameterDescriptor? = null
fieldDescriptor.setType(
capturedValue.type,
capturedValue.descriptor.type,
emptyList<TypeParameterDescriptor>(),
classDescriptor.thisAsReceiverParameter,
extensionReceiverParameter)
localClassContext.capturedValueToField[capturedValue] = fieldDescriptor
localClassContext.capturedValueToField[capturedValue.descriptor] = IrFieldImpl(
localClassContext.declaration.startOffset, localClassContext.declaration.endOffset,
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
fieldDescriptor
)
}
}
private fun LocalContextWithClosureAsParameters.recordCapturedAsParameter(
oldDescriptor: ValueDescriptor,
newDescriptor: ValueParameterDescriptor
) {
capturedValueToParameter[oldDescriptor] = newDescriptor
newParameterToCaptured[newDescriptor] = oldDescriptor
}
private fun <K, V> MutableMap<K, V>.putAbsentOrSame(key: K, value: V) {
val current = this.getOrPut(key, { value })
@@ -605,11 +627,6 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
}
}
private fun recordRemappedParameter(oldDescriptor: ParameterDescriptor, newDescriptor: ParameterDescriptor) {
oldParameterToNew.putAbsentOrSame(oldDescriptor, newDescriptor)
newParameterToOld.putAbsentOrSame(newDescriptor, oldDescriptor)
}
private fun suggestNameForCapturedValue(valueDescriptor: ValueDescriptor): Name =
if (valueDescriptor.name.isSpecial) {
val oldNameStr = valueDescriptor.name.asString()
@@ -126,11 +126,10 @@ fun IrBuilderWithScope.irNot(arg: IrExpression) =
fun IrBuilderWithScope.irThrow(arg: IrExpression) =
IrThrowImpl(startOffset, endOffset, context.builtIns.nothingType, arg)
fun IrBuilderWithScope.irCatch(parameter: VariableDescriptor, result: IrExpression) =
fun IrBuilderWithScope.irCatch(catchParameter: IrVariable) =
IrCatchImpl(
startOffset, endOffset,
IrVariableImpl(startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter),
result
catchParameter
)
fun IrBuilderWithScope.irCast(arg: IrExpression, type: KotlinType, typeOperand: KotlinType) =
@@ -16,22 +16,16 @@
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.DeepCopyIrTreeWithDeclarations
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.collectTailRecursionCalls
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.getOriginalParameter
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.getDefault
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.ir.util.getArgumentsWithSymbols
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -53,11 +47,10 @@ private fun lowerTailRecursionCalls(context: BackendContext, irFunction: IrFunct
return
}
val descriptor = irFunction.descriptor
val oldBody = irFunction.body as IrBlockBody
val builder = context.createIrBuilder(descriptor).at(oldBody)
val builder = context.createIrBuilder(irFunction.symbol).at(oldBody)
val parameters = descriptor.explicitParameters
val parameters = irFunction.explicitParameters
irFunction.body = builder.irBlockBody {
// Define variables containing current values of parameters:
@@ -74,7 +67,7 @@ private fun lowerTailRecursionCalls(context: BackendContext, irFunction: IrFunct
// Read variables containing current values of parameters:
val parameterToNew = parameters.associate {
val variable = parameterToVariable[it]!!
it to defineTemporary(irGet(variable), nameHint = it.suggestVariableName())
it to irTemporary(irGet(variable), nameHint = it.suggestVariableName()).symbol
}
val transformer = BodyTransformer(builder, irFunction, loop,
@@ -94,16 +87,16 @@ private class BodyTransformer(
val builder: IrBuilderWithScope,
val irFunction: IrFunction,
val loop: IrLoop,
val parameterToNew: Map<ParameterDescriptor, ValueDescriptor>,
val parameterToVariable: Map<ParameterDescriptor, IrVariableSymbol>,
val parameterToNew: Map<IrValueParameterSymbol, IrValueSymbol>,
val parameterToVariable: Map<IrValueParameterSymbol, IrVariableSymbol>,
val tailRecursionCalls: Set<IrCall>
) : IrElementTransformerVoid() {
val parameters = irFunction.descriptor.explicitParameters
val parameters = irFunction.explicitParameters
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val value = parameterToNew[expression.descriptor] ?: return expression
val value = parameterToNew[expression.symbol] ?: return expression
return builder.at(expression).irGet(value)
}
@@ -118,8 +111,8 @@ private class BodyTransformer(
private fun IrBuilderWithScope.genTailCall(expression: IrCall) = this.irBlock(expression) {
// Get all specified arguments:
val parameterToArgument = expression.getArguments().map { (parameter, argument) ->
expression.descriptor.getOriginalParameter(parameter) to argument
val parameterToArgument = expression.getArgumentsWithSymbols().map { (parameter, argument) ->
parameter to argument
}
// For each specified argument set the corresponding variable to it in the correct order:
@@ -135,15 +128,24 @@ private class BodyTransformer(
// For each unspecified argument set the corresponding variable to default:
parameters.filter { it !in specifiedParameters }.forEach { parameter ->
val originalDefaultValue = irFunction.getDefaultArgumentExpression(parameter) ?:
val originalDefaultValue = parameter.owner.defaultValue?.expression ?:
throw Error("no argument specified for $parameter")
// Copy default value, mapping parameters to variables containing freshly computed arguments:
val defaultValue = originalDefaultValue.transform(object : DeepCopyIrTreeWithDeclarations() {
override fun mapValueReference(descriptor: ValueDescriptor): ValueDescriptor {
return parameterToVariable[descriptor]?.descriptor ?: super.mapValueReference(descriptor)
}
}, data = null)
val defaultValue = originalDefaultValue
.deepCopyWithVariables()
.transform(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val variableSymbol = parameterToVariable[expression.symbol] ?: return expression
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
variableSymbol, expression.origin
)
}
}, data = null)
+irSetVar(parameterToVariable[parameter]!!, defaultValue)
}
@@ -153,23 +155,9 @@ private class BodyTransformer(
}
}
private fun IrFunction.getDefaultArgumentExpression(parameter: ParameterDescriptor): IrExpression? {
if (parameter !is ValueParameterDescriptor) {
return null
}
val body = this.getDefault(parameter) ?: return null
if (body !is IrExpressionBody) {
throw Error("unexpected default argument body: $body")
}
return body.expression
}
private fun ParameterDescriptor.suggestVariableName(): String = if (name.isSpecial) {
val oldNameStr = name.asString()
private fun IrValueParameterSymbol.suggestVariableName(): String = if (descriptor.name.isSpecial) {
val oldNameStr = descriptor.name.asString()
"$" + oldNameStr.substring(1, oldNameStr.length - 1)
} else {
name.identifier
descriptor.name.identifier
}
@@ -32,15 +32,15 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -55,22 +55,34 @@ import java.util.*
import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty
internal class SpecialDescriptorsFactory(val context: Context) {
private val enumSpecialDescriptorsFactory by lazy { EnumSpecialDescriptorsFactory(context) }
private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>()
internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, FunctionDescriptor>()
private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>()
fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor =
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
fun getOuterThisField(innerClassDescriptor: ClassDescriptor): IrField =
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor")
else outerThisDescriptors.getOrPut(innerClassDescriptor) {
else outerThisFields.getOrPut(innerClassDescriptor) {
val outerClassDescriptor = DescriptorUtils.getContainingClass(innerClassDescriptor) ?:
throw AssertionError("No containing class for inner class $innerClassDescriptor")
val receiver = ReceiverParameterDescriptorImpl(innerClassDescriptor, ImplicitClassReceiver(innerClassDescriptor))
PropertyDescriptorImpl.create(innerClassDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
false, "this$0".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
val descriptor = PropertyDescriptorImpl.create(
innerClassDescriptor, Annotations.EMPTY, Modality.FINAL,
Visibilities.PRIVATE, false, "this$0".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE, false, false, false, false, false, false
).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
IrFieldImpl(
innerClassDescriptor.startOffsetOrUndefined,
innerClassDescriptor.endOffsetOrUndefined,
DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
descriptor
)
}
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
@@ -93,7 +105,7 @@ internal class SpecialDescriptorsFactory(val context: Context) {
fun getLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
assert(enumClassDescriptor.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: $enumClassDescriptor" })
return loweredEnums.getOrPut(enumClassDescriptor) {
enumSpecialDescriptorsFactory.createLoweredEnum(enumClassDescriptor)
enumSpecialDeclarationsFactory.createLoweredEnum(enumClassDescriptor)
}
}
@@ -219,7 +231,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
override val builtIns: KonanBuiltIns by lazy(PUBLICATION) { moduleDescriptor.builtIns as KonanBuiltIns }
val specialDescriptorsFactory = SpecialDescriptorsFactory(this)
val specialDeclarationsFactory = SpecialDeclarationsFactory(this)
val reflectionTypes: ReflectionTypes by lazy(PUBLICATION) { ReflectionTypes(moduleDescriptor) }
private val vtableBuilders = mutableMapOf<ClassDescriptor, ClassVtablesBuilder>()
@@ -233,6 +245,9 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
// to dump this information into generated file.
var serializedLinkData: LinkData? = null
@Deprecated("")
lateinit var psi2IrGeneratorContext: GeneratorContext
// TODO: make lateinit?
var irModule: IrModuleFragment? = null
set(module: IrModuleFragment?) {
@@ -244,7 +259,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
ir = Ir(this, module)
}
lateinit var ir: Ir
override lateinit var ir: Ir
override val irBuiltIns
get() = ir.irModule.irBuiltins
@@ -22,7 +22,13 @@ import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructorDe
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -32,19 +38,33 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.replace
internal data class LoweredEnum(val implObjectDescriptor: ClassDescriptor,
val valuesProperty: PropertyDescriptor,
val valuesGetter: FunctionDescriptor,
val itemGetter: FunctionDescriptor,
internal object DECLARATION_ORIGIN_ENUM :
IrDeclarationOriginImpl("ENUM")
internal data class LoweredEnum(val implObject: IrClass,
val valuesField: IrField,
val valuesGetter: IrSimpleFunction,
val itemGetterSymbol: IrFunctionSymbol,
val itemGetterDescriptor: FunctionDescriptor,
val entriesMap: Map<Name, Int>)
internal class EnumSpecialDescriptorsFactory(val context: Context) {
internal class EnumSpecialDeclarationsFactory(val context: Context) {
fun createLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
val startOffset = enumClassDescriptor.startOffsetOrUndefined
val endOffset = enumClassDescriptor.endOffsetOrUndefined
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL,
ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false)
val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor)
val valuesGetter = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty)
val valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
val valuesGetter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesGetterDescriptor).apply {
createParameterDeclarations()
}
val memberScope = MemberScope.Empty
@@ -53,9 +73,18 @@ internal class EnumSpecialDescriptorsFactory(val context: Context) {
val constructorDescriptor = implObjectDescriptor.createSimpleDelegatingConstructorDescriptor(constructorOfAny, true)
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply {
createParameterDeclarations()
}
return LoweredEnum(implObjectDescriptor, valuesProperty, valuesGetter,
getEnumItemGetter(enumClassDescriptor), createEnumEntriesMap(enumClassDescriptor))
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
return LoweredEnum(
implObject,
valuesField,
valuesGetter,
itemGetterSymbol, itemGetterDescriptor,
createEnumEntriesMap(enumClassDescriptor))
}
private fun createValuesGetterDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
@@ -87,15 +116,15 @@ internal class EnumSpecialDescriptorsFactory(val context: Context) {
}
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private val genericArrayType = context.ir.symbols.array.descriptor
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): FunctionDescriptor {
val getter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND).single()
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair<IrFunctionSymbol, FunctionDescriptor> {
val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val typeParameterT = genericArrayType.declaredTypeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
return getter.substitute(typeSubstitutor)!!
return getter to getter.descriptor.substitute(typeSubstitutor)!!
}
private fun createEnumEntriesMap(enumClassDescriptor: ClassDescriptor): Map<Name, Int> {
@@ -18,13 +18,16 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.konan.descriptors.KonanSharedVariablesManager
import org.jetbrains.kotlin.backend.konan.ir.Ir
abstract internal class KonanBackendContext(val config: KonanConfig) : BackendContext {
abstract override val builtIns: KonanBuiltIns
abstract val ir: Ir
override val sharedVariablesManager by lazy {
// Creating lazily because builtIns module seems to be incomplete during `link` test;
// TODO: investigate this.
KonanSharedVariablesManager(builtIns)
KonanSharedVariablesManager(this)
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.messageCollector
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex
import org.jetbrains.kotlin.backend.konan.ir.Symbols
import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializationUtil
import org.jetbrains.kotlin.backend.konan.serialization.markBackingFields
@@ -81,10 +82,15 @@ public fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEn
phaser.phase(KonanPhase.PSI_TO_IR) {
// Translate AST to high level IR.
val translator = Psi2IrTranslator(Psi2IrConfiguration(false))
val module = translator.generateModule(context.moduleDescriptor,
environment.getSourceFiles(), bindingContext)
val generatorContext = translator.createGeneratorContext(context.moduleDescriptor, bindingContext)
context.psi2IrGeneratorContext = generatorContext
val symbols = Symbols(context, generatorContext.symbolTable)
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles())
context.irModule = module
context.ir.symbols = symbols
validateIrModule(context, module)
}
@@ -20,8 +20,12 @@ import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.validateIrFile
import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.IrSymbolBindingChecker
import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols
import org.jetbrains.kotlin.ir.visitors.acceptVoid
internal class KonanLower(val context: Context) {
@@ -45,6 +49,8 @@ internal class KonanLower(val context: Context) {
// Inlining must be run before other phases.
phaser.phase(KonanPhase.LOWER_INLINE) {
FunctionInlining(context).inline(irModule)
irModule.replaceUnboundSymbols(context)
irModule.checkSymbolsBound()
}
}
@@ -53,24 +59,31 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_STRING_CONCAT) {
StringConcatenationLowering(context).lower(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
SharedVariablesLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_DELEGATION) {
PropertyDelegationLowering(context).lower(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_TAILREC) {
TailrecLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
}
phaser.phase(KonanPhase.LOWER_FINALLY) {
FinallyBlocksLowering(context).runOnFilePostfix(irFile)
@@ -112,4 +125,10 @@ internal class KonanLower(val context: Context) {
Autoboxing(context).lower(irFile)
}
}
private fun IrElement.checkSymbolsBound() {
if (context.shouldVerifyIr()) {
this.acceptVoid(IrSymbolBindingChecker())
}
}
}
@@ -18,12 +18,14 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -32,24 +34,33 @@ import org.jetbrains.kotlin.ir.expressions.IrSetVariable
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.types.*
internal class KonanSharedVariablesManager(val builtIns: KonanBuiltIns) : SharedVariablesManager {
internal class KonanSharedVariablesManager(val context: KonanBackendContext) : SharedVariablesManager {
private val refClass = builtIns.getKonanInternalClass("Ref")
private val refClass = context.ir.symbols.refClass
private val refClassConstructor = refClass.unsubstitutedPrimaryConstructor!!
private val refClassConstructor = refClass.constructors.single()
private val elementProperty = refClass.owner.declarations.filterIsInstance<IrProperty>().single()
// TODO: refactor `SharedVariablesManager` interface instead of tracking the mapping:
private val sharedVariableDescriptorToSymbol = mutableMapOf<VariableDescriptor, IrVariableSymbol>()
private fun refConstructor(elementType: KotlinType): ClassConstructorDescriptor {
val typeParameter = refClassConstructor.typeParameters[0]
val typeParameter = refClassConstructor.descriptor.typeParameters[0]
return refClassConstructor.substitute(TypeSubstitutor.create(
return refClassConstructor.descriptor.substitute(TypeSubstitutor.create(
mapOf(typeParameter.typeConstructor to TypeProjectionImpl(Variance.INVARIANT, elementType))
))!!
}
private fun refType(elementType: KotlinType): KotlinType {
return refClass.defaultType.replace(listOf(TypeProjectionImpl(elementType)))
return refClass.owner.defaultType.replace(listOf(TypeProjectionImpl(elementType)))
}
override fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor {
@@ -57,10 +68,12 @@ internal class KonanSharedVariablesManager(val builtIns: KonanBuiltIns) : Shared
variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name,
refType(variableDescriptor.type),
false, false, variableDescriptor.source
)
).also {
sharedVariableDescriptorToSymbol[it] = IrVariableSymbolImpl(it)
}
}
private fun getElementProperty(sharedVariableDescriptor: VariableDescriptor): PropertyDescriptor {
private fun getElementPropertyDescriptor(sharedVariableDescriptor: VariableDescriptor): PropertyDescriptor {
return sharedVariableDescriptor.type.memberScope.getContributedDescriptors()
.filterIsInstance<PropertyDescriptor>()
.single {
@@ -71,49 +84,62 @@ internal class KonanSharedVariablesManager(val builtIns: KonanBuiltIns) : Shared
override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor,
originalDeclaration: IrVariable): IrStatement {
val sharedVariableSymbol = sharedVariableDescriptorToSymbol[sharedVariableDescriptor]!!
val valueType = originalDeclaration.descriptor.type
val refConstructorTypeArguments = mapOf(refClassConstructor.typeParameters[0] to valueType)
val refConstructorTypeArguments = mapOf(refClassConstructor.descriptor.typeParameters[0] to valueType)
val refConstructorCall = IrCallImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset,
refConstructor(valueType), refConstructorTypeArguments
refClassConstructor, refConstructor(valueType), refConstructorTypeArguments
)
val sharedVariableDeclaration = IrVariableImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin,
sharedVariableDescriptor, refConstructorCall
)
sharedVariableSymbol
).apply {
initializer = refConstructorCall
}
val initializer = originalDeclaration.initializer ?:
return sharedVariableDeclaration
val elementProperty = getElementProperty(sharedVariableDescriptor)
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDescriptor)
val sharedVariableInitialization =
IrCallImpl(initializer.startOffset, initializer.endOffset, elementProperty.setter!!)
IrCallImpl(initializer.startOffset, initializer.endOffset, elementProperty.setter!!.symbol,
elementPropertyDescriptor.setter!!)
sharedVariableInitialization.dispatchReceiver =
IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDescriptor)
IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableSymbol)
sharedVariableInitialization.putValueArgument(0, initializer)
return IrCompositeImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, builtIns.unitType, null,
originalDeclaration.startOffset, originalDeclaration.endOffset, context.builtIns.unitType, null,
listOf(sharedVariableDeclaration, sharedVariableInitialization)
)
}
override fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression {
val elementProperty = getElementProperty(sharedVariableDescriptor)
return IrCallImpl(originalGet.startOffset, originalGet.endOffset, elementProperty.getter!!).apply {
dispatchReceiver = IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableDescriptor)
val sharedVariableSymbol = sharedVariableDescriptorToSymbol[sharedVariableDescriptor]!!
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDescriptor)
return IrCallImpl(originalGet.startOffset, originalGet.endOffset, elementProperty.getter!!.symbol,
elementPropertyDescriptor.getter!!).apply {
dispatchReceiver = IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableSymbol)
}
}
override fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression {
val elementProperty = getElementProperty(sharedVariableDescriptor)
return IrCallImpl(originalSet.startOffset, originalSet.endOffset, elementProperty.setter!!).apply {
dispatchReceiver = IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableDescriptor)
val sharedVariableSymbol = sharedVariableDescriptorToSymbol[sharedVariableDescriptor]!!
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDescriptor)
return IrCallImpl(originalSet.startOffset, originalSet.endOffset, elementProperty.setter!!.symbol,
elementPropertyDescriptor.setter!!).apply {
dispatchReceiver = IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableSymbol)
putValueArgument(0, originalSet.value)
}
}
@@ -17,10 +17,18 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.generators.SymbolTable
// This is what Context collects about IR.
internal class Ir(val context: Context, val irModule: IrModuleFragment) {
@@ -31,4 +39,63 @@ internal class Ir(val context: Context, val irModule: IrModuleFragment) {
val originalModuleIndex = ModuleIndex(irModule)
lateinit var moduleIndexForCodegen: ModuleIndex
lateinit var symbols: Symbols
}
internal class Symbols(val context: Context, val symbolTable: SymbolTable) {
val builtIns: KonanBuiltIns get() = context.builtIns
private fun builtInsPackage(vararg packageNameSegments: String) =
builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope
val refClass = symbolTable.referenceClass(builtIns.getKonanInternalClass("Ref"))
val areEqualByValue = builtIns.getKonanInternalFunctions("areEqualByValue").map {
symbolTable.referenceSimpleFunction(it)
}
val areEqual = symbolTable.referenceSimpleFunction(builtIns.getKonanInternalFunctions("areEqual").single())
val ThrowNullPointerException = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("ThrowNullPointerException").single())
val ThrowNoWhenBranchMatchedException = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("ThrowNoWhenBranchMatchedException").single())
val ThrowTypeCastException = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("ThrowTypeCastException").single())
val stringBuilder = symbolTable.referenceClass(
builtInsPackage("kotlin", "text").getContributedClassifier(
Name.identifier("StringBuilder"), NoLookupLocation.FROM_BACKEND
) as ClassDescriptor
)
val any = symbolTable.referenceClass(builtIns.any)
val arrayOf = symbolTable.referenceSimpleFunction(
builtInsPackage("kotlin").getContributedFunctions(
Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND
).single()
)
val array = symbolTable.referenceClass(builtIns.array)
val valuesForEnum = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("valuesForEnum").single())
val valueOfForEnum = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("valueOfForEnum").single())
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
val kMutableProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0Impl)
val kMutableProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1Impl)
val kMutableProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2Impl)
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
}
@@ -20,17 +20,16 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -91,30 +90,38 @@ internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superCo
return constructorDescriptor
}
internal fun ClassDescriptor.createSimpleDelegatingConstructor(superConstructorDescriptor: ClassConstructorDescriptor,
constructorDescriptor: ClassConstructorDescriptor,
startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin)
internal fun IrClass.addSimpleDelegatingConstructor(superConstructorSymbol: IrConstructorSymbol,
constructorDescriptor: ClassConstructorDescriptor,
origin: IrDeclarationOrigin)
: IrConstructor {
val body = IrBlockBodyImpl(startOffset, endOffset,
listOf(
IrDelegatingConstructorCallImpl(startOffset, endOffset, superConstructorDescriptor).apply {
constructorDescriptor.valueParameters.forEachIndexed { idx, parameter ->
putValueArgument(idx, IrGetValueImpl(startOffset, endOffset, parameter))
}
},
IrInstanceInitializerCallImpl(startOffset, endOffset, this)
)
)
return IrConstructorImpl(startOffset, endOffset, origin, constructorDescriptor, body).apply {
createParameterDeclarations()
return IrConstructorImpl(startOffset, endOffset, origin, constructorDescriptor).also { constructor ->
constructor.createParameterDeclarations()
constructor.body = IrBlockBodyImpl(startOffset, endOffset,
listOf(
IrDelegatingConstructorCallImpl(
startOffset, endOffset,
superConstructorSymbol, superConstructorSymbol.descriptor
).apply {
constructor.valueParameters.forEachIndexed { idx, parameter ->
putValueArgument(idx, IrGetValueImpl(startOffset, endOffset, parameter.symbol))
}
},
IrInstanceInitializerCallImpl(startOffset, endOffset, this.symbol)
)
)
this.declarations.add(constructor)
}
}
internal fun Context.createArrayOfExpression(arrayElementType: KotlinType,
arrayElements: List<IrExpression>,
startOffset: Int, endOffset: Int): IrExpression {
val kotlinPackage = irModule!!.descriptor.getPackage(FqName("kotlin"))
val genericArrayOfFun = kotlinPackage.memberScope.getContributedFunctions(Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND).first()
val genericArrayOfFunSymbol = ir.symbols.arrayOf
val genericArrayOfFun = genericArrayOfFunSymbol.descriptor
val typeParameter0 = genericArrayOfFun.typeParameters[0]
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
@@ -126,7 +133,7 @@ internal fun Context.createArrayOfExpression(arrayElementType: KotlinType,
val arg0VarargElementType = valueParameter0.varargElementType!!
val arg0 = IrVarargImpl(startOffset, endOffset, arg0VarargType, arg0VarargElementType, arrayElements)
return IrCallImpl(startOffset, endOffset, substitutedArrayOfFun, typeArguments).apply {
return IrCallImpl(startOffset, endOffset, genericArrayOfFunSymbol, substitutedArrayOfFun, typeArguments).apply {
putValueArgument(0, arg0)
}
}
@@ -16,33 +16,55 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
//-----------------------------------------------------------------------------//
interface IrReturnableBlock: IrBlock {
val descriptor: CallableDescriptor
interface IrReturnableBlockSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrReturnableBlock>
interface IrReturnableBlock: IrBlock, IrSymbolOwner {
override val symbol: IrReturnableBlockSymbol
val descriptor: FunctionDescriptor
}
class IrReturnableBlockSymbolImpl(descriptor: FunctionDescriptor) :
IrBindableSymbolBase<FunctionDescriptor, IrReturnableBlock>(descriptor),
IrReturnableBlockSymbol
class IrReturnableBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType,
override val descriptor: CallableDescriptor, origin: IrStatementOrigin? = null)
override val symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin? = null)
: IrContainerExpressionBase(startOffset, endOffset, type, origin), IrReturnableBlock {
override val descriptor = symbol.descriptor
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
descriptor: CallableDescriptor, origin: IrStatementOrigin?, statements: List<IrStatement>) :
descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null) :
this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin)
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
descriptor: FunctionDescriptor, origin: IrStatementOrigin?, statements: List<IrStatement>) :
this(startOffset, endOffset, type, descriptor, origin) {
this.statements.addAll(statements)
}
init {
symbol.bind(this)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitBlock(this, data)
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
@@ -191,6 +190,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
} else {
descriptor
}
return context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
return context.specialDeclarationsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
}
}
@@ -112,7 +112,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
val bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor)
val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val target = descriptor.descriptor.target
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target,
@@ -19,17 +19,15 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys.Companion.ENABLE_ASSERTIONS
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.util.type
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -89,17 +87,17 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
return when (descriptor) {
irBuiltins.eqeq -> {
val binary = expression as IrBinaryPrimitiveImpl
lowerEqeq(binary.argument0, binary.argument1, expression.startOffset, expression.endOffset)
lowerEqeq(expression.getValueArgument(0)!!, expression.getValueArgument(1)!!,
expression.startOffset, expression.endOffset)
}
irBuiltins.eqeqeq -> lowerEqeqeq(expression)
irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset,
builtIns.getKonanInternalFunctions("ThrowNullPointerException").single())
context.ir.symbols.ThrowNullPointerException)
irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset,
builtIns.getKonanInternalFunctions("ThrowNoWhenBranchMatchedException").single())
context.ir.symbols.ThrowNoWhenBranchMatchedException)
else -> expression
}
@@ -129,29 +127,30 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
}
}
private fun selectEqualsFunction(lhs: IrExpression, rhs: IrExpression): FunctionDescriptor {
private fun selectEqualsFunction(lhs: IrExpression, rhs: IrExpression): IrSimpleFunctionSymbol {
val nullableNothingType = builtIns.nullableNothingType
if (lhs.type.isSubtypeOf(nullableNothingType) && rhs.type.isSubtypeOf(nullableNothingType)) {
// Compare by reference if each part is either `Nothing` or `Nothing?`:
return irBuiltins.eqeqeq
return irBuiltins.eqeqeqSymbol
}
// TODO: areEqualByValue intrinsics are specially treated by code generator
// and thus can be declared synthetically in the compiler instead of explicitly in the runtime.
// Find a type-compatible `konan.internal.areEqualByValue` intrinsic:
builtIns.getKonanInternalFunctions("areEqualByValue").atMostOne {
lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type)
context.ir.symbols.areEqualByValue.atMostOne {
lhs.type.isSubtypeOf(it.owner.valueParameters[0].type) &&
rhs.type.isSubtypeOf(it.owner.valueParameters[1].type)
}?.let {
return it
}
return if (lhs.isNullConst() || rhs.isNullConst()) {
// or compare by reference if left or right part is `null`:
irBuiltins.eqeqeq
irBuiltins.eqeqeqSymbol
} else {
// or use the general implementation:
builtIns.getKonanInternalFunctions("areEqual").single()
context.ir.symbols.areEqual
}
}
}
@@ -33,10 +33,12 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrCallableReference
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -48,39 +50,48 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private fun getKPropertyImplConstructorDescriptor(receiverTypes: List<KotlinType>,
returnType: KotlinType,
isLocal: Boolean,
isMutable: Boolean) : ClassConstructorDescriptor {
val classDescriptor =
private fun getKPropertyImplConstructor(receiverTypes: List<KotlinType>,
returnType: KotlinType,
isLocal: Boolean,
isMutable: Boolean) : Pair<IrConstructorSymbol, ClassConstructorDescriptor> {
val symbols = context.ir.symbols
val classSymbol =
if (isLocal) {
assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" })
when {
isMutable -> reflectionTypes.kLocalDelegatedMutablePropertyImpl
else -> reflectionTypes.kLocalDelegatedPropertyImpl
isMutable -> symbols.kLocalDelegatedMutablePropertyImpl
else -> symbols.kLocalDelegatedPropertyImpl
}
} else {
when (receiverTypes.size) {
0 -> when {
isMutable -> reflectionTypes.kMutableProperty0Impl
else -> reflectionTypes.kProperty0Impl
isMutable -> symbols.kMutableProperty0Impl
else -> symbols.kProperty0Impl
}
1 -> when {
isMutable -> reflectionTypes.kMutableProperty1Impl
else -> reflectionTypes.kProperty1Impl
isMutable -> symbols.kMutableProperty1Impl
else -> symbols.kProperty1Impl
}
2 -> when {
isMutable -> reflectionTypes.kMutableProperty2Impl
else -> reflectionTypes.kProperty2Impl
isMutable -> symbols.kMutableProperty2Impl
else -> symbols.kProperty2Impl
}
else -> throw AssertionError("More than 2 receivers is not allowed")
}
}
val classDescriptor = classSymbol.descriptor
val typeParameters = classDescriptor.declaredTypeParameters
val arguments = (receiverTypes + listOf(returnType))
.mapIndexed { index, type -> typeParameters[index].typeConstructor to TypeProjectionImpl(type) }
.toMap()
return classDescriptor.unsubstitutedPrimaryConstructor!!.substitute(TypeSubstitutor.create(arguments))!!
val constructorSymbol = classSymbol.constructors.single()
return constructorSymbol to constructorSymbol.descriptor.substitute(TypeSubstitutor.create(arguments))!!
}
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
@@ -90,14 +101,21 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
override fun lower(irFile: IrFile) {
val kProperties = mutableMapOf<VariableDescriptorWithAccessors, Pair<IrExpression, Int>>()
val arrayItemGetter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"),
NoLookupLocation.FROM_BACKEND).single()
val arrayClass = context.ir.symbols.array
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") }
val typeParameterT = genericArrayType.declaredTypeParameters[0]
val kPropertyImplType = reflectionTypes.kProperty1Impl.replace(context.builtIns.anyType, context.builtIns.anyType)
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType)))
val substitutedArrayItemGetter = arrayItemGetter.substitute(typeSubstitutor)!!
val substitutedArrayItemGetter = arrayItemGetter.descriptor.substitute(typeSubstitutor)!!
val kPropertiesField = createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, genericArrayType.replace(kPropertyImplType))
val kPropertiesField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor,
genericArrayType.replace(kPropertyImplType)
)
)
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitFunction(declaration: IrFunction): IrStatement {
@@ -120,22 +138,52 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
}
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
expression.transformChildrenVoid(this)
val propertyDescriptor = expression.descriptor as? VariableDescriptorWithAccessors
if (propertyDescriptor == null) return expression
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
if (receiversCount == 1 && propertyDescriptor is PropertyDescriptor) // Has receiver and is not local delegated.
return createKProperty(expression, propertyDescriptor)
if (receiversCount == 1) // Has receiver.
return createKProperty(expression)
else if (receiversCount == 2)
throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor")
throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
else { // Cache KProperties with no arguments.
val field = kProperties.getOrPut(propertyDescriptor) {
createKProperty(expression, propertyDescriptor) to kProperties.size
val field = kProperties.getOrPut(expression.descriptor) {
createKProperty(expression) to kProperties.size
}
return IrCallImpl(expression.startOffset, expression.endOffset, substitutedArrayItemGetter).apply {
dispatchReceiver = IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField)
return IrCallImpl(
expression.startOffset, expression.endOffset,
arrayItemGetter, substitutedArrayItemGetter
).apply {
dispatchReceiver =
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
}
}
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
expression.transformChildrenVoid(this)
val propertyDescriptor = expression.descriptor
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
if (receiversCount == 2)
throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor")
else { // Cache KProperties with no arguments.
// TODO: what about `receiversCount == 1` case?
val field = kProperties.getOrPut(propertyDescriptor) {
createLocalKProperty(expression, propertyDescriptor) to kProperties.size
}
return IrCallImpl(
expression.startOffset, expression.endOffset,
arrayItemGetter, substitutedArrayItemGetter
).apply {
dispatchReceiver =
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
}
}
@@ -146,66 +194,68 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
if (kProperties.isNotEmpty()) {
val initializers = kProperties.values.sortedBy { it.second }.map { it.first }
// TODO: move to object for lazy initialization.
irFile.declarations.add(0, IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
kPropertiesField,
IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.createArrayOfExpression(kPropertyImplType, initializers, UNDEFINED_OFFSET, UNDEFINED_OFFSET))))
irFile.declarations.add(0, kPropertiesField.apply {
initializer = IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.createArrayOfExpression(kPropertyImplType, initializers, UNDEFINED_OFFSET, UNDEFINED_OFFSET))
})
}
}
private fun createKProperty(expression: IrCallableReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
private fun createKProperty(expression: IrPropertyReference): IrCallImpl {
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val receiverTypes = mutableListOf<KotlinType>()
val isLocal = propertyDescriptor !is PropertyDescriptor
val propertyDescriptor = expression.descriptor
val returnType = propertyDescriptor.type
val getterCallableReference = propertyDescriptor.getter.let {
if (it == null || isLocal) null
else {
val getter = propertyDescriptor.getter!!
getter.extensionReceiverParameter.let {
if (it != null && expression.extensionReceiver == null)
receiverTypes.add(it.type)
}
getter.dispatchReceiverParameter.let {
if (it != null && expression.dispatchReceiver == null)
receiverTypes.add(it.type)
}
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY,
receiverType = receiverTypes.firstOrNull(),
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
returnType = returnType)
IrFunctionReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
}
val getterCallableReference = propertyDescriptor.getter?.let { getter ->
getter.extensionReceiverParameter.let {
if (it != null && expression.extensionReceiver == null)
receiverTypes.add(it.type)
}
getter.dispatchReceiverParameter.let {
if (it != null && expression.dispatchReceiver == null)
receiverTypes.add(it.type)
}
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY,
receiverType = receiverTypes.firstOrNull(),
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
returnType = returnType)
IrFunctionReferenceImpl(
startOffset, endOffset,
getterKFunctionType, expression.getter!!, getter, null
).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
}
}
val setterCallableReference = propertyDescriptor.setter.let {
if (it == null || isLocal || !isKMutablePropertyType(expression.type)) null
val setterCallableReference = propertyDescriptor.setter?.let {
if (!isKMutablePropertyType(expression.type)) null
else {
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY,
receiverType = receiverTypes.firstOrNull(),
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType),
returnType = context.builtIns.unitType)
IrFunctionReferenceImpl(startOffset, endOffset, setterKFunctionType, it, null).apply {
IrFunctionReferenceImpl(
startOffset, endOffset,
setterKFunctionType, expression.setter!!, it, null
).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
}
}
}
val descriptor = getKPropertyImplConstructorDescriptor(
val (symbol, descriptor) = getKPropertyImplConstructor(
receiverTypes = receiverTypes,
returnType = returnType,
isLocal = isLocal,
isLocal = false,
isMutable = setterCallableReference != null)
val initializer = IrCallImpl(startOffset, endOffset, descriptor).apply {
val initializer = IrCallImpl(startOffset, endOffset, symbol, descriptor).apply {
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
if (getterCallableReference != null)
@@ -216,6 +266,25 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
return initializer
}
private fun createLocalKProperty(expression: IrLocalDelegatedPropertyReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val returnType = propertyDescriptor.type
val (symbol, descriptor) = getKPropertyImplConstructor(
receiverTypes = emptyList(),
returnType = returnType,
isLocal = true,
isMutable = false)
val initializer = IrCallImpl(startOffset, endOffset, symbol, descriptor).apply {
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
}
return initializer
}
private fun isKMutablePropertyType(type: KotlinType): Boolean {
val arguments = type.arguments
val expectedClassDescriptor = when (arguments.size) {
@@ -22,26 +22,23 @@ import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.konan.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.konan.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructorDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.transform
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -53,43 +50,47 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
fun buildValuesExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor): IrExpression {
val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(enumClassDescriptor)
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val typeParameterT = genericValuesDescriptor.typeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
val substitutedValueOf = genericValuesDescriptor.substitute(typeSubstitutor)!!
return IrCallImpl(startOffset, endOffset, substitutedValueOf, mapOf(typeParameterT to enumClassType))
return IrCallImpl(startOffset, endOffset,
genericValuesSymbol, substitutedValueOf, mapOf(typeParameterT to enumClassType))
.apply {
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
putValueArgument(0, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesProperty, receiver))
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
putValueArgument(0, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver))
}
}
fun buildValueOfExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor,
value: IrExpression): IrExpression {
val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(enumClassDescriptor)
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val typeParameterT = genericValueOfDescriptor.typeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
val substitutedValueOf = genericValueOfDescriptor.substitute(typeSubstitutor)!!
return IrCallImpl(startOffset, endOffset, substitutedValueOf, mapOf(typeParameterT to enumClassType))
return IrCallImpl(startOffset, endOffset,
genericValueOfSymbol, substitutedValueOf, mapOf(typeParameterT to enumClassType))
.apply {
putValueArgument(0, value)
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
putValueArgument(1, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesProperty, receiver))
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
putValueArgument(1, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver))
}
}
private val genericValueOfDescriptor = context.builtIns.getKonanInternalFunctions("valueOfForEnum").single()
private val genericValueOfSymbol = context.ir.symbols.valueOfForEnum
private val genericValueOfDescriptor = genericValueOfSymbol.descriptor
private val genericValuesDescriptor = context.builtIns.getKonanInternalFunctions("valuesForEnum").single()
private val genericValuesSymbol = context.ir.symbols.valuesForEnum
private val genericValuesDescriptor = genericValuesSymbol.descriptor
}
internal class EnumUsageLowering(val context: Context)
@@ -142,10 +143,10 @@ internal class EnumUsageLowering(val context: Context)
Name.identifier("enumValues"), NoLookupLocation.FROM_BACKEND).single()
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClassDescriptor: ClassDescriptor, name: Name): IrExpression {
val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(enumClassDescriptor)
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val ordinal = loweredEnum.entriesMap[name]!!
return IrCallImpl(startOffset, endOffset, loweredEnum.itemGetter).apply {
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter)
return IrCallImpl(startOffset, endOffset, loweredEnum.itemGetterSymbol, loweredEnum.itemGetterDescriptor).apply {
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, enumClassDescriptor.module.builtIns.intType, ordinal))
}
}
@@ -169,11 +170,11 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private inner class EnumClassTransformer(val irClass: IrClass) {
private val loweredEnum = context.specialDescriptorsFactory.getLoweredEnum(irClass.descriptor)
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass.descriptor)
private val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>()
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, ClassConstructorDescriptor>()
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, ClassConstructorDescriptor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val loweredEnumConstructorParameters = mutableMapOf<ValueParameterDescriptor, ValueParameterDescriptor>()
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
@@ -205,7 +206,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.descriptor))
irClass.symbol))
else null
}
}
@@ -254,21 +255,21 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val constructors = mutableSetOf<ClassConstructorDescriptor>()
descriptor.constructors.forEach {
val loweredEnumConstructor = loweredEnumConstructors[it]!!
val loweredEnumConstructorSymbol = loweredEnumConstructors[it]!!.symbol
val loweredEnumConstructor = loweredEnumConstructorSymbol.descriptor
val constructorDescriptor = defaultClassDescriptor.createSimpleDelegatingConstructorDescriptor(loweredEnumConstructor)
val constructor = defaultClassDescriptor.createSimpleDelegatingConstructor(
loweredEnumConstructor, constructorDescriptor,
startOffset, endOffset, DECLARATION_ORIGIN_ENUM)
val constructor = defaultClass.addSimpleDelegatingConstructor(
loweredEnumConstructorSymbol, constructorDescriptor,
DECLARATION_ORIGIN_ENUM)
constructors.add(constructorDescriptor)
defaultClass.declarations.add(constructor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor)
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
if (irConstructor != null) {
it.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val loweredArgument = loweredEnumConstructor.valueParameters[argument.loweredIndex()]
val body = irConstructor.getDefault(loweredArgument)!!
body.transformChildrenVoid(ParameterMapper(constructorDescriptor))
body.transformChildrenVoid(ParameterMapper(constructor))
constructor.putDefault(constructorDescriptor.valueParameters[loweredArgument.index], body)
}
}
@@ -285,12 +286,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private fun createImplObject() {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val implObjectDescriptor = loweredEnum.implObjectDescriptor
val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor)
implObject.createParameterDeclarations()
val implObject = loweredEnum.implObject
val enumEntries = mutableListOf<IrEnumEntry>()
var i = 0
@@ -307,9 +303,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
if (body is IrSyntheticBody) {
when (body.kind) {
IrSyntheticBodyKind.ENUM_VALUEOF ->
declaration.body = createSyntheticValueOfMethodBody(declaration.descriptor)
declaration.body = createSyntheticValueOfMethodBody(declaration)
IrSyntheticBodyKind.ENUM_VALUES ->
declaration.body = createSyntheticValuesMethodBody(declaration.descriptor)
declaration.body = createSyntheticValuesMethodBody(declaration)
}
}
}
@@ -320,12 +316,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
++i
}
val constructorOfAny = irClass.descriptor.module.builtIns.any.constructors.first()
val constructor = implObjectDescriptor.createSimpleDelegatingConstructor(
constructorOfAny, implObjectDescriptor.constructors.single(),
startOffset, endOffset, DECLARATION_ORIGIN_ENUM)
val constructorOfAny = context.ir.symbols.any.constructors.single()
implObject.addSimpleDelegatingConstructor(
constructorOfAny, implObject.descriptor.constructors.single(),
DECLARATION_ORIGIN_ENUM)
implObject.declarations.add(constructor)
implObject.declarations.add(createSyntheticValuesPropertyDeclaration(enumEntries))
irClass.declarations.add(implObject)
@@ -337,47 +333,42 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType,
enumEntries.sortedBy { it.descriptor.name }.map { it.initializerExpression!! }, startOffset, endOffset)
val irField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
loweredEnum.valuesProperty,
IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer))
val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
}
val getter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.valuesGetter)
getter.createParameterDeclarations()
val getter = loweredEnum.valuesGetter
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObjectDescriptor.defaultType, loweredEnum.implObjectDescriptor)
val value = IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesProperty, receiver)
val returnStatement = IrReturnImpl(startOffset, endOffset, loweredEnum.valuesGetter, value)
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
val value = IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver)
val returnStatement = IrReturnImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol, value)
getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
val irProperty = IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
false, loweredEnum.valuesProperty, irField, getter, null)
false, loweredEnum.valuesField.descriptor, irField, getter, null)
return irProperty
}
private object DECLARATION_ORIGIN_ENUM :
IrDeclarationOriginImpl("ENUM")
private fun createSyntheticValuesMethodBody(descriptor: FunctionDescriptor): IrBody {
private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val valuesExpression = enumSyntheticFunctionsBuilder.buildValuesExpression(startOffset, endOffset, irClass.descriptor)
return IrBlockBodyImpl(startOffset, endOffset,
listOf(IrReturnImpl(startOffset, endOffset, descriptor, valuesExpression))
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valuesExpression))
)
}
private fun createSyntheticValueOfMethodBody(descriptor: FunctionDescriptor): IrBody {
private fun createSyntheticValueOfMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val value = IrGetValueImpl(startOffset, endOffset, descriptor.valueParameters[0])
val value = IrGetValueImpl(startOffset, endOffset, declaration.valueParameters[0].symbol)
val valueOfExpression = enumSyntheticFunctionsBuilder.buildValueOfExpression(startOffset, endOffset, irClass.descriptor, value)
return IrBlockBodyImpl(
startOffset, endOffset,
listOf(IrReturnImpl(startOffset, endOffset, descriptor, valueOfExpression))
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valueOfExpression))
)
}
@@ -397,11 +388,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
enumConstructor.body!! // will be transformed later
)
loweredEnumConstructors[constructorDescriptor] = loweredEnumConstructor
loweredEnumConstructor.createParameterDeclarations()
enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach {
val body = enumConstructor.getDefault(it)!!
body.transformChildrenVoid(ParameterMapper(constructorDescriptor))
body.transformChildrenVoid(ParameterMapper(enumConstructor))
loweredEnumConstructor.putDefault(loweredConstructorDescriptor.valueParameters[it.loweredIndex()], body)
descriptorToIrConstructorWithDefaultArguments[loweredConstructorDescriptor] = loweredEnumConstructor
}
@@ -428,8 +421,6 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
loweredConstructorDescriptor.returnType = constructorDescriptor.returnType
loweredEnumConstructors[constructorDescriptor] = loweredConstructorDescriptor
return loweredConstructorDescriptor
}
@@ -450,14 +441,15 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
irClass.transformChildrenVoid(EnumClassBodyTransformer())
}
private inner class InEnumClassConstructor(val enumClassConstructor: ClassConstructorDescriptor) :
private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) :
EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, enumConstructorCall.descriptor)
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
enumConstructorCall.symbol, enumConstructorCall.descriptor)
assert(result.descriptor.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}"
@@ -471,8 +463,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor")
}
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, nameParameter, origin))
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, ordinalParameter, origin))
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, nameParameter.symbol, origin))
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, ordinalParameter.symbol, origin))
return result
}
@@ -486,10 +478,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
}
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredDelegatedConstructor)
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor)
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[0]))
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[1]))
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[0].symbol))
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[1].symbol))
descriptor.valueParameters.forEach { valueParameter ->
result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(valueParameter))
@@ -512,7 +507,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
}
val result = createConstructorCall(startOffset, endOffset, loweredConstructor)
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
result.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, name))
result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, ordinal))
@@ -529,17 +524,19 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("Unexpected delegating constructor call within enum entry: $enumEntry")
}
abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: ClassConstructorDescriptor): IrMemberAccessExpression
abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression
}
private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: ClassConstructorDescriptor)
= IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredConstructor)
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol)
= IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredConstructor, loweredConstructor.descriptor)
}
private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: ClassConstructorDescriptor)
= IrCallImpl(startOffset, endOffset, defaultEnumEntryConstructors[loweredConstructor] ?: loweredConstructor)
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
return IrCallImpl(startOffset, endOffset,
defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol ?: loweredConstructor)
}
}
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() {
@@ -571,7 +568,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
enumConstructorCallTransformer = InEnumEntryClassConstructor(containingClass)
} else if (containingClass.kind == ClassKind.ENUM_CLASS) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumClassConstructor(constructorDescriptor)
enumConstructorCallTransformer = InEnumClassConstructor(declaration)
}
val result = super.visitConstructor(declaration)
@@ -605,10 +602,15 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val loweredParameter = loweredEnumConstructorParameters[expression.descriptor]
if (loweredParameter != null)
return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter, expression.origin)
else
if (loweredParameter != null) {
val loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!!
val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index]
assert(loweredIrParameter.descriptor == loweredParameter)
return IrGetValueImpl(expression.startOffset, expression.endOffset,
loweredIrParameter.symbol, expression.origin)
} else {
return expression
}
}
}
}
@@ -616,14 +618,14 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2
private class ParameterMapper(val originalDescriptor: FunctionDescriptor) : IrElementTransformerVoid() {
private class ParameterMapper(val originalConstructor: IrConstructor) : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
when (descriptor) {
is ValueParameterDescriptor -> {
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
originalDescriptor.valueParameters[descriptor.index])
originalConstructor.valueParameters[descriptor.index].symbol)
}
}
return expression
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
@@ -204,17 +205,21 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
name = Name.identifier("t"),
outType = context.builtIns.throwable.defaultType
)
val catchParameter = IrVariableImpl(
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter)
val syntheticTry = IrTryImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.nothingType,
tryResult = transformedTry,
catches = listOf(
irCatch(parameter,
irBlock {
irCatch(catchParameter).apply {
result = irBlock {
+finallyExpression.copy()
+irThrow(irGet(parameter))
})),
+irThrow(irGet(catchParameter.symbol))
}
}),
finallyExpression = null
)
using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
@@ -243,22 +248,15 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
+finallyExpression.copy()
}
else -> irBlock(value, null, returnType) {
val tmp = IrTemporaryVariableDescriptorImpl(
functionDescriptor,
"tmp${tempIndex++}".synthesizedName,
returnType
)
+irVar(tmp, irReturnableBlock(descriptor) {
val tmp = irTemporary(irReturnableBlock(descriptor) {
+irReturn(descriptor, value)
})
+finallyExpression.copy()
+irGet(tmp)
+irGet(tmp.symbol)
}
}
}
private var tempIndex = 0
private fun getFakeFunctionDescriptor(name: String, returnType: KotlinType): FunctionDescriptor {
return SimpleFunctionDescriptorImpl.create(
functionDescriptor,
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -46,8 +47,8 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
fun lowerInitializers() {
collectAndRemoveInitializers()
val initializerMethodDescriptor = createInitializerMethod()
lowerConstructors(initializerMethodDescriptor)
val initializerMethodSymbol = createInitializerMethod()
lowerConstructors(initializerMethodSymbol)
}
object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER :
@@ -72,13 +73,12 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
override fun visitField(declaration: IrField): IrStatement {
val initializer = declaration.initializer ?: return declaration
val propertyDescriptor = declaration.descriptor
val startOffset = initializer.startOffset
val endOffset = initializer.endOffset
initializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
listOf(
IrSetFieldImpl(startOffset, endOffset, propertyDescriptor,
IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter),
IrSetFieldImpl(startOffset, endOffset, declaration.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
declaration.initializer = null
return declaration
@@ -92,7 +92,7 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
}
}
private fun createInitializerMethod(): FunctionDescriptor? {
private fun createInitializerMethod(): IrSimpleFunctionSymbol? {
if (irClass.descriptor.hasPrimaryConstructor())
return null // Place initializers in the primary constructor.
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
@@ -118,10 +118,10 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
irClass.declarations.add(initializer)
return initializerMethodDescriptor
return initializer.symbol
}
private fun lowerConstructors(initializerMethodDescriptor: FunctionDescriptor?) {
private fun lowerConstructors(initializerMethodSymbol: IrSimpleFunctionSymbol?) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
@@ -135,14 +135,14 @@ internal class InitializersLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.transformFlat {
when {
it is IrInstanceInitializerCall -> {
if (initializerMethodDescriptor == null) {
if (initializerMethodSymbol == null) {
assert(declaration.descriptor.isPrimary)
initializers
} else {
val startOffset = it.startOffset
val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset, initializerMethodDescriptor).apply {
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter)
listOf(IrCallImpl(startOffset, endOffset, initializerMethodSymbol).apply {
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol)
})
}
}
@@ -23,14 +23,14 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -44,7 +44,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
private inner class InnerClassTransformer(val irClass: IrClass) {
val classDescriptor = irClass.descriptor
lateinit var outerThisFieldDescriptor: PropertyDescriptor
lateinit var outerThisFieldSymbol: IrFieldSymbol
fun lowerInnerClass() {
if (!irClass.descriptor.isInner) return
@@ -54,17 +54,10 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
lowerConstructors()
}
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
private fun createOuterThisField() {
outerThisFieldDescriptor = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(classDescriptor)
irClass.declarations.add(IrFieldImpl(
irClass.startOffset, irClass.endOffset,
DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
outerThisFieldDescriptor
))
val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor)
outerThisFieldSymbol = field.symbol
irClass.declarations.add(field)
}
private fun lowerConstructors() {
@@ -86,9 +79,9 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.add(
0,
IrSetFieldImpl(
startOffset, endOffset, outerThisFieldDescriptor,
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
IrGetValueImpl(startOffset, endOffset, irConstructor.descriptor.dispatchReceiverParameter!!)
startOffset, endOffset, outerThisFieldSymbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
IrGetValueImpl(startOffset, endOffset, irConstructor.dispatchReceiverParameter!!.symbol)
)
)
}
@@ -106,7 +99,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
if (implicitThisClass == classDescriptor) return expression
val constructorDescriptor = currentFunction!!.scope.scopeOwner as? ConstructorDescriptor
val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol
val startOffset = expression.startOffset
val endOffset = expression.endOffset
@@ -114,14 +107,15 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
var irThis: IrExpression
var innerClass: ClassDescriptor
if (constructorDescriptor == null || constructorDescriptor.constructedClass != classDescriptor) {
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) {
innerClass = classDescriptor
irThis = IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter, origin)
irThis = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin)
} else {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?:
throw AssertionError("No containing class for inner class $classDescriptor")
irThis = IrGetValueImpl(startOffset, endOffset, constructorDescriptor.dispatchReceiverParameter!!, origin)
irThis = IrGetValueImpl(startOffset, endOffset,
constructorSymbol.owner.dispatchReceiverParameter!!.symbol, origin)
}
while (innerClass != implicitThisClass) {
@@ -131,8 +125,8 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
return expression
}
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
val outerThisField = context.specialDeclarationsFactory.getOuterThisField(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, irThis, origin)
val outer = innerClass.containingDeclaration
innerClass = outer as? ClassDescriptor ?:
@@ -18,23 +18,21 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.signature2Descriptor
import org.jetbrains.kotlin.ir.builders.irLetSequence
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSymbolDeclaration
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.type
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
@@ -57,30 +55,36 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower
private val typesWithSpecialAppendFunction =
PrimitiveType.values().map { builtIns.getPrimitiveKotlinType(it) } + builtIns.stringType
private val kotlinTextFqName = FqName.fromSegments(listOf("kotlin", "text"))
private val nameToString = Name.identifier("toString")
private val nameStringBuilder = Name.identifier("StringBuilder")
private val nameAppend = Name.identifier("append")
private val classStringBuilder = builtIns.builtInsModule.getPackage(kotlinTextFqName).
memberScope.getContributedClassifier(nameStringBuilder,
NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private val stringBuilder = context.ir.symbols.stringBuilder
//TODO: calculate and pass string length to the constructor.
private val constructor = classStringBuilder.constructors.firstOrNull {
it.valueParameters.size == 0
}!!
private val constructor = stringBuilder.constructors.single {
it.owner.valueParameters.size == 0
}
private val toStringFunction = classStringBuilder.signature2Descriptor(nameToString)!!
private val defaultAppendFunction =
classStringBuilder.signature2Descriptor(nameAppend, arrayOf(builtIns.nullableAnyType))!!
private val toStringFunction = stringBuilder.functions.single {
it.owner.valueParameters.size == 0 && it.descriptor.name == nameToString
}
private val defaultAppendFunction = stringBuilder.functions.single {
it.descriptor.name == nameAppend &&
it.owner.valueParameters.size == 1 &&
it.owner.valueParameters.single().type == builtIns.nullableAnyType
}
private val appendFunctions: Map<KotlinType, FunctionDescriptor?> =
typesWithSpecialAppendFunction.map {
it to classStringBuilder.signature2Descriptor(nameAppend, arrayOf(it))
private val appendFunctions: Map<KotlinType, IrFunctionSymbol?> =
typesWithSpecialAppendFunction.map { type ->
type to stringBuilder.functions.toList().atMostOne {
it.descriptor.name == nameAppend &&
it.owner.valueParameters.size == 1 &&
it.owner.valueParameters.single().type == type
}
}.toMap()
private fun typeToAppendFunction(type : KotlinType) : FunctionDescriptor {
private fun typeToAppendFunction(type : KotlinType) : IrFunctionSymbol {
return appendFunctions[type]?:defaultAppendFunction
}
@@ -89,11 +93,8 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower
expression.transformChildrenVoid(this)
val blockBuilder = buildersStack.last()
return blockBuilder.irLetSequence(
value = blockBuilder.irCall(constructor),
startOffset = expression.startOffset,
endOffset = expression.endOffset,
resultType = expression.type) { stringBuilderImpl ->
return blockBuilder.irBlock(expression) {
val stringBuilderImpl = irTemporary(irCall(constructor)).symbol
expression.arguments.forEach { arg ->
val appendFunction = typeToAppendFunction(arg.type)
+irCall(appendFunction).apply {
@@ -19,9 +19,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -29,6 +27,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
@@ -42,19 +41,17 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
*/
internal class TypeOperatorLowering(val context: Context) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
val transformer = TypeOperatorTransformer(context, irFunction.descriptor)
val transformer = TypeOperatorTransformer(context, irFunction.symbol)
irFunction.transformChildrenVoid(transformer)
}
}
private class TypeOperatorTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() {
private class TypeOperatorTransformer(val context: Context, val function: IrFunctionSymbol) : IrElementTransformerVoid() {
private val builder = context.createIrBuilder(function)
val throwTypeCastException by lazy {
context.builtIns.getKonanInternalFunctions("ThrowTypeCastException").single()
}
val throwTypeCastException = context.ir.symbols.ThrowTypeCastException
override fun visitFunction(declaration: IrFunction): IrStatement {
// ignore inner functions during this pass
@@ -93,7 +90,7 @@ private class TypeOperatorTransformer(val context: Context, val function: Functi
expression.argument.type.isNullable() -> {
with (builder) {
irLet(expression.argument) { argument ->
irLetS(expression.argument) { argument ->
irIfThenElse(
type = expression.type,
condition = irEqeqeq(irGet(argument), irNull()),
@@ -123,7 +120,7 @@ private class TypeOperatorTransformer(val context: Context, val function: Functi
val typeOperand = expression.typeOperand.erasure()
return builder.irBlock(expression) {
+irLet(expression.argument) { variable ->
+irLetS(expression.argument) { variable ->
irIfThenElse(expression.type,
condition = irIs(irGet(variable), typeOperand),
thenPart = irImplicitCast(irGet(variable), typeOperand),
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -138,31 +139,31 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
descriptor = arrayHandle.setMethodDescriptor,
typeArguments = null
)
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.descriptor)
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.descriptor) else irConstInt(i))
setArrayElementCall.putValueArgument(1, irGet(dst.descriptor))
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.symbol)
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.symbol) else irConstInt(i))
setArrayElementCall.putValueArgument(1, irGet(dst.symbol))
block.statements.add(setArrayElementCall)
if (hasSpreadElement) {
block.statements.add(incrementVariable(indexTmpVariable.descriptor, kIntOne))
block.statements.add(incrementVariable(indexTmpVariable.symbol, kIntOne))
}
} else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.descriptor)), "length".synthesizedString)
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.symbol)), "length".synthesizedString)
block.statements.add(arraySizeVariable)
val copyCall = irCall(arrayHandle.copyRangeToDescriptor, null).apply {
extensionReceiver = irGet(dst.descriptor)
putValueArgument(0, irGet(arrayTmpVariable.descriptor)) /* destination */
extensionReceiver = irGet(dst.symbol)
putValueArgument(0, irGet(arrayTmpVariable.symbol)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable.descriptor)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable.descriptor)) /* destinationIndex */
putValueArgument(2, irGet(arraySizeVariable.symbol)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable.symbol)) /* destinationIndex */
}
block.statements.add(copyCall)
block.statements.add(incrementVariable(indexTmpVariable.descriptor,
irGet(arraySizeVariable.descriptor)))
block.statements.add(incrementVariable(indexTmpVariable.symbol,
irGet(arraySizeVariable.symbol)))
log("element:$i:spread element> ${ir2string(element.expression)}")
}
}
}
block.statements.add(irGet(arrayTmpVariable.descriptor))
block.statements.add(irGet(arrayTmpVariable.symbol))
return block
}
}
@@ -203,9 +204,9 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
}
}
private fun IrBuilderWithScope.incrementVariable(descriptor: VariableDescriptor, value: IrExpression): IrExpression {
return irSetVar(descriptor, intPlus().apply {
dispatchReceiver = irGet(descriptor)
private fun IrBuilderWithScope.incrementVariable(symbol: IrVariableSymbol, value: IrExpression): IrExpression {
return irSetVar(symbol, intPlus().apply {
dispatchReceiver = irGet(symbol)
putValueArgument(0, value)
})
}
@@ -216,7 +217,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size
val initialValue = irConstInt(notSpreadElementCount) as IrExpression
return vars.filter{it.key is IrSpreadElement}.toList().fold( initial = initialValue) { result, it ->
val arraySize = irArraySize(arrayHandle, irGet(it.second.descriptor))
val arraySize = irArraySize(arrayHandle, irGet(it.second.symbol))
increment(result, arraySize)
}
}
@@ -0,0 +1,386 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.psi2ir.generators.ModuleDependenciesGenerator
import org.jetbrains.kotlin.psi2ir.generators.SymbolTable
@Deprecated("")
internal fun IrModuleFragment.replaceUnboundSymbols(context: Context) {
val collector = DeclarationSymbolCollector()
with(collector) {
with(irBuiltins) {
for (op in arrayOf(eqeqeqFun, eqeqFun, lt0Fun, lteq0Fun, gt0Fun, gteq0Fun, throwNpeFun, booleanNotFun,
noWhenBranchMatchedExceptionFun)) {
register(op.symbol)
}
}
}
this.acceptVoid(collector)
val symbolTable = context.ir.symbols.symbolTable
this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol))
// Generate missing external stubs:
ModuleDependenciesGenerator(context.psi2IrGeneratorContext).generateUnboundSymbolsAsDependencies(this)
// Merge duplicated module and package declarations:
this.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {}
override fun visitModuleFragment(declaration: IrModuleFragment) {
declaration.dependencyModules.forEach { it.acceptVoid(this) }
val dependencyModules = declaration.dependencyModules.groupBy { it.descriptor }.map { (_, fragments) ->
fragments.reduce { firstModule, nextModule ->
firstModule.apply {
mergeFrom(nextModule)
}
}
}
declaration.dependencyModules.clear()
declaration.dependencyModules.addAll(dependencyModules)
}
})
}
private fun IrModuleFragment.mergeFrom(other: IrModuleFragment): Unit {
assert(this.files.isEmpty())
assert(other.files.isEmpty())
val thisPackages = this.externalPackageFragments.groupBy { it.packageFragmentDescriptor }
other.externalPackageFragments.forEach {
val thisPackage = thisPackages[it.packageFragmentDescriptor]?.single()
if (thisPackage == null) {
this.externalPackageFragments.add(it)
} else {
thisPackage.declarations.addAll(it.declarations)
}
}
}
private class DeclarationSymbolCollector : IrElementVisitorVoid {
val descriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
fun register(symbol: IrSymbol) {
descriptorToSymbol[symbol.descriptor] = symbol
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
if (element is IrSymbolOwner && element !is IrAnonymousInitializer) {
register(element.symbol)
}
}
}
private class IrUnboundSymbolReplacer(
val symbolTable: SymbolTable,
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
) : IrElementTransformerVoid() {
private inline fun <D : DeclarationDescriptor, reified S : IrBindableSymbol<D, *>> S.replace(
referenceSymbol: (SymbolTable, D) -> S): S? {
if (this.isBound) {
return null
}
descriptorToSymbol[this.descriptor]?.let {
return it as S
}
return referenceSymbol(symbolTable, this.descriptor)
}
private inline fun <D : DeclarationDescriptor, reified S : IrBindableSymbol<D, *>> S.replaceOrSame(
referenceSymbol: (SymbolTable, D) -> S): S = this.replace(referenceSymbol) ?: this
private fun IrFunctionSymbol.replace(
referenceSymbol: (SymbolTable, FunctionDescriptor) -> IrFunctionSymbol): IrFunctionSymbol? {
if (this.isBound) {
return null
}
descriptorToSymbol[this.descriptor]?.let {
return it as IrFunctionSymbol
}
return referenceSymbol(symbolTable, this.descriptor)
}
private inline fun <reified S : IrSymbol> S.replaceLocal(): S? {
return if (this.isBound) {
null
} else {
descriptorToSymbol[this.descriptor] as S
}
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val symbol = expression.symbol.replaceLocal() ?: return super.visitGetValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetValueImpl(startOffset, endOffset, symbol, origin)
}
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
val symbol = expression.symbol.replaceLocal() ?: return super.visitSetVariable(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrSetVariableImpl(startOffset, endOffset, symbol, value, origin)
}
}
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceClass) ?:
return super.visitGetObjectValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetObjectValueImpl(startOffset, endOffset, type, symbol)
}
}
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceEnumEntry) ?:
return super.visitGetEnumValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
}
}
override fun visitClassReference(expression: IrClassReference): IrExpression {
val symbol = expression.symbol.let {
if (it.isBound) {
return super.visitClassReference(expression)
}
descriptorToSymbol[it.descriptor]?.let {
it as IrClassifierSymbol
}
symbolTable.referenceClassifier(it.descriptor)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol)
}
}
override fun visitGetField(expression: IrGetField): IrExpression {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitGetField(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrGetFieldImpl(startOffset, endOffset, symbol, receiver, origin, superQualifierSymbol)
}
}
override fun visitSetField(expression: IrSetField): IrExpression {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitSetField(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, origin, superQualifierSymbol)
}
}
override fun visitCall(expression: IrCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
return super.visitCall(expression)
}
expression.transformChildrenVoid()
return with(expression) {
IrCallImpl(startOffset, endOffset, symbol, descriptor,
getTypeArgumentsMap(),
origin, superQualifierSymbol).also {
it.copyArgumentsFrom(this)
}
}
}
private fun IrMemberAccessExpression.getTypeArgumentsMap() =
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) }
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
dispatchReceiver = original.dispatchReceiver
extensionReceiver = original.extensionReceiver
original.descriptor.valueParameters.forEachIndexed { index, _ ->
putValueArgument(index, original.getValueArgument(index))
}
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitEnumConstructorCall(expression)
return with(expression) {
IrEnumConstructorCallImpl(startOffset, endOffset, symbol).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitDelegatingConstructorCall(expression)
expression.transformChildrenVoid()
return with(expression) {
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
return super.visitFunctionReference(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
if (field == expression.field && getter == expression.getter && setter == expression.setter) {
return super.visitPropertyReference(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
field,
getter,
setter,
getTypeArgumentsMap(), origin).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
val delegate = expression.delegate.replaceOrSame(SymbolTable::referenceVariable)
val getter = expression.getter.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
if (delegate == expression.delegate && getter == expression.getter && setter == expression.setter) {
return super.visitLocalDelegatedPropertyReference(expression)
}
expression.transformChildrenVoid(this)
return with(expression) {
IrLocalDelegatedPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
delegate, getter, setter, origin).also {
it.copyArgumentsFrom(this)
}
}
}
private val returnTargetStack = mutableListOf<IrFunctionSymbol>()
override fun visitFunction(declaration: IrFunction): IrStatement {
returnTargetStack.push(declaration.symbol)
try {
return super.visitFunction(declaration)
} finally {
returnTargetStack.pop()
}
}
override fun visitBlock(expression: IrBlock): IrExpression {
if (expression is IrReturnableBlock) {
returnTargetStack.push(expression.symbol)
try {
return super.visitBlock(expression)
} finally {
returnTargetStack.pop()
}
} else {
return super.visitBlock(expression)
}
}
override fun visitReturn(expression: IrReturn): IrExpression {
if (expression.returnTargetSymbol.isBound) {
return super.visitReturn(expression)
}
val returnTargetSymbol = returnTargetStack.last { it.descriptor == expression.returnTarget }
expression.transformChildrenVoid(this)
return with(expression) {
IrReturnImpl(startOffset, endOffset, type, returnTargetSymbol, value)
}
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val classSymbol = expression.classSymbol.replace(SymbolTable::referenceClass) ?:
return super.visitInstanceInitializerCall(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol)
}
}
}
@@ -19,17 +19,21 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType
/**
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
@@ -59,6 +63,32 @@ internal fun IrMemberAccessExpression.getArguments(): List<Pair<ParameterDescrip
return res
}
/**
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
* The arguments are to be evaluated in the same order as they appear in the resulting list.
*/
internal fun IrFunctionAccessExpression.getArgumentsWithSymbols(): List<Pair<IrValueParameterSymbol, IrExpression>> {
val res = mutableListOf<Pair<IrValueParameterSymbol, IrExpression>>()
val irFunction = symbol.owner as IrFunction
dispatchReceiver?.let {
res += (irFunction.dispatchReceiverParameter!!.symbol to it)
}
extensionReceiver?.let {
res += (irFunction.extensionReceiverParameter!!.symbol to it)
}
irFunction.valueParameters.forEach {
val arg = getValueArgument(it.descriptor as ValueParameterDescriptor)
if (arg != null) {
res += (it.symbol to arg)
}
}
return res
}
/**
* Sets arguments that are specified by given mapping of parameters.
*/
@@ -146,7 +176,93 @@ fun IrClass.createParameterDeclarations() {
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
(descriptor.source as? PsiSourceElement)?.psi?.startOffset ?: this.startOffset
descriptor.startOffset ?: this.startOffset
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
(descriptor.source as? PsiSourceElement)?.psi?.endOffset ?: this.endOffset
descriptor.endOffset ?: this.endOffset
val DeclarationDescriptorWithSource.startOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.startOffset
val DeclarationDescriptorWithSource.endOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.endOffset
val DeclarationDescriptorWithSource.startOffsetOrUndefined: Int get() = startOffset ?: UNDEFINED_OFFSET
val DeclarationDescriptorWithSource.endOffsetOrUndefined: Int get() = endOffset ?: UNDEFINED_OFFSET
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
get() = this.owner.declarations.asSequence().filterIsInstance<IrSimpleFunction>().map { it.symbol }
val IrClassSymbol.constructors: Sequence<IrConstructorSymbol>
get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol }
val IrFunction.explicitParameters: List<IrValueParameterSymbol>
get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
val IrValueParameter.type: KotlinType
get() = this.descriptor.type
val IrClass.defaultType: KotlinType
get() = this.descriptor.defaultType
class IrSymbolBindingChecker : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitDeclarationReference(expression: IrDeclarationReference) {
super.visitDeclarationReference(expression)
expression.symbol.ensureBound(expression)
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
super.visitFunctionAccess(expression)
expression.symbol.ensureBound(expression)
}
override fun visitFunctionReference(expression: IrFunctionReference) {
super.visitFunctionReference(expression)
expression.symbol.ensureBound(expression)
}
override fun visitCall(expression: IrCall) {
super.visitCall(expression)
expression.superQualifierSymbol?.ensureBound(expression)
}
override fun visitPropertyReference(expression: IrPropertyReference) {
super.visitPropertyReference(expression)
expression.field?.ensureBound(expression)
expression.getter?.ensureBound(expression)
expression.setter?.ensureBound(expression)
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
super.visitLocalDelegatedPropertyReference(expression)
expression.delegate.ensureBound(expression)
expression.getter.ensureBound(expression)
expression.setter?.ensureBound(expression)
}
override fun visitReturn(expression: IrReturn) {
super.visitReturn(expression)
expression.returnTargetSymbol.ensureBound(expression)
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) {
super.visitInstanceInitializerCall(expression)
expression.classSymbol.ensureBound(expression)
}
private fun IrSymbol.ensureBound(expression: IrExpression) {
if (!this.isBound) {
throw Error("Unbound symbol ${this} found in ${expression.render()}")
}
}
}