Migrate native to moved common lowers
(cherry picked from commit 6665d48017540afd8b8cb2fa0f104cab93e73473)
This commit is contained in:
committed by
Vasily Levchenko
parent
d9c04eaaf5
commit
8296c65aeb
-253
@@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
|
||||||
|
|
||||||
typealias ReportError = (element: IrElement, message: String) -> Unit
|
|
||||||
|
|
||||||
class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: ReportError, val ensureAllNodesAreDifferent: Boolean) : IrElementVisitorVoid {
|
|
||||||
|
|
||||||
val set = mutableSetOf<IrElement>()
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
if (ensureAllNodesAreDifferent) {
|
|
||||||
if (set.contains(element))
|
|
||||||
reportError(element, "Duplicate IR node")
|
|
||||||
set.add(element)
|
|
||||||
}
|
|
||||||
// Nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.ensureTypeIs(expectedType: KotlinType) {
|
|
||||||
if (expectedType != type) {
|
|
||||||
reportError(this, "unexpected expression.type: expected $expectedType, got ${type}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrSymbol.ensureBound(expression: IrExpression) {
|
|
||||||
if (!this.isBound) {
|
|
||||||
reportError(expression, "Unbound symbol ${this}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> visitConst(expression: IrConst<T>) {
|
|
||||||
super.visitConst(expression)
|
|
||||||
|
|
||||||
val naturalType = when (expression.kind) {
|
|
||||||
IrConstKind.Null -> builtIns.nullableNothingType
|
|
||||||
IrConstKind.Boolean -> builtIns.booleanType
|
|
||||||
IrConstKind.Char -> builtIns.charType
|
|
||||||
IrConstKind.Byte -> builtIns.byteType
|
|
||||||
IrConstKind.Short -> builtIns.shortType
|
|
||||||
IrConstKind.Int -> builtIns.intType
|
|
||||||
IrConstKind.Long -> builtIns.longType
|
|
||||||
IrConstKind.String -> builtIns.stringType
|
|
||||||
IrConstKind.Float -> builtIns.floatType
|
|
||||||
IrConstKind.Double -> builtIns.doubleType
|
|
||||||
}
|
|
||||||
|
|
||||||
expression.ensureTypeIs(naturalType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation) {
|
|
||||||
super.visitStringConcatenation(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.stringType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue) {
|
|
||||||
super.visitGetObjectValue(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(expression.descriptor.defaultType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: visitGetEnumValue
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue) {
|
|
||||||
super.visitGetValue(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(expression.descriptor.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetVariable(expression: IrSetVariable) {
|
|
||||||
super.visitSetVariable(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.unitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField) {
|
|
||||||
super.visitGetField(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(expression.descriptor.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField) {
|
|
||||||
super.visitSetField(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.unitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall) {
|
|
||||||
super.visitCall(expression)
|
|
||||||
|
|
||||||
val returnType = expression.descriptor.returnType
|
|
||||||
if (returnType == null) {
|
|
||||||
reportError(expression, "${expression.descriptor} return type is null")
|
|
||||||
} else {
|
|
||||||
expression.ensureTypeIs(returnType)
|
|
||||||
}
|
|
||||||
|
|
||||||
expression.superQualifierSymbol?.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
|
||||||
super.visitDelegatingConstructorCall(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.unitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) {
|
|
||||||
super.visitEnumConstructorCall(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.unitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) {
|
|
||||||
super.visitInstanceInitializerCall(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.unitType)
|
|
||||||
expression.classSymbol.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall) {
|
|
||||||
super.visitTypeOperator(expression)
|
|
||||||
|
|
||||||
val operator = expression.operator
|
|
||||||
val typeOperand = expression.typeOperand
|
|
||||||
|
|
||||||
val naturalType = when (operator) {
|
|
||||||
IrTypeOperator.CAST,
|
|
||||||
IrTypeOperator.IMPLICIT_CAST,
|
|
||||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
|
||||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> typeOperand
|
|
||||||
|
|
||||||
IrTypeOperator.SAFE_CAST -> typeOperand.makeNullable()
|
|
||||||
|
|
||||||
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> builtIns.booleanType
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT && typeOperand != builtIns.unitType) {
|
|
||||||
reportError(expression, "typeOperand is $typeOperand")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check IMPLICIT_NOTNULL's argument type.
|
|
||||||
|
|
||||||
expression.ensureTypeIs(naturalType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLoop(loop: IrLoop) {
|
|
||||||
super.visitLoop(loop)
|
|
||||||
|
|
||||||
loop.ensureTypeIs(builtIns.unitType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBreakContinue(jump: IrBreakContinue) {
|
|
||||||
super.visitBreakContinue(jump)
|
|
||||||
|
|
||||||
jump.ensureTypeIs(builtIns.nothingType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn) {
|
|
||||||
super.visitReturn(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.nothingType)
|
|
||||||
expression.returnTargetSymbol.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitThrow(expression: IrThrow) {
|
|
||||||
super.visitThrow(expression)
|
|
||||||
|
|
||||||
expression.ensureTypeIs(builtIns.nothingType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
|
||||||
super.visitClass(declaration)
|
|
||||||
|
|
||||||
if (declaration.descriptor.kind != ClassKind.ANNOTATION_CLASS) {
|
|
||||||
// Check that all functions and properties from memberScope are present in IR
|
|
||||||
// (including FAKE_OVERRIDE ones).
|
|
||||||
|
|
||||||
val allDescriptors = declaration.descriptor.unsubstitutedMemberScope
|
|
||||||
.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>()
|
|
||||||
|
|
||||||
val presentDescriptors = declaration.declarations.map { it.descriptor }
|
|
||||||
|
|
||||||
val missingDescriptors = allDescriptors - presentDescriptors
|
|
||||||
|
|
||||||
if (missingDescriptors.isNotEmpty()) {
|
|
||||||
reportError(declaration, "Missing declarations for descriptors:\n" +
|
|
||||||
missingDescriptors.joinToString("\n"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclarationReference(expression: IrDeclarationReference) {
|
|
||||||
super.visitDeclarationReference(expression)
|
|
||||||
|
|
||||||
expression.symbol.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
|
||||||
super.visitFunctionAccess(expression)
|
|
||||||
|
|
||||||
expression.symbol.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
|
||||||
super.visitFunctionReference(expression)
|
|
||||||
|
|
||||||
expression.symbol.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitPropertyReference(expression: IrPropertyReference) {
|
|
||||||
super.visitPropertyReference(expression)
|
|
||||||
|
|
||||||
expression.field?.ensureBound(expression)
|
|
||||||
expression.getter?.ensureBound(expression)
|
|
||||||
expression.setter?.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
|
|
||||||
super.visitLocalDelegatedPropertyReference(expression)
|
|
||||||
|
|
||||||
expression.delegate.ensureBound(expression)
|
|
||||||
expression.getter.ensureBound(expression)
|
|
||||||
expression.setter?.ensureBound(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-107
@@ -1,107 +0,0 @@
|
|||||||
package org.jetbrains.kotlin.backend.common
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
|
||||||
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
|
||||||
import org.jetbrains.kotlin.types.TypeProjection
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
|
|
||||||
interface CommonBackendContext : BackendContext {
|
|
||||||
|
|
||||||
val ir: Ir<CommonBackendContext>
|
|
||||||
|
|
||||||
//TODO move to builtins
|
|
||||||
fun getInternalClass(name: String): ClassDescriptor
|
|
||||||
|
|
||||||
//TODO move to builtins
|
|
||||||
fun getInternalFunctions(name: String): List<FunctionDescriptor>
|
|
||||||
|
|
||||||
val reflectionTypes: ReflectionTypes
|
|
||||||
|
|
||||||
fun log(message: () -> String)
|
|
||||||
|
|
||||||
val messageCollector: MessageCollector
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
|
|
||||||
|
|
||||||
private val kotlinReflectScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
|
||||||
module.getPackage(KOTLIN_REFLECT_FQ_NAME).memberScope
|
|
||||||
}
|
|
||||||
|
|
||||||
private val internalScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
|
||||||
module.getPackage(internalPackage).memberScope
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
|
|
||||||
val name = Name.identifier(className)
|
|
||||||
return memberScope.getContributedClassifier(name, NoLookupLocation.FROM_REFLECTION) as ClassDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ClassLookup(val memberScope: MemberScope) {
|
|
||||||
operator fun getValue(types: ReflectionTypes, property: KProperty<*>): ClassDescriptor {
|
|
||||||
return types.find(memberScope, property.name.capitalize())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFunctionTypeArgumentProjections(
|
|
||||||
receiverType: KotlinType?,
|
|
||||||
parameterTypes: List<KotlinType>,
|
|
||||||
returnType: KotlinType
|
|
||||||
): List<TypeProjection> {
|
|
||||||
val arguments = ArrayList<TypeProjection>(parameterTypes.size + (if (receiverType != null) 1 else 0) + 1)
|
|
||||||
|
|
||||||
arguments.addIfNotNull(receiverType?.asTypeProjection())
|
|
||||||
|
|
||||||
parameterTypes.mapTo(arguments, KotlinType::asTypeProjection)
|
|
||||||
|
|
||||||
arguments.add(returnType.asTypeProjection())
|
|
||||||
|
|
||||||
return arguments
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getKFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KFunction$n")
|
|
||||||
|
|
||||||
val kClass: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kMutableProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
|
||||||
val kFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kMutableProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kMutableProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kMutableProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
|
||||||
|
|
||||||
fun getKFunctionType(
|
|
||||||
annotations: Annotations,
|
|
||||||
receiverType: KotlinType?,
|
|
||||||
parameterTypes: List<KotlinType>,
|
|
||||||
returnType: KotlinType
|
|
||||||
): KotlinType {
|
|
||||||
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType)
|
|
||||||
val classDescriptor = getKFunction(arguments.size - 1 /* return type */)
|
|
||||||
return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
|
||||||
import org.jetbrains.kotlin.ir.util.DeepCopySymbolsRemapper
|
|
||||||
import org.jetbrains.kotlin.ir.util.DescriptorsRemapper
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|
||||||
|
|
||||||
fun IrElement.deepCopyWithVariablesImpl(): IrElement {
|
|
||||||
val descriptorsRemapper = object : DescriptorsRemapper {
|
|
||||||
override fun remapDeclaredVariable(descriptor: VariableDescriptor) = LocalVariableDescriptor(
|
|
||||||
/* containingDeclaration = */ descriptor.containingDeclaration,
|
|
||||||
/* annotations = */ descriptor.annotations,
|
|
||||||
/* name = */ descriptor.name,
|
|
||||||
/* type = */ descriptor.type,
|
|
||||||
/* mutable = */ descriptor.isVar,
|
|
||||||
/* isDelegated = */ false,
|
|
||||||
/* source = */ descriptor.source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val symbolsRemapper = DeepCopySymbolsRemapper(descriptorsRemapper)
|
|
||||||
acceptVoid(symbolsRemapper)
|
|
||||||
|
|
||||||
return this.transform(
|
|
||||||
object : DeepCopyIrTreeWithReturnableBlockSymbols(symbolsRemapper) {
|
|
||||||
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
|
|
||||||
return irLoop
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : IrElement> T.deepCopyWithVariables(): T =
|
|
||||||
this.deepCopyWithVariablesImpl() as T
|
|
||||||
-621
@@ -1,621 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
|
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.*
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|
||||||
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.util.DeepCopyIrTree
|
|
||||||
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.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
|
||||||
|
|
||||||
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
|
|
||||||
val context: Context) {
|
|
||||||
|
|
||||||
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
|
|
||||||
private var typeSubstitutor: TypeSubstitutor? = null
|
|
||||||
private var nameIndex = 0
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
|
|
||||||
this.typeSubstitutor = typeSubstitutor
|
|
||||||
irElement.acceptChildrenVoid(DescriptorCollector())
|
|
||||||
return irElement.accept(InlineCopyIr(), null)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
inner class DescriptorCollector: IrElementVisitorVoid {
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptChildren(this, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
|
||||||
|
|
||||||
val oldDescriptor = declaration.descriptor
|
|
||||||
val newDescriptor = copyClassDescriptor(oldDescriptor)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
|
|
||||||
|
|
||||||
super.visitClass(declaration)
|
|
||||||
|
|
||||||
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
|
|
||||||
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
|
|
||||||
}.toSet()
|
|
||||||
|
|
||||||
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
|
|
||||||
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
|
|
||||||
|
|
||||||
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
|
|
||||||
.getContributedDescriptors()
|
|
||||||
.map {
|
|
||||||
descriptorSubstituteMap[it]!!
|
|
||||||
}
|
|
||||||
newDescriptor.initialize(
|
|
||||||
SimpleMemberScope(contributedDescriptors),
|
|
||||||
constructors,
|
|
||||||
primaryConstructor
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitProperty(declaration: IrProperty) {
|
|
||||||
|
|
||||||
copyPropertyOrField(declaration.descriptor)
|
|
||||||
super.visitProperty(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitField(declaration: IrField) {
|
|
||||||
|
|
||||||
val oldDescriptor = declaration.descriptor
|
|
||||||
if (descriptorSubstituteMap[oldDescriptor] == null) {
|
|
||||||
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
|
|
||||||
}
|
|
||||||
super.visitField(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction) {
|
|
||||||
|
|
||||||
val oldDescriptor = declaration.descriptor
|
|
||||||
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
|
|
||||||
val newDescriptor = copyFunctionDescriptor(oldDescriptor)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
oldDescriptor.extensionReceiverParameter?.let{
|
|
||||||
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.visitFunction(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable) {
|
|
||||||
|
|
||||||
val oldDescriptor = declaration.descriptor
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
|
||||||
val newDescriptor = IrTemporaryVariableDescriptorImpl(
|
|
||||||
containingDeclaration = newContainingDeclaration,
|
|
||||||
name = generateCopyName(oldDescriptor.name),
|
|
||||||
outType = substituteType(oldDescriptor.type)!!,
|
|
||||||
isMutable = oldDescriptor.isVar)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
|
|
||||||
super.visitVariable(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitCatch(aCatch: IrCatch) {
|
|
||||||
val oldDescriptor = aCatch.parameter
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
|
||||||
val newDescriptor = IrTemporaryVariableDescriptorImpl(
|
|
||||||
containingDeclaration = newContainingDeclaration,
|
|
||||||
name = generateCopyName(oldDescriptor.name),
|
|
||||||
outType = substituteType(oldDescriptor.type)!!,
|
|
||||||
isMutable = oldDescriptor.isVar)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
|
|
||||||
super.visitCatch(aCatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--- Copy descriptors ------------------------------------------------//
|
|
||||||
|
|
||||||
private fun generateCopyName(name: Name): Name {
|
|
||||||
|
|
||||||
val declarationName = name.toString() // Name of declaration
|
|
||||||
val indexStr = (nameIndex++).toString() // Unique for inline target index
|
|
||||||
return Name.identifier(declarationName + "_" + indexStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor {
|
|
||||||
|
|
||||||
return when (oldDescriptor) {
|
|
||||||
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
|
|
||||||
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor)
|
|
||||||
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor) : FunctionDescriptor {
|
|
||||||
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
|
||||||
return SimpleFunctionDescriptorImpl.create(
|
|
||||||
/* containingDeclaration = */ newContainingDeclaration,
|
|
||||||
/* annotations = */ oldDescriptor.annotations,
|
|
||||||
/* name = */ generateCopyName(oldDescriptor.name),
|
|
||||||
/* kind = */ oldDescriptor.kind,
|
|
||||||
/* source = */ oldDescriptor.source
|
|
||||||
).apply {
|
|
||||||
|
|
||||||
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
|
|
||||||
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
|
|
||||||
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
|
|
||||||
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
|
||||||
val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
|
|
||||||
val newReturnType = substituteType(oldDescriptor.returnType)
|
|
||||||
|
|
||||||
initialize(
|
|
||||||
/* receiverParameterType = */ newReceiverParameterType,
|
|
||||||
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
|
|
||||||
/* typeParameters = */ newTypeParameters,
|
|
||||||
/* unsubstitutedValueParameters = */ newValueParameters,
|
|
||||||
/* unsubstitutedReturnType = */ newReturnType,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* visibility = */ oldDescriptor.visibility
|
|
||||||
)
|
|
||||||
isTailrec = oldDescriptor.isTailrec
|
|
||||||
isSuspend = oldDescriptor.isSuspend
|
|
||||||
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
|
|
||||||
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
|
||||||
return ClassConstructorDescriptorImpl.create(
|
|
||||||
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
|
|
||||||
/* annotations = */ oldDescriptor.annotations,
|
|
||||||
/* isPrimary = */ oldDescriptor.isPrimary,
|
|
||||||
/* source = */ oldDescriptor.source
|
|
||||||
).apply {
|
|
||||||
|
|
||||||
val newTypeParameters = oldDescriptor.typeParameters
|
|
||||||
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
|
||||||
val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
|
|
||||||
val returnType = substituteType(oldDescriptor.returnType)
|
|
||||||
|
|
||||||
initialize(
|
|
||||||
/* receiverParameterType = */ receiverParameterType,
|
|
||||||
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
|
|
||||||
/* typeParameters = */ newTypeParameters,
|
|
||||||
/* unsubstitutedValueParameters = */ newValueParameters,
|
|
||||||
/* unsubstitutedReturnType = */ returnType,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* visibility = */ oldDescriptor.visibility
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
|
|
||||||
|
|
||||||
val newDescriptor = copyPropertyDescriptor(oldDescriptor)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
oldDescriptor.getter?.let {
|
|
||||||
descriptorSubstituteMap[it] = newDescriptor.getter!!
|
|
||||||
}
|
|
||||||
oldDescriptor.setter?.let {
|
|
||||||
descriptorSubstituteMap[it] = newDescriptor.setter!!
|
|
||||||
}
|
|
||||||
oldDescriptor.extensionReceiverParameter?.let{
|
|
||||||
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyPropertyDescriptor(oldDescriptor: PropertyDescriptor): PropertyDescriptor {
|
|
||||||
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
|
|
||||||
return PropertyDescriptorImpl.create(
|
|
||||||
/* containingDeclaration = */ newContainingDeclaration,
|
|
||||||
/* annotations = */ oldDescriptor.annotations,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* visibility = */ oldDescriptor.visibility,
|
|
||||||
/* isVar = */ oldDescriptor.isVar,
|
|
||||||
/* name = */ oldDescriptor.name,
|
|
||||||
/* kind = */ oldDescriptor.kind,
|
|
||||||
/* source = */ oldDescriptor.source,
|
|
||||||
/* lateInit = */ oldDescriptor.isLateInit,
|
|
||||||
/* isConst = */ oldDescriptor.isConst,
|
|
||||||
/* isHeader = */ oldDescriptor.isHeader,
|
|
||||||
/* isImpl = */ oldDescriptor.isImpl,
|
|
||||||
/* isExternal = */ oldDescriptor.isExternal,
|
|
||||||
/* isDelegated = */ oldDescriptor.isDelegated
|
|
||||||
).apply {
|
|
||||||
|
|
||||||
setType(
|
|
||||||
/* outType = */ oldDescriptor.type,
|
|
||||||
/* typeParameters = */ oldDescriptor.typeParameters,
|
|
||||||
/* dispatchReceiverParameter = */ newContainingDeclaration.thisAsReceiverParameter,
|
|
||||||
/* receiverType = */ oldDescriptor.extensionReceiverParameter?.type)
|
|
||||||
|
|
||||||
initialize(
|
|
||||||
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
|
|
||||||
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
|
|
||||||
|
|
||||||
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
|
|
||||||
: PropertyGetterDescriptorImpl {
|
|
||||||
|
|
||||||
return PropertyGetterDescriptorImpl(
|
|
||||||
/* correspondingProperty = */ newPropertyDescriptor,
|
|
||||||
/* annotations = */ oldDescriptor.annotations,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* visibility = */ oldDescriptor.visibility,
|
|
||||||
/* isDefault = */ oldDescriptor.isDefault,
|
|
||||||
/* isExternal = */ oldDescriptor.isExternal,
|
|
||||||
/* isInline = */ oldDescriptor.isInline,
|
|
||||||
/* kind = */ oldDescriptor.kind,
|
|
||||||
/* original = */ null,
|
|
||||||
/* source = */ oldDescriptor.source).apply {
|
|
||||||
initialize(oldDescriptor.returnType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
|
|
||||||
: PropertySetterDescriptorImpl {
|
|
||||||
|
|
||||||
return PropertySetterDescriptorImpl(
|
|
||||||
/* correspondingProperty = */ newPropertyDescriptor,
|
|
||||||
/* annotations = */ oldDescriptor.annotations,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* visibility = */ oldDescriptor.visibility,
|
|
||||||
/* isDefault = */ oldDescriptor.isDefault,
|
|
||||||
/* isExternal = */ oldDescriptor.isExternal,
|
|
||||||
/* isInline = */ oldDescriptor.isInline,
|
|
||||||
/* kind = */ oldDescriptor.kind,
|
|
||||||
/* original = */ null,
|
|
||||||
/* source = */ oldDescriptor.source).apply {
|
|
||||||
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
|
|
||||||
|
|
||||||
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
|
|
||||||
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
|
|
||||||
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
|
||||||
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
|
||||||
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
|
|
||||||
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
|
|
||||||
else
|
|
||||||
generateCopyName(oldDescriptor.name)
|
|
||||||
return ClassDescriptorImpl(
|
|
||||||
/* containingDeclaration = */ newContainingDeclaration,
|
|
||||||
/* name = */ newName,
|
|
||||||
/* modality = */ oldDescriptor.modality,
|
|
||||||
/* kind = */ oldDescriptor.kind,
|
|
||||||
/* supertypes = */ listOf(newSuperClass.defaultType),
|
|
||||||
/* source = */ oldDescriptor.source,
|
|
||||||
/* isExternal = */ oldDescriptor.isExternal
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
inner class InlineCopyIr : DeepCopyIrTree() {
|
|
||||||
|
|
||||||
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
|
||||||
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
|
|
||||||
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
|
||||||
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
|
||||||
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
|
||||||
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
|
||||||
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
|
||||||
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
|
||||||
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
|
|
||||||
|
|
||||||
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
|
||||||
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
|
|
||||||
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
|
||||||
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
|
||||||
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
|
||||||
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
|
||||||
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
|
||||||
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
|
||||||
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
|
|
||||||
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
|
|
||||||
if (qualifier == null) return null
|
|
||||||
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
//--- Visits ----------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrCall {
|
|
||||||
if (expression !is IrCallImpl) return super.visitCall(expression)
|
|
||||||
val newDescriptor = mapCallee(expression.descriptor)
|
|
||||||
return IrCallImpl(
|
|
||||||
startOffset = expression.startOffset,
|
|
||||||
endOffset = expression.endOffset,
|
|
||||||
type = newDescriptor.returnType!!,
|
|
||||||
calleeDescriptor = newDescriptor,
|
|
||||||
typeArguments = substituteTypeArguments(expression.transformTypeArguments(newDescriptor)),
|
|
||||||
origin = expression.origin,
|
|
||||||
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
|
|
||||||
).transformValueArguments(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction): IrFunction =
|
|
||||||
IrFunctionImpl(
|
|
||||||
startOffset = declaration.startOffset,
|
|
||||||
endOffset = declaration.endOffset,
|
|
||||||
origin = mapDeclarationOrigin(declaration.origin),
|
|
||||||
descriptor = mapFunctionDeclaration(declaration.descriptor),
|
|
||||||
body = declaration.body?.transform(this, null)
|
|
||||||
).transformParameters(declaration)
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun <T : IrFunction> T.transformDefaults(original: T): T {
|
|
||||||
for (originalValueParameter in original.descriptor.valueParameters) {
|
|
||||||
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
|
|
||||||
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
|
|
||||||
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
|
|
||||||
return when (operator) {
|
|
||||||
IrTypeOperator.CAST,
|
|
||||||
IrTypeOperator.IMPLICIT_CAST,
|
|
||||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
|
||||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
|
|
||||||
IrTypeOperator.SAFE_CAST -> type.makeNullable()
|
|
||||||
IrTypeOperator.INSTANCEOF,
|
|
||||||
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
|
|
||||||
val typeOperand = substituteType(expression.typeOperand)!!
|
|
||||||
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand)
|
|
||||||
return IrTypeOperatorCallImpl(
|
|
||||||
startOffset = expression.startOffset,
|
|
||||||
endOffset = expression.endOffset,
|
|
||||||
type = returnType,
|
|
||||||
operator = expression.operator,
|
|
||||||
typeOperand = typeOperand,
|
|
||||||
argument = expression.argument.transform(this, null)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrReturn =
|
|
||||||
IrReturnImpl(
|
|
||||||
startOffset = expression.startOffset,
|
|
||||||
endOffset = expression.endOffset,
|
|
||||||
type = substituteType(expression.type)!!,
|
|
||||||
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
|
|
||||||
value = expression.value.transform(this, null)
|
|
||||||
)
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock): IrBlock {
|
|
||||||
return if (expression is IrReturnableBlock) {
|
|
||||||
IrReturnableBlockImpl(
|
|
||||||
startOffset = expression.startOffset,
|
|
||||||
endOffset = expression.endOffset,
|
|
||||||
type = expression.type,
|
|
||||||
descriptor = expression.descriptor,
|
|
||||||
origin = mapStatementOrigin(expression.origin),
|
|
||||||
statements = expression.statements.map { it.transform(this, null) },
|
|
||||||
sourceFileName = expression.sourceFileName
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
super.visitBlock(expression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
|
|
||||||
return irLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor): List <ValueParameterDescriptor> {
|
|
||||||
|
|
||||||
return oldValueParameters.map { oldDescriptor ->
|
|
||||||
val newDescriptor = ValueParameterDescriptorImpl(
|
|
||||||
containingDeclaration = containingDeclaration,
|
|
||||||
original = oldDescriptor.original,
|
|
||||||
index = oldDescriptor.index,
|
|
||||||
annotations = oldDescriptor.annotations,
|
|
||||||
name = oldDescriptor.name,
|
|
||||||
outType = substituteType(oldDescriptor.type)!!,
|
|
||||||
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
|
|
||||||
isCrossinline = oldDescriptor.isCrossinline,
|
|
||||||
isNoinline = oldDescriptor.isNoinline,
|
|
||||||
varargElementType = substituteType(oldDescriptor.varargElementType),
|
|
||||||
source = oldDescriptor.source
|
|
||||||
)
|
|
||||||
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
|
||||||
newDescriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun substituteType(oldType: KotlinType?): KotlinType? {
|
|
||||||
if (typeSubstitutor == null) return oldType
|
|
||||||
if (oldType == null) return oldType
|
|
||||||
return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun substituteTypeArguments(oldTypeArguments: Map <TypeParameterDescriptor, KotlinType>?): Map <TypeParameterDescriptor, KotlinType>? {
|
|
||||||
|
|
||||||
if (oldTypeArguments == null) return null
|
|
||||||
if (typeSubstitutor == null) return oldTypeArguments
|
|
||||||
|
|
||||||
val newTypeArguments = oldTypeArguments.entries.associate {
|
|
||||||
val typeParameterDescriptor = it.key
|
|
||||||
val oldTypeArgument = it.value
|
|
||||||
val newTypeArgument = substituteType(oldTypeArgument)!!
|
|
||||||
typeParameterDescriptor to newTypeArgument
|
|
||||||
}
|
|
||||||
return newTypeArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
|
|
||||||
descriptorSubstituteMap.forEach { t, u ->
|
|
||||||
globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
|
|
||||||
|
|
||||||
internal class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
|
|
||||||
: IrElementTransformerVoidWithContext() {
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
|
||||||
val oldExpression = super.visitCall(expression) as IrCall
|
|
||||||
|
|
||||||
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
|
|
||||||
?: return oldExpression
|
|
||||||
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
|
|
||||||
return oldExpression
|
|
||||||
return when (oldExpression) {
|
|
||||||
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
|
|
||||||
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
|
|
||||||
else -> oldExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
|
|
||||||
|
|
||||||
val oldDescriptor = oldExpression.descriptor
|
|
||||||
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
|
||||||
|
|
||||||
if (newDescriptor == oldDescriptor)
|
|
||||||
return oldExpression
|
|
||||||
|
|
||||||
val newExpression = IrCallImpl(
|
|
||||||
startOffset = oldExpression.startOffset,
|
|
||||||
endOffset = oldExpression.endOffset,
|
|
||||||
type = oldExpression.type,
|
|
||||||
calleeDescriptor = newDescriptor,
|
|
||||||
typeArguments = oldExpression.typeArguments,
|
|
||||||
origin = oldExpression.origin,
|
|
||||||
superQualifierDescriptor = oldExpression.superQualifier
|
|
||||||
).apply {
|
|
||||||
oldExpression.descriptor.valueParameters.forEach {
|
|
||||||
val valueArgument = oldExpression.getValueArgument(it)
|
|
||||||
putValueArgument(it.index, valueArgument)
|
|
||||||
}
|
|
||||||
extensionReceiver = oldExpression.extensionReceiver
|
|
||||||
dispatchReceiver = oldExpression.dispatchReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
return newExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
|
|
||||||
|
|
||||||
val oldDescriptor = oldExpression.descriptor
|
|
||||||
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
|
||||||
|
|
||||||
if (newDescriptor == oldDescriptor)
|
|
||||||
return oldExpression
|
|
||||||
|
|
||||||
return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, oldExpression.superQualifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-366
@@ -1,366 +0,0 @@
|
|||||||
package org.jetbrains.kotlin.backend.common
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|
||||||
import org.jetbrains.kotlin.renderer.*
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
|
|
||||||
class RenderIrElementWithDescriptorsVisitor : IrElementVisitor<String, Nothing?> {
|
|
||||||
override fun visitElement(element: IrElement, data: Nothing?): String =
|
|
||||||
"? ${element.javaClass.simpleName}"
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
|
|
||||||
"? ${declaration.javaClass.simpleName} ${declaration.descriptor.ref()}"
|
|
||||||
|
|
||||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): String =
|
|
||||||
"MODULE_FRAGMENT ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitFile(declaration: IrFile, data: Nothing?): String =
|
|
||||||
"FILE ${declaration.name}"
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
|
|
||||||
"FUN ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor, data: Nothing?): String =
|
|
||||||
"CONSTRUCTOR ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
|
|
||||||
"PROPERTY ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitField(declaration: IrField, data: Nothing?): String =
|
|
||||||
"FIELD ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass, data: Nothing?): String =
|
|
||||||
"CLASS ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): String =
|
|
||||||
"TYPEALIAS ${declaration.descriptor} type=${declaration.descriptor.underlyingType.render()}"
|
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
|
|
||||||
"VAR ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String =
|
|
||||||
"ENUM_ENTRY ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String =
|
|
||||||
"ANONYMOUS_INITIALIZER ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
|
|
||||||
"LOCAL_DELEGATED_PROPERTY ${declaration.descriptor}"
|
|
||||||
|
|
||||||
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
|
|
||||||
"EXPRESSION_BODY"
|
|
||||||
|
|
||||||
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): String =
|
|
||||||
"BLOCK_BODY"
|
|
||||||
|
|
||||||
override fun visitSyntheticBody(body: IrSyntheticBody, data: Nothing?): String =
|
|
||||||
"SYNTHETIC_BODY kind=${body.kind}"
|
|
||||||
|
|
||||||
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
|
||||||
"? ${expression.javaClass.simpleName} type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): String =
|
|
||||||
"CONST ${expression.kind} type=${expression.type.render()} value='${expression.value}'"
|
|
||||||
|
|
||||||
override fun visitVararg(expression: IrVararg, data: Nothing?): String =
|
|
||||||
"VARARG type=${expression.type} varargElementType=${expression.varargElementType}"
|
|
||||||
|
|
||||||
override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?): String =
|
|
||||||
"SPREAD_ELEMENT"
|
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock, data: Nothing?): String =
|
|
||||||
"BLOCK type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitComposite(expression: IrComposite, data: Nothing?): String =
|
|
||||||
"COMPOSITE type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: Nothing?): String =
|
|
||||||
"RETURN type=${expression.type.render()} from='${expression.returnTarget}'"
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: Nothing?): String =
|
|
||||||
"CALL '${expression.descriptor}' ${expression.renderSuperQualifier()}" +
|
|
||||||
"type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
private fun IrCall.renderSuperQualifier(): String =
|
|
||||||
superQualifier?.let { "superQualifier=${it.name} " } ?: ""
|
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String =
|
|
||||||
"DELEGATING_CONSTRUCTOR_CALL '${expression.descriptor}'"
|
|
||||||
|
|
||||||
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String =
|
|
||||||
"ENUM_CONSTRUCTOR_CALL '${expression.descriptor}'"
|
|
||||||
|
|
||||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): String =
|
|
||||||
"INSTANCE_INITIALIZER_CALL classDescriptor='${expression.classDescriptor}'"
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: Nothing?): String =
|
|
||||||
"GET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): String =
|
|
||||||
"SET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField, data: Nothing?): String =
|
|
||||||
"GET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField, data: Nothing?): String =
|
|
||||||
"SET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue, data: Nothing?): String =
|
|
||||||
"GET_OBJECT '${expression.descriptor}' type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitGetEnumValue(expression: IrGetEnumValue, data: Nothing?): String =
|
|
||||||
"GET_ENUM '${expression.descriptor}' type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): String =
|
|
||||||
"STRING_CONCATENATION type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): String =
|
|
||||||
"TYPE_OP origin=${expression.operator} typeOperand=${expression.typeOperand.render()}"
|
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: Nothing?): String =
|
|
||||||
"WHEN type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitBranch(branch: IrBranch, data: Nothing?): String =
|
|
||||||
"BRANCH"
|
|
||||||
|
|
||||||
override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String =
|
|
||||||
"WHILE label=${loop.label} origin=${loop.origin}"
|
|
||||||
|
|
||||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String =
|
|
||||||
"DO_WHILE label=${loop.label} origin=${loop.origin}"
|
|
||||||
|
|
||||||
override fun visitBreak(jump: IrBreak, data: Nothing?): String =
|
|
||||||
"BREAK label=${jump.label} loop.label=${jump.loop.label}"
|
|
||||||
|
|
||||||
override fun visitContinue(jump: IrContinue, data: Nothing?): String =
|
|
||||||
"CONTINUE label=${jump.label} loop.label=${jump.loop.label}"
|
|
||||||
|
|
||||||
override fun visitThrow(expression: IrThrow, data: Nothing?): String =
|
|
||||||
"THROW type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitCallableReference(expression: IrCallableReference, data: Nothing?): String =
|
|
||||||
"CALLABLE_REFERENCE '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
|
|
||||||
|
|
||||||
override fun visitClassReference(expression: IrClassReference, data: Nothing?): String =
|
|
||||||
"CLASS_REFERENCE '${expression.descriptor}' type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitGetClass(expression: IrGetClass, data: Nothing?): String =
|
|
||||||
"GET_CLASS type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitTry(aTry: IrTry, data: Nothing?): String =
|
|
||||||
"TRY type=${aTry.type.render()}"
|
|
||||||
|
|
||||||
override fun visitCatch(aCatch: IrCatch, data: Nothing?): String =
|
|
||||||
"CATCH parameter=${aCatch.parameter.ref()}"
|
|
||||||
|
|
||||||
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
|
|
||||||
"ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.ref()}"
|
|
||||||
|
|
||||||
override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String =
|
|
||||||
"ERROR_EXPR '${expression.description}' type=${expression.type.render()}"
|
|
||||||
|
|
||||||
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
|
|
||||||
"ERROR_CALL '${expression.description}' type=${expression.type.render()}"
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DECLARATION_RENDERER = DescriptorRenderer.withOptions {
|
|
||||||
withDefinedIn = false
|
|
||||||
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE
|
|
||||||
includePropertyConstant = true
|
|
||||||
classifierNamePolicy = ClassifierNamePolicy.FULLY_QUALIFIED
|
|
||||||
verbose = false
|
|
||||||
modifiers = DescriptorRendererModifier.ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
val REFERENCE_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES
|
|
||||||
|
|
||||||
internal fun IrDeclaration.name(): String =
|
|
||||||
descriptor.let { it.name.toString() }
|
|
||||||
|
|
||||||
internal fun IrDeclaration.renderDeclared(): String =
|
|
||||||
DECLARATION_RENDERER.render(this.descriptor)
|
|
||||||
|
|
||||||
internal fun DeclarationDescriptor.ref(): String =
|
|
||||||
if (this is ReceiverParameterDescriptor)
|
|
||||||
"<receiver: ${containingDeclaration.ref()}>"
|
|
||||||
else
|
|
||||||
REFERENCE_RENDERER.render(this)
|
|
||||||
|
|
||||||
internal fun KotlinType.render(): String =
|
|
||||||
DECLARATION_RENDERER.renderType(this)
|
|
||||||
|
|
||||||
internal fun IrDeclaration.renderOrigin(): String =
|
|
||||||
if (origin != IrDeclarationOrigin.DEFINED) origin.toString() + " " else ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DumpIrTreeWithDescriptorsVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
|
||||||
val printer = Printer(out, " ")
|
|
||||||
val elementRenderer = RenderIrElementWithDescriptorsVisitor()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val ANNOTATIONS_RENDERER = DescriptorRenderer.withOptions {
|
|
||||||
verbose = true
|
|
||||||
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: String) {
|
|
||||||
element.dumpLabeledSubTree(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFile(declaration: IrFile, data: String) {
|
|
||||||
declaration.dumpLabeledElementWith(data) {
|
|
||||||
if (declaration.fileAnnotations.isNotEmpty()) {
|
|
||||||
printer.println("fileAnnotations:")
|
|
||||||
indented {
|
|
||||||
declaration.fileAnnotations.forEach {
|
|
||||||
printer.println(ANNOTATIONS_RENDERER.renderAnnotation(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
declaration.declarations.forEach { it.accept(this, "") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock, data: String) {
|
|
||||||
if (expression is IrReturnableBlock) {
|
|
||||||
printer.println("RETURNABLE BLOCK " + expression.descriptor)
|
|
||||||
indented { super.visitBlock(expression, data) }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
super.visitBlock(expression, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction, data: String) {
|
|
||||||
visitFunctionWithParameters(declaration, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor, data: String) {
|
|
||||||
visitFunctionWithParameters(declaration, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) {
|
|
||||||
expression.dumpLabeledElementWith(data) {
|
|
||||||
expression.explicitReceiver?.accept(this, "receiver")
|
|
||||||
expression.arguments.forEach { it.accept(this, "") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitFunctionWithParameters(declaration: IrFunction, data: String) {
|
|
||||||
declaration.dumpLabeledElementWith(data) {
|
|
||||||
declaration.descriptor.valueParameters.forEach { valueParameter ->
|
|
||||||
declaration.getDefault(valueParameter)?.accept(this, valueParameter.name.asString())
|
|
||||||
}
|
|
||||||
declaration.body?.accept(this, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitEnumEntry(declaration: IrEnumEntry, data: String) {
|
|
||||||
declaration.dumpLabeledElementWith(data) {
|
|
||||||
declaration.initializerExpression?.accept(this, "init")
|
|
||||||
declaration.correspondingClass?.accept(this, "class")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: String) {
|
|
||||||
expression.dumpLabeledElementWith(data) {
|
|
||||||
dumpTypeArguments(expression)
|
|
||||||
|
|
||||||
expression.dispatchReceiver?.accept(this, "\$this")
|
|
||||||
expression.extensionReceiver?.accept(this, "\$receiver")
|
|
||||||
for (valueParameter in expression.descriptor.valueParameters) {
|
|
||||||
expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dumpTypeArguments(expression: IrMemberAccessExpression) {
|
|
||||||
for (typeParameter in expression.descriptor.original.typeParameters) {
|
|
||||||
val typeArgument = expression.getTypeArgument(typeParameter) ?: continue
|
|
||||||
val renderedParameter = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(typeParameter)
|
|
||||||
val renderedType = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.renderType(typeArgument)
|
|
||||||
printer.println("$renderedParameter: $renderedType")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField, data: String) {
|
|
||||||
expression.dumpLabeledElementWith(data) {
|
|
||||||
expression.receiver?.accept(this, "receiver")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetField(expression: IrSetField, data: String) {
|
|
||||||
expression.dumpLabeledElementWith(data) {
|
|
||||||
expression.receiver?.accept(this, "receiver")
|
|
||||||
expression.value.accept(this, "value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: String) {
|
|
||||||
expression.dumpLabeledElementWith(data) {
|
|
||||||
expression.branches.forEach {
|
|
||||||
it.accept(this, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBranch(branch: IrBranch, data: String) {
|
|
||||||
branch.dumpLabeledElementWith(data) {
|
|
||||||
branch.condition.accept(this, "if")
|
|
||||||
branch.result.accept(this, "then")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhileLoop(loop: IrWhileLoop, data: String) {
|
|
||||||
loop.dumpLabeledElementWith(data) {
|
|
||||||
loop.condition.accept(this, "condition")
|
|
||||||
loop.body?.accept(this, "body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) {
|
|
||||||
loop.dumpLabeledElementWith(data) {
|
|
||||||
loop.body?.accept(this, "body")
|
|
||||||
loop.condition.accept(this, "condition")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitTry(aTry: IrTry, data: String) {
|
|
||||||
aTry.dumpLabeledElementWith(data) {
|
|
||||||
aTry.tryResult.accept(this, "try")
|
|
||||||
for (aCatch in aTry.catches) {
|
|
||||||
aCatch.accept(this, "")
|
|
||||||
}
|
|
||||||
aTry.finallyExpression?.accept(this, "finally")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
|
|
||||||
printer.println(accept(elementRenderer, null).withLabel(label))
|
|
||||||
indented(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrElement.dumpLabeledSubTree(label: String) {
|
|
||||||
printer.println(accept(elementRenderer, null).withLabel(label))
|
|
||||||
indented {
|
|
||||||
acceptChildren(this@DumpIrTreeWithDescriptorsVisitor, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun indented(body: () -> Unit) {
|
|
||||||
printer.pushIndent()
|
|
||||||
body()
|
|
||||||
printer.popIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.withLabel(label: String) =
|
|
||||||
if (label.isEmpty()) this else "$label: $this"
|
|
||||||
}
|
|
||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
|
||||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
|
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolRemapper
|
|
||||||
|
|
||||||
open class DeepCopyIrTreeWithReturnableBlockSymbols(
|
|
||||||
private val symbolRemapper: SymbolRemapper
|
|
||||||
) : DeepCopyIrTreeWithSymbols(symbolRemapper) {
|
|
||||||
|
|
||||||
private inline fun <reified T : IrElement> T.transform() =
|
|
||||||
transform(this@DeepCopyIrTreeWithReturnableBlockSymbols, null) as T
|
|
||||||
|
|
||||||
private val transformedReturnableBlocks = mutableMapOf<IrReturnableBlock, IrReturnableBlock>()
|
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock): IrBlock = if (expression is IrReturnableBlock) {
|
|
||||||
IrReturnableBlockImpl(
|
|
||||||
expression.startOffset, expression.endOffset,
|
|
||||||
expression.type,
|
|
||||||
expression.descriptor,
|
|
||||||
expression.origin,
|
|
||||||
expression.sourceFileName
|
|
||||||
).also {
|
|
||||||
transformedReturnableBlocks.put(expression, it)
|
|
||||||
it.statements.addAll(expression.statements.map { it.transform() })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.visitBlock(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrReturn {
|
|
||||||
val returnTargetSymbol = expression.returnTargetSymbol
|
|
||||||
return if (returnTargetSymbol is IrReturnableBlockSymbol) {
|
|
||||||
IrReturnImpl(
|
|
||||||
expression.startOffset, expression.endOffset,
|
|
||||||
expression.type,
|
|
||||||
transformedReturnableBlocks.getOrElse(returnTargetSymbol.owner) { returnTargetSymbol.owner }.symbol,
|
|
||||||
expression.value.transform()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
super.visitReturn(expression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-166
@@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.builders.Scope
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
|
|
||||||
internal class ScopeWithIr(val scope: Scope, val irElement: IrElement)
|
|
||||||
|
|
||||||
abstract internal class IrElementTransformerVoidWithContext : IrElementTransformerVoid() {
|
|
||||||
|
|
||||||
private val scopeStack = mutableListOf<ScopeWithIr>()
|
|
||||||
|
|
||||||
override final fun visitFile(declaration: IrFile): IrFile {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
val result = visitFileNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitClass(declaration: IrClass): IrStatement {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
val result = visitClassNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitProperty(declaration: IrProperty): IrStatement {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
|
||||||
val result = visitPropertyNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitField(declaration: IrField): IrStatement {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
val result = visitFieldNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitFunction(declaration: IrFunction): IrStatement {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
val result = visitFunctionNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile
|
|
||||||
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
|
|
||||||
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
|
|
||||||
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
|
|
||||||
protected val currentScope get() = scopeStack.peek()
|
|
||||||
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
|
||||||
protected val allScopes get() = scopeStack
|
|
||||||
|
|
||||||
fun printScopeStack() {
|
|
||||||
scopeStack.forEach { println(it.scope.scopeOwner) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFileNew(declaration: IrFile): IrFile {
|
|
||||||
return super.visitFile(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitClassNew(declaration: IrClass): IrStatement {
|
|
||||||
return super.visitClass(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFunctionNew(declaration: IrFunction): IrStatement {
|
|
||||||
return super.visitFunction(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitPropertyNew(declaration: IrProperty): IrStatement {
|
|
||||||
return super.visitProperty(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFieldNew(declaration: IrField): IrStatement {
|
|
||||||
return super.visitField(declaration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract internal class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
|
|
||||||
|
|
||||||
private val scopeStack = mutableListOf<ScopeWithIr>()
|
|
||||||
|
|
||||||
override final fun visitFile(declaration: IrFile) {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
visitFileNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitClass(declaration: IrClass) {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
visitClassNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitProperty(declaration: IrProperty) {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
|
||||||
visitPropertyNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitField(declaration: IrField) {
|
|
||||||
val isDelegated = declaration.descriptor.isDelegated
|
|
||||||
if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
|
|
||||||
visitFieldNew(declaration)
|
|
||||||
if (isDelegated) scopeStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override final fun visitFunction(declaration: IrFunction) {
|
|
||||||
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
|
|
||||||
visitFunctionNew(declaration)
|
|
||||||
scopeStack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected val currentFile get() = scopeStack.lastOrNull { it.scope.scopeOwner is PackageFragmentDescriptor }
|
|
||||||
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
|
|
||||||
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
|
|
||||||
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
|
|
||||||
protected val currentScope get() = scopeStack.peek()
|
|
||||||
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
|
||||||
|
|
||||||
fun printScopeStack() {
|
|
||||||
scopeStack.forEach { println(it.scope.scopeOwner) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFileNew(declaration: IrFile) {
|
|
||||||
super.visitFile(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitClassNew(declaration: IrClass) {
|
|
||||||
super.visitClass(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFunctionNew(declaration: IrFunction) {
|
|
||||||
super.visitFunction(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitPropertyNew(declaration: IrProperty) {
|
|
||||||
super.visitProperty(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun visitFieldNew(declaration: IrField) {
|
|
||||||
super.visitField(declaration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-72
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|
||||||
|
|
||||||
fun validateIrFile(context: CommonBackendContext, irFile: IrFile) {
|
|
||||||
val visitor = IrValidator(context, false)
|
|
||||||
irFile.acceptVoid(visitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun validateIrModule(context: CommonBackendContext, irModule: IrModuleFragment) {
|
|
||||||
val visitor = IrValidator(context, true) // TODO: consider taking the boolean from settings.
|
|
||||||
irModule.acceptVoid(visitor)
|
|
||||||
|
|
||||||
// TODO: also check that all referenced symbol targets are reachable.
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CommonBackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) {
|
|
||||||
try {
|
|
||||||
this.reportWarning("[IR VALIDATION] $message", irFile, irElement)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
println("an error trying to print a warning message: $e")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
// TODO: throw an exception after fixing bugs leading to invalid IR.
|
|
||||||
}
|
|
||||||
|
|
||||||
private class IrValidator(val context: CommonBackendContext, performHeavyValidations: Boolean) : IrElementVisitorVoid {
|
|
||||||
|
|
||||||
val builtIns = context.builtIns
|
|
||||||
lateinit var currentFile: IrFile
|
|
||||||
|
|
||||||
override fun visitFile(declaration: IrFile) {
|
|
||||||
currentFile = declaration
|
|
||||||
super.visitFile(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun error(element: IrElement, message: String) {
|
|
||||||
// TODO: render all element's parents.
|
|
||||||
context.reportIrValidationError(
|
|
||||||
"$message\n" +
|
|
||||||
element.render(),
|
|
||||||
currentFile, element)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val elementChecker = CheckIrElementVisitor(builtIns, this::error, performHeavyValidations)
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptVoid(elementChecker)
|
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-160
@@ -1,160 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.util.usesDefaultArguments
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects calls to be treated as tail recursion.
|
|
||||||
* The checks are partially based on the frontend implementation
|
|
||||||
* in `ControlFlowInformationProvider.markAndCheckRecursiveTailCalls()`.
|
|
||||||
*
|
|
||||||
* This analysis is not very precise and can miss some calls.
|
|
||||||
* It is also not guaranteed that each returned call is detected as tail recursion by the frontend.
|
|
||||||
* However any returned call can be correctly optimized as tail recursion.
|
|
||||||
*/
|
|
||||||
fun collectTailRecursionCalls(irFunction: IrFunction): Set<IrCall> {
|
|
||||||
if (!irFunction.descriptor.isTailrec) {
|
|
||||||
return emptySet()
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = mutableSetOf<IrCall>()
|
|
||||||
|
|
||||||
val visitor = object : IrElementVisitor<Unit, ElementKind> {
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: ElementKind) {
|
|
||||||
val childKind = ElementKind.NOT_SURE // Not sure by default.
|
|
||||||
element.acceptChildren(this, childKind)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction, data: ElementKind) {
|
|
||||||
// Ignore local functions.
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass, data: ElementKind) {
|
|
||||||
// Ignore local classes.
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitTry(aTry: IrTry, data: ElementKind) {
|
|
||||||
// We do not support tail calls in try-catch-finally, for simplicity of the mental model
|
|
||||||
// very few cases there would be real tail-calls, and it's often not so easy for the user to see why
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: ElementKind) {
|
|
||||||
val valueKind = if (expression.returnTarget == irFunction.descriptor) {
|
|
||||||
ElementKind.TAIL_STATEMENT
|
|
||||||
} else {
|
|
||||||
ElementKind.NOT_SURE
|
|
||||||
}
|
|
||||||
expression.value.accept(this, valueKind)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitContainerExpression(expression: IrContainerExpression, data: ElementKind) {
|
|
||||||
expression.statements.forEachIndexed { index, irStatement ->
|
|
||||||
val statementKind = if (index == expression.statements.lastIndex) {
|
|
||||||
// The last statement defines the result of the container expression, so it has the same kind.
|
|
||||||
data
|
|
||||||
} else {
|
|
||||||
ElementKind.NOT_SURE
|
|
||||||
}
|
|
||||||
irStatement.accept(this, statementKind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: ElementKind) {
|
|
||||||
expression.branches.forEach {
|
|
||||||
it.condition.accept(this, ElementKind.NOT_SURE)
|
|
||||||
it.result.accept(this, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: ElementKind) {
|
|
||||||
expression.acceptChildren(this, ElementKind.NOT_SURE)
|
|
||||||
|
|
||||||
// Is it a tail call?
|
|
||||||
if (data != ElementKind.TAIL_STATEMENT) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it a recursive call?
|
|
||||||
if (expression.descriptor.original != irFunction.descriptor) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO: check type arguments
|
|
||||||
|
|
||||||
if (DescriptorUtils.isOverride(irFunction.descriptor) && expression.usesDefaultArguments()) {
|
|
||||||
// Overridden functions using default arguments at tail call are not included: KT-4285
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
expression.dispatchReceiver?.let {
|
|
||||||
if (it !is IrGetValue || it.descriptor != irFunction.descriptor.dispatchReceiverParameter) {
|
|
||||||
// A tail call is not allowed to change dispatch receiver
|
|
||||||
// class C {
|
|
||||||
// fun foo(other: C) {
|
|
||||||
// other.foo(this) // not a tail call
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.add(expression)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
val body = irFunction.body
|
|
||||||
if (body !is IrBlockBody) {
|
|
||||||
return emptySet() // TODO: should an assert be here instead?
|
|
||||||
}
|
|
||||||
|
|
||||||
body.statements.forEachIndexed { index, irStatement ->
|
|
||||||
val kind = if (index == body.statements.lastIndex && irFunction.descriptor.returnType?.isUnit() == true) {
|
|
||||||
ElementKind.TAIL_STATEMENT
|
|
||||||
} else {
|
|
||||||
ElementKind.NOT_SURE
|
|
||||||
}
|
|
||||||
irStatement.accept(visitor, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The kind of IR element used to detect tail calls.
|
|
||||||
*/
|
|
||||||
private enum class ElementKind {
|
|
||||||
/**
|
|
||||||
* This element is the last statement to be executed before the return from the function.
|
|
||||||
* If the return type is not `Unit`, the result of this statement defines the result of the entire function.
|
|
||||||
*/
|
|
||||||
TAIL_STATEMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not sure if the element meets the requirements to be [TAIL_STATEMENT].
|
|
||||||
*/
|
|
||||||
NOT_SURE
|
|
||||||
}
|
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
|
||||||
import org.jetbrains.kotlin.ir.util.getCompilerMessageLocation
|
|
||||||
|
|
||||||
fun CommonBackendContext.reportWarning(message: String, irFile: IrFile, irElement: IrElement) {
|
|
||||||
val location = irElement.getCompilerMessageLocation(irFile)
|
|
||||||
messageCollector.report(CompilerMessageSeverity.WARNING, message, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <E> MutableList<E>.push(element: E) = this.add(element)
|
|
||||||
|
|
||||||
fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
|
|
||||||
|
|
||||||
fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
|
|
||||||
|
|
||||||
fun <T> Collection<T>.atMostOne(): T? {
|
|
||||||
return when (this.size) {
|
|
||||||
0 -> null
|
|
||||||
1 -> this.iterator().next()
|
|
||||||
else -> throw IllegalArgumentException("Collection has more than one element.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
|
|
||||||
|
|
||||||
fun <T: Any> T.onlyIf(condition: T.()->Boolean, then: (T)->Unit): T {
|
|
||||||
if (this.condition()) then(this)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
-94
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.descriptors
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.replace
|
|
||||||
|
|
||||||
internal val CallableDescriptor.isSuspend: Boolean
|
|
||||||
get() = this is FunctionDescriptor && isSuspend
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return naturally-ordered list of all parameters available inside the function body.
|
|
||||||
*/
|
|
||||||
internal val CallableDescriptor.allParameters: List<ParameterDescriptor>
|
|
||||||
get() = if (this is ConstructorDescriptor) {
|
|
||||||
listOf(this.constructedClass.thisAsReceiverParameter) + explicitParameters
|
|
||||||
} else {
|
|
||||||
explicitParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return naturally-ordered list of the parameters that can have values specified at call site.
|
|
||||||
*/
|
|
||||||
internal val CallableDescriptor.explicitParameters: List<ParameterDescriptor>
|
|
||||||
get() {
|
|
||||||
val result = ArrayList<ParameterDescriptor>(valueParameters.size + 2)
|
|
||||||
|
|
||||||
this.dispatchReceiverParameter?.let {
|
|
||||||
result.add(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.extensionReceiverParameter?.let {
|
|
||||||
result.add(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.addAll(valueParameters)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KotlinType.replace(types: List<KotlinType>) = this.replace(types.map(::TypeProjectionImpl))
|
|
||||||
|
|
||||||
fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor {
|
|
||||||
val typeSubstitutor = TypeSubstitutor.create(
|
|
||||||
typeParameters
|
|
||||||
.withIndex()
|
|
||||||
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
|
|
||||||
)
|
|
||||||
return substitute(typeSubstitutor)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FunctionDescriptor.substitute(typeArguments: Map<TypeParameterDescriptor, KotlinType>): FunctionDescriptor {
|
|
||||||
val typeSubstitutor = TypeSubstitutor.create(
|
|
||||||
typeParameters.associateBy({ it.typeConstructor }, { TypeProjectionImpl(typeArguments[it]!!) })
|
|
||||||
)
|
|
||||||
return substitute(typeSubstitutor)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ClassDescriptor.getFunction(name: String, types: List<KotlinType>): FunctionDescriptor {
|
|
||||||
val typeSubstitutor = TypeSubstitutor.create(
|
|
||||||
declaredTypeParameters
|
|
||||||
.withIndex()
|
|
||||||
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
|
|
||||||
)
|
|
||||||
return unsubstitutedMemberScope
|
|
||||||
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
val KotlinType.isFunctionOrKFunctionType: Boolean
|
|
||||||
get() {
|
|
||||||
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
|
|
||||||
return kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
|
|
||||||
}
|
|
||||||
-208
@@ -1,208 +0,0 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.ir
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
|
|
||||||
// This is what Context collects about IR.
|
|
||||||
abstract class Ir<out T: CommonBackendContext>(val context: T, val irModule: IrModuleFragment) {
|
|
||||||
|
|
||||||
abstract val symbols: Symbols<T>
|
|
||||||
|
|
||||||
val defaultParameterDeclarationsCache = mutableMapOf<FunctionDescriptor, IrFunction>()
|
|
||||||
|
|
||||||
open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Symbols<out T: CommonBackendContext>(val context: T, private val symbolTable: SymbolTable) {
|
|
||||||
|
|
||||||
private val builtIns
|
|
||||||
get() = context.builtIns
|
|
||||||
|
|
||||||
protected fun builtInsPackage(vararg packageNameSegments: String) =
|
|
||||||
context.builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope
|
|
||||||
|
|
||||||
val refClass = symbolTable.referenceClass(context.getInternalClass("Ref"))
|
|
||||||
|
|
||||||
abstract val areEqual: IrFunctionSymbol
|
|
||||||
abstract val ThrowNullPointerException: IrFunctionSymbol
|
|
||||||
abstract val ThrowNoWhenBranchMatchedException: IrFunctionSymbol
|
|
||||||
abstract val ThrowTypeCastException: IrFunctionSymbol
|
|
||||||
abstract val ThrowUninitializedPropertyAccessException: IrFunctionSymbol
|
|
||||||
|
|
||||||
abstract val stringBuilder: IrClassSymbol
|
|
||||||
|
|
||||||
val iterator = symbolTable.referenceClass(
|
|
||||||
builtInsPackage("kotlin", "collections").getContributedClassifier(
|
|
||||||
Name.identifier("Iterator"), NoLookupLocation.FROM_BACKEND
|
|
||||||
) as ClassDescriptor)
|
|
||||||
|
|
||||||
val asserts = builtInsPackage("kotlin")
|
|
||||||
.getContributedFunctions(Name.identifier("assert"), NoLookupLocation.FROM_BACKEND)
|
|
||||||
.map { symbolTable.referenceFunction(it) }
|
|
||||||
|
|
||||||
private fun progression(name: String) = symbolTable.referenceClass(
|
|
||||||
builtInsPackage("kotlin", "ranges").getContributedClassifier(
|
|
||||||
Name.identifier(name), NoLookupLocation.FROM_BACKEND
|
|
||||||
) as ClassDescriptor
|
|
||||||
)
|
|
||||||
|
|
||||||
val charProgression = progression("CharProgression")
|
|
||||||
val intProgression = progression("IntProgression")
|
|
||||||
val longProgression = progression("LongProgression")
|
|
||||||
val progressionClasses = listOf(charProgression, intProgression, longProgression)
|
|
||||||
val progressionClassesTypes = progressionClasses.map { it.descriptor.defaultType }.toSet()
|
|
||||||
|
|
||||||
val defaultConstructorMarker = symbolTable.referenceClass(context.getInternalClass("DefaultConstructorMarker"))
|
|
||||||
|
|
||||||
val any = symbolTable.referenceClass(builtIns.any)
|
|
||||||
val unit = symbolTable.referenceClass(builtIns.unit)
|
|
||||||
|
|
||||||
val char = symbolTable.referenceClass(builtIns.char)
|
|
||||||
|
|
||||||
val byte = symbolTable.referenceClass(builtIns.byte)
|
|
||||||
val short = symbolTable.referenceClass(builtIns.short)
|
|
||||||
val int = symbolTable.referenceClass(builtIns.int)
|
|
||||||
val long = symbolTable.referenceClass(builtIns.long)
|
|
||||||
|
|
||||||
val integerClasses = listOf(byte, short, int, long)
|
|
||||||
val integerClassesTypes = integerClasses.map { it.descriptor.defaultType }
|
|
||||||
|
|
||||||
val arrayOf = symbolTable.referenceSimpleFunction(
|
|
||||||
builtInsPackage("kotlin").getContributedFunctions(
|
|
||||||
Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND
|
|
||||||
).single()
|
|
||||||
)
|
|
||||||
|
|
||||||
val array = symbolTable.referenceClass(builtIns.array)
|
|
||||||
|
|
||||||
private fun primitiveArrayClass(type: PrimitiveType) =
|
|
||||||
symbolTable.referenceClass(builtIns.getPrimitiveArrayClassDescriptor(type))
|
|
||||||
|
|
||||||
val byteArray = primitiveArrayClass(PrimitiveType.BYTE)
|
|
||||||
val charArray = primitiveArrayClass(PrimitiveType.CHAR)
|
|
||||||
val shortArray = primitiveArrayClass(PrimitiveType.SHORT)
|
|
||||||
val intArray = primitiveArrayClass(PrimitiveType.INT)
|
|
||||||
val longArray = primitiveArrayClass(PrimitiveType.LONG)
|
|
||||||
val floatArray = primitiveArrayClass(PrimitiveType.FLOAT)
|
|
||||||
val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE)
|
|
||||||
val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN)
|
|
||||||
|
|
||||||
val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array
|
|
||||||
|
|
||||||
protected fun arrayExtensionFun(type: KotlinType, name: String): IrSimpleFunctionSymbol {
|
|
||||||
val descriptor = builtInsPackage("kotlin")
|
|
||||||
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
|
|
||||||
.singleOrNull { it.valueParameters.isEmpty()
|
|
||||||
&& (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type }
|
|
||||||
?: throw Error(type.toString())
|
|
||||||
return symbolTable.referenceSimpleFunction(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected val arrayTypes = arrayOf(
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BYTE),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.CHAR),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.SHORT),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.INT),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.LONG),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.FLOAT),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.DOUBLE),
|
|
||||||
builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BOOLEAN),
|
|
||||||
builtIns.array.defaultType
|
|
||||||
)
|
|
||||||
|
|
||||||
val copyRangeTo = arrays.map { symbol ->
|
|
||||||
val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME)
|
|
||||||
val functionDescriptor = packageViewDescriptor.memberScope
|
|
||||||
.getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND)
|
|
||||||
.first {
|
|
||||||
it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == symbol.descriptor
|
|
||||||
}
|
|
||||||
symbol.descriptor to symbolTable.referenceSimpleFunction(functionDescriptor)
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
val intAnd = symbolTable.referenceFunction(
|
|
||||||
builtIns.intType.memberScope
|
|
||||||
.getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single()
|
|
||||||
)
|
|
||||||
|
|
||||||
val intPlusInt = symbolTable.referenceFunction(
|
|
||||||
builtIns.intType.memberScope
|
|
||||||
.getContributedFunctions(OperatorNameConventions.PLUS, NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single {
|
|
||||||
it.valueParameters.single().type == builtIns.intType
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
abstract val valuesForEnum: IrFunctionSymbol
|
|
||||||
abstract val valueOfForEnum: IrFunctionSymbol
|
|
||||||
abstract val getContinuation: IrFunctionSymbol
|
|
||||||
|
|
||||||
val coroutineImpl = symbolTable.referenceClass(context.getInternalClass("CoroutineImpl"))
|
|
||||||
|
|
||||||
val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction(
|
|
||||||
builtInsPackage("kotlin", "coroutines", "experimental", "intrinsics")
|
|
||||||
.getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single().getter!!
|
|
||||||
)
|
|
||||||
|
|
||||||
val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
|
|
||||||
|
|
||||||
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
|
|
||||||
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
|
|
||||||
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
|
|
||||||
val kMutableProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0Impl)
|
|
||||||
val kMutableProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1Impl)
|
|
||||||
val kMutableProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2Impl)
|
|
||||||
|
|
||||||
fun getFunction(name: Name, receiverType: KotlinType, vararg argTypes: KotlinType) =
|
|
||||||
symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single {
|
|
||||||
var i = 0
|
|
||||||
it.valueParameters.size == argTypes.size && it.valueParameters.all { type -> type == argTypes[i++] }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
private val binaryOperatorCache = mutableMapOf<Triple<Name, KotlinType, KotlinType>, IrFunctionSymbol>()
|
|
||||||
fun getBinaryOperator(name: Name, lhsType: KotlinType, rhsType: KotlinType): IrFunctionSymbol {
|
|
||||||
val key = Triple(name, lhsType, rhsType)
|
|
||||||
var result = binaryOperatorCache[key]
|
|
||||||
if (result == null) {
|
|
||||||
result = symbolTable.referenceFunction(lhsType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single { it.valueParameters.size == 1 && it.valueParameters[0].type == rhsType }
|
|
||||||
)
|
|
||||||
binaryOperatorCache[key] = result
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private val unaryOperatorCache = mutableMapOf<Pair<Name, KotlinType>, IrFunctionSymbol>()
|
|
||||||
fun getUnaryOperator(name: Name, receiverType: KotlinType): IrFunctionSymbol {
|
|
||||||
val key = name to receiverType
|
|
||||||
var result = unaryOperatorCache[key]
|
|
||||||
if (result == null) {
|
|
||||||
result = symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
|
|
||||||
.single { it.valueParameters.isEmpty() }
|
|
||||||
)
|
|
||||||
unaryOperatorCache[key] = result
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-140
@@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ir
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|
||||||
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
|
||||||
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import java.io.StringWriter
|
|
||||||
|
|
||||||
|
|
||||||
fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' }
|
|
||||||
|
|
||||||
fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String {
|
|
||||||
val strWriter = StringWriter()
|
|
||||||
|
|
||||||
if (withDescriptors)
|
|
||||||
ir?.accept(DumpIrTreeWithDescriptorsVisitor(strWriter), "")
|
|
||||||
else
|
|
||||||
ir?.accept(DumpIrTreeVisitor(strWriter), "")
|
|
||||||
return strWriter.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun DeclarationDescriptor.createFakeOverrideDescriptor(owner: ClassDescriptor): DeclarationDescriptor? {
|
|
||||||
// We need to copy descriptors for vtable building, thus take only functions and properties.
|
|
||||||
return when (this) {
|
|
||||||
is CallableMemberDescriptor ->
|
|
||||||
copy(
|
|
||||||
/* newOwner = */ owner,
|
|
||||||
/* modality = */ modality,
|
|
||||||
/* visibility = */ visibility,
|
|
||||||
/* kind = */ CallableMemberDescriptor.Kind.FAKE_OVERRIDE,
|
|
||||||
/* copyOverrides = */ true).apply {
|
|
||||||
overriddenDescriptors += this@createFakeOverrideDescriptor
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
|
|
||||||
return this.newCopyBuilder()
|
|
||||||
.setOwner(owner)
|
|
||||||
.setCopyOverrides(true)
|
|
||||||
.setModality(if (final) Modality.FINAL else Modality.OPEN)
|
|
||||||
.setDispatchReceiverParameter(owner.thisAsReceiverParameter)
|
|
||||||
.build()!!.apply {
|
|
||||||
overriddenDescriptors += this@createOverriddenDescriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor, isPrimary: Boolean = false)
|
|
||||||
: ClassConstructorDescriptor {
|
|
||||||
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
|
|
||||||
/* containingDeclaration = */ this,
|
|
||||||
/* annotations = */ Annotations.EMPTY,
|
|
||||||
/* isPrimary = */ isPrimary,
|
|
||||||
/* source = */ SourceElement.NO_SOURCE)
|
|
||||||
val valueParameters = superConstructorDescriptor.valueParameters.map {
|
|
||||||
it.copy(constructorDescriptor, it.name, it.index)
|
|
||||||
}
|
|
||||||
constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
|
|
||||||
constructorDescriptor.returnType = superConstructorDescriptor.returnType
|
|
||||||
return constructorDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrClass.addSimpleDelegatingConstructor(superConstructorSymbol: IrConstructorSymbol,
|
|
||||||
constructorDescriptor: ClassConstructorDescriptor,
|
|
||||||
origin: IrDeclarationOrigin)
|
|
||||||
: IrConstructor {
|
|
||||||
|
|
||||||
return IrConstructorImpl(startOffset, endOffset, origin, constructorDescriptor).also { constructor ->
|
|
||||||
constructor.createParameterDeclarations()
|
|
||||||
|
|
||||||
constructor.body = IrBlockBodyImpl(startOffset, endOffset,
|
|
||||||
listOf(
|
|
||||||
IrDelegatingConstructorCallImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
superConstructorSymbol, superConstructorSymbol.descriptor
|
|
||||||
).apply {
|
|
||||||
constructor.valueParameters.forEachIndexed { idx, parameter ->
|
|
||||||
putValueArgument(idx, IrGetValueImpl(startOffset, endOffset, parameter.symbol))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IrInstanceInitializerCallImpl(startOffset, endOffset, this.symbol)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
this.declarations.add(constructor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun CommonBackendContext.createArrayOfExpression(arrayElementType: KotlinType,
|
|
||||||
arrayElements: List<IrExpression>,
|
|
||||||
startOffset: Int, endOffset: Int): IrExpression {
|
|
||||||
|
|
||||||
val genericArrayOfFunSymbol = ir.symbols.arrayOf
|
|
||||||
val genericArrayOfFun = genericArrayOfFunSymbol.descriptor
|
|
||||||
val typeParameter0 = genericArrayOfFun.typeParameters[0]
|
|
||||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
|
|
||||||
val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
|
|
||||||
|
|
||||||
val typeArguments = mapOf(typeParameter0 to arrayElementType)
|
|
||||||
|
|
||||||
val valueParameter0 = substitutedArrayOfFun.valueParameters[0]
|
|
||||||
val arg0VarargType = valueParameter0.type
|
|
||||||
val arg0VarargElementType = valueParameter0.varargElementType!!
|
|
||||||
val arg0 = IrVarargImpl(startOffset, endOffset, arg0VarargType, arg0VarargElementType, arrayElements)
|
|
||||||
|
|
||||||
return IrCallImpl(startOffset, endOffset, genericArrayOfFunSymbol, substitutedArrayOfFun, typeArguments).apply {
|
|
||||||
putValueArgument(0, arg0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-189
@@ -1,189 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-460
@@ -1,460 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.konan.Context
|
|
||||||
import org.jetbrains.kotlin.backend.konan.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)
|
|
||||||
}
|
|
||||||
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
@@ -1,216 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,729 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.konan.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
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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")
|
|
||||||
}
|
|
||||||
-123
@@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.backend.common.atMostOne
|
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
|
||||||
import org.jetbrains.kotlin.ir.util.type
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This lowering pass replaces [IrStringConcatenation]s with StringBuilder appends.
|
|
||||||
*/
|
|
||||||
internal class StringConcatenationLowering(val context: CommonBackendContext) : FileLoweringPass {
|
|
||||||
override fun lower(irFile: IrFile) {
|
|
||||||
irFile.transformChildrenVoid(StringConcatenationTransformer(this))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StringConcatenationTransformer(val lower: StringConcatenationLowering) : IrElementTransformerVoid() {
|
|
||||||
|
|
||||||
private val buildersStack = mutableListOf<IrBuilderWithScope>()
|
|
||||||
private val context = lower.context
|
|
||||||
private val builtIns = context.builtIns
|
|
||||||
|
|
||||||
private val typesWithSpecialAppendFunction =
|
|
||||||
PrimitiveType.values().map { builtIns.getPrimitiveKotlinType(it) } + builtIns.stringType
|
|
||||||
|
|
||||||
private val nameToString = Name.identifier("toString")
|
|
||||||
private val nameAppend = Name.identifier("append")
|
|
||||||
|
|
||||||
private val stringBuilder = context.ir.symbols.stringBuilder
|
|
||||||
|
|
||||||
//TODO: calculate and pass string length to the constructor.
|
|
||||||
private val constructor = stringBuilder.constructors.single {
|
|
||||||
it.owner.valueParameters.size == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private val toStringFunction = stringBuilder.functions.single {
|
|
||||||
it.owner.valueParameters.size == 0 && it.descriptor.name == nameToString
|
|
||||||
}
|
|
||||||
private val defaultAppendFunction = stringBuilder.functions.single {
|
|
||||||
it.descriptor.name == nameAppend &&
|
|
||||||
it.owner.valueParameters.size == 1 &&
|
|
||||||
it.owner.valueParameters.single().type == builtIns.nullableAnyType
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private val appendFunctions: Map<KotlinType, IrFunctionSymbol?> =
|
|
||||||
typesWithSpecialAppendFunction.map { type ->
|
|
||||||
type to stringBuilder.functions.toList().atMostOne {
|
|
||||||
it.descriptor.name == nameAppend &&
|
|
||||||
it.owner.valueParameters.size == 1 &&
|
|
||||||
it.owner.valueParameters.single().type == type
|
|
||||||
}
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
private fun typeToAppendFunction(type : KotlinType) : IrFunctionSymbol {
|
|
||||||
return appendFunctions[type]?:defaultAppendFunction
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
|
|
||||||
assert(!buildersStack.isEmpty())
|
|
||||||
|
|
||||||
expression.transformChildrenVoid(this)
|
|
||||||
val blockBuilder = buildersStack.last()
|
|
||||||
return blockBuilder.irBlock(expression) {
|
|
||||||
val stringBuilderImpl = irTemporary(irCall(constructor)).symbol
|
|
||||||
expression.arguments.forEach { arg ->
|
|
||||||
val appendFunction = typeToAppendFunction(arg.type)
|
|
||||||
+irCall(appendFunction).apply {
|
|
||||||
dispatchReceiver = irGet(stringBuilderImpl)
|
|
||||||
putValueArgument(0, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+irCall(toStringFunction).apply {
|
|
||||||
dispatchReceiver = irGet(stringBuilderImpl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
|
||||||
if (declaration !is IrSymbolDeclaration<*>) {
|
|
||||||
return super.visitDeclaration(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(declaration) {
|
|
||||||
buildersStack.add(
|
|
||||||
context.createIrBuilder(declaration.symbol, startOffset, endOffset)
|
|
||||||
)
|
|
||||||
transformChildrenVoid(this@StringConcatenationTransformer)
|
|
||||||
buildersStack.removeAt(buildersStack.lastIndex)
|
|
||||||
return this@with
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-163
@@ -1,163 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
-262
@@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.DeclarationContainerLoweringPass
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedString
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.ir2string
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
|
||||||
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
|
|
||||||
|
|
||||||
class VarargInjectionLowering internal constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
|
|
||||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
|
||||||
irDeclarationContainer.declarations.forEach{
|
|
||||||
when (it) {
|
|
||||||
is IrField -> lower(it.symbol, it.initializer)
|
|
||||||
is IrFunction -> lower(it.symbol, it.body)
|
|
||||||
is IrProperty -> {
|
|
||||||
it.backingField?.let { field ->
|
|
||||||
lower(field.symbol, field)
|
|
||||||
}
|
|
||||||
it.getter?.let { getter ->
|
|
||||||
lower(getter.symbol, getter)
|
|
||||||
}
|
|
||||||
it.setter?.let { setter ->
|
|
||||||
lower(setter.symbol, setter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lower(owner: IrSymbol, element: IrElement?) {
|
|
||||||
element?.transformChildrenVoid(object: IrElementTransformerVoid() {
|
|
||||||
val transformer = this
|
|
||||||
|
|
||||||
private fun replaceEmptyParameterWithEmptyArray(expression: IrMemberAccessExpression) {
|
|
||||||
log("call of: ${expression.descriptor}")
|
|
||||||
context.createIrBuilder(owner, expression.startOffset, expression.endOffset).apply {
|
|
||||||
expression.descriptor.valueParameters.forEach {
|
|
||||||
log("varargElementType: ${it.varargElementType} expr: ${ir2string(expression.getValueArgument(it))}")
|
|
||||||
}
|
|
||||||
expression.descriptor.valueParameters.filter { it.varargElementType != null && expression.getValueArgument(it) == null }.forEach {
|
|
||||||
expression.putValueArgument(it.index,
|
|
||||||
IrVarargImpl(startOffset = startOffset,
|
|
||||||
endOffset = endOffset,
|
|
||||||
type = it.type,
|
|
||||||
varargElementType = it.varargElementType!!)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expression.transformChildrenVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
|
||||||
replaceEmptyParameterWithEmptyArray(expression)
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
|
||||||
replaceEmptyParameterWithEmptyArray(expression)
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVararg(expression: IrVararg): IrExpression {
|
|
||||||
expression.transformChildrenVoid(transformer)
|
|
||||||
val hasSpreadElement = hasSpreadElement(expression)
|
|
||||||
if (!hasSpreadElement && expression.elements.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type) }) {
|
|
||||||
log("skipped vararg expression because it's string array literal")
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset)
|
|
||||||
irBuilder.run {
|
|
||||||
val type = expression.varargElementType
|
|
||||||
log("$expression: array type:$type, is array of primitives ${!KotlinBuiltIns.isArray(expression.type)}")
|
|
||||||
val arrayHandle = arrayType(expression.type)
|
|
||||||
val arrayConstructor = arrayHandle.arraySymbol.constructors.find { it.owner.valueParameters.size == 1 }!!
|
|
||||||
val block = irBlock(arrayHandle.arraySymbol.owner.defaultType)
|
|
||||||
val arrayConstructorCall = if (arrayConstructor.owner.typeParameters.isEmpty()) {
|
|
||||||
irCall(arrayConstructor)
|
|
||||||
} else {
|
|
||||||
irCall(arrayConstructor, listOf(type))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val vars = expression.elements.map {
|
|
||||||
val initVar = scope.createTemporaryVariable(
|
|
||||||
(it as? IrSpreadElement)?.expression ?: it as IrExpression,
|
|
||||||
"elem".synthesizedString, true)
|
|
||||||
block.statements.add(initVar)
|
|
||||||
it to initVar
|
|
||||||
}.toMap()
|
|
||||||
arrayConstructorCall.putValueArgument(0, calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars))
|
|
||||||
val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "array".synthesizedString, true)
|
|
||||||
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "index".synthesizedString, true)
|
|
||||||
block.statements.add(arrayTmpVariable)
|
|
||||||
if (hasSpreadElement) {
|
|
||||||
block.statements.add(indexTmpVariable)
|
|
||||||
}
|
|
||||||
expression.elements.forEachIndexed { i, element ->
|
|
||||||
irBuilder.startOffset = element.startOffset
|
|
||||||
irBuilder.endOffset = element.endOffset
|
|
||||||
irBuilder.apply {
|
|
||||||
log("element:$i> ${ir2string(element)}")
|
|
||||||
val dst = vars[element]!!
|
|
||||||
if (element !is IrSpreadElement) {
|
|
||||||
val setArrayElementCall = irCall(arrayHandle.setMethodSymbol)
|
|
||||||
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.symbol)
|
|
||||||
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.symbol) else irConstInt(i))
|
|
||||||
setArrayElementCall.putValueArgument(1, irGet(dst.symbol))
|
|
||||||
block.statements.add(setArrayElementCall)
|
|
||||||
if (hasSpreadElement) {
|
|
||||||
block.statements.add(incrementVariable(indexTmpVariable.symbol, kIntOne))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.symbol)), "length".synthesizedString)
|
|
||||||
block.statements.add(arraySizeVariable)
|
|
||||||
val copyCall = irCall(arrayHandle.copyRangeToSymbol).apply {
|
|
||||||
extensionReceiver = irGet(dst.symbol)
|
|
||||||
putValueArgument(0, irGet(arrayTmpVariable.symbol)) /* destination */
|
|
||||||
putValueArgument(1, kIntZero) /* fromIndex */
|
|
||||||
putValueArgument(2, irGet(arraySizeVariable.symbol)) /* toIndex */
|
|
||||||
putValueArgument(3, irGet(indexTmpVariable.symbol)) /* destinationIndex */
|
|
||||||
}
|
|
||||||
block.statements.add(copyCall)
|
|
||||||
block.statements.add(incrementVariable(indexTmpVariable.symbol,
|
|
||||||
irGet(arraySizeVariable.symbol)))
|
|
||||||
log("element:$i:spread element> ${ir2string(element.expression)}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block.statements.add(irGet(arrayTmpVariable.symbol))
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private val symbols = context.ir.symbols
|
|
||||||
private val intPlusInt = symbols.intPlusInt
|
|
||||||
|
|
||||||
private fun arrayType(type: KotlinType): ArrayHandle = when {
|
|
||||||
KotlinBuiltIns.isPrimitiveArray(type) -> {
|
|
||||||
val primitiveType = KotlinBuiltIns.getPrimitiveArrayType(type.constructor.declarationDescriptor!!)
|
|
||||||
when (primitiveType) {
|
|
||||||
PrimitiveType.BYTE -> kByteArrayHandler
|
|
||||||
PrimitiveType.SHORT -> kShortArrayHandler
|
|
||||||
PrimitiveType.CHAR -> kCharArrayHandler
|
|
||||||
PrimitiveType.INT -> kIntArrayHandler
|
|
||||||
PrimitiveType.LONG -> kLongArrayHandler
|
|
||||||
PrimitiveType.FLOAT -> kFloatArrayHandler
|
|
||||||
PrimitiveType.DOUBLE -> kDoubleArrayHandler
|
|
||||||
PrimitiveType.BOOLEAN -> kBooleanArrayHandler
|
|
||||||
else -> TODO("unsupported type: $primitiveType")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> kArrayHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrBuilderWithScope.intPlus() = irCall(intPlusInt)
|
|
||||||
private fun IrBuilderWithScope.increment(expression: IrExpression, value: IrExpression): IrExpression {
|
|
||||||
return intPlus().apply {
|
|
||||||
dispatchReceiver = expression
|
|
||||||
putValueArgument(0, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrBuilderWithScope.incrementVariable(symbol: IrVariableSymbol, value: IrExpression): IrExpression {
|
|
||||||
return irSetVar(symbol, intPlus().apply {
|
|
||||||
dispatchReceiver = irGet(symbol)
|
|
||||||
putValueArgument(0, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map<IrVarargElement, IrVariable>): IrExpression? {
|
|
||||||
context.createIrBuilder(scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
|
||||||
if (!hasSpreadElement)
|
|
||||||
return irConstInt(expression.elements.size)
|
|
||||||
val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size
|
|
||||||
val initialValue = irConstInt(notSpreadElementCount) as IrExpression
|
|
||||||
return vars.filter{it.key is IrSpreadElement}.toList().fold( initial = initialValue) { result, it ->
|
|
||||||
val arraySize = irArraySize(arrayHandle, irGet(it.second.symbol))
|
|
||||||
increment(result, arraySize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrBuilderWithScope.irArraySize(arrayHandle: ArrayHandle, expression: IrExpression): IrExpression {
|
|
||||||
val arraySize = irCall(arrayHandle.sizeGetterSymbol).apply {
|
|
||||||
dispatchReceiver = expression
|
|
||||||
}
|
|
||||||
return arraySize
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun hasSpreadElement(expression: IrVararg?) = expression?.elements?.any { it is IrSpreadElement }?:false
|
|
||||||
|
|
||||||
private fun log(msg:String) {
|
|
||||||
context.log{"VARARG-INJECTOR: $msg"}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ArrayHandle(val arraySymbol: IrClassSymbol,
|
|
||||||
val setMethodSymbol: IrFunctionSymbol,
|
|
||||||
val sizeGetterSymbol: IrFunctionSymbol,
|
|
||||||
val copyRangeToSymbol: IrFunctionSymbol)
|
|
||||||
|
|
||||||
val kByteArrayHandler = handle(symbols.byteArray)
|
|
||||||
val kCharArrayHandler = handle(symbols.charArray)
|
|
||||||
val kShortArrayHandler = handle(symbols.shortArray)
|
|
||||||
val kIntArrayHandler = handle(symbols.intArray)
|
|
||||||
val kLongArrayHandler = handle(symbols.longArray)
|
|
||||||
val kFloatArrayHandler = handle(symbols.floatArray)
|
|
||||||
val kDoubleArrayHandler = handle(symbols.doubleArray)
|
|
||||||
val kBooleanArrayHandler = handle(symbols.booleanArray)
|
|
||||||
val kArrayHandler = handle(symbols.array)
|
|
||||||
|
|
||||||
private fun handle(symbol: IrClassSymbol) = ArrayHandle(
|
|
||||||
arraySymbol = symbol,
|
|
||||||
setMethodSymbol = symbol.functions.single { it.descriptor.name == OperatorNameConventions.SET },
|
|
||||||
sizeGetterSymbol = symbol.getPropertyGetter("size")!!,
|
|
||||||
copyRangeToSymbol = symbols.copyRangeTo[symbol.descriptor]!!
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> = IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, value)
|
|
||||||
private fun IrBuilderWithScope.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
|
|
||||||
private val IrBuilderWithScope.kIntZero get() = irConstInt(0)
|
|
||||||
private val IrBuilderWithScope.kIntOne get() = irConstInt(1)
|
|
||||||
-1
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.backend.common.peek
|
|||||||
import org.jetbrains.kotlin.backend.common.pop
|
import org.jetbrains.kotlin.backend.common.pop
|
||||||
import org.jetbrains.kotlin.backend.common.push
|
import org.jetbrains.kotlin.backend.common.push
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.target
|
import org.jetbrains.kotlin.backend.konan.descriptors.target
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression
|
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
|
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
|
|||||||
+1
-63
@@ -16,83 +16,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.ir
|
package org.jetbrains.kotlin.backend.konan.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.SourceManager
|
import org.jetbrains.kotlin.ir.SourceManager
|
||||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
|
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.konan.file.*
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
interface IrReturnableBlockSymbol : IrFunctionSymbol, IrBindableSymbol<FunctionDescriptor, IrReturnableBlock>
|
|
||||||
|
|
||||||
interface IrReturnableBlock: IrBlock, IrSymbolOwner {
|
|
||||||
override val symbol: IrReturnableBlockSymbol
|
|
||||||
val descriptor: FunctionDescriptor
|
|
||||||
val sourceFileName: String
|
|
||||||
}
|
|
||||||
|
|
||||||
class IrReturnableBlockSymbolImpl(descriptor: FunctionDescriptor) :
|
|
||||||
IrBindableSymbolBase<FunctionDescriptor, IrReturnableBlock>(descriptor),
|
|
||||||
IrReturnableBlockSymbol
|
|
||||||
|
|
||||||
class IrReturnableBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType,
|
|
||||||
override val symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin? = null, override val sourceFileName: String = "no source file")
|
|
||||||
: IrContainerExpressionBase(startOffset, endOffset, type, origin), IrReturnableBlock {
|
|
||||||
override val descriptor = symbol.descriptor
|
|
||||||
|
|
||||||
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
|
||||||
symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin?, statements: List<IrStatement>, sourceFileName: String = "no source file") :
|
|
||||||
this(startOffset, endOffset, type, symbol, origin, sourceFileName) {
|
|
||||||
this.statements.addAll(statements)
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
|
||||||
descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null, sourceFileName: String = "no source file") :
|
|
||||||
this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin, sourceFileName)
|
|
||||||
|
|
||||||
constructor(startOffset: Int, endOffset: Int, type: KotlinType,
|
|
||||||
descriptor: FunctionDescriptor, origin: IrStatementOrigin?, statements: List<IrStatement>, sourceFileName: String = "no source file") :
|
|
||||||
this(startOffset, endOffset, type, descriptor, origin, sourceFileName) {
|
|
||||||
this.statements.addAll(statements)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
symbol.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
|
||||||
visitor.visitBlock(this, data)
|
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
|
||||||
statements.forEach { it.accept(visitor, data) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
|
|
||||||
statements.forEachIndexed { i, irStatement ->
|
|
||||||
statements[i] = irStatement.transform(transformer, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
|
|||||||
+1
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.ir.IrStatement
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.util.getArguments
|
import org.jetbrains.kotlin.ir.util.getArguments
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
|||||||
+2
-3
@@ -4,9 +4,6 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
|||||||
import org.jetbrains.kotlin.backend.common.*
|
import org.jetbrains.kotlin.backend.common.*
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockSymbol
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
@@ -21,6 +18,8 @@ import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
|
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlockImpl
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
||||||
@@ -37,6 +36,7 @@ import org.jetbrains.kotlin.ir.declarations.getDefault
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase
|
import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|||||||
-58
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ir.builders
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.substitute
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irWhile(origin: IrStatementOrigin? = null) =
|
|
||||||
IrWhileLoopImpl(startOffset, endOffset, context.builtIns.unitType, origin)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irBreak(loop: IrLoop) =
|
|
||||||
IrBreakImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irContinue(loop: IrLoop) =
|
|
||||||
IrContinueImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, true)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol): IrCallImpl {
|
|
||||||
return IrCallImpl(this.startOffset, this.endOffset, symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: Map<TypeParameterDescriptor, KotlinType>) =
|
|
||||||
IrCallImpl(this.startOffset, this.endOffset, symbol, symbol.descriptor.substitute(typeArguments), typeArguments)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<KotlinType>) =
|
|
||||||
irCall(symbol, symbol.descriptor.typeParameters.zip(typeArguments).toMap())
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irGetObject(classSymbol: IrClassSymbol) =
|
|
||||||
IrGetObjectValueImpl(startOffset, endOffset, classSymbol.owner.defaultType, classSymbol)
|
|
||||||
|
|
||||||
fun IrBuilderWithScope.irGetField(receiver: IrExpression?, symbol: IrFieldSymbol) =
|
|
||||||
IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
|
|
||||||
-1
@@ -3,7 +3,6 @@ package org.jetbrains.kotlin.ir.util
|
|||||||
import org.jetbrains.kotlin.backend.common.pop
|
import org.jetbrains.kotlin.backend.common.pop
|
||||||
import org.jetbrains.kotlin.backend.common.push
|
import org.jetbrains.kotlin.backend.common.push
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.IrReturnableBlock
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
|||||||
-241
@@ -1,241 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ir.util
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
|
||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
|
||||||
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
|
||||||
*/
|
|
||||||
internal fun IrMemberAccessExpression.getArguments(): List<Pair<ParameterDescriptor, IrExpression>> {
|
|
||||||
val res = mutableListOf<Pair<ParameterDescriptor, IrExpression>>()
|
|
||||||
val descriptor = descriptor
|
|
||||||
|
|
||||||
// TODO: ensure the order below corresponds to the one defined in Kotlin specs.
|
|
||||||
|
|
||||||
dispatchReceiver?.let {
|
|
||||||
res += (descriptor.dispatchReceiverParameter!! to it)
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionReceiver?.let {
|
|
||||||
res += (descriptor.extensionReceiverParameter!! to it)
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.valueParameters.forEach {
|
|
||||||
val arg = getValueArgument(it.index)
|
|
||||||
if (arg != null) {
|
|
||||||
res += (it to arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
|
|
||||||
* The arguments are to be evaluated in the same order as they appear in the resulting list.
|
|
||||||
*/
|
|
||||||
internal fun IrFunctionAccessExpression.getArgumentsWithSymbols(): List<Pair<IrValueParameterSymbol, IrExpression>> {
|
|
||||||
val res = mutableListOf<Pair<IrValueParameterSymbol, IrExpression>>()
|
|
||||||
val irFunction = symbol.owner as IrFunction
|
|
||||||
|
|
||||||
dispatchReceiver?.let {
|
|
||||||
res += (irFunction.dispatchReceiverParameter!!.symbol to it)
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionReceiver?.let {
|
|
||||||
res += (irFunction.extensionReceiverParameter!!.symbol to it)
|
|
||||||
}
|
|
||||||
|
|
||||||
irFunction.valueParameters.forEach {
|
|
||||||
val arg = getValueArgument(it.descriptor as ValueParameterDescriptor)
|
|
||||||
if (arg != null) {
|
|
||||||
res += (it.symbol to arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets arguments that are specified by given mapping of parameters.
|
|
||||||
*/
|
|
||||||
internal fun IrMemberAccessExpression.addArguments(args: Map<ParameterDescriptor, IrExpression>) {
|
|
||||||
descriptor.dispatchReceiverParameter?.let {
|
|
||||||
val arg = args[it]
|
|
||||||
if (arg != null) {
|
|
||||||
this.dispatchReceiver = arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.extensionReceiverParameter?.let {
|
|
||||||
val arg = args[it]
|
|
||||||
if (arg != null) {
|
|
||||||
this.extensionReceiver = arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.valueParameters.forEach {
|
|
||||||
val arg = args[it]
|
|
||||||
if (arg != null) {
|
|
||||||
this.putValueArgument(it.index, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) =
|
|
||||||
this.addArguments(args.toMap())
|
|
||||||
|
|
||||||
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
|
|
||||||
|
|
||||||
fun IrCall.usesDefaultArguments(): Boolean =
|
|
||||||
this.descriptor.valueParameters.any { this.getValueArgument(it) == null }
|
|
||||||
|
|
||||||
fun IrElement.getCompilerMessageLocation(containingFile: IrFile): CompilerMessageLocation? {
|
|
||||||
val sourceRangeInfo = containingFile.fileEntry.getSourceRangeInfo(this.startOffset, this.endOffset)
|
|
||||||
return CompilerMessageLocation.create(
|
|
||||||
path = sourceRangeInfo.filePath,
|
|
||||||
line = sourceRangeInfo.startLineNumber,
|
|
||||||
column = sourceRangeInfo.startColumnNumber,
|
|
||||||
lineContent = null // TODO: retrieve the line content.
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrFunction.createParameterDeclarations() {
|
|
||||||
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
|
|
||||||
innerStartOffset(this), innerEndOffset(this),
|
|
||||||
IrDeclarationOrigin.DEFINED,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
|
|
||||||
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
|
|
||||||
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
|
|
||||||
|
|
||||||
assert(valueParameters.isEmpty())
|
|
||||||
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
|
|
||||||
|
|
||||||
assert(typeParameters.isEmpty())
|
|
||||||
descriptor.typeParameters.mapTo(typeParameters) {
|
|
||||||
IrTypeParameterImpl(
|
|
||||||
innerStartOffset(it), innerEndOffset(it),
|
|
||||||
IrDeclarationOrigin.DEFINED,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrClass.createParameterDeclarations() {
|
|
||||||
descriptor.thisAsReceiverParameter.let {
|
|
||||||
thisReceiver = IrValueParameterImpl(
|
|
||||||
innerStartOffset(it), innerEndOffset(it),
|
|
||||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(typeParameters.isEmpty())
|
|
||||||
descriptor.declaredTypeParameters.mapTo(typeParameters) {
|
|
||||||
IrTypeParameterImpl(
|
|
||||||
innerStartOffset(it), innerEndOffset(it),
|
|
||||||
IrDeclarationOrigin.DEFINED,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrClass.addFakeOverrides() {
|
|
||||||
|
|
||||||
val startOffset = this.startOffset
|
|
||||||
val endOffset = this.endOffset
|
|
||||||
|
|
||||||
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
IrDeclarationOrigin.FAKE_OVERRIDE, this
|
|
||||||
).apply {
|
|
||||||
createParameterDeclarations()
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
|
||||||
.filterIsInstance<CallableMemberDescriptor>()
|
|
||||||
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
|
||||||
.mapTo(this.declarations) {
|
|
||||||
when (it) {
|
|
||||||
is FunctionDescriptor -> it.createFunction()
|
|
||||||
is PropertyDescriptor ->
|
|
||||||
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
|
|
||||||
// TODO: add field if getter is missing?
|
|
||||||
getter = it.getter?.createFunction()
|
|
||||||
setter = it.setter?.createFunction()
|
|
||||||
}
|
|
||||||
else -> TODO(it.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
|
||||||
descriptor.startOffset ?: this.startOffset
|
|
||||||
|
|
||||||
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
|
|
||||||
descriptor.endOffset ?: this.endOffset
|
|
||||||
|
|
||||||
val DeclarationDescriptorWithSource.startOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.startOffset
|
|
||||||
val DeclarationDescriptorWithSource.endOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.endOffset
|
|
||||||
|
|
||||||
val DeclarationDescriptorWithSource.startOffsetOrUndefined: Int get() = startOffset ?: UNDEFINED_OFFSET
|
|
||||||
val DeclarationDescriptorWithSource.endOffsetOrUndefined: Int get() = endOffset ?: UNDEFINED_OFFSET
|
|
||||||
|
|
||||||
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
|
|
||||||
get() = this.owner.declarations.asSequence().filterIsInstance<IrSimpleFunction>().map { it.symbol }
|
|
||||||
|
|
||||||
val IrClassSymbol.constructors: Sequence<IrConstructorSymbol>
|
|
||||||
get() = this.owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.symbol }
|
|
||||||
|
|
||||||
private fun IrClassSymbol.getPropertyDeclaration(name: String) =
|
|
||||||
this.owner.declarations.filterIsInstance<IrProperty>()
|
|
||||||
.atMostOne { it.descriptor.name == Name.identifier(name) }
|
|
||||||
|
|
||||||
fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
|
|
||||||
this.getPropertyDeclaration(name)?.getter?.symbol
|
|
||||||
|
|
||||||
fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
|
|
||||||
this.getPropertyDeclaration(name)?.setter?.symbol
|
|
||||||
|
|
||||||
val IrFunction.explicitParameters: List<IrValueParameterSymbol>
|
|
||||||
get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
|
|
||||||
|
|
||||||
val IrValueParameter.type: KotlinType
|
|
||||||
get() = this.descriptor.type
|
|
||||||
|
|
||||||
val IrClass.defaultType: KotlinType
|
|
||||||
get() = this.descriptor.defaultType
|
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
|
||||||
|
//TODO: delete file on next kotlin dependency update
|
||||||
|
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
|
||||||
|
|
||||||
Reference in New Issue
Block a user