From 27365dc4bed8833880dc7bd0fc0189fed5ff6fed Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Wed, 31 May 2017 11:33:14 +0200 Subject: [PATCH] Copy common utils from Native --- compiler/ir/backend.common/backend.common.iml | 2 + .../backend/common/CheckIrElementVisitor.kt | 253 +++++++ .../backend/common/CommonBackendContext.kt | 107 +++ .../common/DeepCopyIrTreeWithDeclarations.kt | 54 ++ .../common/DeepCopyIrTreeWithDescriptoros.kt | 618 ++++++++++++++++++ .../DumpIrTreeWithDescriptorsVisitor.kt | 365 +++++++++++ .../jetbrains/kotlin/backend/common/IrCopy.kt | 66 ++ .../IrElementTransformerVoidWithContext.kt | 166 +++++ .../kotlin/backend/common/IrValidator.kt | 72 ++ .../common/TailRecursionCallsCollector.kt | 160 +++++ .../jetbrains/kotlin/backend/common/Utils.kt | 48 ++ .../common/descriptors/DescriptorUtils.kt | 94 +++ .../backend/common/descriptors/utils.kt | 72 ++ .../jetbrains/kotlin/backend/common/ir/Ir.kt | 236 +++++++ .../kotlin/backend/common/ir/IrUtils.kt | 140 ++++ .../kotlin/ir/builders/IrBuilders.kt | 54 ++ .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 241 +++++++ .../kotlin/ir/expressions/IrBlock.kt | 10 + .../kotlin/ir/expressions/impl/IrBlockImpl.kt | 46 ++ .../jetbrains/kotlin/ir/symbols/IrSymbol.kt | 5 +- .../kotlin/ir/symbols/impl/IrSymbolBase.kt | 13 +- 21 files changed, 2820 insertions(+), 2 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt diff --git a/compiler/ir/backend.common/backend.common.iml b/compiler/ir/backend.common/backend.common.iml index 56e15c15f12..a98ff1c560f 100644 --- a/compiler/ir/backend.common/backend.common.iml +++ b/compiler/ir/backend.common/backend.common.iml @@ -10,5 +10,7 @@ + + \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt new file mode 100644 index 00000000000..a7029a86c45 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt @@ -0,0 +1,253 @@ +/* + * 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() + + 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 visitConst(expression: IrConst) { + 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() + + 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) + } + +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt new file mode 100644 index 00000000000..6a65cce7003 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt @@ -0,0 +1,107 @@ +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 + + //TODO move to builtins + fun getInternalClass(name: String): ClassDescriptor + + //TODO move to builtins + fun getInternalFunctions(name: String): List + + 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, + returnType: KotlinType + ): List { + val arguments = ArrayList(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, + returnType: KotlinType + ): KotlinType { + val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType) + val classDescriptor = getKFunction(arguments.size - 1 /* return type */) + return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt new file mode 100644 index 00000000000..c7f69b754e4 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt @@ -0,0 +1,54 @@ +/* + * 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 T.deepCopyWithVariables(): T = + this.deepCopyWithVariablesImpl() as T \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt new file mode 100644 index 00000000000..2946a4f5a4c --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt @@ -0,0 +1,618 @@ +/* + * 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.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: CommonBackendContext) { + + private val descriptorSubstituteMap: MutableMap = 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.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 , containingDeclaration: CallableDescriptor): List { + + 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 ?): Map ? { + + 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) { + 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) + : 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) + } +} + diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt new file mode 100644 index 00000000000..b27f0e2c024 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt @@ -0,0 +1,365 @@ +package org.jetbrains.kotlin.backend.common + +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 { + 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 visitConst(expression: IrConst, 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) + "" + 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 { + 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" +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt new file mode 100644 index 00000000000..9c7b90e2dcb --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt @@ -0,0 +1,66 @@ +/* + * 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.expressions.IrBlock +import org.jetbrains.kotlin.ir.expressions.IrReturn +import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock +import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl +import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol +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 T.transform() = + transform(this@DeepCopyIrTreeWithReturnableBlockSymbols, null) as T + + private val transformedReturnableBlocks = mutableMapOf() + + 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) + } + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt new file mode 100644 index 00000000000..dc2a673c438 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt @@ -0,0 +1,166 @@ +/* + * 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.* + +class ScopeWithIr(val scope: Scope, val irElement: IrElement) + +abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() { + + private val scopeStack = mutableListOf() + + 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() + + 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) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt new file mode 100644 index 00000000000..6457f235a87 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.common + +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) + } +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt new file mode 100644 index 00000000000..66e1e4e3e6f --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt @@ -0,0 +1,160 @@ +/* + * 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 { + if (!irFunction.descriptor.isTailrec) { + return emptySet() + } + + val result = mutableSetOf() + + val visitor = object : IrElementVisitor { + + 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 +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt new file mode 100644 index 00000000000..eaa9236628b --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt @@ -0,0 +1,48 @@ +/* + * 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 MutableList.push(element: E) = this.add(element) + +fun MutableList.pop() = this.removeAt(size - 1) + +fun MutableList.peek(): E? = if (size == 0) null else this[size - 1] + +fun Collection.atMostOne(): T? { + return when (this.size) { + 0 -> null + 1 -> this.iterator().next() + else -> throw IllegalArgumentException("Collection has more than one element.") + } +} + +inline fun Iterable.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne() + +fun T.onlyIf(condition: T.()->Boolean, then: (T)->Unit): T { + if (this.condition()) then(this) + return this +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt new file mode 100644 index 00000000000..ba40b8a7369 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt @@ -0,0 +1,94 @@ +/* + * 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 + +val CallableDescriptor.isSuspend: Boolean + get() = this is FunctionDescriptor && isSuspend + +/** + * @return naturally-ordered list of all parameters available inside the function body. + */ +val CallableDescriptor.allParameters: List + 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. + */ +val CallableDescriptor.explicitParameters: List + get() { + val result = ArrayList(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) = 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): FunctionDescriptor { + val typeSubstitutor = TypeSubstitutor.create( + typeParameters.associateBy({ it.typeConstructor }, { TypeProjectionImpl(typeArguments[it]!!) }) + ) + return substitute(typeSubstitutor)!! +} + +fun ClassDescriptor.getFunction(name: String, types: List): 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 + } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt new file mode 100644 index 00000000000..16b4c60c40a --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.common.descriptors + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor +import org.jetbrains.kotlin.types.KotlinType + +fun ClassDescriptor?.getter2Descriptor(methodName: Name) = this?.let { + this.unsubstitutedMemberScope.getContributedDescriptors{true} + .firstOrNull { + it.name == methodName + } ?.let { + return@let (it as? PropertyDescriptor)?.getter + } +} + +fun ClassDescriptor?.signature2Descriptor(methodName: Name, signature:Array = emptyArray()) = this?.let { + this + .unsubstitutedMemberScope + .getContributedFunctions(methodName, NoLookupLocation.FROM_BACKEND) + .firstOrNull { + return@firstOrNull it.valueParameters.size == signature.size + && (signature.isEmpty() || it.valueParameters.any { + p -> val index = it.valueParameters.indexOf(p) + return@any p.type == signature[index] + }) + } +} + +val String.synthesizedName get() = Name.identifier(this.synthesizedString) + +val String.synthesizedString get() = "\$$this" + +val DeclarationDescriptor.propertyIfAccessor + get() = if (this is PropertyAccessorDescriptor) + this.correspondingProperty + else this + +val CallableMemberDescriptor.propertyIfAccessor + get() = if (this is PropertyAccessorDescriptor) + this.correspondingProperty + else this + +val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCallableMemberDescriptor + get() { + val member = this.propertyIfAccessor + if (member is DeserializedCallableMemberDescriptor) + return member + else + error("Unexpected deserializable callable descriptor") + } + +val CallableMemberDescriptor.isDeserializableCallable + get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor) \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt new file mode 100644 index 00000000000..6c5d44343b4 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -0,0 +1,236 @@ +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.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(val context: T, val irModule: IrModuleFragment) { + + abstract val symbols: Symbols + + val defaultParameterDeclarationsCache = mutableMapOf() + + open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false +} + +open class Symbols(val context: T, private val symbolTable: SymbolTable) { + + private val builtIns + get() = context.builtIns + + private fun builtInsPackage(vararg packageNameSegments: String) = + context.builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope + + val refClass = symbolTable.referenceClass(context.getInternalClass("Ref")) + +// val areEqualByValue = context.getInternalFunctions("areEqualByValue").map { +// symbolTable.referenceSimpleFunction(it) +// } + + val areEqual = symbolTable.referenceSimpleFunction(context.getInternalFunctions("areEqual").single()) + + val ThrowNullPointerException = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("ThrowNullPointerException").single()) + + val ThrowNoWhenBranchMatchedException = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("ThrowNoWhenBranchMatchedException").single()) + + val ThrowTypeCastException = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("ThrowTypeCastException").single()) + + val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("ThrowUninitializedPropertyAccessException").single() + ) + + val stringBuilder = symbolTable.referenceClass( + context.getClass(FqName("java.lang.StringBuilder")) as ClassDescriptor + ) + + 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 checkProgressionStep = context.getInternalFunctions("checkProgressionStep") + .map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap() + val getProgressionLast = context.getInternalFunctions("getProgressionLast") + .map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap() + + 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 + + private 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) + } + + + private 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 arrayContentToString = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentToString") }) + val arrayContentHashCode = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentHashCode") }) + + val copyRangeTo = arrays.map { symbol -> + val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME) + val functionDescriptor = packageViewDescriptor.memberScope + .getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND) + .first { + it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == symbol.descriptor + } + symbol.descriptor to symbolTable.referenceSimpleFunction(functionDescriptor) + }.toMap() + + val intAnd = symbolTable.referenceFunction( + builtIns.intType.memberScope + .getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND) + .single() + ) + + val intPlusInt = symbolTable.referenceFunction( + builtIns.intType.memberScope + .getContributedFunctions(OperatorNameConventions.PLUS, NoLookupLocation.FROM_BACKEND) + .single { + it.valueParameters.single().type == builtIns.intType + } + ) + + + + val valuesForEnum = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("valuesForEnum").single()) + + val valueOfForEnum = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("valueOfForEnum").single()) + + val getContinuation = symbolTable.referenceSimpleFunction( + context.getInternalFunctions("getContinuation").single()) + + 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) + val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl) + val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl) + + 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, 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, 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 + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt new file mode 100644 index 00000000000..0b71d4ca629 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -0,0 +1,140 @@ +/* + * 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() +} + +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, + 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) + } +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt new file mode 100644 index 00000000000..58f14aa16f8 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt @@ -0,0 +1,54 @@ +/* + * 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, typeArguments: Map) = + IrCallImpl(this.startOffset, this.endOffset, symbol, symbol.descriptor.substitute(typeArguments), typeArguments) + +fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List) = + 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) \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt new file mode 100644 index 00000000000..72631e12ad4 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -0,0 +1,241 @@ +/* + * 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. + */ +fun IrMemberAccessExpression.getArguments(): List> { + val res = mutableListOf>() + 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> { + val res = mutableListOf>() + 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) { + 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>) = + 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() + .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 + get() = this.owner.declarations.asSequence().filterIsInstance().map { it.symbol } + +val IrClassSymbol.constructors: Sequence + get() = this.owner.declarations.asSequence().filterIsInstance().map { it.symbol } + +private fun IrClassSymbol.getPropertyDeclaration(name: String) = + this.owner.declarations.filterIsInstance() + .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 + get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol } + +val IrValueParameter.type: KotlinType + get() = this.descriptor.type + +val IrClass.defaultType: KotlinType + get() = this.descriptor.defaultType diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt index 7c2d4595b3d..52bedecc858 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt @@ -16,6 +16,10 @@ package org.jetbrains.kotlin.ir.expressions +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner +import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol + interface IrContainerExpression : IrExpression, IrStatementContainer { val origin: IrStatementOrigin? val isTransparentScope: Boolean @@ -30,3 +34,9 @@ interface IrComposite : IrContainerExpression { override val isTransparentScope: Boolean get() = true } + +interface IrReturnableBlock: IrBlock, IrSymbolOwner { + override val symbol: IrReturnableBlockSymbol + val descriptor: FunctionDescriptor + val sourceFileName: String +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt index dc62e92235b..7fe34ed05f5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt @@ -16,9 +16,15 @@ package org.jetbrains.kotlin.ir.expressions.impl +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.expressions.IrBlock +import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin +import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase +import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.types.KotlinType @@ -44,4 +50,44 @@ fun IrBlockImpl.inlineStatement(statement: IrStatement) { else { statements.add(statement) } +} + + +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, 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, sourceFileName: String = "no source file") : + this(startOffset, endOffset, type, descriptor, origin, sourceFileName) { + this.statements.addAll(statements) + } + + init { + symbol.bind(this) + } + + override fun accept(visitor: IrElementVisitor, data: D): R = + visitor.visitBlock(this, data) + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + statements.forEach { it.accept(visitor, data) } + } + + override fun transformChildren(transformer: IrElementTransformer, data: D) { + statements.forEachIndexed { i, irStatement -> + statements[i] = irStatement.transform(transformer, data) + } + } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt index 4889c5ddf25..d20fdd6c4fe 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir.symbols import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock interface IrSymbol { val owner : IrSymbolOwner @@ -59,4 +60,6 @@ interface IrFunctionSymbol : IrSymbol { override val descriptor: FunctionDescriptor } interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol -interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol \ No newline at end of file +interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol + +interface IrReturnableBlockSymbol : IrFunctionSymbol, IrBindableSymbol diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt index 4a3737e690d..454f99c77e6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt @@ -17,8 +17,15 @@ package org.jetbrains.kotlin.ir.symbols.impl import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock +import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin +import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.types.KotlinType abstract class IrSymbolBase(override val descriptor: D) : IrSymbol @@ -110,4 +117,8 @@ fun createFunctionSymbol(descriptor: CallableMemberDescriptor): IrFunctionSymbol is ClassConstructorDescriptor -> IrConstructorSymbolImpl(descriptor.original) is FunctionDescriptor -> IrSimpleFunctionSymbolImpl(descriptor.original) else -> throw IllegalArgumentException("Unexpected descriptor kind: $descriptor") - } \ No newline at end of file + } + +class IrReturnableBlockSymbolImpl(descriptor: FunctionDescriptor) : + IrBindableSymbolBase(descriptor), + IrReturnableBlockSymbol \ No newline at end of file