Continue updating compiler to IR with symbols:

The symbols produced by the lowering are now bound.

Also:
* Simplify interop lowering and bridges building.
* Refactor IR validation.
This commit is contained in:
SvyatoslavScherbina
2017-05-24 11:30:28 +03:00
committed by GitHub
parent 9d6846947e
commit d08438da5f
30 changed files with 711 additions and 1117 deletions
@@ -54,13 +54,14 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
protected open fun IrExpression.useAsArgument(parameter: ParameterDescriptor): IrExpression = protected open fun IrExpression.useAsArgument(parameter: ParameterDescriptor): IrExpression =
this.useAsValue(parameter) this.useAsValue(parameter)
protected open fun IrExpression.useAsDispatchReceiver(function: CallableDescriptor): IrExpression = protected open fun IrExpression.useAsDispatchReceiver(expression: IrMemberAccessExpression): IrExpression =
this.useAsArgument(function.dispatchReceiverParameter!!) this.useAsArgument(expression.descriptor.dispatchReceiverParameter!!)
protected open fun IrExpression.useAsExtensionReceiver(function: CallableDescriptor): IrExpression = protected open fun IrExpression.useAsExtensionReceiver(expression: IrMemberAccessExpression): IrExpression =
this.useAsArgument(function.extensionReceiverParameter!!) this.useAsArgument(expression.descriptor.extensionReceiverParameter!!)
protected open fun IrExpression.useAsValueArgument(parameter: ValueParameterDescriptor): IrExpression = protected open fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression,
parameter: ValueParameterDescriptor): IrExpression =
this.useAsArgument(parameter) this.useAsArgument(parameter)
protected open fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression = protected open fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression =
@@ -81,12 +82,12 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
with(expression) { with(expression) {
dispatchReceiver = dispatchReceiver?.useAsDispatchReceiver(descriptor) dispatchReceiver = dispatchReceiver?.useAsDispatchReceiver(expression)
extensionReceiver = extensionReceiver?.useAsExtensionReceiver(descriptor) extensionReceiver = extensionReceiver?.useAsExtensionReceiver(expression)
for (index in descriptor.valueParameters.indices) { for (index in descriptor.valueParameters.indices) {
val argument = getValueArgument(index) ?: continue val argument = getValueArgument(index) ?: continue
val parameter = descriptor.valueParameters[index] val parameter = descriptor.valueParameters[index]
putValueArgument(index, argument.useAsValueArgument(parameter)) putValueArgument(index, argument.useAsValueArgument(expression, parameter))
} }
} }
@@ -240,7 +241,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
declaration.descriptor.valueParameters.forEach { parameter -> declaration.descriptor.valueParameters.forEach { parameter ->
val defaultValue = declaration.getDefault(parameter) val defaultValue = declaration.getDefault(parameter)
if (defaultValue is IrExpressionBody) { if (defaultValue is IrExpressionBody) {
defaultValue.expression = defaultValue.expression.useAsValueArgument(parameter) defaultValue.expression = defaultValue.expression.useAsArgument(parameter)
} }
} }
@@ -17,8 +17,12 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
@@ -44,6 +48,12 @@ class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: Repor
} }
} }
private fun IrSymbol.ensureBound(expression: IrExpression) {
if (!this.isBound) {
reportError(expression, "Unbound symbol ${this}")
}
}
override fun <T> visitConst(expression: IrConst<T>) { override fun <T> visitConst(expression: IrConst<T>) {
super.visitConst(expression) super.visitConst(expression)
@@ -110,6 +120,8 @@ class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: Repor
} else { } else {
expression.ensureTypeIs(returnType) expression.ensureTypeIs(returnType)
} }
expression.superQualifierSymbol?.ensureBound(expression)
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
@@ -128,6 +140,7 @@ class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: Repor
super.visitInstanceInitializerCall(expression) super.visitInstanceInitializerCall(expression)
expression.ensureTypeIs(builtIns.unitType) expression.ensureTypeIs(builtIns.unitType)
expression.classSymbol.ensureBound(expression)
} }
override fun visitTypeOperator(expression: IrTypeOperatorCall) { override fun visitTypeOperator(expression: IrTypeOperatorCall) {
@@ -173,6 +186,7 @@ class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: Repor
super.visitReturn(expression) super.visitReturn(expression)
expression.ensureTypeIs(builtIns.nothingType) expression.ensureTypeIs(builtIns.nothingType)
expression.returnTargetSymbol.ensureBound(expression)
} }
override fun visitThrow(expression: IrThrow) { override fun visitThrow(expression: IrThrow) {
@@ -180,4 +194,60 @@ class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: Repor
expression.ensureTypeIs(builtIns.nothingType) expression.ensureTypeIs(builtIns.nothingType)
} }
override fun visitClass(declaration: IrClass) {
super.visitClass(declaration)
if (declaration.descriptor.kind != ClassKind.ANNOTATION_CLASS) {
// Check that all functions and properties from memberScope are present in IR
// (including FAKE_OVERRIDE ones).
val allDescriptors = declaration.descriptor.unsubstitutedMemberScope
.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>()
val presentDescriptors = declaration.declarations.map { it.descriptor }
val missingDescriptors = allDescriptors - presentDescriptors
if (missingDescriptors.isNotEmpty()) {
reportError(declaration, "Missing declarations for descriptors:\n" +
missingDescriptors.joinToString("\n"))
}
}
}
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 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)
}
} }
@@ -16,54 +16,18 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock import org.jetbrains.kotlin.backend.konan.ir.DeepCopyKonanIrTreeWithSymbols
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.expressions.IrLoop
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.util.DeepCopySymbolsRemapper
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.util.DescriptorsRemapper
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
/** fun IrElement.deepCopyWithVariablesImpl(): IrElement {
* Copies IR tree with descriptors of all declarations inside; val descriptorsRemapper = object : DescriptorsRemapper {
* updates the references to these declarations. override fun remapDeclaredVariable(descriptor: VariableDescriptor) = LocalVariableDescriptor(
*/
@Deprecated("Creates unbound symbols")
open class DeepCopyIrTreeWithDeclarations : DeepCopyIrTree() {
private fun DeclarationDescriptor.notSupported(): Nothing = TODO("${this}")
override fun mapModuleDescriptor(descriptor: ModuleDescriptor) = descriptor.notSupported()
override fun mapPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor) = descriptor.notSupported()
override fun mapClassDeclaration(descriptor: ClassDescriptor) = descriptor.notSupported()
override fun mapTypeAliasDeclaration(descriptor: TypeAliasDescriptor) = descriptor.notSupported()
override fun mapFunctionDeclaration(descriptor: FunctionDescriptor) = descriptor.notSupported()
override fun mapConstructorDeclaration(descriptor: ClassConstructorDescriptor) = descriptor.notSupported()
override fun mapPropertyDeclaration(descriptor: PropertyDescriptor) = descriptor.notSupported()
override fun mapLocalPropertyDeclaration(descriptor: VariableDescriptorWithAccessors) = descriptor.notSupported()
override fun mapEnumEntryDeclaration(descriptor: ClassDescriptor) = descriptor.notSupported()
val copiedVariables = mutableMapOf<VariableDescriptor, VariableDescriptor>()
override fun mapVariableDeclaration(descriptor: VariableDescriptor): VariableDescriptor {
// TODO: how to ensure that the variable is not visible from outside of the transformed IR?
if (descriptor is VariableDescriptorWithAccessors && (descriptor.getter != null || descriptor.setter != null)) {
TODO("$descriptor with accessors")
}
val newDescriptor = LocalVariableDescriptor(
/* containingDeclaration = */ descriptor.containingDeclaration, /* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ descriptor.annotations, /* annotations = */ descriptor.annotations,
/* name = */ descriptor.name, /* name = */ descriptor.name,
@@ -72,103 +36,19 @@ open class DeepCopyIrTreeWithDeclarations : DeepCopyIrTree() {
/* isDelegated = */ false, /* isDelegated = */ false,
/* source = */ descriptor.source /* source = */ descriptor.source
) )
assert (descriptor !in copiedVariables)
copiedVariables[descriptor] = newDescriptor
return newDescriptor
} }
// Note: the reference to a variable can be traversed only after the declaration of that variable, val symbolsRemapper = DeepCopySymbolsRemapper(descriptorsRemapper)
// so it is correct to map only references whose descriptors have copies. acceptVoid(symbolsRemapper)
// However such approach can be incorrect when copying functions, classes etc.
override fun mapValueReference(descriptor: ValueDescriptor) = return this.transform(
copiedVariables[descriptor] ?: descriptor object : DeepCopyKonanIrTreeWithSymbols(symbolsRemapper) {
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
override fun mapVariableReference(descriptor: VariableDescriptor) = return irLoop
copiedVariables[descriptor] ?: descriptor
override fun visitBlock(expression: IrBlock): IrBlock {
return if (expression is IrReturnableBlock) {
IrReturnableBlockImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
descriptor = expression.descriptor,
origin = mapStatementOrigin(expression.origin),
statements = expression.statements.map { it.transform(this, null) }
)
} else {
super.visitBlock(expression)
}
}
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
} }
} },
null
} )
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 = inline fun <reified T : IrElement> T.deepCopyWithVariables(): T =
@@ -86,9 +86,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: DeclarationDe
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
.getContributedDescriptors() .getContributedDescriptors()
.map { .map {
if (it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) descriptorSubstituteMap[it]!!
it
else descriptorSubstituteMap[it]!!
} }
newDescriptor.initialize( newDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), SimpleMemberScope(contributedDescriptors),
@@ -16,21 +16,12 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.module
fun validateIrFunction(context: BackendContext, irFunction: IrFunction) {
val visitor = IrValidator(context, false)
irFunction.acceptVoid(visitor)
}
fun validateIrFile(context: BackendContext, irFile: IrFile) { fun validateIrFile(context: BackendContext, irFile: IrFile) {
val visitor = IrValidator(context, false) val visitor = IrValidator(context, false)
@@ -41,51 +32,7 @@ fun validateIrModule(context: BackendContext, irModule: IrModuleFragment) {
val visitor = IrValidator(context, true) // TODO: consider taking the boolean from settings. val visitor = IrValidator(context, true) // TODO: consider taking the boolean from settings.
irModule.acceptVoid(visitor) irModule.acceptVoid(visitor)
// TODO: investigate and re-enable // TODO: also check that all referenced symbol targets are reachable.
val ENABLE_EXTENDED_VALIDATION = false
if (!ENABLE_EXTENDED_VALIDATION) {
return
}
val moduleDeclarations = visitor.foundDeclarations
irModule.acceptVoid(object : IrElementVisitorVoid {
lateinit var currentFile: IrFile
override fun visitFile(declaration: IrFile) {
currentFile = declaration
declaration.acceptChildrenVoid(this)
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitProperty(declaration: IrProperty) {
if (declaration.descriptor.modality == Modality.ABSTRACT) {
return // Workaround TODO
}
declaration.acceptChildrenVoid(this)
}
override fun visitDeclarationReference(expression: IrDeclarationReference) {
expression.acceptChildrenVoid(this)
val declarationDescriptor = expression.irDeclarationDescriptor ?: return
val declarationModule = declarationDescriptor.module
if (declarationModule == irModule.descriptor && !moduleDeclarations.hasTarget(expression)) {
context.reportIrValidationError(
"declaration $declarationDescriptor is missing;\n" +
"references from:\n" +
expression.render(),
currentFile, expression)
}
}
})
} }
private fun BackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) { private fun BackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) {
@@ -98,86 +45,8 @@ private fun BackendContext.reportIrValidationError(message: String, irFile: IrFi
// TODO: throw an exception after fixing bugs leading to invalid IR. // TODO: throw an exception after fixing bugs leading to invalid IR.
} }
/**
* Descriptor to be found in IR element declaring target of this reference,
* or `null` if it is not supported yet.
*/
private val IrDeclarationReference.irDeclarationDescriptor: DeclarationDescriptor?
get() {
when (this) {
is IrFieldAccessExpression -> return this.descriptor.original
is IrMemberAccessExpression -> {
val original = this.descriptor.original
if (original is CallableMemberDescriptor && !original.kind.isReal) {
return null
}
if (original is TypeAliasConstructorDescriptor) {
return original.underlyingConstructorDescriptor
}
return original
}
is IrGetValue -> {
if (this.descriptor is ParameterDescriptor) {
return null
}
return this.descriptor
}
else -> return this.descriptor
}
}
private val IrDeclarationReference.declarationKind: IrDeclarationKind
get() = when (this) {
is IrClassReference, is IrGetObjectValue -> IrDeclarationKind.CLASS
is IrFieldAccessExpression -> IrDeclarationKind.FIELD
is IrGetEnumValue -> IrDeclarationKind.ENUM_ENTRY
is IrValueAccessExpression -> IrDeclarationKind.VARIABLE
is IrMemberAccessExpression -> when (this.descriptor) {
is ConstructorDescriptor -> IrDeclarationKind.CONSTRUCTOR
is PropertyDescriptor -> IrDeclarationKind.PROPERTY
is VariableDescriptorWithAccessors -> IrDeclarationKind.LOCAL_PROPERTY
else -> IrDeclarationKind.FUNCTION
}
else -> TODO()
}
/**
* The collection of IR declarations.
*/
private class Declarations {
private data class DeclarationKey(val descriptor: DeclarationDescriptor, val kind: IrDeclarationKind)
private val declarations = mutableSetOf<DeclarationKey>()
private fun createKey(declaration: IrDeclaration) =
DeclarationKey(declaration.descriptor, declaration.declarationKind)
fun add(declaration: IrDeclaration) {
declarations.add(createKey(declaration))
}
fun isAlreadyDeclared(declaration: IrDeclaration): Boolean {
return createKey(declaration) in declarations
}
fun hasTarget(reference: IrDeclarationReference): Boolean {
val descriptor = reference.irDeclarationDescriptor ?: return false
val kind = reference.declarationKind
return DeclarationKey(descriptor, kind) in declarations
}
}
private class IrValidator(val context: BackendContext, performHeavyValidations: Boolean) : IrElementVisitorVoid { private class IrValidator(val context: BackendContext, performHeavyValidations: Boolean) : IrElementVisitorVoid {
val foundDeclarations = Declarations()
val builtIns = context.builtIns val builtIns = context.builtIns
lateinit var currentFile: IrFile lateinit var currentFile: IrFile
@@ -200,25 +69,4 @@ private class IrValidator(val context: BackendContext, performHeavyValidations:
element.acceptVoid(elementChecker) element.acceptVoid(elementChecker)
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
private fun recordDeclaration(declaration: IrDeclaration) {
if (foundDeclarations.isAlreadyDeclared(declaration)) {
if (declaration !is IrValueParameter && declaration !is IrTypeParameter) {
// TODO: remove the check.
error(declaration, "redeclaration")
}
} else {
foundDeclarations.add(declaration)
}
}
override fun visitDeclaration(declaration: IrDeclaration) {
recordDeclaration(declaration)
super.visitDeclaration(declaration)
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
// Do not treat anonymous initializers as declarations, because they are not unique.
super.visitDeclaration(declaration)
}
} }
@@ -58,20 +58,6 @@ internal val CallableDescriptor.explicitParameters: List<ParameterDescriptor>
return result return result
} }
/**
* Returns the parameter in the original function corresponding to given parameter of this function.
*
* Note: `parameter.original` doesn't seem to be always the parameter of `this.original`.
*
* @param parameter must be declared in this function
*/
fun CallableDescriptor.getOriginalParameter(parameter: ParameterDescriptor): ParameterDescriptor = when (parameter) {
is ValueParameterDescriptor -> this.original.valueParameters[parameter.index]
this.dispatchReceiverParameter -> this.original.dispatchReceiverParameter!!
this.extensionReceiverParameter -> this.original.extensionReceiverParameter!!
else -> TODO("$parameter in $this")
}
fun KotlinType.replace(types: List<KotlinType>) = this.replace(types.map(::TypeProjectionImpl)) fun KotlinType.replace(types: List<KotlinType>) = this.replace(types.map(::TypeProjectionImpl))
fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor { fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor {
@@ -83,6 +69,13 @@ fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor
return substitute(typeSubstitutor)!! return substitute(typeSubstitutor)!!
} }
fun FunctionDescriptor.substitute(typeArguments: Map<TypeParameterDescriptor, KotlinType>): FunctionDescriptor {
val typeSubstitutor = TypeSubstitutor.create(
typeParameters.associateBy({ it.typeConstructor }, { TypeProjectionImpl(typeArguments[it]!!) })
)
return substitute(typeSubstitutor)!!
}
fun ClassDescriptor.getFunction(name: String, types: List<KotlinType>): FunctionDescriptor { fun ClassDescriptor.getFunction(name: String, types: List<KotlinType>): FunctionDescriptor {
val typeSubstitutor = TypeSubstitutor.create( val typeSubstitutor = TypeSubstitutor.create(
declaredTypeParameters declaredTypeParameters
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
@@ -48,39 +47,16 @@ import org.jetbrains.kotlin.utils.Printer
class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns) class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns)
class DeclarationIrBuilder : IrBuilderWithScope { class DeclarationIrBuilder(
backendContext: BackendContext,
constructor( symbol: IrSymbol,
backendContext: BackendContext, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET
symbol: IrSymbol, ) : IrBuilderWithScope(
startOffset: Int = UNDEFINED_OFFSET, IrLoweringContext(backendContext),
endOffset: Int = UNDEFINED_OFFSET Scope(symbol),
) : super( startOffset,
IrLoweringContext(backendContext), endOffset
Scope(symbol), )
startOffset,
endOffset
)
@Deprecated("Creates unbound symbol")
constructor(
backendContext: BackendContext,
declarationDescriptor: DeclarationDescriptor,
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET
) : super(
IrLoweringContext(backendContext),
Scope(declarationDescriptor),
startOffset,
endOffset
)
}
@Deprecated("Creates unbound symbol")
fun BackendContext.createIrBuilder(declarationDescriptor: DeclarationDescriptor,
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET) =
DeclarationIrBuilder(this, declarationDescriptor, startOffset, endOffset)
fun BackendContext.createIrBuilder(symbol: IrSymbol, fun BackendContext.createIrBuilder(symbol: IrSymbol,
startOffset: Int = UNDEFINED_OFFSET, startOffset: Int = UNDEFINED_OFFSET,
@@ -101,25 +77,9 @@ inline fun IrGeneratorWithScope.irBlock(expression: IrExpression, origin: IrStat
inline fun IrGeneratorWithScope.irBlockBody(irElement: IrElement, body: IrBlockBodyBuilder.() -> Unit) = inline fun IrGeneratorWithScope.irBlockBody(irElement: IrElement, body: IrBlockBodyBuilder.() -> Unit) =
this.irBlockBody(irElement.startOffset, irElement.endOffset, body) this.irBlockBody(irElement.startOffset, irElement.endOffset, body)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irUnit() =
IrGetObjectValueImpl(startOffset, endOffset, context.builtIns.unitType, context.builtIns.unit)
fun IrBuilderWithScope.irIfThen(condition: IrExpression, thenPart: IrExpression) = fun IrBuilderWithScope.irIfThen(condition: IrExpression, thenPart: IrExpression) =
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, thenPart, null) IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, thenPart, null)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irGet(descriptor: PropertyDescriptor) =
IrCallImpl(startOffset, endOffset, descriptor.getter!!)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irSet(receiver: IrExpression, descriptor: PropertyDescriptor, arg: IrExpression) =
IrCallImpl(startOffset, endOffset, descriptor.setter!!).apply {
dispatchReceiver = receiver
putValueArgument(0, arg)
}
fun IrBuilderWithScope.irNot(arg: IrExpression) = fun IrBuilderWithScope.irNot(arg: IrExpression) =
primitiveOp1(startOffset, endOffset, context.irBuiltIns.booleanNotSymbol, IrStatementOrigin.EXCL, arg) primitiveOp1(startOffset, endOffset, context.irBuiltIns.booleanNotSymbol, IrStatementOrigin.EXCL, arg)
@@ -139,30 +99,21 @@ fun IrBuilderWithScope.irImplicitCoercionToUnit(arg: IrExpression) =
IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.unitType, IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, context.builtIns.unitType, arg) IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, context.builtIns.unitType, arg)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irGetField(receiver: IrExpression, descriptor: PropertyDescriptor) =
IrGetFieldImpl(startOffset, endOffset, descriptor, receiver)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irSetField(receiver: IrExpression, descriptor: PropertyDescriptor, value: IrExpression) =
IrSetFieldImpl(startOffset, endOffset, descriptor, receiver, value)
fun IrBuilderWithScope.irGetField(receiver: IrExpression, symbol: IrFieldSymbol) = fun IrBuilderWithScope.irGetField(receiver: IrExpression, symbol: IrFieldSymbol) =
IrGetFieldImpl(startOffset, endOffset, symbol, receiver) IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
fun IrBuilderWithScope.irSetField(receiver: IrExpression, symbol: IrFieldSymbol, value: IrExpression) = fun IrBuilderWithScope.irSetField(receiver: IrExpression, symbol: IrFieldSymbol, value: IrExpression) =
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value) IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value)
@Deprecated("Creates unbound symbol")
open class IrBuildingTransformer(private val context: BackendContext) : IrElementTransformerVoid() { open class IrBuildingTransformer(private val context: BackendContext) : IrElementTransformerVoid() {
private var currentBuilder: IrBuilderWithScope? = null private var currentBuilder: IrBuilderWithScope? = null
protected val builder: IrBuilderWithScope protected val builder: IrBuilderWithScope
get() = currentBuilder!! get() = currentBuilder!!
private inline fun <T> withBuilder(declarationDescriptor: DeclarationDescriptor, block: () -> T): T { private inline fun <T> withBuilder(symbol: IrSymbol, block: () -> T): T {
val oldBuilder = currentBuilder val oldBuilder = currentBuilder
currentBuilder = context.createIrBuilder(declarationDescriptor) currentBuilder = context.createIrBuilder(symbol)
return try { return try {
block() block()
} finally { } finally {
@@ -171,20 +122,20 @@ open class IrBuildingTransformer(private val context: BackendContext) : IrElemen
} }
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
withBuilder(declaration.descriptor) { withBuilder(declaration.symbol) {
return super.visitFunction(declaration) return super.visitFunction(declaration)
} }
} }
override fun visitField(declaration: IrField): IrStatement { override fun visitField(declaration: IrField): IrStatement {
withBuilder(declaration.descriptor) { withBuilder(declaration.symbol) {
// Transforms initializer: // Transforms initializer:
return super.visitField(declaration) return super.visitField(declaration)
} }
} }
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement { override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
withBuilder(declaration.descriptor) { withBuilder(declaration.symbol) {
return super.visitAnonymousInitializer(declaration) return super.visitAnonymousInitializer(declaration)
} }
} }
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
* This pass lowers tail recursion calls in `tailrec` functions. * This pass lowers tail recursion calls in `tailrec` functions.
* *
* Note: it currently can't handle local functions and classes declared in default arguments. * Note: it currently can't handle local functions and classes declared in default arguments.
* See [DeepCopyIrTreeWithDeclarations]. * See [deepCopyWithVariables].
*/ */
internal class TailrecLowering(val context: BackendContext) : FunctionLoweringPass { internal class TailrecLowering(val context: BackendContext) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) { override fun lower(irFunction: IrFunction) {
@@ -25,10 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.*
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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -75,6 +72,7 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor) implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply { val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply {
createParameterDeclarations() createParameterDeclarations()
addFakeOverrides()
} }
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor) val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
@@ -16,17 +16,12 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.StarProjectionImpl
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.replace
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
private val cPointerName = "CPointer" private val cPointerName = "CPointer"
private val nativePointedName = "NativePointed" private val nativePointedName = "NativePointed"
@@ -67,53 +62,12 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == nativePointed TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == nativePointed
} }
val memberAt = packageScope.getContributedFunctions("memberAt").single()
val interpretNullablePointed = packageScope.getContributedFunctions("interpretNullablePointed").single() val interpretNullablePointed = packageScope.getContributedFunctions("interpretNullablePointed").single()
val interpretCPointer = packageScope.getContributedFunctions("interpretCPointer").single() val interpretCPointer = packageScope.getContributedFunctions("interpretCPointer").single()
val variableClass = packageScope.getContributedClassifier("CVariable") as ClassDescriptor
val arrayGetByIntIndex = packageScope.getContributedFunctions("get").single {
KotlinBuiltIns.isInt(it.valueParameters.single().type) &&
it.typeParameters.single().upperBounds.single() == variableClass.defaultType
}
val arrayGetByLongIndex = packageScope.getContributedFunctions("get").single {
KotlinBuiltIns.isLong(it.valueParameters.single().type) &&
it.typeParameters.single().upperBounds.single() == variableClass.defaultType
}
val allocUninitializedArrayWithIntLength = packageScope.getContributedFunctions("allocArray").single {
it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type)
}
val allocUninitializedArrayWithLongLength = packageScope.getContributedFunctions("allocArray").single {
it.valueParameters.size == 1 && KotlinBuiltIns.isLong(it.valueParameters[0].type)
}
val allocVariable = packageScope.getContributedFunctions("alloc").single {
it.valueParameters.size == 0
}
val readValue = packageScope.getContributedFunctions("readValue").single {
it.valueParameters.size == 0
}
val readValueBySizeAndAlign = packageScope.getContributedFunctions("readValue").single {
it.valueParameters.size == 2
}
val typeOf = packageScope.getContributedFunctions("typeOf").single() val typeOf = packageScope.getContributedFunctions("typeOf").single()
val variableTypeClass =
variableClass.unsubstitutedInnerClassesScope.getContributedClassifier("Type") as ClassDescriptor
val variableTypeSize = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("size").single()
val variableTypeAlign = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("align").single()
val nativeMemUtils = packageScope.getContributedClassifier("nativeMemUtils") as ClassDescriptor val nativeMemUtils = packageScope.getContributedClassifier("nativeMemUtils") as ClassDescriptor
private val primitives = listOf( private val primitives = listOf(
@@ -19,13 +19,11 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.validateIrFile import org.jetbrains.kotlin.backend.common.validateIrFile
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.lower.* 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.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment 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.util.replaceUnboundSymbols
import org.jetbrains.kotlin.ir.visitors.acceptVoid
internal class KonanLower(val context: Context) { internal class KonanLower(val context: Context) {
@@ -49,9 +47,14 @@ internal class KonanLower(val context: Context) {
// Inlining must be run before other phases. // Inlining must be run before other phases.
phaser.phase(KonanPhase.LOWER_INLINE) { phaser.phase(KonanPhase.LOWER_INLINE) {
FunctionInlining(context).inline(irModule) FunctionInlining(context).inline(irModule)
irModule.replaceUnboundSymbols(context)
irModule.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_INTEROP_PART1) {
irModule.files.forEach(InteropLoweringPart1(context)::lower)
}
irModule.replaceUnboundSymbols(context)
validateIrModule(context, irModule)
} }
fun lowerFile(irFile: IrFile) { fun lowerFile(irFile: IrFile) {
@@ -59,31 +62,24 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_STRING_CONCAT) { phaser.phase(KonanPhase.LOWER_STRING_CONCAT) {
StringConcatenationLowering(context).lower(irFile) StringConcatenationLowering(context).lower(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_ENUMS) { phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile) EnumClassLowering(context).run(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_INITIALIZERS) { phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile) InitializersLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) { phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
SharedVariablesLowering(context).runOnFilePostfix(irFile) SharedVariablesLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_DELEGATION) { phaser.phase(KonanPhase.LOWER_DELEGATION) {
PropertyDelegationLowering(context).lower(irFile) PropertyDelegationLowering(context).lower(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile) LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_TAILREC) { phaser.phase(KonanPhase.LOWER_TAILREC) {
TailrecLowering(context).runOnFilePostfix(irFile) TailrecLowering(context).runOnFilePostfix(irFile)
irFile.checkSymbolsBound()
} }
phaser.phase(KonanPhase.LOWER_FINALLY) { phaser.phase(KonanPhase.LOWER_FINALLY) {
FinallyBlocksLowering(context).runOnFilePostfix(irFile) FinallyBlocksLowering(context).runOnFilePostfix(irFile)
@@ -101,8 +97,8 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
InnerClassLowering(context).runOnFilePostfix(irFile) InnerClassLowering(context).runOnFilePostfix(irFile)
} }
phaser.phase(KonanPhase.LOWER_INTEROP) { phaser.phase(KonanPhase.LOWER_INTEROP_PART2) {
InteropLowering(context).lower(irFile) InteropLoweringPart2(context).lower(irFile)
} }
phaser.phase(KonanPhase.LOWER_CALLABLES) { phaser.phase(KonanPhase.LOWER_CALLABLES) {
CallableReferenceLowering(context).runOnFilePostfix(irFile) CallableReferenceLowering(context).runOnFilePostfix(irFile)
@@ -118,7 +114,6 @@ internal class KonanLower(val context: Context) {
} }
phaser.phase(KonanPhase.BRIDGES_BUILDING) { phaser.phase(KonanPhase.BRIDGES_BUILDING) {
BridgesBuilding(context).runOnFilePostfix(irFile) BridgesBuilding(context).runOnFilePostfix(irFile)
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
} }
phaser.phase(KonanPhase.AUTOBOX) { phaser.phase(KonanPhase.AUTOBOX) {
validateIrFile(context, irFile) validateIrFile(context, irFile)
@@ -126,9 +121,4 @@ internal class KonanLower(val context: Context) {
} }
} }
private fun IrElement.checkSymbolsBound() {
if (context.shouldVerifyIr()) {
this.acceptVoid(IrSymbolBindingChecker())
}
}
} }
@@ -30,13 +30,14 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation"), /* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation"),
/* ... ... */ LOWER_INLINE("Functions inlining", LOWER_INLINE_CONSTRUCTORS), /* ... ... */ LOWER_INLINE("Functions inlining", LOWER_INLINE_CONSTRUCTORS),
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"), /* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
/* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"), /* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"), /* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS), /* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS), /* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES), /* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES),
/* ... ... */ LOWER_INTEROP("Interop lowering", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_INTEROP, LOWER_DELEGATION, LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_INTEROP_PART2, LOWER_DELEGATION, LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES), /* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES),
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC), /* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC),
@@ -18,23 +18,29 @@ package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.konanInternal
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment 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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.generators.SymbolTable import org.jetbrains.kotlin.psi2ir.generators.SymbolTable
import org.jetbrains.kotlin.util.OperatorNameConventions
// This is what Context collects about IR. // This is what Context collects about IR.
internal class Ir(val context: Context, val irModule: IrModuleFragment) { internal class Ir(val context: Context, val irModule: IrModuleFragment) {
val propertiesWithBackingFields = mutableSetOf<PropertyDescriptor>() val propertiesWithBackingFields = mutableSetOf<PropertyDescriptor>()
val defaultParameterDescriptorsCache = mutableMapOf<FunctionDescriptor, FunctionDescriptor>() val defaultParameterDeclarationsCache = mutableMapOf<FunctionDescriptor, IrFunction>()
val originalModuleIndex = ModuleIndex(irModule) val originalModuleIndex = ModuleIndex(irModule)
@@ -67,13 +73,31 @@ internal class Symbols(val context: Context, val symbolTable: SymbolTable) {
val ThrowTypeCastException = symbolTable.referenceSimpleFunction( val ThrowTypeCastException = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("ThrowTypeCastException").single()) builtIns.getKonanInternalFunctions("ThrowTypeCastException").single())
val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("ThrowUninitializedPropertyAccessException").single()
)
val stringBuilder = symbolTable.referenceClass( val stringBuilder = symbolTable.referenceClass(
builtInsPackage("kotlin", "text").getContributedClassifier( builtInsPackage("kotlin", "text").getContributedClassifier(
Name.identifier("StringBuilder"), NoLookupLocation.FROM_BACKEND Name.identifier("StringBuilder"), NoLookupLocation.FROM_BACKEND
) as ClassDescriptor ) as ClassDescriptor
) )
val defaultArgumentMarker = symbolTable.referenceClass(
builtIns.konanInternal.getContributedClassifier(
Name.identifier("DefaultArgumentMarker"), NoLookupLocation.FROM_BACKEND
) as ClassDescriptor
)
val any = symbolTable.referenceClass(builtIns.any) val any = symbolTable.referenceClass(builtIns.any)
val unit = symbolTable.referenceClass(builtIns.unit)
val byte = symbolTable.referenceClass(builtIns.byte)
val short = symbolTable.referenceClass(builtIns.short)
val int = symbolTable.referenceClass(builtIns.int)
val long = symbolTable.referenceClass(builtIns.long)
val integerClasses = listOf(byte, short, int, long)
val arrayOf = symbolTable.referenceSimpleFunction( val arrayOf = symbolTable.referenceSimpleFunction(
builtInsPackage("kotlin").getContributedFunctions( builtInsPackage("kotlin").getContributedFunctions(
@@ -83,12 +107,86 @@ internal class Symbols(val context: Context, val symbolTable: SymbolTable) {
val array = symbolTable.referenceClass(builtIns.array) val array = symbolTable.referenceClass(builtIns.array)
private fun primitiveArrayClass(type: PrimitiveType) =
symbolTable.referenceClass(builtIns.getPrimitiveArrayClassDescriptor(type))
val byteArray = primitiveArrayClass(PrimitiveType.BYTE)
val charArray = primitiveArrayClass(PrimitiveType.CHAR)
val shortArray = primitiveArrayClass(PrimitiveType.SHORT)
val intArray = primitiveArrayClass(PrimitiveType.INT)
val longArray = primitiveArrayClass(PrimitiveType.LONG)
val floatArray = primitiveArrayClass(PrimitiveType.FLOAT)
val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE)
val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN)
val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array
val copyRangeTo = arrays.map { symbol ->
val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME)
val functionDescriptor = packageViewDescriptor.memberScope
.getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND)
.first {
it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == symbol.descriptor
}
symbol.descriptor to symbolTable.referenceSimpleFunction(functionDescriptor)
}.toMap()
val intAnd = symbolTable.referenceFunction(
builtIns.intType.memberScope
.getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND)
.single()
)
val intPlusInt = symbolTable.referenceFunction(
builtIns.intType.memberScope
.getContributedFunctions(OperatorNameConventions.PLUS, NoLookupLocation.FROM_BACKEND)
.single {
it.valueParameters.single().type == builtIns.intType
}
)
val boxFunctions = ValueType.values().associate {
val boxFunctionName = "box${it.classFqName.shortName()}"
it to symbolTable.referenceSimpleFunction(context.builtIns.getKonanInternalFunctions(boxFunctionName).single())
}
val boxClasses = ValueType.values().associate {
it to symbolTable.referenceClass(context.builtIns.getKonanInternalClass("${it.classFqName.shortName()}Box"))
}
val unboxFunctions = ValueType.values().mapNotNull {
val unboxFunctionName = "unbox${it.classFqName.shortName()}"
context.builtIns.getKonanInternalFunctions(unboxFunctionName).atMostOne()?.let { descriptor ->
it to symbolTable.referenceSimpleFunction(descriptor)
}
}.toMap()
val interopNativePointedGetRawPointer =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer)
val interopCPointerGetRawValue = symbolTable.referenceSimpleFunction(context.interopBuiltIns.cPointerGetRawValue)
val getNativeNullPtr = symbolTable.referenceSimpleFunction(builtIns.getNativeNullPtr)
val valuesForEnum = symbolTable.referenceSimpleFunction( val valuesForEnum = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("valuesForEnum").single()) builtIns.getKonanInternalFunctions("valuesForEnum").single())
val valueOfForEnum = symbolTable.referenceSimpleFunction( val valueOfForEnum = symbolTable.referenceSimpleFunction(
builtIns.getKonanInternalFunctions("valueOfForEnum").single()) builtIns.getKonanInternalFunctions("valueOfForEnum").single())
val getContinuation = symbolTable.referenceSimpleFunction(
context.builtIns.getKonanInternalFunctions("getContinuation").single())
val coroutineImpl = symbolTable.referenceClass(context.builtIns.getKonanInternalClass("CoroutineImpl"))
val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction(
builtInsPackage("kotlin", "coroutines", "experimental", "intrinsics")
.getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND)
.single().getter!!
)
val kFunctionImpl = symbolTable.referenceClass(context.builtIns.getKonanInternalClass("KFunctionImpl"))
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl) val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl) val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl) val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
@@ -51,6 +51,12 @@ class IrReturnableBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType,
override val descriptor = symbol.descriptor override val descriptor = symbol.descriptor
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin?, statements: List<IrStatement>) :
this(startOffset, endOffset, type, symbol, origin) {
this.statements.addAll(statements)
}
constructor(startOffset: Int, endOffset: Int, type: KotlinType, constructor(startOffset: Int, endOffset: Int, type: KotlinType,
descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null) : descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null) :
this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin) this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin)
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.SymbolRemapper
internal open class DeepCopyKonanIrTreeWithSymbols(
private val symbolRemapper: SymbolRemapper
) : DeepCopyIrTreeWithSymbols(symbolRemapper) {
private inline fun <reified T : IrElement> T.transform() =
transform(this@DeepCopyKonanIrTreeWithSymbols, null) as T
private val transformedReturnableBlocks = mutableMapOf<IrReturnableBlock, IrReturnableBlock>()
override fun visitBlock(expression: IrBlock): IrBlock = if (expression is IrReturnableBlock) {
IrReturnableBlockImpl(
expression.startOffset, expression.endOffset,
expression.type,
expression.descriptor,
expression.origin
).also {
transformedReturnableBlocks.put(expression, it)
it.statements.addAll(expression.statements.map { it.transform() })
}
} else {
super.visitBlock(expression)
}
override fun visitReturn(expression: IrReturn): IrReturn {
val returnTargetSymbol = expression.returnTargetSymbol
return if (returnTargetSymbol is IrReturnableBlockSymbol) {
IrReturnImpl(
expression.startOffset, expression.endOffset,
expression.type,
transformedReturnableBlocks.getOrElse(returnTargetSymbol.owner) { returnTargetSymbol.owner }.symbol,
expression.value.transform()
)
} else {
super.visitReturn(expression)
}
}
}
@@ -20,8 +20,8 @@ import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.util.atMostOne import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -29,7 +29,10 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.util.isNullConst import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.type
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
@@ -50,6 +53,8 @@ internal class Autoboxing(val context: Context) : FileLoweringPass {
private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTransformer(context.builtIns) { private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTransformer(context.builtIns) {
val symbols = context.ir.symbols
// TODO: should we handle the cases when expression type // TODO: should we handle the cases when expression type
// is not equal to e.g. called function return type? // is not equal to e.g. called function return type?
@@ -133,13 +138,13 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
override fun IrExpression.useAs(type: KotlinType): IrExpression { override fun IrExpression.useAs(type: KotlinType): IrExpression {
val interop = context.interopBuiltIns val interop = context.interopBuiltIns
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) { if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) {
return IrCallImpl(startOffset, endOffset, context.builtIns.getNativeNullPtr).uncheckedCast(type) return IrCallImpl(startOffset, endOffset, symbols.getNativeNullPtr).uncheckedCast(type)
} }
val actualType = when (this) { val actualType = when (this) {
is IrCall -> { is IrCall -> {
if (this.descriptor.isSuspend) context.builtIns.nullableAnyType if (this.descriptor.isSuspend) context.builtIns.nullableAnyType
else this.descriptor.original.returnType ?: this.type else this.callTarget.returnType ?: this.type
} }
is IrGetField -> this.descriptor.original.type is IrGetField -> this.descriptor.original.type
@@ -157,17 +162,32 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
return this.adaptIfNecessary(actualType, type) return this.adaptIfNecessary(actualType, type)
} }
override fun IrExpression.useAsDispatchReceiver(function: CallableDescriptor): IrExpression { private val IrMemberAccessExpression.target: CallableDescriptor get() = when (this) {
return this.useAsArgument(function.original.dispatchReceiverParameter!!) is IrCall -> this.callTarget
is IrDelegatingConstructorCall -> this.descriptor.original
else -> TODO(this.render())
} }
override fun IrExpression.useAsExtensionReceiver(function: CallableDescriptor): IrExpression { private val IrCall.callTarget: FunctionDescriptor
return this.useAsArgument(function.original.extensionReceiverParameter!!) get() = if (superQualifier == null && descriptor.isOverridable) {
// A virtual call.
descriptor.original
} else {
descriptor.target
}
override fun IrExpression.useAsDispatchReceiver(expression: IrMemberAccessExpression): IrExpression {
return this.useAsArgument(expression.target.dispatchReceiverParameter!!)
} }
override fun IrExpression.useAsValueArgument(parameter: ValueParameterDescriptor): IrExpression { override fun IrExpression.useAsExtensionReceiver(expression: IrMemberAccessExpression): IrExpression {
val function = parameter.containingDeclaration return this.useAsArgument(expression.target.extensionReceiverParameter!!)
return this.useAsArgument(function.original.valueParameters[parameter.index]) }
override fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression,
parameter: ValueParameterDescriptor): IrExpression {
return this.useAsArgument(expression.target.valueParameters[parameter.index])
} }
override fun IrExpression.useForField(field: PropertyDescriptor): IrExpression { override fun IrExpression.useForField(field: PropertyDescriptor): IrExpression {
@@ -211,9 +231,7 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
context.builtIns.getKonanInternalClass("${valueType.shortName}Box").defaultType context.builtIns.getKonanInternalClass("${valueType.shortName}Box").defaultType
private fun IrExpression.box(valueType: ValueType): IrExpression { private fun IrExpression.box(valueType: ValueType): IrExpression {
val boxFunctionName = "box${valueType.shortName}" val boxFunction = symbols.boxFunctions[valueType]!!
val boxFunction = context.builtIns.getKonanInternalFunctions(boxFunctionName).singleOrNull() ?:
TODO(valueType.toString())
return IrCallImpl(startOffset, endOffset, boxFunction).apply { return IrCallImpl(startOffset, endOffset, boxFunction).apply {
putValueArgument(0, this@box) putValueArgument(0, this@box)
@@ -221,22 +239,16 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
} }
private fun IrExpression.unbox(valueType: ValueType): IrExpression { private fun IrExpression.unbox(valueType: ValueType): IrExpression {
val unboxFunctionName = "unbox${valueType.shortName}" symbols.unboxFunctions[valueType]?.let {
context.builtIns.getKonanInternalFunctions(unboxFunctionName).atMostOne()?.let {
return IrCallImpl(startOffset, endOffset, it).apply { return IrCallImpl(startOffset, endOffset, it).apply {
putValueArgument(0, this@unbox.uncheckedCast(it.valueParameters[0].type)) putValueArgument(0, this@unbox.uncheckedCast(it.owner.valueParameters[0].type))
}.uncheckedCast(this.type) }.uncheckedCast(this.type)
} }
val boxGetter = getBoxType(valueType) val boxGetter = symbols.boxClasses[valueType]!!.getPropertyGetter("value")!!
.memberScope.getContributedDescriptors()
.filterIsInstance<PropertyDescriptor>()
.single { it.name.asString() == "value" }
.getter!!
return IrCallImpl(startOffset, endOffset, boxGetter).apply { return IrCallImpl(startOffset, endOffset, boxGetter).apply {
dispatchReceiver = this@unbox.uncheckedCast(boxGetter.dispatchReceiverParameter!!.type) dispatchReceiver = this@unbox.uncheckedCast(boxGetter.descriptor.dispatchReceiverParameter!!.type)
}.uncheckedCast(this.type) // Try not to bring new type incompatibilities. }.uncheckedCast(this.type) // Try not to bring new type incompatibilities.
} }
@@ -16,13 +16,11 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -36,6 +34,7 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.type import org.jetbrains.kotlin.ir.util.type
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -43,46 +42,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass {
override fun lower(irBody: IrBody) {
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val descriptor = expression.descriptor as? FunctionDescriptor ?: return expression
if (descriptor.modality == Modality.ABSTRACT
|| (expression.superQualifier == null && descriptor.isOverridable)) {
// A virtual call. boxing/unboxing will be in the corresponding bridge.
return expression
}
val target = descriptor.target
if (!descriptor.original.needBridgeTo(target)) return expression
return IrCallImpl(expression.startOffset, expression.endOffset,
target, remapTypeArguments(expression, target), expression.origin,
superQualifierDescriptor = target.containingDeclaration as ClassDescriptor /* Call non-virtually */
).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
mapValueParameters { expression.getValueArgument(it)!! }
}
}
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor)
: Map<TypeParameterDescriptor, KotlinType>? {
val oldCallee = oldExpression.descriptor
return if (oldCallee.typeParameters.isEmpty())
null
else oldCallee.typeParameters.associateBy(
{ newCallee.typeParameters[it.index] },
{ oldExpression.getTypeArgument(it)!! }
)
}
})
}
}
internal class BridgesBuilding(val context: Context) : ClassLoweringPass { internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression, private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
@@ -162,30 +121,31 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
private object DECLARATION_ORIGIN_BRIDGE_METHOD : private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD") IrDeclarationOriginImpl("BRIDGE_METHOD")
private val ValueType.shortName
get() = this.classFqName.shortName()
private fun getBoxType(valueType: ValueType) =
context.builtIns.getKonanInternalClass("${valueType.shortName}Box").defaultType
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) { private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor) val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val target = descriptor.descriptor.target val bridge = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_BRIDGE_METHOD,
bridgeDescriptor).apply { createParameterDeclarations() }
val target = descriptor.descriptor
assert(target.containingDeclaration == irClass.descriptor)
val superQualifierSymbol = irClass.symbol
val targetSymbol = irClass.findMember(target) // TODO: optimize
val statements = mutableListOf<IrExpression>() val statements = mutableListOf<IrExpression>()
val irBuilder = context.createIrBuilder(bridgeDescriptor, irClass.startOffset, irClass.endOffset) val irBuilder = context.createIrBuilder(bridge.symbol, irClass.startOffset, irClass.endOffset)
irBuilder.run { irBuilder.run {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor) val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor)
if (typeSafeBarrierDescription != null) { if (typeSafeBarrierDescription != null) {
val valueParameters = bridgeDescriptor.valueParameters val valueParameters = bridge.valueParameters
for (i in valueParameters.indices) { for (i in valueParameters.indices) {
if (!typeSafeBarrierDescription.checkParameter(i)) if (!typeSafeBarrierDescription.checkParameter(i))
continue continue
val type = target.valueParameters[i].type val type = target.valueParameters[i].type
if (type != context.builtIns.nullableAnyType) { if (type != context.builtIns.nullableAnyType) {
statements += returnIfBadType(irGet(valueParameters[i]), type, statements += returnIfBadType(irGet(valueParameters[i].symbol), type,
if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT) if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
irGet(valueParameters[2]) irGet(valueParameters[2].symbol)
else irConst(typeSafeBarrierDescription.defaultValue) else irConst(typeSafeBarrierDescription.defaultValue)
) )
} }
@@ -193,22 +153,22 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
} }
} }
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target, val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetSymbol, target,
superQualifierDescriptor = target.containingDeclaration as ClassDescriptor /* Call non-virtually */ superQualifierSymbol = superQualifierSymbol /* Call non-virtually */
).apply { ).apply {
val dispatchReceiverParameter = bridgeDescriptor.dispatchReceiverParameter val dispatchReceiverParameter = bridge.dispatchReceiverParameter
if (dispatchReceiverParameter != null) if (dispatchReceiverParameter != null)
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter) dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter.symbol)
val extensionReceiverParameter = bridgeDescriptor.extensionReceiverParameter val extensionReceiverParameter = bridge.extensionReceiverParameter
if (extensionReceiverParameter != null) if (extensionReceiverParameter != null)
extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter) extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter.symbol)
bridgeDescriptor.valueParameters.forEach { bridge.valueParameters.forEachIndexed { index, parameter ->
this.putValueArgument(it.index, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it)) this.putValueArgument(index, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.symbol))
} }
} }
val bridgeBody = if (bridgeDescriptor.returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) }) val bridgeBody = if (bridgeDescriptor.returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) })
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridgeDescriptor, delegatingCall) IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridge.symbol, delegatingCall)
else else
delegatingCall delegatingCall
statements += bridgeBody statements += bridgeBody
@@ -219,3 +179,12 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
) )
} }
} }
private fun IrClass.findMember(descriptor: FunctionDescriptor): IrFunctionSymbol {
val functions = this.declarations.filterIsInstance<IrFunction>().map { it.symbol }
val propertyAccessors = this.declarations
.filterIsInstance<IrProperty>()
.flatMap { listOfNotNull(it.getter?.symbol, it.setter?.symbol) }
return (functions + propertyAccessors).single { it.descriptor == descriptor }
}
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionOrKFunctionType import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.createFakeOverrideDescriptor import org.jetbrains.kotlin.backend.konan.ir.createFakeOverrideDescriptor
@@ -45,8 +43,6 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -54,9 +50,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
internal class CallableReferenceLowering(val context: Context): DeclarationContainerLoweringPass { internal class CallableReferenceLowering(val context: Context): DeclarationContainerLoweringPass {
@@ -122,7 +118,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
private val continuationClassDescriptor = coroutinesScope private val continuationClassDescriptor = coroutinesScope
.getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor .getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private val getContinuationDescriptor = context.builtIns.getKonanInternalFunctions("getContinuation").single() private val getContinuationSymbol = context.ir.symbols.getContinuation
private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor, private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor,
val functionReference: IrFunctionReference) { val functionReference: IrFunctionReference) {
@@ -137,7 +133,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
private lateinit var functionReferenceThis: IrValueParameterSymbol private lateinit var functionReferenceThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol> private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private val kFunctionImplClassDescriptor = context.builtIns.getKonanInternalClass("KFunctionImpl") private val kFunctionImplSymbol = context.ir.symbols.kFunctionImpl
fun build(): BuiltFunctionReference { fun build(): BuiltFunctionReference {
val startOffset = functionReference.startOffset val startOffset = functionReference.startOffset
@@ -145,7 +141,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
val returnType = functionDescriptor.returnType!! val returnType = functionDescriptor.returnType!!
val superTypes = mutableListOf( val superTypes = mutableListOf(
kFunctionImplClassDescriptor.defaultType.replace(listOf(returnType)) kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType))
) )
val numberOfParameters = unboundFunctionParameters.size val numberOfParameters = unboundFunctionParameters.size
@@ -196,7 +192,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor) suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor)
} }
val inheritedKFunctionImpl = kFunctionImplClassDescriptor.unsubstitutedMemberScope val inheritedKFunctionImpl = kFunctionImplSymbol.descriptor.unsubstitutedMemberScope
.getContributedDescriptors() .getContributedDescriptors()
.map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) } .map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNotNull() .filterNotNull()
@@ -206,6 +202,8 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
functionReferenceClassDescriptor.initialize( functionReferenceClassDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null) SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null)
functionReferenceClass.addFakeOverrides()
constructorBuilder.initialize() constructorBuilder.initialize()
functionReferenceClass.declarations.add(constructorBuilder.ir) functionReferenceClass.declarations.add(constructorBuilder.ir)
@@ -223,7 +221,7 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
private fun createConstructorBuilder() private fun createConstructorBuilder()
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val kFunctionImplConstructorDescriptor = kFunctionImplClassDescriptor.constructors.single() private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single()
override fun buildSymbol() = IrConstructorSymbolImpl( override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
@@ -261,7 +259,8 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
createParameterDeclarations() createParameterDeclarations()
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, kFunctionImplConstructorDescriptor).apply { +IrDelegatingConstructorCallImpl(startOffset, endOffset,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor).apply {
val name = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, val name = IrConstImpl(startOffset, endOffset, context.builtIns.stringType,
IrConstKind.String, functionDescriptor.name.asString()) IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name) putValueArgument(0, name)
@@ -356,7 +355,8 @@ internal class CallableReferenceLowering(val context: Context): DeclarationConta
else { else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit. // For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationDescriptor.substitute(ourSymbol.descriptor.returnType!!)) irCall(getContinuationSymbol,
listOf(ourSymbol.descriptor.returnType!!))
else else
irGet(valueParameters[unboundIndex++].symbol) irGet(valueParameters[unboundIndex++].symbol)
} }
@@ -21,8 +21,6 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.descriptors.konanInternal
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.ir2string import org.jetbrains.kotlin.backend.konan.ir.ir2string
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -32,7 +30,6 @@ import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl 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.IrElement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -42,8 +39,9 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -52,7 +50,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.util.OperatorNameConventions
class DefaultArgumentStubGenerator internal constructor(val context: Context): DeclarationContainerLoweringPass { class DefaultArgumentStubGenerator internal constructor(val context: Context): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
@@ -65,8 +62,7 @@ class DefaultArgumentStubGenerator internal constructor(val context: Context): D
} }
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER : private val symbols = context.ir.symbols
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
private fun lower(irFunction: IrFunction): List<IrFunction> { private fun lower(irFunction: IrFunction): List<IrFunction> {
val functionDescriptor = irFunction.descriptor val functionDescriptor = irFunction.descriptor
@@ -81,27 +77,28 @@ class DefaultArgumentStubGenerator internal constructor(val context: Context): D
log("detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions") log("detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions")
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} } functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
if (bodies.isNotEmpty()) { if (bodies.isNotEmpty()) {
val descriptor = functionDescriptor.generateDefaultsDescription(context) val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
val descriptor = newIrFunction.descriptor
log("$functionDescriptor -> $descriptor") log("$functionDescriptor -> $descriptor")
val builder = context.createIrBuilder(descriptor) val builder = context.createIrBuilder(newIrFunction.symbol)
val body = builder.irBlockBody(irFunction) { val body = builder.irBlockBody(irFunction) {
val params = mutableListOf<VariableDescriptor>() val params = mutableListOf<IrVariableSymbol>()
val variables = mutableMapOf<ValueDescriptor, ValueDescriptor>() val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
if (descriptor.extensionReceiverParameter != null) { if (descriptor.extensionReceiverParameter != null) {
variables[functionDescriptor.extensionReceiverParameter!!] = descriptor.extensionReceiverParameter!! variables[functionDescriptor.extensionReceiverParameter!!] =
newIrFunction.extensionReceiverParameter!!.symbol
} }
for (valueParameter in functionDescriptor.valueParameters) { for (valueParameter in functionDescriptor.valueParameters) {
val parameterDescriptor = descriptor.valueParameters[valueParameter.index] val parameterSymbol = newIrFunction.valueParameters[valueParameter.index].symbol
val temporaryVariableDescriptor = scope.createTemporaryVariableDescriptor(parameterDescriptor) val temporaryVariableSymbol =
params.add(temporaryVariableDescriptor) IrVariableSymbolImpl(scope.createTemporaryVariableDescriptor(parameterSymbol.descriptor))
variables.put(valueParameter, temporaryVariableDescriptor) params.add(temporaryVariableSymbol)
variables.put(valueParameter, temporaryVariableSymbol)
if (valueParameter.hasDefaultValue()) { if (valueParameter.hasDefaultValue()) {
val kIntAnd = valueParameter.builtIns.intType.memberScope val kIntAnd = symbols.intAnd
.getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND)
.single()
val condition = irNotEquals(irCall(kIntAnd).apply { val condition = irNotEquals(irCall(kIntAnd).apply {
dispatchReceiver = irGet(maskParameterDescriptor(descriptor, valueParameter.index / 32)) dispatchReceiver = irGet(maskParameterSymbol(newIrFunction, valueParameter.index / 32))
putValueArgument(0, irInt(1 shl (valueParameter.index % 32))) putValueArgument(0, irInt(1 shl (valueParameter.index % 32)))
}, irInt(0)) }, irInt(0))
val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter) val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
@@ -110,51 +107,45 @@ class DefaultArgumentStubGenerator internal constructor(val context: Context): D
expressionBody.transformChildrenVoid(object:IrElementTransformerVoid() { expressionBody.transformChildrenVoid(object:IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
log("GetValue: ${expression.descriptor}") log("GetValue: ${expression.descriptor}")
val valueDescriptor = variables[expression.descriptor] val valueSymbol = variables[expression.descriptor] ?: return expression
return when (valueDescriptor) { return irGet(valueSymbol)
is VariableDescriptor -> irGet(valueDescriptor)
is ReceiverParameterDescriptor -> irGet(valueDescriptor)
null -> expression
else -> TODO("$valueDescriptor")
}
} }
}) })
val variableInitialization = irIfThenElse( val variableInitialization = irIfThenElse(
type = temporaryVariableDescriptor.type, type = temporaryVariableSymbol.descriptor.type,
condition = condition, condition = condition,
thenPart = expressionBody.expression, thenPart = expressionBody.expression,
elsePart = irGet(parameterDescriptor)) elsePart = irGet(parameterSymbol))
+ scope.createTemporaryVariable( + scope.createTemporaryVariable(
descriptor = temporaryVariableDescriptor, symbol = temporaryVariableSymbol,
initializer = variableInitialization) initializer = variableInitialization)
/* Mapping calculated values with its origin variables. */ /* Mapping calculated values with its origin variables. */
} else { } else {
+ scope.createTemporaryVariable( + scope.createTemporaryVariable(
descriptor = temporaryVariableDescriptor, symbol = temporaryVariableSymbol,
initializer = irGet(parameterDescriptor)) initializer = irGet(parameterSymbol))
} }
} }
if (functionDescriptor is ClassConstructorDescriptor) { if (irFunction is IrConstructor) {
+ IrDelegatingConstructorCallImpl( + IrDelegatingConstructorCallImpl(
startOffset = irFunction.startOffset, startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset, endOffset = irFunction.endOffset,
constructorDescriptor = functionDescriptor symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor
).apply { ).apply {
params.forEachIndexed { i, variable -> params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable)) putValueArgument(i, irGet(variable))
} }
if (functionDescriptor.dispatchReceiverParameter != null) { if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irThis() dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
} }
} }
} else { } else {
+irReturn(irCall(functionDescriptor).apply { +irReturn(irCall(irFunction.symbol).apply {
if (functionDescriptor.dispatchReceiverParameter != null) { if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irThis() dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
} }
if (functionDescriptor.extensionReceiverParameter != null) { if (functionDescriptor.extensionReceiverParameter != null) {
extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!] as ReceiverParameterDescriptor) extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!]!!)
} }
params.forEachIndexed { i, variable -> params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable)) putValueArgument(i, irGet(variable))
@@ -188,26 +179,31 @@ class DefaultArgumentStubGenerator internal constructor(val context: Context): D
private fun log(msg:String) = context.log{"DEFAULT-REPLACER: $msg"} private fun log(msg:String) = context.log{"DEFAULT-REPLACER: $msg"}
} }
private fun Scope.createTemporaryVariableDescriptor(parameterDescriptor: ValueParameterDescriptor?): VariableDescriptor = private fun Scope.createTemporaryVariableDescriptor(parameterDescriptor: ParameterDescriptor?): VariableDescriptor =
IrTemporaryVariableDescriptorImpl( IrTemporaryVariableDescriptorImpl(
containingDeclaration = this.scopeOwner, containingDeclaration = this.scopeOwner,
name = parameterDescriptor!!.name.asString().synthesizedName, name = parameterDescriptor!!.name.asString().synthesizedName,
outType = parameterDescriptor.type, outType = parameterDescriptor.type,
isMutable = false) isMutable = false)
private fun Scope.createTemporaryVariable(descriptor: VariableDescriptor, initializer: IrExpression) = private fun Scope.createTemporaryVariable(symbol: IrVariableSymbol, initializer: IrExpression) =
IrVariableImpl( IrVariableImpl(
startOffset = initializer.startOffset, startOffset = initializer.startOffset,
endOffset = initializer.endOffset, endOffset = initializer.endOffset,
origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
descriptor = descriptor, symbol = symbol).apply {
initializer = initializer)
this.initializer = initializer
}
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody { private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody {
return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!") return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!")
} }
private fun maskParameterDescriptor(descriptor: FunctionDescriptor, number:Int)= descriptor.valueParameters.single { it.name == parameterMaskName(number) } private fun maskParameterDescriptor(function: IrFunction, number: Int) =
maskParameterSymbol(function, number).descriptor as ValueParameterDescriptor
private fun maskParameterSymbol(function: IrFunction, number: Int) =
function.valueParameters.single { it.descriptor.name == parameterMaskName(number) }.symbol
private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single { it.name == kConstructorMarkerName } private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single { it.name == kConstructorMarkerName }
@@ -237,11 +233,12 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
val argumentsCount = argumentCount(expression) val argumentsCount = argumentCount(expression)
if (argumentsCount == descriptor.valueParameters.size) if (argumentsCount == descriptor.valueParameters.size)
return expression return expression
val (descriptorForCall, params) = parametersForCall(expression) val (symbolForCall, params) = parametersForCall(expression)
return IrDelegatingConstructorCallImpl( return IrDelegatingConstructorCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
constructorDescriptor = descriptorForCall as ClassConstructorDescriptor) symbol = symbolForCall as IrConstructorSymbol,
descriptor = symbolForCall.descriptor)
.apply { .apply {
params.forEach { params.forEach {
log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}") log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}")
@@ -254,7 +251,7 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression) super.visitCall(expression)
val functionDescriptor = expression.descriptor as FunctionDescriptor val functionDescriptor = expression.descriptor
if (!functionDescriptor.needsDefaultArgumentsLowering) if (!functionDescriptor.needsDefaultArgumentsLowering)
return expression return expression
@@ -262,13 +259,15 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
val argumentsCount = argumentCount(expression) val argumentsCount = argumentCount(expression)
if (argumentsCount == functionDescriptor.valueParameters.size) if (argumentsCount == functionDescriptor.valueParameters.size)
return expression return expression
val (descriptor, params) = parametersForCall(expression) val (symbol, params) = parametersForCall(expression)
val descriptor = symbol.descriptor
descriptor.typeParameters.forEach { log("$descriptor [${it.index}]: $it") } descriptor.typeParameters.forEach { log("$descriptor [${it.index}]: $it") }
descriptor.original.typeParameters.forEach { log("${descriptor.original}[${it.index}] : $it") } descriptor.original.typeParameters.forEach { log("${descriptor.original}[${it.index}] : $it") }
return IrCallImpl( return IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
calleeDescriptor = descriptor, symbol = symbol,
descriptor = descriptor,
typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap()) typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap())
.apply { .apply {
params.forEach { params.forEach {
@@ -286,13 +285,14 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
} }
} }
private fun parametersForCall(expression: IrMemberAccessExpression): Pair<FunctionDescriptor, List<Pair<ValueParameterDescriptor, IrExpression?>>> { private fun parametersForCall(expression: IrMemberAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> {
val descriptor = expression.descriptor as FunctionDescriptor val descriptor = expression.descriptor as FunctionDescriptor
val keyDescriptor = if (DescriptorUtils.isOverride(descriptor)) val keyDescriptor = if (DescriptorUtils.isOverride(descriptor))
DescriptorUtils.getAllOverriddenDescriptors(descriptor).first() DescriptorUtils.getAllOverriddenDescriptors(descriptor).first()
else else
descriptor.original descriptor.original
val realDescriptor = keyDescriptor.generateDefaultsDescription(context) val realFunction = keyDescriptor.generateDefaultsFunction(context)
val realDescriptor = realFunction.descriptor
log("$descriptor -> $realDescriptor") log("$descriptor -> $realDescriptor")
val maskValues = Array(descriptor.valueParameters.size / 32 + 1, {0}) val maskValues = Array(descriptor.valueParameters.size / 32 + 1, {0})
@@ -308,24 +308,24 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
return@mapIndexed pair return@mapIndexed pair
}) })
maskValues.forEachIndexed { i, maskValue -> maskValues.forEachIndexed { i, maskValue ->
params += maskParameterDescriptor(realDescriptor, i) to IrConstImpl.int( params += maskParameterDescriptor(realFunction, i) to IrConstImpl.int(
startOffset = irBody.startOffset, startOffset = irBody.startOffset,
endOffset = irBody.endOffset, endOffset = irBody.endOffset,
type = descriptor.builtIns.intType, type = descriptor.builtIns.intType,
value = maskValue) value = maskValue)
} }
if (expression.descriptor is ClassConstructorDescriptor) { if (expression.descriptor is ClassConstructorDescriptor) {
val defaultArgumentMarker = getDefaultArgumentMarkerClassDescriptor(context.builtIns) val defaultArgumentMarker = context.ir.symbols.defaultArgumentMarker
params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl( params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl(
startOffset = irBody.startOffset, startOffset = irBody.startOffset,
endOffset = irBody.endOffset, endOffset = irBody.endOffset,
type = defaultArgumentMarker.defaultType, type = defaultArgumentMarker.owner.defaultType,
descriptor = defaultArgumentMarker) symbol = defaultArgumentMarker)
} }
params.forEach { params.forEach {
log("descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}") log("descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}")
} }
return Pair(realDescriptor, params) return Pair(realFunction.symbol, params)
} }
private fun argumentCount(expression: IrMemberAccessExpression) = private fun argumentCount(expression: IrMemberAccessExpression) =
@@ -339,8 +339,8 @@ class DefaultParameterInjector internal constructor(val context: Context): BodyL
private val CallableMemberDescriptor.needsDefaultArgumentsLowering private val CallableMemberDescriptor.needsDefaultArgumentsLowering
get() = valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline) get() = valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline)
private fun FunctionDescriptor.generateDefaultsDescription(context: Context): FunctionDescriptor { private fun FunctionDescriptor.generateDefaultsFunction(context: Context): IrFunction {
return context.ir.defaultParameterDescriptorsCache.getOrPut(this) { return context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
val descriptor = when (this) { val descriptor = when (this) {
is ClassConstructorDescriptor -> is ClassConstructorDescriptor ->
ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
@@ -367,7 +367,7 @@ private fun FunctionDescriptor.generateDefaultsDescription(context: Context): Fu
if (this is ClassConstructorDescriptor) { if (this is ClassConstructorDescriptor) {
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1, syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
kConstructorMarkerName, kConstructorMarkerName,
getDefaultArgumentMarkerClassDescriptor(context.builtIns).defaultType) context.ir.symbols.defaultArgumentMarker.owner.defaultType)
} }
descriptor.initialize( descriptor.initialize(
/* receiverParameterType = */ extensionReceiverParameter?.type, /* receiverParameterType = */ extensionReceiverParameter?.type,
@@ -407,10 +407,33 @@ private fun FunctionDescriptor.generateDefaultsDescription(context: Context): Fu
/* visibility = */ this.visibility) /* visibility = */ this.visibility)
descriptor.isSuspend = this.isSuspend descriptor.isSuspend = this.isSuspend
context.log{"adds to cache[$this] = $descriptor"} context.log{"adds to cache[$this] = $descriptor"}
descriptor
val startOffset = this.startOffsetOrUndefined
val endOffset = this.endOffsetOrUndefined
val result: IrFunction = when (descriptor) {
is ClassConstructorDescriptor -> IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
else -> IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
}
result.createParameterDeclarations()
result
} }
} }
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER :
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: KotlinType):ValueParameterDescriptor { private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: KotlinType):ValueParameterDescriptor {
return ValueParameterDescriptorImpl( return ValueParameterDescriptorImpl(
containingDeclaration = descriptor, containingDeclaration = descriptor,
@@ -429,9 +452,4 @@ private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Nam
internal val kConstructorMarkerName = "marker".synthesizedName internal val kConstructorMarkerName = "marker".synthesizedName
private fun getDefaultArgumentMarkerClassDescriptor(builtIns: KonanBuiltIns): ClassDescriptor =
builtIns.konanInternal.getContributedClassifier(
Name.identifier("DefaultArgumentMarker"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
internal fun IrBuilderWithScope.irGet(descriptor: ReceiverParameterDescriptor):IrGetValue = IrGetValueImpl(startOffset, endOffset, descriptor)
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
@@ -282,6 +282,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
.toList() .toList()
defaultClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null) defaultClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
defaultClass.addFakeOverrides()
return defaultClass return defaultClass
} }
@@ -1,24 +1,25 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.DeepCopyIrTreeWithDeclarations
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockSymbol
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin 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.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -32,9 +33,9 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression
} }
private data class Return(val functionDescriptor: FunctionDescriptor): HighLevelJump { private data class Return(val target: IrFunctionSymbol): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression) override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression)
= IrReturnImpl(startOffset, endOffset, functionDescriptor, value) = IrReturnImpl(startOffset, endOffset, target, value)
} }
private data class Break(val loop: IrLoop): HighLevelJump { private data class Break(val loop: IrLoop): HighLevelJump {
@@ -64,7 +65,7 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
private class TryScope(var expression: IrExpression, private class TryScope(var expression: IrExpression,
val finallyExpression: IrExpression, val finallyExpression: IrExpression,
val irBuilder: IrBuilderWithScope): Scope() { val irBuilder: IrBuilderWithScope): Scope() {
val jumps = mutableMapOf<HighLevelJump, FunctionDescriptor>() val jumps = mutableMapOf<HighLevelJump, IrFunctionSymbol>()
} }
private val scopeStack = mutableListOf<Scope>() private val scopeStack = mutableListOf<Scope>()
@@ -101,26 +102,26 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
override fun visitBreak(jump: IrBreak): IrExpression { override fun visitBreak(jump: IrBreak): IrExpression {
val startOffset = jump.startOffset val startOffset = jump.startOffset
val endOffset = jump.endOffset val endOffset = jump.endOffset
val irBuilder = context.createIrBuilder(functionDescriptor, startOffset, endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset)
return performHighLevelJump( return performHighLevelJump(
targetScopePredicate = { it is LoopScope && it.loop == jump.loop }, targetScopePredicate = { it is LoopScope && it.loop == jump.loop },
jump = Break(jump.loop), jump = Break(jump.loop),
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
value = irBuilder.irUnit() value = irBuilder.irGetObject(context.ir.symbols.unit)
) ?: jump ) ?: jump
} }
override fun visitContinue(jump: IrContinue): IrExpression { override fun visitContinue(jump: IrContinue): IrExpression {
val startOffset = jump.startOffset val startOffset = jump.startOffset
val endOffset = jump.endOffset val endOffset = jump.endOffset
val irBuilder = context.createIrBuilder(functionDescriptor, startOffset, endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset)
return performHighLevelJump( return performHighLevelJump(
targetScopePredicate = { it is LoopScope && it.loop == jump.loop }, targetScopePredicate = { it is LoopScope && it.loop == jump.loop },
jump = Continue(jump.loop), jump = Continue(jump.loop),
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
value = irBuilder.irUnit() value = irBuilder.irGetObject(context.ir.symbols.unit)
) ?: jump ) ?: jump
} }
@@ -129,7 +130,7 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
return performHighLevelJump( return performHighLevelJump(
targetScopePredicate = { it is ReturnableScope && it.descriptor == expression.returnTarget }, targetScopePredicate = { it is ReturnableScope && it.descriptor == expression.returnTarget },
jump = Return(expression.returnTarget), jump = Return(expression.returnTargetSymbol),
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
value = expression.value value = expression.value
@@ -161,10 +162,10 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
val currentTryScope = tryScopes[index] val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) { currentTryScope.jumps.getOrPut(jump) {
val descriptor = getFakeFunctionDescriptor(jump.toString(), value.type) val symbol = getIrReturnableBlockSymbol(jump.toString(), value.type)
with(currentTryScope) { with(currentTryScope) {
irBuilder.run { irBuilder.run {
val inlinedFinally = irInlineFinally(descriptor, expression, finallyExpression) val inlinedFinally = irInlineFinally(symbol, expression, finallyExpression)
expression = performHighLevelJump( expression = performHighLevelJump(
tryScopes = tryScopes, tryScopes = tryScopes,
index = index + 1, index = index + 1,
@@ -174,12 +175,12 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
value = inlinedFinally) value = inlinedFinally)
} }
} }
descriptor symbol
}.let { }.let {
return IrReturnImpl( return IrReturnImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
returnTargetDescriptor = it, returnTargetSymbol = it,
value = value) value = value)
} }
} }
@@ -191,7 +192,7 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
val startOffset = aTry.startOffset val startOffset = aTry.startOffset
val endOffset = aTry.endOffset val endOffset = aTry.endOffset
val irBuilder = context.createIrBuilder(functionDescriptor, startOffset, endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset)
val transformer = this val transformer = this
irBuilder.run { irBuilder.run {
val transformedTry = IrTryImpl( val transformedTry = IrTryImpl(
@@ -223,33 +224,33 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
finallyExpression = null finallyExpression = null
) )
using(TryScope(syntheticTry, transformedFinallyExpression, this)) { using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughDescriptor = getFakeFunctionDescriptor("fallThrough", aTry.type) val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", aTry.type)
val transformedResult = aTry.tryResult.transform(transformer, null) val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughDescriptor, transformedResult) transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) { for (aCatch in aTry.catches) {
val transformedCatch = aCatch.transform(transformer, null) val transformedCatch = aCatch.transform(transformer, null)
transformedCatch.result = irReturn(fallThroughDescriptor, transformedCatch.result) transformedCatch.result = irReturn(fallThroughSymbol, transformedCatch.result)
transformedTry.catches.add(transformedCatch) transformedTry.catches.add(transformedCatch)
} }
return irInlineFinally(fallThroughDescriptor, it.expression, it.finallyExpression) return irInlineFinally(fallThroughSymbol, it.expression, it.finallyExpression)
} }
} }
} }
private fun IrBuilderWithScope.irInlineFinally(descriptor: FunctionDescriptor, private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol,
value: IrExpression, value: IrExpression,
finallyExpression: IrExpression): IrExpression { finallyExpression: IrExpression): IrExpression {
val returnType = descriptor.returnType!! val returnType = symbol.descriptor.returnType!!
return when { return when {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, returnType) { returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, returnType) {
+irReturnableBlock(descriptor) { +irReturnableBlock(symbol) {
+value +value
} }
+finallyExpression.copy() +finallyExpression.copy()
} }
else -> irBlock(value, null, returnType) { else -> irBlock(value, null, returnType) {
val tmp = irTemporary(irReturnableBlock(descriptor) { val tmp = irTemporary(irReturnableBlock(symbol) {
+irReturn(descriptor, value) +irReturn(symbol, value)
}) })
+finallyExpression.copy() +finallyExpression.copy()
+irGet(tmp.symbol) +irGet(tmp.symbol)
@@ -268,23 +269,19 @@ internal class FinallyBlocksLowering(val context: Context): FunctionLoweringPass
} }
} }
@Suppress("UNCHECKED_CAST") private fun getIrReturnableBlockSymbol(name: String, returnType: KotlinType): IrReturnableBlockSymbol =
private fun <T: IrElement> T.copy() = this.transform(DeepCopyIrTreeWithDeclarations(), data = null) as T IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType))
private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables()
}) })
} }
} }
private object DECLARATION_ORIGIN_FINALLY_BLOCK : fun IrBuilderWithScope.irReturn(target: IrFunctionSymbol, value: IrExpression) =
IrDeclarationOriginImpl("FINALLY_BLOCK")
private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, initializer: IrExpression?) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_FINALLY_BLOCK, descriptor, initializer)
fun IrBuilderWithScope.irReturn(target: FunctionDescriptor, value: IrExpression) =
IrReturnImpl(startOffset, endOffset, target, value) IrReturnImpl(startOffset, endOffset, target, value)
inline fun IrBuilderWithScope.irReturnableBlock(descriptor: FunctionDescriptor, body: IrBlockBuilder.() -> Unit) = inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, descriptor.returnType!!, descriptor, null, IrReturnableBlockImpl(startOffset, endOffset, symbol.descriptor.returnType!!, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, descriptor.returnType!!) IrBlockBuilder(context, scope, startOffset, endOffset, null, symbol.descriptor.returnType!!)
.block(body).statements) .block(body).statements)
} }
@@ -25,32 +25,60 @@ import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.reportCompilationError import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilder import org.jetbrains.kotlin.ir.builders.IrBuilder
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
internal class InteropLoweringPart1(val context: Context) : IrElementTransformerVoid(), FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(this)
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid()
return when (expression.descriptor.original) {
context.interopBuiltIns.typeOf -> {
val typeArgument = expression.getSingleTypeArgument()
val classDescriptor = TypeUtils.getClassDescriptor(typeArgument)
if (classDescriptor == null) {
expression
} else {
val companionObjectDescriptor = classDescriptor.companionObjectDescriptor ?:
error("native variable class $classDescriptor must have the companion object")
IrGetObjectValueImpl(
expression.startOffset, expression.endOffset,
companionObjectDescriptor.defaultType, companionObjectDescriptor
)
}
}
else -> expression
}
}
}
/** /**
* Lowers some interop intrinsic calls. * Lowers some interop intrinsic calls.
*/ */
internal class InteropLowering(val context: Context) : FileLoweringPass { internal class InteropLoweringPart2(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
val transformer = InteropTransformer(context, irFile) val transformer = InteropTransformer(context, irFile)
irFile.transformChildrenVoid(transformer) irFile.transformChildrenVoid(transformer)
@@ -60,142 +88,7 @@ internal class InteropLowering(val context: Context) : FileLoweringPass {
private class InteropTransformer(val context: Context, val irFile: IrFile) : IrBuildingTransformer(context) { private class InteropTransformer(val context: Context, val irFile: IrFile) : IrBuildingTransformer(context) {
val interop = context.interopBuiltIns val interop = context.interopBuiltIns
val konanBuiltins = context.builtIns val symbols = context.ir.symbols
private fun MemberScope.getSingleContributedFunction(name: String,
predicate: (SimpleFunctionDescriptor) -> Boolean) =
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single(predicate)
private fun IrBuilder.irGetObject(descriptor: ClassDescriptor): IrExpression {
return IrGetObjectValueImpl(startOffset, endOffset, descriptor.defaultType, descriptor)
}
private fun IrBuilder.typeOf(descriptor: ClassDescriptor): IrExpression {
val companionObject = descriptor.companionObjectDescriptor ?:
error("native variable class $descriptor must have the companion object")
// TODO: add more checks and produce the compile error instead of exception.
return irGetObject(companionObject)
}
private fun IrBuilder.typeOf(type: KotlinType): IrExpression? {
val descriptor = TypeUtils.getClassDescriptor(type) ?: return null
return typeOf(descriptor)
}
private fun KotlinType.findOverride(property: PropertyDescriptor): PropertyDescriptor {
val result = this.memberScope.getContributedVariables(property.name, NoLookupLocation.FROM_BACKEND).single()
assert (OverridingUtil.overrides(result, property))
return result
}
private fun IrBuilderWithScope.sizeOf(typeObject: IrExpression): IrExpression {
val sizeProperty = typeObject.type.findOverride(interop.variableTypeSize)
return irGet(typeObject, sizeProperty)
}
private fun IrBuilderWithScope.sizeOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return sizeOf(typeObject)
}
private fun IrBuilderWithScope.alignOf(typeObject: IrExpression): IrExpression {
val alignProperty = typeObject.type.findOverride(interop.variableTypeAlign)
return irGet(typeObject, alignProperty)
}
private fun IrBuilderWithScope.alignOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return alignOf(typeObject)
}
@Suppress("UNUSED_PARAMETER")
private fun IrBuilderWithScope.interpretPointed(expression: IrCall, type: KotlinType): IrExpression =
irCall(interop.interpretNullablePointed).apply {
putValueArgument(0, expression)
}
// TODO: make the result type more correct.
private fun IrBuilderWithScope.arrayGet(array: IrExpression, index: IrExpression): IrExpression? {
val elementType = array.type.arguments.single().type
val elementSize = sizeOf(elementType) ?: return null
val resultRawPtr = irCall(konanBuiltins.nativePtrPlusLong).apply {
dispatchReceiver = irCall(interop.cPointerGetRawValue).apply {
extensionReceiver = array
}
putValueArgument(0, times(elementSize, index))
}
return interpretPointed(resultRawPtr, elementType)
}
private fun IrBuilderWithScope.times(left: IrExpression, right: IrExpression): IrCall {
val times = left.type.memberScope.getSingleContributedFunction("times") {
right.type.isSubtypeOf(it.valueParameters.single().type)
}
return irCall(times).apply {
dispatchReceiver = left
putValueArgument(0, right)
}
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, size: IrExpression, align: IrExpression): IrExpression {
val alloc = placement.type.memberScope.getSingleContributedFunction("alloc") {
size.type.isSubtypeOf(it.valueParameters[0]!!.type) &&
align.type.isSubtypeOf(it.valueParameters[1]!!.type)
}
return irCall(alloc).apply {
dispatchReceiver = placement
putValueArgument(0, size)
putValueArgument(1, align)
}
}
@Suppress("UNUSED_PARAMETER")
private fun IrBuilderWithScope.nativePointedToCPointer(
expression: IrExpression, pointeeType: KotlinType
): IrExpression = irCall(interop.interpretCPointer).apply {
putValueArgument(0, irCall(interop.nativePointedGetRawPointer).apply {
extensionReceiver = expression
})
}
// TODO: make the result type more correct.
private fun IrBuilderWithScope.allocArray(placement: IrExpression,
elementType: KotlinType,
length: IrExpression
): IrExpression? {
val elementSize = sizeOf(elementType) ?: return null
val size = times(elementSize, length)
val align = alignOf(elementType) ?: return null
return nativePointedToCPointer(alloc(placement, size, align), elementType)
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, type: KotlinType): IrExpression? {
val size = sizeOf(type) ?: return null
val align = alignOf(type) ?: return null
return alloc(placement, size, align)
}
private fun IrBuilderWithScope.readValue(receiver: IrExpression, typeArgument: KotlinType): IrCallImpl? {
val size = sizeOf(typeArgument) ?: return null
val align = alignOf(typeArgument) ?: return null
val callee = interop.readValueBySizeAndAlign
val typeParameter = callee.typeParameters.single()
val typeArguments = mapOf(typeParameter to typeArgument)
return irCall(callee, typeArguments).apply {
extensionReceiver = receiver
putValueArgument(0, size)
putValueArgument(1, align)
}
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
@@ -214,7 +107,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) { OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) {
// Replace by the intrinsic call to be handled by code generator: // Replace by the intrinsic call to be handled by code generator:
return builder.irCall(interop.nativePointedGetRawPointer).apply { return builder.irCall(symbols.interopNativePointedGetRawPointer).apply {
extensionReceiver = expression.dispatchReceiver extensionReceiver = expression.dispatchReceiver
} }
} }
@@ -222,34 +115,10 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
return when (descriptor) { return when (descriptor) {
interop.cPointerRawValue.getter -> interop.cPointerRawValue.getter ->
// Replace by the intrinsic call to be handled by code generator: // Replace by the intrinsic call to be handled by code generator:
builder.irCall(interop.cPointerGetRawValue).apply { builder.irCall(symbols.interopCPointerGetRawValue).apply {
extensionReceiver = expression.dispatchReceiver extensionReceiver = expression.dispatchReceiver
} }
interop.arrayGetByIntIndex, interop.arrayGetByLongIndex -> {
val array = expression.extensionReceiver!!
val index = expression.getValueArgument(0)!!
builder.arrayGet(array, index) ?: expression
}
interop.allocUninitializedArrayWithIntLength, interop.allocUninitializedArrayWithLongLength -> {
val placement = expression.extensionReceiver!!
val elementType = expression.type.arguments.single().type
val length = expression.getValueArgument(0)!!
builder.allocArray(placement, elementType, length) ?: expression
}
interop.allocVariable -> {
val placement = expression.extensionReceiver!!
val type = expression.getSingleTypeArgument()
builder.alloc(placement, type) ?: expression
}
interop.typeOf -> {
val type = expression.getSingleTypeArgument()
builder.typeOf(type) ?: expression
}
interop.bitsToFloat -> { interop.bitsToFloat -> {
val argument = expression.getValueArgument(0) val argument = expression.getValueArgument(0)
if (argument is IrConst<*> && argument.kind == IrConstKind.Int) { if (argument is IrConst<*> && argument.kind == IrConstKind.Int) {
@@ -270,13 +139,6 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
} }
} }
interop.readValue -> {
val typeArgument = expression.getSingleTypeArgument()
val receiver = expression.extensionReceiver!!
builder.readValue(receiver, typeArgument) ?: expression
}
in interop.staticCFunction -> { in interop.staticCFunction -> {
val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(0)!!) val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(0)!!)
@@ -288,7 +150,8 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
// TODO: should probably be reported during analysis. // TODO: should probably be reported during analysis.
} }
val target = irCallableReference.descriptor.original val targetSymbol = irCallableReference.symbol
val target = targetSymbol.descriptor
val signatureTypes = target.allParameters.map { it.type } + target.returnType!! val signatureTypes = target.allParameters.map { it.type } + target.returnType!!
signatureTypes.forEachIndexed { index, type -> signatureTypes.forEachIndexed { index, type ->
@@ -312,7 +175,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
builder.startOffset, builder.endOffset, builder.startOffset, builder.endOffset,
expression.type, expression.type,
target, targetSymbol, target,
typeArguments = null) typeArguments = null)
} }
@@ -352,10 +215,14 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
else -> throw Error() else -> throw Error()
} }
val conversionDescriptor = receiver.type.memberScope.getContributedFunctions( val receiverClass = symbols.integerClasses.single {
Name.identifier("to$typeOperand"), NoLookupLocation.FROM_BACKEND).single() receiver.type.isSubtypeOf(it.owner.defaultType)
}
val conversionSymbol = receiverClass.functions.single {
it.descriptor.name == Name.identifier("to$typeOperand")
}
builder.irCall(conversionDescriptor).apply { builder.irCall(conversionSymbol).apply {
dispatchReceiver = receiver dispatchReceiver = receiver
} }
} }
@@ -415,11 +282,11 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
return argument.statements.last() as? IrFunctionReference return argument.statements.last() as? IrFunctionReference
} }
}
private fun IrCall.getSingleTypeArgument(): KotlinType { private fun IrCall.getSingleTypeArgument(): KotlinType {
val typeParameter = descriptor.original.typeParameters.single() val typeParameter = descriptor.original.typeParameters.single()
return getTypeArgument(typeParameter)!! return getTypeArgument(typeParameter)!!
}
} }
private fun IrBuilder.irFloat(value: Float) = private fun IrBuilder.irFloat(value: Float) =
@@ -19,19 +19,16 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.isValueType import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -41,22 +38,24 @@ internal class LateinitLowering(val context: Context): FileLoweringPass {
irFile.transformChildrenVoid(object: IrElementTransformerVoid() { irFile.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitProperty(declaration: IrProperty): IrStatement { override fun visitProperty(declaration: IrProperty): IrStatement {
if (declaration.descriptor.isLateInit) if (declaration.descriptor.isLateInit)
transformGetter(declaration.descriptor, declaration.getter!!) transformGetter(declaration.backingField!!.symbol, declaration.getter!!)
return declaration return declaration
} }
private fun transformGetter(propertyDescriptor: PropertyDescriptor, getter: IrFunction) { private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) {
assert (!propertyDescriptor.type.isValueType(), { "'lateinit' modifier is not allowed on value types" }) val type = backingFieldSymbol.descriptor.type
assert (!type.isValueType(), { "'lateinit' modifier is not allowed on value types" })
val startOffset = getter.startOffset val startOffset = getter.startOffset
val endOffset = getter.endOffset val endOffset = getter.endOffset
val irBuilder = context.createIrBuilder(getter.descriptor, startOffset, endOffset) val irBuilder = context.createIrBuilder(getter.symbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val block = irBlock(propertyDescriptor.type) val block = irBlock(type)
val resultVar = scope.createTemporaryVariable(irGetField(irThis(), propertyDescriptor)) val resultVar = scope.createTemporaryVariable(
irGetField(irGet(getter.dispatchReceiverParameter!!.symbol), backingFieldSymbol))
block.statements.add(resultVar) block.statements.add(resultVar)
val throwIfNull = irIfThenElse(context.builtIns.nothingType, val throwIfNull = irIfThenElse(context.builtIns.nothingType,
irNotEquals(irGet(resultVar.descriptor), irNull()), irNotEquals(irGet(resultVar.symbol), irNull()),
irReturn(irGet(resultVar.descriptor)), irReturn(irGet(resultVar.symbol)),
irCall(throwErrorFunction)) irCall(throwErrorFunction))
block.statements.add(throwIfNull) block.statements.add(throwIfNull)
getter.body = IrExpressionBodyImpl(startOffset, endOffset, block) getter.body = IrExpressionBodyImpl(startOffset, endOffset, block)
@@ -65,11 +64,9 @@ internal class LateinitLowering(val context: Context): FileLoweringPass {
}) })
} }
private val throwErrorFunction = context.builtIns.getKonanInternalFunctions("ThrowUninitializedPropertyAccessException").single() private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock
= IrBlockImpl(startOffset, endOffset, type) = IrBlockImpl(startOffset, endOffset, type)
private fun IrBuilderWithScope.irGetField(receiver: IrExpression?, property: PropertyDescriptor): IrExpression
= IrGetFieldImpl(startOffset, endOffset, property, receiver)
} }
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.isSuspendFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.util.atMostOne import org.jetbrains.kotlin.backend.konan.util.atMostOne
@@ -43,9 +41,6 @@ import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -53,6 +48,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.ir.util.*
internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass { internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass {
@@ -67,7 +63,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
else null else null
} }
transformCallableReferencesToSuspendLambdas(irDeclarationContainer) transformCallableReferencesToSuspendLambdas(irDeclarationContainer)
transformCallsToExtensionSuspendFunctions(irDeclarationContainer)
} }
private fun markSuspendLambdas(irDeclarationContainer: IrDeclarationContainer) { private fun markSuspendLambdas(irDeclarationContainer: IrDeclarationContainer) {
@@ -116,36 +111,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
} }
private fun transformCallsToExtensionSuspendFunctions(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.forEach {
it.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val descriptor = expression.descriptor
if (!descriptor.isSuspendFunctionInvoke || descriptor.extensionReceiverParameter == null)
return expression
val invokeFunctionDescriptor = descriptor.dispatchReceiverParameter!!.type.memberScope
.getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single()
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
calleeDescriptor = invokeFunctionDescriptor
).apply {
dispatchReceiver = expression.dispatchReceiver
putValueArgument(0, expression.extensionReceiver)
invokeFunctionDescriptor.valueParameters.drop(1).forEach {
putValueArgument(it.index, expression.getValueArgument(it.index - 1))
}
}
}
})
}
}
private enum class SuspendFunctionKind { private enum class SuspendFunctionKind {
NO_SUSPEND_CALLS, NO_SUSPEND_CALLS,
DELEGATING, DELEGATING,
@@ -235,7 +200,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
} }
private val getContinuationDescriptor = context.builtIns.getKonanInternalFunctions("getContinuation").single() private val symbols = context.ir.symbols
private val getContinuationSymbol = symbols.getContinuation
private val returnIfSuspendedDescriptor = context.builtIns.getKonanInternalFunctions("returnIfSuspended").single() private val returnIfSuspendedDescriptor = context.builtIns.getKonanInternalFunctions("returnIfSuspended").single()
private fun removeReturnIfSuspendedCall(irFunction: IrFunction) { private fun removeReturnIfSuspendedCall(irFunction: IrFunction) {
@@ -262,15 +228,15 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
+irReturn( +irReturn(
irCall(coroutine.doResumeFunction.symbol).apply { irCall(coroutine.doResumeFunction.symbol).apply {
dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply { dispatchReceiver = irCall(coroutine.coroutineConstructor.symbol).apply {
val functionParameters = irFunction.descriptor.explicitParameters val functionParameters = irFunction.explicitParameters
functionParameters.forEachIndexed { index, argument -> functionParameters.forEachIndexed { index, argument ->
putValueArgument(index, irGet(argument)) putValueArgument(index, irGet(argument))
} }
putValueArgument(functionParameters.size, putValueArgument(functionParameters.size,
irCall(getContinuationDescriptor.substitute(descriptor.returnType!!))) irCall(getContinuationSymbol, listOf(descriptor.returnType!!)))
} }
putValueArgument(0, irUnit()) // value putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception putValueArgument(1, irNull()) // exception
}) })
} }
} }
@@ -285,17 +251,13 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private var coroutineId = 0 private var coroutineId = 0
private val COROUTINES_FQ_NAME = FqName.fromSegments(listOf("kotlin", "coroutines", "experimental")) private val COROUTINES_FQ_NAME = FqName.fromSegments(listOf("kotlin", "coroutines", "experimental"))
private val COROUTINES_INTRINSICS_FQ_NAME = FqName.fromSegments(listOf("kotlin", "coroutines", "experimental", "intrinsics"))
private val KOTLIN_FQ_NAME = FqName("kotlin") private val KOTLIN_FQ_NAME = FqName("kotlin")
private val coroutinesScope = context.irModule!!.descriptor.getPackage(COROUTINES_FQ_NAME).memberScope private val coroutinesScope = context.irModule!!.descriptor.getPackage(COROUTINES_FQ_NAME).memberScope
private val coroutinesIntrinsicsScope = context.irModule!!.descriptor.getPackage(COROUTINES_INTRINSICS_FQ_NAME).memberScope
private val kotlinPackageScope = context.irModule!!.descriptor.getPackage(KOTLIN_FQ_NAME).memberScope private val kotlinPackageScope = context.irModule!!.descriptor.getPackage(KOTLIN_FQ_NAME).memberScope
private val continuationClassDescriptor = coroutinesScope private val continuationClassDescriptor = coroutinesScope
.getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor .getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private val COROUTINE_SUSPENDED = coroutinesIntrinsicsScope
.getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND).first()
private inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) { private inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) {
@@ -313,12 +275,17 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private lateinit var coroutineClassThis: IrValueParameterSymbol private lateinit var coroutineClassThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol> private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private val coroutineImplClassDescriptor = context.builtIns.getKonanInternalClass("CoroutineImpl") private val coroutineImplSymbol = symbols.coroutineImpl
private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single()
private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor
private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
.single { it.valueParameters.size == 1 } .single { it.valueParameters.size == 1 }
private val create1CompletionParameter = create1FunctionDescriptor.valueParameters[0] private val create1CompletionParameter = create1FunctionDescriptor.valueParameters[0]
private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!!
private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!!
fun build(): BuiltCoroutine { fun build(): BuiltCoroutine {
val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType) val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType)
var suspendFunctionClassDescriptor: ClassDescriptor? = null var suspendFunctionClassDescriptor: ClassDescriptor? = null
@@ -406,6 +373,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
).filterNotNull().toList() ).filterNotNull().toList()
coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null) coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
coroutineClass.addFakeOverrides()
coroutineConstructorBuilder.initialize() coroutineConstructorBuilder.initialize()
coroutineClass.declarations.add(coroutineConstructorBuilder.ir) coroutineClass.declarations.add(coroutineConstructorBuilder.ir)
@@ -437,8 +406,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createConstructorBuilder() private fun createConstructorBuilder()
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single()
override fun buildSymbol() = IrConstructorSymbolImpl( override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
@@ -452,7 +419,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = ( val constructorParameters = (
functionParameters functionParameters
+ coroutineImplConstructorDescriptor.valueParameters[0] // completion. + coroutineImplConstructorSymbol.descriptor.valueParameters[0] // completion.
).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) } ).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) }
descriptor.initialize(constructorParameters, Visibilities.PUBLIC) descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
@@ -478,7 +445,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
val completionParameter = valueParameters.last() val completionParameter = valueParameters.last()
+IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply { +IrDelegatingConstructorCallImpl(startOffset, endOffset,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply {
putValueArgument(0, irGet(completionParameter.symbol)) putValueArgument(0, irGet(completionParameter.symbol))
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
@@ -493,8 +461,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createFactoryConstructorBuilder(boundParams: List<ParameterDescriptor>) private fun createFactoryConstructorBuilder(boundParams: List<ParameterDescriptor>)
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private val coroutineImplConstructorDescriptor = coroutineImplClassDescriptor.constructors.single()
override fun buildSymbol() = IrConstructorSymbolImpl( override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.create( ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ coroutineClassDescriptor, /* containingDeclaration = */ coroutineClassDescriptor,
@@ -526,7 +492,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, coroutineImplConstructorDescriptor).apply { +IrDelegatingConstructorCallImpl(startOffset, endOffset,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply {
putValueArgument(0, irNull()) // Completion. putValueArgument(0, irNull()) // Completion.
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
@@ -669,9 +636,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
putValueArgument(index, irGet(parameter.symbol)) putValueArgument(index, irGet(parameter.symbol))
} }
putValueArgument(valueParameters.size, putValueArgument(valueParameters.size,
irCall(getContinuationDescriptor.substitute(symbol.descriptor.returnType!!))) irCall(getContinuationSymbol, listOf(symbol.descriptor.returnType!!)))
} }
putValueArgument(0, irUnit()) // value putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception putValueArgument(1, irNull()) // exception
} }
) )
@@ -803,7 +770,10 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
scope.forEach { scope.forEach {
+irSetField(irGet(coroutineClassThis), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it)) +irSetField(irGet(coroutineClassThis), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it))
} }
+irSet(irGet(coroutineClassThis), label, irGet(suspensionPoint.suspensionPointIdParameter.symbol)) +irCall(coroutineImplLabelSetterSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis)
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol))
}
} }
} }
restoreStateSymbol -> { restoreStateSymbol -> {
@@ -828,13 +798,15 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.unitType, type = context.builtIns.unitType,
suspensionPointId = irGet(irGet(coroutineClassThis), label), suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis)
},
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. +irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception.
statements.forEach { +it } statements.forEach { +it }
}) })
if (irFunction.descriptor.returnType!!.isUnit()) if (irFunction.descriptor.returnType!!.isUnit())
+irReturn(irUnit()) // Insert explicit return for Unit functions. +irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions.
} }
return function return function
} }
@@ -1156,7 +1128,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueSymbol) = private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueSymbol) =
irIfThen(irEqeqeq(irGet(value), irGet(COROUTINE_SUSPENDED)), irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)),
irReturn(irGet(value))) irReturn(irGet(value)))
private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueSymbol) = private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueSymbol) =
@@ -23,47 +23,50 @@ import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.konan.ir.ir2string import org.jetbrains.kotlin.backend.konan.ir.ir2string
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.Scope
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irSetVar
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl 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.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
class VarargInjectionLowering internal constructor(val context: Context): DeclarationContainerLoweringPass { class VarargInjectionLowering internal constructor(val context: Context): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.forEach{ irDeclarationContainer.declarations.forEach{
when (it) { when (it) {
is IrField -> lower(it.descriptor, it.initializer) is IrField -> lower(it.symbol, it.initializer)
is IrFunction -> lower(it.descriptor, it.body) is IrFunction -> lower(it.symbol, it.body)
is IrProperty -> { is IrProperty -> {
lower(it.descriptor, it.backingField) it.backingField?.let { field ->
if (it.getter != null) lower(field.symbol, field)
lower(it.getter!!.descriptor, it.getter) }
if (it.setter != null) it.getter?.let { getter ->
lower(it.setter!!.descriptor, it.setter) lower(getter.symbol, getter)
}
it.setter?.let { setter ->
lower(setter.symbol, setter)
}
} }
} }
} }
} }
private fun lower(owner:DeclarationDescriptor, element: IrElement?) { private fun lower(owner: IrSymbol, element: IrElement?) {
element?.transformChildrenVoid(object: IrElementTransformerVoid() { element?.transformChildrenVoid(object: IrElementTransformerVoid() {
val transformer = this val transformer = this
@@ -107,11 +110,13 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
val type = expression.varargElementType val type = expression.varargElementType
log("$expression: array type:$type, is array of primitives ${!KotlinBuiltIns.isArray(expression.type)}") log("$expression: array type:$type, is array of primitives ${!KotlinBuiltIns.isArray(expression.type)}")
val arrayHandle = arrayType(expression.type) val arrayHandle = arrayType(expression.type)
val arrayConstructor = arrayHandle.arrayDescriptor.constructors.find { it.valueParameters.size == 1 }!! val arrayConstructor = arrayHandle.arraySymbol.constructors.find { it.owner.valueParameters.size == 1 }!!
val block = irBlock(arrayHandle.arrayDescriptor.defaultType) val block = irBlock(arrayHandle.arraySymbol.owner.defaultType)
val arrayConstructorCall = irCall( val arrayConstructorCall = if (arrayConstructor.owner.typeParameters.isEmpty()) {
descriptor = arrayConstructor, irCall(arrayConstructor)
typeArguments = typeArgument(arrayConstructor, type)) } else {
irCall(arrayConstructor, listOf(type))
}
val vars = expression.elements.map { val vars = expression.elements.map {
@@ -135,10 +140,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
log("element:$i> ${ir2string(element)}") log("element:$i> ${ir2string(element)}")
val dst = vars[element]!! val dst = vars[element]!!
if (element !is IrSpreadElement) { if (element !is IrSpreadElement) {
val setArrayElementCall = irCall( val setArrayElementCall = irCall(arrayHandle.setMethodSymbol)
descriptor = arrayHandle.setMethodDescriptor,
typeArguments = null
)
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.symbol) setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.symbol)
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.symbol) else irConstInt(i)) setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.symbol) else irConstInt(i))
setArrayElementCall.putValueArgument(1, irGet(dst.symbol)) setArrayElementCall.putValueArgument(1, irGet(dst.symbol))
@@ -149,7 +151,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
} else { } else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.symbol)), "length".synthesizedString) val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.symbol)), "length".synthesizedString)
block.statements.add(arraySizeVariable) block.statements.add(arraySizeVariable)
val copyCall = irCall(arrayHandle.copyRangeToDescriptor, null).apply { val copyCall = irCall(arrayHandle.copyRangeToSymbol).apply {
extensionReceiver = irGet(dst.symbol) extensionReceiver = irGet(dst.symbol)
putValueArgument(0, irGet(arrayTmpVariable.symbol)) /* destination */ putValueArgument(0, irGet(arrayTmpVariable.symbol)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */ putValueArgument(1, kIntZero) /* fromIndex */
@@ -170,13 +172,8 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
}) })
} }
private val symbols = context.ir.symbols
private fun typeArgument(arrayConstructor: ClassConstructorDescriptor, type: KotlinType):Map<TypeParameterDescriptor, KotlinType>? { private val intPlusInt = symbols.intPlusInt
return if (!arrayConstructor.typeParameters.isEmpty())
mapOf(arrayConstructor.typeParameters.first() to type)
else
null
}
private fun arrayType(type: KotlinType): ArrayHandle = when { private fun arrayType(type: KotlinType): ArrayHandle = when {
KotlinBuiltIns.isPrimitiveArray(type) -> { KotlinBuiltIns.isPrimitiveArray(type) -> {
@@ -196,7 +193,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
else -> kArrayHandler else -> kArrayHandler
} }
private fun IrBuilderWithScope.intPlus() = irCall(kIntPlusDescriptor, null) private fun IrBuilderWithScope.intPlus() = irCall(intPlusInt)
private fun IrBuilderWithScope.increment(expression: IrExpression, value: IrExpression): IrExpression { private fun IrBuilderWithScope.increment(expression: IrExpression, value: IrExpression): IrExpression {
return intPlus().apply { return intPlus().apply {
dispatchReceiver = expression dispatchReceiver = expression
@@ -211,7 +208,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
}) })
} }
private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map<IrVarargElement, IrVariable>): IrExpression? { private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map<IrVarargElement, IrVariable>): IrExpression? {
context.createIrBuilder(scope.scopeOwner, expression.startOffset, expression.endOffset).run { context.createIrBuilder(scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
if (!hasSpreadElement) if (!hasSpreadElement)
return irConstInt(expression.elements.size) return irConstInt(expression.elements.size)
val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size
@@ -224,7 +221,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
} }
private fun IrBuilderWithScope.irArraySize(arrayHandle: ArrayHandle, expression: IrExpression): IrExpression { private fun IrBuilderWithScope.irArraySize(arrayHandle: ArrayHandle, expression: IrExpression): IrExpression {
val arraySize = irCall((arrayHandle.sizeDescriptor as PropertyDescriptor).getter as FunctionDescriptor, null).apply { val arraySize = irCall(arrayHandle.sizeGetterSymbol).apply {
dispatchReceiver = expression dispatchReceiver = expression
} }
return arraySize return arraySize
@@ -237,48 +234,31 @@ class VarargInjectionLowering internal constructor(val context: Context): Declar
context.log{"VARARG-INJECTOR: $msg"} context.log{"VARARG-INJECTOR: $msg"}
} }
data class ArrayHandle(val arrayDescriptor:ClassDescriptor, data class ArrayHandle(val arraySymbol: IrClassSymbol,
val setMethodDescriptor: FunctionDescriptor, val setMethodSymbol: IrFunctionSymbol,
val sizeDescriptor:DeclarationDescriptor, val sizeGetterSymbol: IrFunctionSymbol,
val copyRangeToDescriptor:FunctionDescriptor) val copyRangeToSymbol: IrFunctionSymbol)
val kKotlinPackage = context.builtIns.builtInsModule.getPackage(FqName("kotlin"))
val kByteArrayHandler = handle(arrayClassDescriptor("ByteArray"))
val kCharArrayHandler = handle(arrayClassDescriptor("CharArray"))
val kShortArrayHandler = handle(arrayClassDescriptor("ShortArray"))
val kIntArrayHandler = handle(arrayClassDescriptor("IntArray"))
val kLongArrayHandler = handle(arrayClassDescriptor("LongArray"))
val kFloatArrayHandler = handle(arrayClassDescriptor("FloatArray"))
val kDoubleArrayHandler = handle(arrayClassDescriptor("DoubleArray"))
val kBooleanArrayHandler = handle(arrayClassDescriptor("BooleanArray"))
val kArrayHandler = handle(context.builtIns.array)
val kInt = context.builtIns.int val kByteArrayHandler = handle(symbols.byteArray)
val kIntType = context.builtIns.intType val kCharArrayHandler = handle(symbols.charArray)
val kIntPlusDescriptor = DescriptorUtils.getAllDescriptors(kInt.unsubstitutedMemberScope).find { val kShortArrayHandler = handle(symbols.shortArray)
it.name.asString() == "plus" val kIntArrayHandler = handle(symbols.intArray)
&& (it as FunctionDescriptor).valueParameters[0].type == kIntType} as FunctionDescriptor val kLongArrayHandler = handle(symbols.longArray)
val kFloatArrayHandler = handle(symbols.floatArray)
val kDoubleArrayHandler = handle(symbols.doubleArray)
val kBooleanArrayHandler = handle(symbols.booleanArray)
val kArrayHandler = handle(symbols.array)
private fun handle(descriptor:ClassDescriptor) = ArrayHandle( private fun handle(symbol: IrClassSymbol) = ArrayHandle(
arrayDescriptor = descriptor, arraySymbol = symbol,
setMethodDescriptor = setMethodDescriptor(descriptor), setMethodSymbol = symbol.functions.single { it.descriptor.name == OperatorNameConventions.SET },
sizeDescriptor = sizeMethodDescriptor(descriptor)!!, sizeGetterSymbol = symbol.getPropertyGetter("size")!!,
copyRangeToDescriptor = copyRangeToFunctionDescriptor(descriptor)) copyRangeToSymbol = symbols.copyRangeTo[symbol.descriptor]!!
)
private fun copyRangeToFunctionDescriptor(descriptor: ClassDescriptor): FunctionDescriptor {
val packageViewDescriptor = descriptor.module.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME)
return packageViewDescriptor.memberScope.getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND).first {
it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == descriptor
}
}
private fun setMethodDescriptor(descriptor:ClassDescriptor) = methodDescriptor(descriptor, "set")
private fun sizeMethodDescriptor(descriptor:ClassDescriptor) = descriptor(descriptor, "size")
private fun methodDescriptor(descriptor:ClassDescriptor, methodName:String) = DescriptorUtils.getFunctionByName(descriptor.unsubstitutedMemberScope, Name.identifier(methodName))
private fun arrayClassDescriptor(name:String) = kKotlinPackage.memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private fun descriptor(descriptor: ClassDescriptor, name:String) = DescriptorUtils.getAllDescriptors(descriptor.unsubstitutedMemberScope).find{it.name.asString() == name}
} }
private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> = IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, value) private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> = IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, value)
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type) private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
private fun IrBuilderWithScope.irCall(descriptor: FunctionDescriptor, typeArguments: Map<TypeParameterDescriptor, KotlinType>?): IrCall = IrCallImpl(startOffset, endOffset, descriptor, typeArguments)
private val IrBuilderWithScope.kIntZero get() = irConstInt(0) private val IrBuilderWithScope.kIntZero get() = irConstInt(0)
private val IrBuilderWithScope.kIntOne get() = irConstInt(1) private val IrBuilderWithScope.kIntOne get() = irConstInt(1)
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.util.addFakeOverrides
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
import org.jetbrains.kotlin.serialization.KonanIr import org.jetbrains.kotlin.serialization.KonanIr
@@ -1057,6 +1058,7 @@ internal class IrDeserializer(val context: Context,
val clazz = IrClassImpl(start, end, origin, descriptor, members) val clazz = IrClassImpl(start, end, origin, descriptor, members)
clazz.createParameterDeclarations() clazz.createParameterDeclarations()
clazz.addFakeOverrides()
return clazz return clazz
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.backend.konan.PhaseManager
import org.jetbrains.kotlin.backend.konan.KonanPhase import org.jetbrains.kotlin.backend.konan.KonanPhase
import org.jetbrains.kotlin.serialization.MutableTypeTable import org.jetbrains.kotlin.serialization.MutableTypeTable
import org.jetbrains.kotlin.serialization.KonanLinkData import org.jetbrains.kotlin.serialization.KonanLinkData
import org.jetbrains.kotlin.backend.common.validateIrFunction
internal class DeserializerDriver(val context: Context) { internal class DeserializerDriver(val context: Context) {
@@ -16,33 +16,17 @@
package org.jetbrains.kotlin.ir.builders package org.jetbrains.kotlin.ir.builders
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
inline fun IrBuilderWithScope.irLetSequence(
value: IrExpression,
nameHint: String? = null,
startOffset: Int = this.startOffset,
endOffset: Int = this.endOffset,
origin: IrStatementOrigin? = null,
resultType: KotlinType? = null,
body: IrBlockBuilder.(VariableDescriptor) -> Unit
): IrExpression = irBlock(startOffset, endOffset, origin, resultType) {
val irTemporary = defineTemporary(value, nameHint)
this.body(irTemporary)
}
fun IrBuilderWithScope.irWhile(origin: IrStatementOrigin? = null) = fun IrBuilderWithScope.irWhile(origin: IrStatementOrigin? = null) =
IrWhileLoopImpl(startOffset, endOffset, context.builtIns.unitType, origin) IrWhileLoopImpl(startOffset, endOffset, context.builtIns.unitType, origin)
@@ -57,46 +41,18 @@ fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, co
fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false) fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irGet(value: ValueDescriptor) =
IrGetValueImpl(startOffset, endOffset, value)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irGet(receiver: IrExpression?, property: PropertyDescriptor): IrCall =
IrCallImpl(startOffset, endOffset, property.getter!!).apply {
dispatchReceiver = receiver
}
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irThis() =
scope.classOwner().let { classOwner ->
IrGetValueImpl(startOffset, endOffset, classOwner.thisAsReceiverParameter)
}
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irSetVar(variable: VariableDescriptor, value: IrExpression) =
IrSetVariableImpl(startOffset, endOffset, variable, value, IrStatementOrigin.EQ)
@Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irCall(descriptor: FunctionDescriptor): IrCallImpl {
return IrCallImpl(this.startOffset, this.endOffset, descriptor)
}
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol): IrCallImpl { fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol): IrCallImpl {
return IrCallImpl(this.startOffset, this.endOffset, symbol) return IrCallImpl(this.startOffset, this.endOffset, symbol)
} }
@Deprecated("Creates unbound symbol") fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: Map<TypeParameterDescriptor, KotlinType>) =
fun IrBuilderWithScope.irCall( IrCallImpl(this.startOffset, this.endOffset, symbol, symbol.descriptor.substitute(typeArguments), typeArguments)
callee: FunctionDescriptor,
typeArguments: Map<TypeParameterDescriptor, KotlinType>
): IrCallImpl {
val substitutionContext = typeArguments.map { (typeParameter, typeArgument) ->
typeParameter.typeConstructor to TypeProjectionImpl(typeArgument)
}.toMap()
val substitutor = TypeSubstitutor.create(substitutionContext) fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<KotlinType>) =
val substitutedCallee = callee.substitute(substitutor)!! irCall(symbol, symbol.descriptor.typeParameters.zip(typeArguments).toMap())
return IrCallImpl(this.startOffset, this.endOffset, substitutedCallee, typeArguments) fun IrBuilderWithScope.irGetObject(classSymbol: IrClassSymbol) =
} IrGetObjectValueImpl(startOffset, endOffset, classSymbol.owner.defaultType, classSymbol)
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, symbol: IrFieldSymbol) =
IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
@@ -16,20 +16,19 @@
package org.jetbrains.kotlin.ir.util package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.konan.util.atMostOne
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.name.Name
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.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceElement
@@ -175,6 +174,35 @@ fun IrClass.createParameterDeclarations() {
} }
} }
fun IrClass.addFakeOverrides() {
val startOffset = this.startOffset
val endOffset = this.endOffset
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply {
createParameterDeclarations()
}
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.mapTo(this.declarations) {
when (it) {
is FunctionDescriptor -> it.createFunction()
is PropertyDescriptor ->
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
// TODO: add field if getter is missing?
getter = it.getter?.createFunction()
setter = it.setter?.createFunction()
}
else -> TODO(it.toString())
}
}
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int = private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.startOffset ?: this.startOffset descriptor.startOffset ?: this.startOffset
@@ -193,6 +221,16 @@ val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
val IrClassSymbol.constructors: Sequence<IrConstructorSymbol> val IrClassSymbol.constructors: Sequence<IrConstructorSymbol>
get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol } get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol }
private fun IrClassSymbol.getPropertyDeclaration(name: String) =
this.owner.declarations.filterIsInstance<IrProperty>()
.atMostOne { it.descriptor.name == Name.identifier(name) }
fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
this.getPropertyDeclaration(name)?.getter?.symbol
fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
this.getPropertyDeclaration(name)?.setter?.symbol
val IrFunction.explicitParameters: List<IrValueParameterSymbol> val IrFunction.explicitParameters: List<IrValueParameterSymbol>
get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol } get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
@@ -201,68 +239,3 @@ val IrValueParameter.type: KotlinType
val IrClass.defaultType: KotlinType val IrClass.defaultType: KotlinType
get() = this.descriptor.defaultType 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()}")
}
}
}
+1 -1
View File
@@ -24,5 +24,5 @@ testDataVersion=1067176:id
kotlinCompilerRepo=http://dl.bintray.com/jetbrains/kotlin-native-dependencies kotlinCompilerRepo=http://dl.bintray.com/jetbrains/kotlin-native-dependencies
#kotlinCompilerRepo=http://oss.sonatype.org/content/repositories/snapshots #kotlinCompilerRepo=http://oss.sonatype.org/content/repositories/snapshots
#kotlinCompilerRepo=http://dl.bintray.com/kotlin/kotlin-dev #kotlinCompilerRepo=http://dl.bintray.com/kotlin/kotlin-dev
kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-20170519.065155-538 kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-20170521.012435-545
konanVersion=0.2 konanVersion=0.2