diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index 7997053f4fd..1107fc72e52 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator @@ -55,5 +56,7 @@ class Psi2IrTranslator(val configuration: Psi2IrConfiguration = Psi2IrConfigurat insertImplicitCasts(context.builtIns, irElement) postprocessingSteps.forEach { it.postprocess(context, irElement) } + + irElement.patchDeclarationParents() } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index a4a63c30dc7..c6cbcca5e70 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -31,6 +31,8 @@ interface IrDeclaration : IrStatement { val declarationKind: IrDeclarationKind val origin: IrDeclarationOrigin + val parent: IrDeclarationParent + override fun transform(transformer: IrElementTransformer, data: D): IrStatement = accept(transformer, data) as IrStatement } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationContainer.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationContainer.kt index df2cc487a28..f10cb6ddaf8 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationContainer.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationContainer.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.ir.declarations -interface IrDeclarationContainer { +interface IrDeclarationParent + +interface IrDeclarationContainer : IrDeclarationParent { val declarations: MutableList } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt index ce9f9d3aa3b..faf6d39d240 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.types.KotlinType -interface IrFunction : IrDeclaration, IrTypeParametersContainer, IrSymbolOwner { +interface IrFunction : IrDeclaration, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent { override val descriptor: FunctionDescriptor override val symbol: IrFunctionSymbol diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrDeclarationBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrDeclarationBase.kt index 245f592ff38..84a2184e40c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrDeclarationBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrDeclarationBase.kt @@ -19,9 +19,14 @@ package org.jetbrains.kotlin.ir.declarations.impl import org.jetbrains.kotlin.ir.IrElementBase import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent abstract class IrDeclarationBase( startOffset: Int, endOffset: Int, override val origin: IrDeclarationOrigin -) : IrElementBase(startOffset, endOffset), IrDeclaration \ No newline at end of file +) : IrElementBase(startOffset, endOffset), + IrDeclaration { + + override lateinit var parent: IrDeclarationParent +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt index 218fd601948..bb69e8fe1b9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt @@ -31,8 +31,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.types.KotlinType import java.util.* -inline fun T.deepCopyOld() = - transform(DeepCopyIrTree(), null) as T +inline fun T.deepCopyOld(): T = + transform(DeepCopyIrTree(), null).patchDeclarationParents() as T @Deprecated("Creates unbound symbols") open class DeepCopyIrTree : IrElementTransformerVoid() { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index d6a5e076ed8..008a3676cf4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -32,7 +32,7 @@ import java.util.* inline fun T.deepCopyWithSymbols(): T { val remapper = DeepCopySymbolsRemapper() acceptVoid(remapper) - return transform(DeepCopyIrTreeWithSymbols(remapper), null) as T + return transform(DeepCopyIrTreeWithSymbols(remapper), null).patchDeclarationParents() as T } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/PatchDeclarationParents.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/PatchDeclarationParents.kt new file mode 100644 index 00000000000..25324746fe6 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/PatchDeclarationParents.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.util + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent +import org.jetbrains.kotlin.ir.declarations.IrPackageFragment +import org.jetbrains.kotlin.ir.declarations.impl.IrDeclarationBase +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid +import java.util.* + +fun T.patchDeclarationParents() = + apply { + acceptVoid(PatchDeclarationParentsVisitor()) + } + +class PatchDeclarationParentsVisitor : IrElementVisitorVoid { + + private val declarationParentsStack = ArrayDeque() + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitPackageFragment(declaration: IrPackageFragment) { + declarationParentsStack.push(declaration) + super.visitPackageFragment(declaration) + declarationParentsStack.pop() + } + + override fun visitDeclaration(declaration: IrDeclaration) { + patchParent(declaration) + + if (declaration is IrDeclarationParent) { + declarationParentsStack.push(declaration) + } + + super.visitDeclaration(declaration) + + if (declaration is IrDeclarationParent) { + declarationParentsStack.pop() + } + } + + private fun patchParent(declaration: IrDeclaration) { + (declaration as IrDeclarationBase).parent = declarationParentsStack.peekFirst() + } +} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt index 2b0cf46a42e..3a852156ae8 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt @@ -115,6 +115,12 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { errors.add(message) } + private inline fun require(condition: Boolean, message: () -> String) { + if (!condition) { + errors.add(message()) + } + } + fun verifyWithAssert(irFile: IrFile) { irFile.acceptChildrenVoid(this) TestCase.assertFalse(errorsAsMessage + "\n\n\n" + irFile.dump(), hasErrors) @@ -128,8 +134,20 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { if (declaration is IrSymbolOwner) { declaration.symbol.checkBinding("decl", declaration) - if (declaration.symbol.owner != declaration) { - error("Symbol is not bound to declaration: ${declaration.render()}") + require(declaration.symbol.owner == declaration) { + "Symbol is not bound to declaration: ${declaration.render()}" + } + } + + val containingDeclarationDescriptor = declaration.descriptor.containingDeclaration + if (containingDeclarationDescriptor != null) { + val parent = declaration.parent + if (parent is IrDeclaration) { + require(parent.descriptor == containingDeclarationDescriptor) { + "In declaration ${declaration.descriptor}: " + + "Mismatching parent descriptor (${parent.descriptor}) " + + "and containing declaration descriptor ($containingDeclarationDescriptor)" + } } } } @@ -143,20 +161,18 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { val expectedDispatchReceiver = functionDescriptor.dispatchReceiverParameter val actualDispatchReceiver = declaration.dispatchReceiverParameter?.descriptor - if (expectedDispatchReceiver != actualDispatchReceiver) { - error( - "$functionDescriptor: Dispatch receiver parameter mismatch: " + - "expected $expectedDispatchReceiver, actual $actualDispatchReceiver" - ) + require(expectedDispatchReceiver == actualDispatchReceiver) { + "$functionDescriptor: Dispatch receiver parameter mismatch: " + + "expected $expectedDispatchReceiver, actual $actualDispatchReceiver" + } val expectedExtensionReceiver = functionDescriptor.extensionReceiverParameter val actualExtensionReceiver = declaration.extensionReceiverParameter?.descriptor - if (expectedExtensionReceiver != actualExtensionReceiver) { - error( - "$functionDescriptor: Extension receiver parameter mismatch: " + - "expected $expectedExtensionReceiver, actual $actualExtensionReceiver" - ) + require(expectedExtensionReceiver == actualExtensionReceiver) { + "$functionDescriptor: Extension receiver parameter mismatch: " + + "expected $expectedExtensionReceiver, actual $actualExtensionReceiver" + } val declaredValueParameters = declaration.valueParameters.map { it.descriptor } @@ -165,8 +181,8 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { error("$functionDescriptor: Value parameters mismatch: $declaredValueParameters != $actualValueParameters") } else { declaredValueParameters.zip(actualValueParameters).forEach { (declaredValueParameter, actualValueParameter) -> - if (declaredValueParameter != actualValueParameter) { - error("$functionDescriptor: Value parameters mismatch: $declaredValueParameter != $actualValueParameter") + require(declaredValueParameter == actualValueParameter) { + "$functionDescriptor: Value parameters mismatch: $declaredValueParameter != $actualValueParameter" } } } @@ -220,8 +236,8 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { error("$descriptor: Type parameters mismatch: $declaredTypeParameters != $expectedTypeParameters") } else { declaredTypeParameters.zip(expectedTypeParameters).forEach { (declaredTypeParameter, expectedTypeParameter) -> - if (declaredTypeParameter != expectedTypeParameter) { - error("$descriptor: Type parameters mismatch: $declaredTypeParameter != $expectedTypeParameter") + require(declaredTypeParameter == expectedTypeParameter) { + "$descriptor: Type parameters mismatch: $declaredTypeParameter != $expectedTypeParameter" } } }