Copy common lowers
This commit is contained in:
+189
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCatch
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
|
// TODO: synchronize with JVM BE
|
||||||
|
// TODO: rename the file.
|
||||||
|
class Closure(val capturedValues: List<IrValueSymbol> = emptyList())
|
||||||
|
|
||||||
|
class ClosureAnnotator {
|
||||||
|
private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>()
|
||||||
|
|
||||||
|
constructor(declaration: IrDeclaration) {
|
||||||
|
// Collect all closures for classes and functions. Collect call graph
|
||||||
|
declaration.acceptChildrenVoid(ClosureCollectorVisitor())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFunctionClosure(descriptor: FunctionDescriptor) = getClosure(descriptor)
|
||||||
|
fun getClassClosure(descriptor: ClassDescriptor) = getClosure(descriptor)
|
||||||
|
|
||||||
|
private fun getClosure(descriptor: DeclarationDescriptor) : Closure {
|
||||||
|
closureBuilders.values.forEach { it.processed = false }
|
||||||
|
return closureBuilders
|
||||||
|
.getOrElse(descriptor) { throw AssertionError("No closure builder for passed descriptor.") }
|
||||||
|
.buildClosure()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClosureBuilder(val owner: DeclarationDescriptor) {
|
||||||
|
val capturedValues = mutableSetOf<IrValueSymbol>()
|
||||||
|
private val declaredValues = mutableSetOf<ValueDescriptor>()
|
||||||
|
private val includes = mutableSetOf<ClosureBuilder>()
|
||||||
|
|
||||||
|
var processed = false
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Node's closure = variables captured by the node +
|
||||||
|
* closure of all included nodes -
|
||||||
|
* variables declared in the node.
|
||||||
|
*/
|
||||||
|
fun buildClosure(): Closure {
|
||||||
|
val result = mutableSetOf<IrValueSymbol>().apply { addAll(capturedValues) }
|
||||||
|
includes.forEach {
|
||||||
|
if (!it.processed) {
|
||||||
|
it.processed = true
|
||||||
|
it.buildClosure().capturedValues.filterTo(result) { isExternal(it.descriptor) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: We can save the closure and reuse it.
|
||||||
|
return Closure(result.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun include(includingBuilder: ClosureBuilder) {
|
||||||
|
includes.add(includingBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun declareVariable(valueDescriptor: ValueDescriptor?) {
|
||||||
|
if (valueDescriptor != null)
|
||||||
|
declaredValues.add(valueDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun seeVariable(value: IrValueSymbol) {
|
||||||
|
if (isExternal(value.descriptor))
|
||||||
|
capturedValues.add(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isExternal(valueDescriptor: ValueDescriptor): Boolean {
|
||||||
|
return !declaredValues.contains(valueDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
val closuresStack = mutableListOf<ClosureBuilder>()
|
||||||
|
|
||||||
|
fun includeInParent(builder: ClosureBuilder) {
|
||||||
|
// We don't include functions or classes in a parent function when they are declared.
|
||||||
|
// Instead we will include them when are is used (use = call for a function or constructor call for a class).
|
||||||
|
val parentBuilder = closuresStack.peek()
|
||||||
|
if (parentBuilder != null && parentBuilder.owner !is FunctionDescriptor) {
|
||||||
|
parentBuilder.include(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
val classDescriptor = declaration.descriptor
|
||||||
|
val closureBuilder = ClosureBuilder(classDescriptor)
|
||||||
|
closureBuilders[declaration.descriptor] = closureBuilder
|
||||||
|
|
||||||
|
closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter)
|
||||||
|
if (classDescriptor.isInner) {
|
||||||
|
closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter)
|
||||||
|
includeInParent(closureBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
closuresStack.push(closureBuilder)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
closuresStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
val functionDescriptor = declaration.descriptor
|
||||||
|
val closureBuilder = ClosureBuilder(functionDescriptor)
|
||||||
|
closureBuilders[functionDescriptor] = closureBuilder
|
||||||
|
|
||||||
|
functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||||
|
closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter)
|
||||||
|
closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter)
|
||||||
|
if (functionDescriptor is ConstructorDescriptor) {
|
||||||
|
closureBuilder.declareVariable(functionDescriptor.constructedClass.thisAsReceiverParameter)
|
||||||
|
// Include closure of the class in the constructor closure.
|
||||||
|
val classBuilder = closuresStack.peek()
|
||||||
|
classBuilder?.let {
|
||||||
|
assert(classBuilder.owner == functionDescriptor.constructedClass)
|
||||||
|
closureBuilder.include(classBuilder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closuresStack.push(closureBuilder)
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
closuresStack.pop()
|
||||||
|
|
||||||
|
includeInParent(closureBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) {
|
||||||
|
// Getter and setter of local delegated properties are special generated functions and don't have closure.
|
||||||
|
declaration.delegate.initializer?.acceptVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
||||||
|
closuresStack.peek()?.seeVariable(expression.symbol)
|
||||||
|
super.visitVariableAccess(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
closuresStack.peek()?.declareVariable(declaration.descriptor)
|
||||||
|
super.visitVariable(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCatch(aCatch: IrCatch) {
|
||||||
|
closuresStack.peek()?.declareVariable(aCatch.parameter)
|
||||||
|
super.visitCatch(aCatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process delegating constructor calls, enum constructor calls, calls and callable references.
|
||||||
|
override fun visitMemberAccess(expression: IrMemberAccessExpression) {
|
||||||
|
expression.acceptChildrenVoid(this)
|
||||||
|
val descriptor = expression.descriptor
|
||||||
|
if (DescriptorUtils.isLocal(descriptor)) {
|
||||||
|
val builder = closureBuilders[descriptor]
|
||||||
|
builder?.let {
|
||||||
|
closuresStack.peek()?.include(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+463
@@ -0,0 +1,463 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.ir2string
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
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.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
|
open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
|
||||||
|
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||||
|
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||||
|
if (memberDeclaration is IrFunction)
|
||||||
|
lower(memberDeclaration)
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val symbols = context.ir.symbols
|
||||||
|
|
||||||
|
private fun lower(irFunction: IrFunction): List<IrFunction> {
|
||||||
|
val functionDescriptor = irFunction.descriptor
|
||||||
|
|
||||||
|
if (!functionDescriptor.needsDefaultArgumentsLowering)
|
||||||
|
return listOf(irFunction)
|
||||||
|
|
||||||
|
val bodies = functionDescriptor.valueParameters
|
||||||
|
.mapNotNull{irFunction.getDefault(it)}
|
||||||
|
|
||||||
|
|
||||||
|
log("detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions")
|
||||||
|
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
|
||||||
|
if (bodies.isNotEmpty()) {
|
||||||
|
val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
|
||||||
|
val descriptor = newIrFunction.descriptor
|
||||||
|
log("$functionDescriptor -> $descriptor")
|
||||||
|
val builder = context.createIrBuilder(newIrFunction.symbol)
|
||||||
|
val body = builder.irBlockBody(irFunction) {
|
||||||
|
val params = mutableListOf<IrVariableSymbol>()
|
||||||
|
val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
|
||||||
|
if (descriptor.extensionReceiverParameter != null) {
|
||||||
|
variables[functionDescriptor.extensionReceiverParameter!!] =
|
||||||
|
newIrFunction.extensionReceiverParameter!!.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
for (valueParameter in functionDescriptor.valueParameters) {
|
||||||
|
val parameterSymbol = newIrFunction.valueParameters[valueParameter.index].symbol
|
||||||
|
val temporaryVariableSymbol =
|
||||||
|
IrVariableSymbolImpl(scope.createTemporaryVariableDescriptor(parameterSymbol.descriptor))
|
||||||
|
params.add(temporaryVariableSymbol)
|
||||||
|
variables.put(valueParameter, temporaryVariableSymbol)
|
||||||
|
if (valueParameter.hasDefaultValue()) {
|
||||||
|
val kIntAnd = symbols.intAnd
|
||||||
|
val condition = irNotEquals(irCall(kIntAnd).apply {
|
||||||
|
dispatchReceiver = irGet(maskParameterSymbol(newIrFunction, valueParameter.index / 32))
|
||||||
|
putValueArgument(0, irInt(1 shl (valueParameter.index % 32)))
|
||||||
|
}, irInt(0))
|
||||||
|
val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
|
||||||
|
|
||||||
|
/* Use previously calculated values in next expression. */
|
||||||
|
expressionBody.transformChildrenVoid(object:IrElementTransformerVoid() {
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
log("GetValue: ${expression.descriptor}")
|
||||||
|
val valueSymbol = variables[expression.descriptor] ?: return expression
|
||||||
|
return irGet(valueSymbol)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
val variableInitialization = irIfThenElse(
|
||||||
|
type = temporaryVariableSymbol.descriptor.type,
|
||||||
|
condition = condition,
|
||||||
|
thenPart = expressionBody.expression,
|
||||||
|
elsePart = irGet(parameterSymbol))
|
||||||
|
+ scope.createTemporaryVariable(
|
||||||
|
symbol = temporaryVariableSymbol,
|
||||||
|
initializer = variableInitialization)
|
||||||
|
/* Mapping calculated values with its origin variables. */
|
||||||
|
} else {
|
||||||
|
+ scope.createTemporaryVariable(
|
||||||
|
symbol = temporaryVariableSymbol,
|
||||||
|
initializer = irGet(parameterSymbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (irFunction is IrConstructor) {
|
||||||
|
+ IrDelegatingConstructorCallImpl(
|
||||||
|
startOffset = irFunction.startOffset,
|
||||||
|
endOffset = irFunction.endOffset,
|
||||||
|
symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor
|
||||||
|
).apply {
|
||||||
|
params.forEachIndexed { i, variable ->
|
||||||
|
putValueArgument(i, irGet(variable))
|
||||||
|
}
|
||||||
|
if (functionDescriptor.dispatchReceiverParameter != null) {
|
||||||
|
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
+irReturn(irCall(irFunction.symbol).apply {
|
||||||
|
if (functionDescriptor.dispatchReceiverParameter != null) {
|
||||||
|
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
|
||||||
|
}
|
||||||
|
if (functionDescriptor.extensionReceiverParameter != null) {
|
||||||
|
extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!]!!)
|
||||||
|
}
|
||||||
|
params.forEachIndexed { i, variable ->
|
||||||
|
putValueArgument(i, irGet(variable))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove default argument initializers.
|
||||||
|
irFunction.valueParameters.forEach {
|
||||||
|
it.defaultValue = null
|
||||||
|
}
|
||||||
|
return if (functionDescriptor is ClassConstructorDescriptor)
|
||||||
|
listOf(irFunction, IrConstructorImpl(
|
||||||
|
startOffset = irFunction.startOffset,
|
||||||
|
endOffset = irFunction.endOffset,
|
||||||
|
descriptor = descriptor as ClassConstructorDescriptor,
|
||||||
|
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||||
|
body = body).apply { createParameterDeclarations() })
|
||||||
|
else
|
||||||
|
listOf(irFunction, IrFunctionImpl(
|
||||||
|
startOffset = irFunction.startOffset,
|
||||||
|
endOffset = irFunction.endOffset,
|
||||||
|
descriptor = descriptor,
|
||||||
|
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||||
|
body = body).apply { createParameterDeclarations() })
|
||||||
|
}
|
||||||
|
return listOf(irFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun log(msg:String) = context.log{"DEFAULT-REPLACER: $msg"}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Scope.createTemporaryVariableDescriptor(parameterDescriptor: ParameterDescriptor?): VariableDescriptor =
|
||||||
|
IrTemporaryVariableDescriptorImpl(
|
||||||
|
containingDeclaration = this.scopeOwner,
|
||||||
|
name = parameterDescriptor!!.name.asString().synthesizedName,
|
||||||
|
outType = parameterDescriptor.type,
|
||||||
|
isMutable = false)
|
||||||
|
|
||||||
|
private fun Scope.createTemporaryVariable(symbol: IrVariableSymbol, initializer: IrExpression) =
|
||||||
|
IrVariableImpl(
|
||||||
|
startOffset = initializer.startOffset,
|
||||||
|
endOffset = initializer.endOffset,
|
||||||
|
origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
||||||
|
symbol = symbol).apply {
|
||||||
|
|
||||||
|
this.initializer = initializer
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody {
|
||||||
|
return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 nullConst(expression: IrElement, type: KotlinType): IrExpression? {
|
||||||
|
when {
|
||||||
|
KotlinBuiltIns.isFloat(type) -> return IrConstImpl.float (expression.startOffset, expression.endOffset, type, 0.0F)
|
||||||
|
KotlinBuiltIns.isDouble(type) -> return IrConstImpl.double (expression.startOffset, expression.endOffset, type, 0.0)
|
||||||
|
KotlinBuiltIns.isBoolean(type) -> return IrConstImpl.boolean (expression.startOffset, expression.endOffset, type, false)
|
||||||
|
KotlinBuiltIns.isByte(type) -> return IrConstImpl.byte (expression.startOffset, expression.endOffset, type, 0)
|
||||||
|
KotlinBuiltIns.isChar(type) -> return IrConstImpl.char (expression.startOffset, expression.endOffset, type, 0.toChar())
|
||||||
|
KotlinBuiltIns.isShort(type) -> return IrConstImpl.short (expression.startOffset, expression.endOffset, type, 0)
|
||||||
|
KotlinBuiltIns.isInt(type) -> return IrConstImpl.int (expression.startOffset, expression.endOffset, type, 0)
|
||||||
|
KotlinBuiltIns.isLong(type) -> return IrConstImpl.long (expression.startOffset, expression.endOffset, type, 0)
|
||||||
|
else -> return IrConstImpl.constNull (expression.startOffset, expression.endOffset, type.builtIns.nullableNothingType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultParameterInjector constructor(val context: CommonBackendContext): BodyLoweringPass {
|
||||||
|
override fun lower(irBody: IrBody) {
|
||||||
|
|
||||||
|
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
super.visitDelegatingConstructorCall(expression)
|
||||||
|
val descriptor = expression.descriptor
|
||||||
|
if (!descriptor.needsDefaultArgumentsLowering)
|
||||||
|
return expression
|
||||||
|
val argumentsCount = argumentCount(expression)
|
||||||
|
if (argumentsCount == descriptor.valueParameters.size)
|
||||||
|
return expression
|
||||||
|
val (symbolForCall, params) = parametersForCall(expression)
|
||||||
|
return IrDelegatingConstructorCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
symbol = symbolForCall as IrConstructorSymbol,
|
||||||
|
descriptor = symbolForCall.descriptor)
|
||||||
|
.apply {
|
||||||
|
params.forEach {
|
||||||
|
log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}")
|
||||||
|
putValueArgument(it.first.index, it.second)
|
||||||
|
}
|
||||||
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
super.visitCall(expression)
|
||||||
|
val functionDescriptor = expression.descriptor
|
||||||
|
|
||||||
|
if (!functionDescriptor.needsDefaultArgumentsLowering)
|
||||||
|
return expression
|
||||||
|
|
||||||
|
val argumentsCount = argumentCount(expression)
|
||||||
|
if (argumentsCount == functionDescriptor.valueParameters.size)
|
||||||
|
return expression
|
||||||
|
val (symbol, params) = parametersForCall(expression)
|
||||||
|
val descriptor = symbol.descriptor
|
||||||
|
descriptor.typeParameters.forEach { log("$descriptor [${it.index}]: $it") }
|
||||||
|
descriptor.original.typeParameters.forEach { log("${descriptor.original}[${it.index}] : $it") }
|
||||||
|
return IrCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
symbol = symbol,
|
||||||
|
descriptor = descriptor,
|
||||||
|
typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap())
|
||||||
|
.apply {
|
||||||
|
params.forEach {
|
||||||
|
log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}")
|
||||||
|
putValueArgument(it.first.index, it.second)
|
||||||
|
}
|
||||||
|
expression.extensionReceiver?.apply{
|
||||||
|
extensionReceiver = expression.extensionReceiver
|
||||||
|
}
|
||||||
|
expression.dispatchReceiver?.apply {
|
||||||
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
|
}
|
||||||
|
log("call::extension@: ${ir2string(expression.extensionReceiver)}")
|
||||||
|
log("call::dispatch@: ${ir2string(expression.dispatchReceiver)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parametersForCall(expression: IrMemberAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> {
|
||||||
|
val descriptor = expression.descriptor as FunctionDescriptor
|
||||||
|
val keyDescriptor = if (DescriptorUtils.isOverride(descriptor))
|
||||||
|
DescriptorUtils.getAllOverriddenDescriptors(descriptor).first()
|
||||||
|
else
|
||||||
|
descriptor.original
|
||||||
|
val realFunction = keyDescriptor.generateDefaultsFunction(context)
|
||||||
|
val realDescriptor = realFunction.descriptor
|
||||||
|
|
||||||
|
log("$descriptor -> $realDescriptor")
|
||||||
|
val maskValues = Array(descriptor.valueParameters.size / 32 + 1, {0})
|
||||||
|
val params = mutableListOf<Pair<ValueParameterDescriptor, IrExpression?>>()
|
||||||
|
params.addAll(descriptor.valueParameters.mapIndexed { i, _ ->
|
||||||
|
val valueArgument = expression.getValueArgument(i)
|
||||||
|
if (valueArgument == null) {
|
||||||
|
val maskIndex = i / 32
|
||||||
|
maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (i % 32))
|
||||||
|
}
|
||||||
|
val valueParameterDescriptor = realDescriptor.valueParameters[i]
|
||||||
|
val pair = valueParameterDescriptor to (valueArgument ?: nullConst(expression, valueParameterDescriptor.type))
|
||||||
|
return@mapIndexed pair
|
||||||
|
})
|
||||||
|
maskValues.forEachIndexed { i, maskValue ->
|
||||||
|
params += maskParameterDescriptor(realFunction, i) to IrConstImpl.int(
|
||||||
|
startOffset = irBody.startOffset,
|
||||||
|
endOffset = irBody.endOffset,
|
||||||
|
type = descriptor.builtIns.intType,
|
||||||
|
value = maskValue)
|
||||||
|
}
|
||||||
|
if (expression.descriptor is ClassConstructorDescriptor) {
|
||||||
|
val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker
|
||||||
|
params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl(
|
||||||
|
startOffset = irBody.startOffset,
|
||||||
|
endOffset = irBody.endOffset,
|
||||||
|
type = defaultArgumentMarker.owner.defaultType,
|
||||||
|
symbol = defaultArgumentMarker)
|
||||||
|
}
|
||||||
|
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||||
|
params += realDescriptor.valueParameters.last() to
|
||||||
|
IrConstImpl.constNull(irBody.startOffset, irBody.endOffset, context.builtIns.any.defaultType)
|
||||||
|
}
|
||||||
|
params.forEach {
|
||||||
|
log("descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}")
|
||||||
|
}
|
||||||
|
return Pair(realFunction.symbol, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun argumentCount(expression: IrMemberAccessExpression) =
|
||||||
|
expression.descriptor.valueParameters.count { expression.getValueArgument(it) != null }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun log(msg: String) = context.log{"DEFAULT-INJECTOR: $msg"}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val CallableMemberDescriptor.needsDefaultArgumentsLowering
|
||||||
|
get() = valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline)
|
||||||
|
|
||||||
|
private fun FunctionDescriptor.generateDefaultsFunction(context: CommonBackendContext): IrFunction {
|
||||||
|
return context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
|
||||||
|
val descriptor = when (this) {
|
||||||
|
is ClassConstructorDescriptor ->
|
||||||
|
ClassConstructorDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ containingDeclaration,
|
||||||
|
/* annotations = */ annotations,
|
||||||
|
/* isPrimary = */ false,
|
||||||
|
/* source = */ source)
|
||||||
|
is FunctionDescriptor -> {
|
||||||
|
val name = Name.identifier("$name\$default")
|
||||||
|
|
||||||
|
SimpleFunctionDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ containingDeclaration,
|
||||||
|
/* annotations = */ annotations,
|
||||||
|
/* name = */ name,
|
||||||
|
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
/* source = */ source)
|
||||||
|
}
|
||||||
|
else -> TODO("FIXME: $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
val syntheticParameters = MutableList(valueParameters.size / 32 + 1) { i ->
|
||||||
|
valueParameter(descriptor, valueParameters.size + i, parameterMaskName(i), descriptor.builtIns.intType)
|
||||||
|
}
|
||||||
|
if (this is ClassConstructorDescriptor) {
|
||||||
|
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
|
||||||
|
kConstructorMarkerName,
|
||||||
|
context.ir.symbols.defaultConstructorMarker.owner.defaultType)
|
||||||
|
}
|
||||||
|
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||||
|
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
|
||||||
|
"handler".synthesizedName,
|
||||||
|
context.ir.symbols.any.owner.defaultType)
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.initialize(
|
||||||
|
/* receiverParameterType = */ extensionReceiverParameter?.type,
|
||||||
|
/* dispatchReceiverParameter = */ dispatchReceiverParameter,
|
||||||
|
/* typeParameters = */ typeParameters.map {
|
||||||
|
TypeParameterDescriptorImpl.createForFurtherModification(
|
||||||
|
/* containingDeclaration = */ descriptor,
|
||||||
|
/* annotations = */ it.annotations,
|
||||||
|
/* reified = */ it.isReified,
|
||||||
|
/* variance = */ it.variance,
|
||||||
|
/* name = */ it.name,
|
||||||
|
/* index = */ it.index,
|
||||||
|
/* source = */ it.source,
|
||||||
|
/* reportCycleError = */ null,
|
||||||
|
/* supertypeLoopsChecker = */ SupertypeLoopChecker.EMPTY
|
||||||
|
).apply {
|
||||||
|
it.upperBounds.forEach { addUpperBound(it) }
|
||||||
|
setInitialized()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* unsubstitutedValueParameters = */ valueParameters.map {
|
||||||
|
ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = descriptor,
|
||||||
|
original = null, /* ValueParameterDescriptorImpl::copy do not save original. */
|
||||||
|
index = it.index,
|
||||||
|
annotations = it.annotations,
|
||||||
|
name = it.name,
|
||||||
|
outType = it.type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = it.isCrossinline,
|
||||||
|
isNoinline = it.isNoinline,
|
||||||
|
varargElementType = it.varargElementType,
|
||||||
|
source = it.source)
|
||||||
|
} + syntheticParameters,
|
||||||
|
/* unsubstitutedReturnType = */ returnType,
|
||||||
|
/* modality = */ Modality.FINAL,
|
||||||
|
/* visibility = */ this.visibility)
|
||||||
|
descriptor.isSuspend = this.isSuspend
|
||||||
|
context.log{"adds to cache[$this] = $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 {
|
||||||
|
return ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = descriptor,
|
||||||
|
original = null,
|
||||||
|
index = index,
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
name = name,
|
||||||
|
outType = type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
varargElementType = null,
|
||||||
|
source = SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val kConstructorMarkerName = "marker".synthesizedName
|
||||||
|
|
||||||
|
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
|
||||||
+216
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
abstract class SymbolWithIrBuilder<out S: IrSymbol, out D: IrDeclaration> {
|
||||||
|
|
||||||
|
protected abstract fun buildSymbol(): S
|
||||||
|
|
||||||
|
protected open fun doInitialize() { }
|
||||||
|
|
||||||
|
protected abstract fun buildIr(): D
|
||||||
|
|
||||||
|
val symbol by lazy { buildSymbol() }
|
||||||
|
|
||||||
|
private val builtIr by lazy { buildIr() }
|
||||||
|
private var initialized: Boolean = false
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
doInitialize()
|
||||||
|
initialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val ir: D
|
||||||
|
get() {
|
||||||
|
if (!initialized)
|
||||||
|
throw Error("Access to IR before initialization")
|
||||||
|
return builtIr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BackendContext.createPropertyGetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
|
||||||
|
fieldSymbol: IrFieldSymbol, type: KotlinType)
|
||||||
|
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
|
||||||
|
|
||||||
|
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
|
||||||
|
PropertyGetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ fieldSymbol.descriptor,
|
||||||
|
/* annotations = */ Annotations.EMPTY,
|
||||||
|
/* modality = */ Modality.FINAL,
|
||||||
|
/* visibility = */ Visibilities.PRIVATE,
|
||||||
|
/* isDefault = */ false,
|
||||||
|
/* isExternal = */ false,
|
||||||
|
/* isInline = */ false,
|
||||||
|
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun doInitialize() {
|
||||||
|
val descriptor = symbol.descriptor as PropertyGetterDescriptorImpl
|
||||||
|
descriptor.apply {
|
||||||
|
initialize(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildIr() = IrFunctionImpl(
|
||||||
|
startOffset = startOffset,
|
||||||
|
endOffset = endOffset,
|
||||||
|
origin = origin,
|
||||||
|
symbol = symbol).apply {
|
||||||
|
|
||||||
|
createParameterDeclarations()
|
||||||
|
|
||||||
|
body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody {
|
||||||
|
+irReturn(irGetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), fieldSymbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BackendContext.createPropertySetterBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
|
||||||
|
fieldSymbol: IrFieldSymbol, type: KotlinType)
|
||||||
|
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
|
||||||
|
|
||||||
|
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
|
||||||
|
PropertySetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ fieldSymbol.descriptor,
|
||||||
|
/* annotations = */ Annotations.EMPTY,
|
||||||
|
/* modality = */ Modality.FINAL,
|
||||||
|
/* visibility = */ Visibilities.PRIVATE,
|
||||||
|
/* isDefault = */ false,
|
||||||
|
/* isExternal = */ false,
|
||||||
|
/* isInline = */ false,
|
||||||
|
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
lateinit var valueParameterDescriptor: ValueParameterDescriptor
|
||||||
|
|
||||||
|
override fun doInitialize() {
|
||||||
|
val descriptor = symbol.descriptor as PropertySetterDescriptorImpl
|
||||||
|
descriptor.apply {
|
||||||
|
valueParameterDescriptor = ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = this,
|
||||||
|
original = null,
|
||||||
|
index = 0,
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
name = Name.identifier("value"),
|
||||||
|
outType = type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
varargElementType = null,
|
||||||
|
source = SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
|
||||||
|
initialize(valueParameterDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildIr() = IrFunctionImpl(
|
||||||
|
startOffset = startOffset,
|
||||||
|
endOffset = endOffset,
|
||||||
|
origin = origin,
|
||||||
|
symbol = symbol).apply {
|
||||||
|
|
||||||
|
createParameterDeclarations()
|
||||||
|
|
||||||
|
body = createIrBuilder(this.symbol, startOffset, endOffset).irBlockBody {
|
||||||
|
+irSetField(irGet(this@apply.dispatchReceiverParameter!!.symbol), fieldSymbol, irGet(this@apply.valueParameters.single().symbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BackendContext.createPropertyWithBackingFieldBuilder(startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin,
|
||||||
|
owner: ClassDescriptor, name: Name, type: KotlinType, isMutable: Boolean)
|
||||||
|
= object: SymbolWithIrBuilder<IrFieldSymbol, IrProperty>() {
|
||||||
|
|
||||||
|
private lateinit var getterBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>
|
||||||
|
private var setterBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
|
||||||
|
|
||||||
|
override fun buildSymbol() = IrFieldSymbolImpl(
|
||||||
|
PropertyDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ owner,
|
||||||
|
/* annotations = */ Annotations.EMPTY,
|
||||||
|
/* modality = */ Modality.FINAL,
|
||||||
|
/* visibility = */ Visibilities.PRIVATE,
|
||||||
|
/* isVar = */ isMutable,
|
||||||
|
/* name = */ name,
|
||||||
|
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
|
/* source = */ SourceElement.NO_SOURCE,
|
||||||
|
/* lateInit = */ false,
|
||||||
|
/* isConst = */ false,
|
||||||
|
/* isHeader = */ false,
|
||||||
|
/* isImpl = */ false,
|
||||||
|
/* isExternal = */ false,
|
||||||
|
/* isDelegated = */ false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun doInitialize() {
|
||||||
|
val descriptor = symbol.descriptor as PropertyDescriptorImpl
|
||||||
|
getterBuilder = createPropertyGetterBuilder(startOffset, endOffset, origin, symbol, type).apply { initialize() }
|
||||||
|
if (isMutable)
|
||||||
|
setterBuilder = createPropertySetterBuilder(startOffset, endOffset, origin, symbol, type).apply { initialize() }
|
||||||
|
descriptor.initialize(
|
||||||
|
/* getter = */ getterBuilder.symbol.descriptor as PropertyGetterDescriptorImpl,
|
||||||
|
/* setter = */ setterBuilder?.symbol?.descriptor as? PropertySetterDescriptorImpl)
|
||||||
|
val receiverType: KotlinType? = null
|
||||||
|
descriptor.setType(type, emptyList(), owner.thisAsReceiverParameter, receiverType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildIr(): IrProperty {
|
||||||
|
val backingField = IrFieldImpl(
|
||||||
|
startOffset = startOffset,
|
||||||
|
endOffset = endOffset,
|
||||||
|
origin = origin,
|
||||||
|
symbol = symbol)
|
||||||
|
return IrPropertyImpl(
|
||||||
|
startOffset = startOffset,
|
||||||
|
endOffset = endOffset,
|
||||||
|
origin = origin,
|
||||||
|
isDelegated = false,
|
||||||
|
descriptor = symbol.descriptor,
|
||||||
|
backingField = backingField,
|
||||||
|
getter = getterBuilder.ir,
|
||||||
|
setter = setterBuilder?.ir)
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
class LateinitLowering(val context: CommonBackendContext): FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.transformChildrenVoid(object: IrElementTransformerVoid() {
|
||||||
|
override fun visitProperty(declaration: IrProperty): IrStatement {
|
||||||
|
if (declaration.descriptor.isLateInit && declaration.descriptor.kind.isReal)
|
||||||
|
transformGetter(declaration.backingField!!.symbol, declaration.getter!!)
|
||||||
|
return declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) {
|
||||||
|
val type = backingFieldSymbol.descriptor.type
|
||||||
|
assert (!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
|
||||||
|
val startOffset = getter.startOffset
|
||||||
|
val endOffset = getter.endOffset
|
||||||
|
val irBuilder = context.createIrBuilder(getter.symbol, startOffset, endOffset)
|
||||||
|
irBuilder.run {
|
||||||
|
val block = irBlock(type)
|
||||||
|
val resultVar = scope.createTemporaryVariable(
|
||||||
|
irGetField(irGet(getter.dispatchReceiverParameter!!.symbol), backingFieldSymbol))
|
||||||
|
block.statements.add(resultVar)
|
||||||
|
val throwIfNull = irIfThenElse(context.builtIns.nothingType,
|
||||||
|
irNotEquals(irGet(resultVar.symbol), irNull()),
|
||||||
|
irReturn(irGet(resultVar.symbol)),
|
||||||
|
irCall(throwErrorFunction))
|
||||||
|
block.statements.add(throwIfNull)
|
||||||
|
getter.body = IrExpressionBodyImpl(startOffset, endOffset, block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private val throwErrorFunction = context.ir.symbols.ThrowUninitializedPropertyAccessException
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock
|
||||||
|
= IrBlockImpl(startOffset, endOffset, type)
|
||||||
|
|
||||||
|
}
|
||||||
+729
@@ -0,0 +1,729 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||||
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
|
||||||
|
|
||||||
|
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
||||||
|
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE") {}
|
||||||
|
|
||||||
|
private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE :
|
||||||
|
IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE") {}
|
||||||
|
|
||||||
|
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||||
|
if (irDeclarationContainer is IrDeclaration &&
|
||||||
|
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
|
||||||
|
|
||||||
|
// Lowering of non-local declarations handles all local declarations inside.
|
||||||
|
// This declaration is local and shouldn't be considered.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continuous numbering across all declarations in the container.
|
||||||
|
lambdasCount = 0
|
||||||
|
|
||||||
|
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||||
|
// TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
|
||||||
|
when (memberDeclaration) {
|
||||||
|
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||||
|
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||||
|
is IrField -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||||
|
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var lambdasCount = 0
|
||||||
|
|
||||||
|
private abstract class LocalContext {
|
||||||
|
/**
|
||||||
|
* @return the expression to get the value for given descriptor, or `null` if [IrGetValue] should be used.
|
||||||
|
*/
|
||||||
|
abstract fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression?
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class LocalContextWithClosureAsParameters : LocalContext() {
|
||||||
|
|
||||||
|
abstract val declaration: IrFunction
|
||||||
|
open val descriptor: FunctionDescriptor
|
||||||
|
get() = declaration.descriptor
|
||||||
|
|
||||||
|
abstract val transformedDescriptor: FunctionDescriptor
|
||||||
|
abstract val transformedDeclaration: IrFunction
|
||||||
|
|
||||||
|
val capturedValueToParameter: MutableMap<ValueDescriptor, IrValueParameterSymbol> = HashMap()
|
||||||
|
|
||||||
|
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
|
||||||
|
val newSymbol = capturedValueToParameter[descriptor] ?: return null
|
||||||
|
|
||||||
|
return IrGetValueImpl(startOffset, endOffset, newSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LocalFunctionContext(override val declaration: IrFunction) : LocalContextWithClosureAsParameters() {
|
||||||
|
lateinit var closure: Closure
|
||||||
|
|
||||||
|
override lateinit var transformedDescriptor: FunctionDescriptor
|
||||||
|
override lateinit var transformedDeclaration: IrSimpleFunction
|
||||||
|
|
||||||
|
var index: Int = -1
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"LocalFunctionContext for $descriptor"
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LocalClassConstructorContext(override val declaration: IrConstructor) : LocalContextWithClosureAsParameters() {
|
||||||
|
override val descriptor: ClassConstructorDescriptor
|
||||||
|
get() = declaration.descriptor
|
||||||
|
|
||||||
|
override lateinit var transformedDescriptor: ClassConstructorDescriptor
|
||||||
|
override lateinit var transformedDeclaration: IrConstructor
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"LocalClassConstructorContext for $descriptor"
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LocalClassContext(val declaration: IrClass) : LocalContext() {
|
||||||
|
val descriptor: ClassDescriptor
|
||||||
|
get() = declaration.descriptor
|
||||||
|
|
||||||
|
lateinit var closure: Closure
|
||||||
|
|
||||||
|
val capturedValueToField: MutableMap<ValueDescriptor, IrField> = HashMap()
|
||||||
|
|
||||||
|
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
|
||||||
|
val field = capturedValueToField[descriptor] ?: return null
|
||||||
|
|
||||||
|
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
|
||||||
|
receiver = IrGetValueImpl(startOffset, endOffset, declaration.thisReceiver!!.symbol)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"LocalClassContext for ${descriptor}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
|
||||||
|
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
|
||||||
|
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
|
||||||
|
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
|
||||||
|
|
||||||
|
val transformedDeclarations = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||||
|
|
||||||
|
val FunctionDescriptor.transformed: IrFunctionSymbol?
|
||||||
|
get() = transformedDeclarations[this] as IrFunctionSymbol?
|
||||||
|
|
||||||
|
val oldParameterToNew: MutableMap<ParameterDescriptor, IrValueParameterSymbol> = HashMap()
|
||||||
|
val newParameterToOld: MutableMap<ParameterDescriptor, ParameterDescriptor> = HashMap()
|
||||||
|
val newParameterToCaptured: MutableMap<ValueParameterDescriptor, IrValueSymbol> = HashMap()
|
||||||
|
|
||||||
|
fun lowerLocalDeclarations(): List<IrDeclaration>? {
|
||||||
|
collectLocalDeclarations()
|
||||||
|
if (localFunctions.isEmpty() && localClasses.isEmpty()) return null
|
||||||
|
|
||||||
|
collectClosures()
|
||||||
|
|
||||||
|
transformDescriptors()
|
||||||
|
|
||||||
|
rewriteDeclarations()
|
||||||
|
|
||||||
|
val result = collectRewrittenDeclarations()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
||||||
|
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
|
||||||
|
add(memberDeclaration)
|
||||||
|
|
||||||
|
localFunctions.values.mapTo(this) {
|
||||||
|
val original = it.declaration
|
||||||
|
it.transformedDeclaration.apply {
|
||||||
|
this.body = original.body
|
||||||
|
|
||||||
|
original.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
|
||||||
|
val body = original.getDefault(argument)!!
|
||||||
|
oldParameterToNew[argument]!!.owner.defaultValue = body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localClasses.values.mapTo(this) {
|
||||||
|
it.declaration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass): IrStatement {
|
||||||
|
if (declaration.descriptor in localClasses) {
|
||||||
|
// Replace local class definition with an empty composite.
|
||||||
|
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||||
|
} else {
|
||||||
|
return super.visitClass(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
|
if (declaration.descriptor in localFunctions) {
|
||||||
|
// Replace local function definition with an empty composite.
|
||||||
|
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||||
|
} else {
|
||||||
|
return super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
||||||
|
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
|
||||||
|
|
||||||
|
val constructorContext = localClassConstructors[declaration.descriptor]
|
||||||
|
if (constructorContext != null) {
|
||||||
|
return constructorContext.transformedDeclaration.apply {
|
||||||
|
this.body = declaration.body!!
|
||||||
|
|
||||||
|
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
|
||||||
|
val body = declaration.getDefault(argument)!!
|
||||||
|
oldParameterToNew[argument]!!.owner.defaultValue = body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return super.visitConstructor(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
val descriptor = expression.descriptor
|
||||||
|
|
||||||
|
localContext?.irGet(expression.startOffset, expression.endOffset, descriptor)?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
oldParameterToNew[descriptor]?.let {
|
||||||
|
return IrGetValueImpl(expression.startOffset, expression.endOffset, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val oldCallee = expression.descriptor.original
|
||||||
|
val newCallee = oldCallee.transformed ?: return expression
|
||||||
|
|
||||||
|
val newCall = createNewCall(expression, newCallee).fillArguments(expression)
|
||||||
|
|
||||||
|
return newCall
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val oldCallee = expression.descriptor.original
|
||||||
|
val newCallee = transformedDeclarations[oldCallee] as IrConstructorSymbol? ?: return expression
|
||||||
|
|
||||||
|
val newExpression = IrDelegatingConstructorCallImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
newCallee,
|
||||||
|
newCallee.descriptor,
|
||||||
|
remapTypeArguments(expression, newCallee.descriptor)
|
||||||
|
).fillArguments(expression)
|
||||||
|
|
||||||
|
return newExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
|
||||||
|
|
||||||
|
mapValueParameters { newValueParameterDescriptor ->
|
||||||
|
val oldParameter = newParameterToOld[newValueParameterDescriptor]
|
||||||
|
|
||||||
|
if (oldParameter != null) {
|
||||||
|
oldExpression.getValueArgument(oldParameter as ValueParameterDescriptor)
|
||||||
|
} else {
|
||||||
|
// The callee expects captured value as argument.
|
||||||
|
val capturedValueSymbol =
|
||||||
|
newParameterToCaptured[newValueParameterDescriptor] ?:
|
||||||
|
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
|
||||||
|
|
||||||
|
val capturedValueDescriptor = capturedValueSymbol.descriptor
|
||||||
|
localContext?.irGet(
|
||||||
|
oldExpression.startOffset, oldExpression.endOffset,
|
||||||
|
capturedValueDescriptor
|
||||||
|
) ?:
|
||||||
|
// Captured value is directly available for the caller.
|
||||||
|
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
|
||||||
|
oldParameterToNew[capturedValueDescriptor] ?: capturedValueSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchReceiver = oldExpression.dispatchReceiver
|
||||||
|
extensionReceiver = oldExpression.extensionReceiver
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val oldCallee = expression.descriptor.original
|
||||||
|
val newCallee = oldCallee.transformed ?: return expression
|
||||||
|
|
||||||
|
val newCallableReference = IrFunctionReferenceImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
expression.type, // TODO functional type for transformed descriptor
|
||||||
|
newCallee,
|
||||||
|
newCallee.descriptor,
|
||||||
|
remapTypeArguments(expression, newCallee.descriptor),
|
||||||
|
expression.origin
|
||||||
|
).fillArguments(expression)
|
||||||
|
|
||||||
|
return newCallableReference
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val oldReturnTarget = expression.returnTarget
|
||||||
|
val newReturnTarget = oldReturnTarget.transformed ?: return expression
|
||||||
|
|
||||||
|
return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclarationReference(expression: IrDeclarationReference): IrExpression {
|
||||||
|
if (expression.descriptor in transformedDeclarations) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
return super.visitDeclarationReference(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||||
|
if (declaration.descriptor in transformedDeclarations) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
return super.visitDeclaration(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
|
||||||
|
irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteClassMembers(irClass: IrClass, localClassContext: LocalClassContext) {
|
||||||
|
irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext))
|
||||||
|
|
||||||
|
val classDescriptor = irClass.descriptor
|
||||||
|
val constructorsCallingSuper = classDescriptor.constructors
|
||||||
|
.map { localClassConstructors[it]!! }
|
||||||
|
.filter { it.declaration.callsSuper() }
|
||||||
|
assert(constructorsCallingSuper.any(), { "Expected at least one constructor calling super; class: $classDescriptor" })
|
||||||
|
|
||||||
|
localClassContext.capturedValueToField.forEach { capturedValue, field ->
|
||||||
|
val startOffset = irClass.startOffset
|
||||||
|
val endOffset = irClass.endOffset
|
||||||
|
irClass.declarations.add(field)
|
||||||
|
|
||||||
|
for (constructorContext in constructorsCallingSuper) {
|
||||||
|
val blockBody = constructorContext.declaration.body as? IrBlockBody
|
||||||
|
?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}")
|
||||||
|
val capturedValueExpression = constructorContext.irGet(startOffset, endOffset, capturedValue)!!
|
||||||
|
blockBody.statements.add(0,
|
||||||
|
IrSetFieldImpl(startOffset, endOffset, field.symbol,
|
||||||
|
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
|
||||||
|
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteDeclarations() {
|
||||||
|
localFunctions.values.forEach {
|
||||||
|
rewriteFunctionBody(it.declaration, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
localClassConstructors.values.forEach {
|
||||||
|
rewriteFunctionBody(it.declaration, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
localClasses.values.forEach {
|
||||||
|
rewriteClassMembers(it.declaration, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
rewriteFunctionBody(memberDeclaration, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNewCall(oldCall: IrCall, newCallee: IrFunctionSymbol) =
|
||||||
|
if (oldCall is IrCallWithShallowCopy)
|
||||||
|
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifierSymbol)
|
||||||
|
else
|
||||||
|
IrCallImpl(
|
||||||
|
oldCall.startOffset, oldCall.endOffset,
|
||||||
|
newCallee,
|
||||||
|
newCallee.descriptor,
|
||||||
|
remapTypeArguments(oldCall, newCallee.descriptor),
|
||||||
|
oldCall.origin, oldCall.superQualifierSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
|
||||||
|
val oldCallee = oldExpression.descriptor.original
|
||||||
|
|
||||||
|
return if (oldCallee.typeParameters.isEmpty())
|
||||||
|
null
|
||||||
|
else oldCallee.typeParameters.associateBy(
|
||||||
|
{ newCallee.typeParameters[it.index] },
|
||||||
|
{ oldExpression.getTypeArgumentOrDefault(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transformDescriptors() {
|
||||||
|
localFunctions.values.forEach {
|
||||||
|
createLiftedDescriptor(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
localClasses.values.forEach {
|
||||||
|
createFieldsForCapturedValues(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
localClassConstructors.values.forEach {
|
||||||
|
createTransformedConstructorDescriptor(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun suggestLocalName(descriptor: DeclarationDescriptor): String {
|
||||||
|
localFunctions[descriptor]?.let {
|
||||||
|
if (it.index >= 0)
|
||||||
|
return "lambda-${it.index}"
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor.name.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNameForLiftedDeclaration(descriptor: DeclarationDescriptor,
|
||||||
|
newOwner: DeclarationDescriptor): Name =
|
||||||
|
Name.identifier(
|
||||||
|
descriptor.parentsWithSelf
|
||||||
|
.takeWhile { it != newOwner }
|
||||||
|
.toList().reversed()
|
||||||
|
.map { suggestLocalName(it) }
|
||||||
|
.joinToString(separator = "$")
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
|
||||||
|
val oldDescriptor = localFunctionContext.descriptor
|
||||||
|
|
||||||
|
val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
|
||||||
|
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
|
memberOwner,
|
||||||
|
oldDescriptor.annotations,
|
||||||
|
generateNameForLiftedDeclaration(oldDescriptor, memberOwner),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
oldDescriptor.source
|
||||||
|
).apply {
|
||||||
|
isTailrec = oldDescriptor.isTailrec
|
||||||
|
isSuspend = oldDescriptor.isSuspend
|
||||||
|
// TODO: copy other properties or consider using `FunctionDescriptor.CopyBuilder`.
|
||||||
|
}
|
||||||
|
|
||||||
|
localFunctionContext.transformedDescriptor = newDescriptor
|
||||||
|
|
||||||
|
if (oldDescriptor.dispatchReceiverParameter != null) {
|
||||||
|
throw AssertionError("local functions must not have dispatch receiver")
|
||||||
|
}
|
||||||
|
|
||||||
|
val newDispatchReceiverParameter = null
|
||||||
|
|
||||||
|
// Do not substitute type parameters for now.
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters
|
||||||
|
|
||||||
|
// TODO: consider using fields to access the closure of enclosing class.
|
||||||
|
val capturedValues = localFunctionContext.closure.capturedValues
|
||||||
|
|
||||||
|
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
|
||||||
|
|
||||||
|
newDescriptor.initialize(
|
||||||
|
oldDescriptor.extensionReceiverParameter?.type,
|
||||||
|
newDispatchReceiverParameter,
|
||||||
|
newTypeParameters,
|
||||||
|
newValueParameters,
|
||||||
|
oldDescriptor.returnType,
|
||||||
|
Modality.FINAL,
|
||||||
|
Visibilities.PRIVATE
|
||||||
|
)
|
||||||
|
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let {
|
||||||
|
newParameterToOld.putAbsentOrSame(newDescriptor.extensionReceiverParameter!!, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
localFunctionContext.transformedDeclaration = with(localFunctionContext.declaration) {
|
||||||
|
IrFunctionImpl(startOffset, endOffset, origin, newDescriptor)
|
||||||
|
}.apply {
|
||||||
|
createParameterDeclarations()
|
||||||
|
recordTransformedValueParameters(localFunctionContext)
|
||||||
|
transformedDeclarations[oldDescriptor] = this.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTransformedValueParameters(localContext: LocalContextWithClosureAsParameters,
|
||||||
|
capturedValues: List<IrValueSymbol>)
|
||||||
|
: List<ValueParameterDescriptor> {
|
||||||
|
|
||||||
|
val oldDescriptor = localContext.descriptor
|
||||||
|
val newDescriptor = localContext.transformedDescriptor
|
||||||
|
|
||||||
|
val closureParametersCount = capturedValues.size
|
||||||
|
val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
|
||||||
|
|
||||||
|
val newValueParameters = ArrayList<ValueParameterDescriptor>(newValueParametersCount).apply {
|
||||||
|
capturedValues.mapIndexedTo(this) { i, capturedValue ->
|
||||||
|
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValue.descriptor, i).apply {
|
||||||
|
newParameterToCaptured[this] = capturedValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
|
||||||
|
createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
|
||||||
|
newParameterToOld.putAbsentOrSame(this, oldValueParameterDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newValueParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.recordTransformedValueParameters(localContext: LocalContextWithClosureAsParameters) {
|
||||||
|
|
||||||
|
valueParameters.forEach {
|
||||||
|
val capturedValue = newParameterToCaptured[it.descriptor]
|
||||||
|
if (capturedValue != null) {
|
||||||
|
localContext.capturedValueToParameter[capturedValue.descriptor] = it.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).forEach {
|
||||||
|
val oldParameter = newParameterToOld[it.descriptor]
|
||||||
|
if (oldParameter != null) {
|
||||||
|
oldParameterToNew.putAbsentOrSame(oldParameter, it.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
|
||||||
|
val oldDescriptor = constructorContext.descriptor
|
||||||
|
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
|
||||||
|
val newDescriptor = ClassConstructorDescriptorImpl.create(
|
||||||
|
localClassContext.descriptor,
|
||||||
|
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
|
||||||
|
|
||||||
|
constructorContext.transformedDescriptor = newDescriptor
|
||||||
|
|
||||||
|
// Do not substitute type parameters for now.
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters
|
||||||
|
|
||||||
|
val capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues
|
||||||
|
|
||||||
|
val newValueParameters = createTransformedValueParameters(constructorContext, capturedValues)
|
||||||
|
|
||||||
|
newDescriptor.initialize(
|
||||||
|
newValueParameters,
|
||||||
|
Visibilities.PRIVATE,
|
||||||
|
newTypeParameters
|
||||||
|
)
|
||||||
|
newDescriptor.returnType = oldDescriptor.returnType
|
||||||
|
|
||||||
|
oldDescriptor.dispatchReceiverParameter?.let {
|
||||||
|
newParameterToOld.putAbsentOrSame(newDescriptor.dispatchReceiverParameter!!, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let {
|
||||||
|
throw AssertionError("constructors can't have extension receiver")
|
||||||
|
}
|
||||||
|
|
||||||
|
constructorContext.transformedDeclaration = with(constructorContext.declaration) {
|
||||||
|
IrConstructorImpl(startOffset, endOffset, origin, newDescriptor)
|
||||||
|
}.apply {
|
||||||
|
createParameterDeclarations()
|
||||||
|
recordTransformedValueParameters(constructorContext)
|
||||||
|
transformedDeclarations[oldDescriptor] = this.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
|
||||||
|
val classDescriptor = localClassContext.descriptor
|
||||||
|
|
||||||
|
localClassContext.closure.capturedValues.forEach { capturedValue ->
|
||||||
|
val fieldDescriptor = PropertyDescriptorImpl.create(
|
||||||
|
classDescriptor,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Modality.FINAL,
|
||||||
|
Visibilities.PRIVATE,
|
||||||
|
/* isVar = */ false,
|
||||||
|
suggestNameForCapturedValue(capturedValue.descriptor),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
SourceElement.NO_SOURCE,
|
||||||
|
/* lateInit = */ false,
|
||||||
|
/* isConst = */ false,
|
||||||
|
/* isHeader = */ false,
|
||||||
|
/* isImpl = */ false,
|
||||||
|
/* isExternal = */ false,
|
||||||
|
/* isDelegated = */ false)
|
||||||
|
|
||||||
|
fieldDescriptor.initialize(/* getter = */ null, /* setter = */ null)
|
||||||
|
|
||||||
|
val extensionReceiverParameter: ReceiverParameterDescriptor? = null
|
||||||
|
|
||||||
|
fieldDescriptor.setType(
|
||||||
|
capturedValue.descriptor.type,
|
||||||
|
emptyList<TypeParameterDescriptor>(),
|
||||||
|
classDescriptor.thisAsReceiverParameter,
|
||||||
|
extensionReceiverParameter)
|
||||||
|
|
||||||
|
localClassContext.capturedValueToField[capturedValue.descriptor] = IrFieldImpl(
|
||||||
|
localClassContext.declaration.startOffset, localClassContext.declaration.endOffset,
|
||||||
|
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
|
||||||
|
fieldDescriptor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <K, V> MutableMap<K, V>.putAbsentOrSame(key: K, value: V) {
|
||||||
|
val current = this.getOrPut(key, { value })
|
||||||
|
|
||||||
|
if (current != value) {
|
||||||
|
error("$current != $value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun suggestNameForCapturedValue(valueDescriptor: ValueDescriptor): Name =
|
||||||
|
if (valueDescriptor.name.isSpecial) {
|
||||||
|
val oldNameStr = valueDescriptor.name.asString()
|
||||||
|
oldNameStr.substring(1, oldNameStr.length - 1).synthesizedName
|
||||||
|
} else
|
||||||
|
valueDescriptor.name
|
||||||
|
|
||||||
|
private fun createUnsubstitutedCapturedValueParameter(
|
||||||
|
newParameterOwner: CallableMemberDescriptor,
|
||||||
|
valueDescriptor: ValueDescriptor,
|
||||||
|
index: Int
|
||||||
|
): ValueParameterDescriptor =
|
||||||
|
ValueParameterDescriptorImpl(
|
||||||
|
newParameterOwner, null, index,
|
||||||
|
valueDescriptor.annotations,
|
||||||
|
suggestNameForCapturedValue(valueDescriptor),
|
||||||
|
valueDescriptor.type,
|
||||||
|
false, false, false, null, valueDescriptor.source
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createUnsubstitutedParameter(
|
||||||
|
newParameterOwner: CallableMemberDescriptor,
|
||||||
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
|
newIndex: Int
|
||||||
|
): ValueParameterDescriptor =
|
||||||
|
valueParameterDescriptor.copy(newParameterOwner, valueParameterDescriptor.name, newIndex)
|
||||||
|
|
||||||
|
|
||||||
|
private fun collectClosures() {
|
||||||
|
val annotator = ClosureAnnotator(memberDeclaration)
|
||||||
|
localFunctions.forEach { descriptor, context ->
|
||||||
|
context.closure = annotator.getFunctionClosure(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
localClasses.forEach { descriptor, context ->
|
||||||
|
context.closure = annotator.getClassClosure(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectLocalDeclarations() {
|
||||||
|
memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DeclarationDescriptor.declaredInFunction() = when (this.containingDeclaration) {
|
||||||
|
is CallableDescriptor -> true
|
||||||
|
is ClassDescriptor -> false
|
||||||
|
is PackageFragmentDescriptor -> false
|
||||||
|
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
|
val descriptor = declaration.descriptor
|
||||||
|
|
||||||
|
if (descriptor.declaredInFunction()) {
|
||||||
|
val localFunctionContext = LocalFunctionContext(declaration)
|
||||||
|
|
||||||
|
localFunctions[descriptor] = localFunctionContext
|
||||||
|
|
||||||
|
if (descriptor.name.isSpecial) {
|
||||||
|
localFunctionContext.index = lambdasCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor) {
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
|
val descriptor = declaration.descriptor
|
||||||
|
assert(!descriptor.declaredInFunction())
|
||||||
|
|
||||||
|
if (descriptor.constructedClass.isInner) return
|
||||||
|
|
||||||
|
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
|
val descriptor = declaration.descriptor
|
||||||
|
|
||||||
|
if (descriptor.isInner) return
|
||||||
|
|
||||||
|
// Local nested classes can only be inner.
|
||||||
|
assert(descriptor.declaredInFunction())
|
||||||
|
|
||||||
|
val localClassContext = LocalClassContext(declaration)
|
||||||
|
localClasses[descriptor] = localClassContext
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+239
@@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
|
||||||
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
|
class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns)
|
||||||
|
|
||||||
|
class DeclarationIrBuilder(
|
||||||
|
backendContext: BackendContext,
|
||||||
|
symbol: IrSymbol,
|
||||||
|
startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET
|
||||||
|
) : IrBuilderWithScope(
|
||||||
|
IrLoweringContext(backendContext),
|
||||||
|
Scope(symbol),
|
||||||
|
startOffset,
|
||||||
|
endOffset
|
||||||
|
)
|
||||||
|
|
||||||
|
fun BackendContext.createIrBuilder(symbol: IrSymbol,
|
||||||
|
startOffset: Int = UNDEFINED_OFFSET,
|
||||||
|
endOffset: Int = UNDEFINED_OFFSET) =
|
||||||
|
DeclarationIrBuilder(this, symbol, startOffset, endOffset)
|
||||||
|
|
||||||
|
|
||||||
|
fun <T : IrBuilder> T.at(element: IrElement) = this.at(element.startOffset, element.endOffset)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds [IrBlock] to be used instead of given expression.
|
||||||
|
*/
|
||||||
|
inline fun IrGeneratorWithScope.irBlock(expression: IrExpression, origin: IrStatementOrigin? = null,
|
||||||
|
resultType: KotlinType? = expression.type,
|
||||||
|
body: IrBlockBuilder.() -> Unit) =
|
||||||
|
this.irBlock(expression.startOffset, expression.endOffset, origin, resultType, body)
|
||||||
|
|
||||||
|
inline fun IrGeneratorWithScope.irBlockBody(irElement: IrElement, body: IrBlockBodyBuilder.() -> Unit) =
|
||||||
|
this.irBlockBody(irElement.startOffset, irElement.endOffset, body)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irIfThen(condition: IrExpression, thenPart: IrExpression) =
|
||||||
|
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, thenPart, null)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irNot(arg: IrExpression) =
|
||||||
|
primitiveOp1(startOffset, endOffset, context.irBuiltIns.booleanNotSymbol, IrStatementOrigin.EXCL, arg)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irThrow(arg: IrExpression) =
|
||||||
|
IrThrowImpl(startOffset, endOffset, context.builtIns.nothingType, arg)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irCatch(catchParameter: IrVariable) =
|
||||||
|
IrCatchImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
catchParameter
|
||||||
|
)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irCast(arg: IrExpression, type: KotlinType, typeOperand: KotlinType) =
|
||||||
|
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.CAST, typeOperand, arg)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irImplicitCoercionToUnit(arg: IrExpression) =
|
||||||
|
IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.unitType,
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, context.builtIns.unitType, arg)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irGetField(receiver: IrExpression, symbol: IrFieldSymbol) =
|
||||||
|
IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irSetField(receiver: IrExpression, symbol: IrFieldSymbol, value: IrExpression) =
|
||||||
|
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value)
|
||||||
|
|
||||||
|
open class IrBuildingTransformer(private val context: BackendContext) : IrElementTransformerVoid() {
|
||||||
|
private var currentBuilder: IrBuilderWithScope? = null
|
||||||
|
|
||||||
|
protected val builder: IrBuilderWithScope
|
||||||
|
get() = currentBuilder!!
|
||||||
|
|
||||||
|
private inline fun <T> withBuilder(symbol: IrSymbol, block: () -> T): T {
|
||||||
|
val oldBuilder = currentBuilder
|
||||||
|
currentBuilder = context.createIrBuilder(symbol)
|
||||||
|
return try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
currentBuilder = oldBuilder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
|
withBuilder(declaration.symbol) {
|
||||||
|
return super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField): IrStatement {
|
||||||
|
withBuilder(declaration.symbol) {
|
||||||
|
// Transforms initializer:
|
||||||
|
return super.visitField(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
|
||||||
|
withBuilder(declaration.symbol) {
|
||||||
|
return super.visitAnonymousInitializer(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<CallableMemberDescriptor>): List<DeclarationDescriptor> {
|
||||||
|
|
||||||
|
val result = mutableListOf<DeclarationDescriptor>()
|
||||||
|
|
||||||
|
val allSuperDescriptors = current.typeConstructor.supertypes
|
||||||
|
.flatMap { it.memberScope.getContributedDescriptors() }
|
||||||
|
.filterIsInstance<CallableMemberDescriptor>()
|
||||||
|
|
||||||
|
for ((name, group) in allSuperDescriptors.groupBy { it.name }) {
|
||||||
|
OverridingUtil.generateOverridesInFunctionGroup(
|
||||||
|
name,
|
||||||
|
/* membersFromSupertypes = */ group,
|
||||||
|
/* membersFromCurrent = */ functionsFromCurrent.filter { it.name == name },
|
||||||
|
current,
|
||||||
|
object : NonReportingOverrideStrategy() {
|
||||||
|
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
|
||||||
|
result.add(fakeOverride)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun conflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
|
||||||
|
error("Conflict in scope of $current: $fromSuper vs $fromCurrent")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeImpl() {
|
||||||
|
|
||||||
|
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
|
||||||
|
members.filterIsInstance<ClassifierDescriptor>()
|
||||||
|
.atMostOne { it.name == name }
|
||||||
|
|
||||||
|
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
|
||||||
|
members.filterIsInstance<PropertyDescriptor>()
|
||||||
|
.filter { it.name == name }
|
||||||
|
|
||||||
|
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> =
|
||||||
|
members.filterIsInstance<SimpleFunctionDescriptor>()
|
||||||
|
.filter { it.name == name }
|
||||||
|
|
||||||
|
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter,
|
||||||
|
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> =
|
||||||
|
members.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
||||||
|
|
||||||
|
override fun printScopeStructure(p: Printer) = TODO("not implemented")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrConstructor.callsSuper(): Boolean {
|
||||||
|
val constructedClass = descriptor.constructedClass
|
||||||
|
val superClass = constructedClass.getSuperClassOrAny()
|
||||||
|
var callsSuper = false
|
||||||
|
var numberOfCalls = 0
|
||||||
|
acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
// Skip nested
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||||
|
assert(++numberOfCalls == 1, { "More than one delegating constructor call: $descriptor" })
|
||||||
|
if (expression.descriptor.constructedClass == superClass)
|
||||||
|
callsSuper = true
|
||||||
|
else if (expression.descriptor.constructedClass != constructedClass)
|
||||||
|
throw AssertionError("Expected either call to another constructor of the class being constructed or" +
|
||||||
|
" call to super class constructor. But was: ${expression.descriptor.constructedClass}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
assert(numberOfCalls == 1, { "Expected exactly one delegating constructor call but none encountered: $descriptor" })
|
||||||
|
return callsSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index: Int)
|
||||||
|
= when (this) {
|
||||||
|
is ValueParameterDescriptor -> this.copy(newOwner, name, index)
|
||||||
|
is ReceiverParameterDescriptor -> ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = newOwner,
|
||||||
|
original = null,
|
||||||
|
index = index,
|
||||||
|
annotations = annotations,
|
||||||
|
name = name,
|
||||||
|
outType = type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
varargElementType = null,
|
||||||
|
source = source
|
||||||
|
)
|
||||||
|
else -> throw Error("Unexpected parameter descriptor: $this")
|
||||||
|
}
|
||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||||
|
import org.jetbrains.kotlin.ir.util.getArgumentsWithSymbols
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This pass lowers tail recursion calls in `tailrec` functions.
|
||||||
|
*
|
||||||
|
* Note: it currently can't handle local functions and classes declared in default arguments.
|
||||||
|
* See [deepCopyWithVariables].
|
||||||
|
*/
|
||||||
|
class TailrecLowering(val context: BackendContext) : FunctionLoweringPass {
|
||||||
|
override fun lower(irFunction: IrFunction) {
|
||||||
|
lowerTailRecursionCalls(context, irFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerTailRecursionCalls(context: BackendContext, irFunction: IrFunction) {
|
||||||
|
val tailRecursionCalls = collectTailRecursionCalls(irFunction)
|
||||||
|
if (tailRecursionCalls.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val oldBody = irFunction.body as IrBlockBody
|
||||||
|
val builder = context.createIrBuilder(irFunction.symbol).at(oldBody)
|
||||||
|
|
||||||
|
val parameters = irFunction.explicitParameters
|
||||||
|
|
||||||
|
irFunction.body = builder.irBlockBody {
|
||||||
|
// Define variables containing current values of parameters:
|
||||||
|
val parameterToVariable = parameters.associate {
|
||||||
|
it to irTemporaryVar(irGet(it), nameHint = it.suggestVariableName()).symbol
|
||||||
|
}
|
||||||
|
// (these variables are to be updated on any tail call).
|
||||||
|
|
||||||
|
+irWhile().apply {
|
||||||
|
val loop = this
|
||||||
|
condition = irTrue()
|
||||||
|
|
||||||
|
body = irBlock(startOffset, endOffset, resultType = context.builtIns.unitType) {
|
||||||
|
// Read variables containing current values of parameters:
|
||||||
|
val parameterToNew = parameters.associate {
|
||||||
|
val variable = parameterToVariable[it]!!
|
||||||
|
it to irTemporary(irGet(variable), nameHint = it.suggestVariableName()).symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
val transformer = BodyTransformer(builder, irFunction, loop,
|
||||||
|
parameterToNew, parameterToVariable, tailRecursionCalls)
|
||||||
|
|
||||||
|
oldBody.statements.forEach {
|
||||||
|
+it.transform(transformer, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
+irBreak(loop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BodyTransformer(
|
||||||
|
val builder: IrBuilderWithScope,
|
||||||
|
val irFunction: IrFunction,
|
||||||
|
val loop: IrLoop,
|
||||||
|
val parameterToNew: Map<IrValueParameterSymbol, IrValueSymbol>,
|
||||||
|
val parameterToVariable: Map<IrValueParameterSymbol, IrVariableSymbol>,
|
||||||
|
val tailRecursionCalls: Set<IrCall>
|
||||||
|
) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
val parameters = irFunction.explicitParameters
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
val value = parameterToNew[expression.symbol] ?: return expression
|
||||||
|
return builder.at(expression).irGet(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
if (expression !in tailRecursionCalls) {
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.at(expression).genTailCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.genTailCall(expression: IrCall) = this.irBlock(expression) {
|
||||||
|
// Get all specified arguments:
|
||||||
|
val parameterToArgument = expression.getArgumentsWithSymbols().map { (parameter, argument) ->
|
||||||
|
parameter to argument
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each specified argument set the corresponding variable to it in the correct order:
|
||||||
|
parameterToArgument.forEach { (parameter, argument) ->
|
||||||
|
at(argument)
|
||||||
|
// Note that argument can use values of parameters, so it is important that
|
||||||
|
// references to parameters are mapped using `parameterToNew`, not `parameterToVariable`.
|
||||||
|
+irSetVar(parameterToVariable[parameter]!!, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
val specifiedParameters = parameterToArgument.map { (parameter, _) -> parameter }.toSet()
|
||||||
|
|
||||||
|
// For each unspecified argument set the corresponding variable to default:
|
||||||
|
parameters.filter { it !in specifiedParameters }.forEach { parameter ->
|
||||||
|
|
||||||
|
val originalDefaultValue = parameter.owner.defaultValue?.expression ?:
|
||||||
|
throw Error("no argument specified for $parameter")
|
||||||
|
|
||||||
|
// Copy default value, mapping parameters to variables containing freshly computed arguments:
|
||||||
|
val defaultValue = originalDefaultValue
|
||||||
|
.deepCopyWithVariables()
|
||||||
|
.transform(object : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val variableSymbol = parameterToVariable[expression.symbol] ?: return expression
|
||||||
|
return IrGetValueImpl(
|
||||||
|
expression.startOffset, expression.endOffset,
|
||||||
|
variableSymbol, expression.origin
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, data = null)
|
||||||
|
|
||||||
|
+irSetVar(parameterToVariable[parameter]!!, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump to the entry:
|
||||||
|
+irContinue(loop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrValueParameterSymbol.suggestVariableName(): String = if (descriptor.name.isSpecial) {
|
||||||
|
val oldNameStr = descriptor.name.asString()
|
||||||
|
"$" + oldNameStr.substring(1, oldNameStr.length - 1)
|
||||||
|
} else {
|
||||||
|
descriptor.name.identifier
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user