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 b9dcf32a4c0..92a5b5b72a7 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 @@ -66,6 +66,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE IrExternalPackageFragmentImpl( symbolsRemapper.getDeclaredExternalPackageFragment(declaration.symbol) ).apply { + symbol.bind(this) declaration.transformDeclarationsTo(this) } @@ -74,6 +75,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE declaration.fileEntry, symbolsRemapper.getDeclaredFile(declaration.symbol) ).apply { + symbol.bind(this) fileAnnotations.addAll(declaration.fileAnnotations) declaration.transformDeclarationsTo(this) } @@ -87,6 +89,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredClass(declaration.symbol) ).apply { + symbol.bind(this) newInstanceReceiver = declaration.newInstanceReceiver?.transform() declaration.typeParameters.transformTo(typeParameters) declaration.transformDeclarationsTo(this) @@ -104,14 +107,20 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredFunction(declaration.symbol) - ).transformFunctionChildren(declaration) + ).apply { + symbol.bind(this) + transformFunctionChildren(declaration) + } override fun visitConstructor(declaration: IrConstructor): IrConstructor = IrConstructorImpl( declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredConstructor(declaration.symbol) - ).transformFunctionChildren(declaration) + ).apply { + symbol.bind(this) + transformFunctionChildren(declaration) + } private fun T.transformFunctionChildren(declaration: T): T = apply { @@ -139,6 +148,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredField(declaration.symbol) ).apply { + symbol.bind(this) initializer = declaration.initializer?.transform() } @@ -158,6 +168,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredEnumEntry(declaration.symbol) ).apply { + symbol.bind(this) correspondingClass = declaration.correspondingClass?.transform() initializerExpression = declaration.initializerExpression?.transform() } @@ -168,6 +179,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), IrAnonymousInitializerSymbolImpl(declaration.descriptor) ).apply { + symbol.bind(this) body = declaration.body.transform() } @@ -177,6 +189,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredVariable(declaration.symbol) ).apply { + symbol.bind(this) initializer = declaration.initializer?.transform() } @@ -185,7 +198,9 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredTypeParameter(declaration.symbol) - ) + ).apply { + symbol.bind(this) + } override fun visitValueParameter(declaration: IrValueParameter): IrValueParameter = IrValueParameterImpl( @@ -193,6 +208,7 @@ class DeepCopyIrTree(private val symbolsRemapper: DeepCopySymbolsRemapper) : IrE mapDeclarationOrigin(declaration.origin), symbolsRemapper.getDeclaredValueParameter(declaration.symbol) ).apply { + symbol.bind(this) defaultValue = declaration.defaultValue?.transform() } diff --git a/compiler/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt b/compiler/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt index e9c6911011a..6c40fad78ee 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt +++ b/compiler/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt @@ -21,9 +21,15 @@ import junit.framework.TestCase import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference +import org.jetbrains.kotlin.ir.expressions.IrFunctionReference +import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference +import org.jetbrains.kotlin.ir.expressions.IrPropertyReference +import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.deepCopy import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dumpTreesFromLineNumber +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.test.KotlinTestUtils @@ -70,13 +76,13 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { for (irTreeFileLabel in expectations.irTreeFileLabels) { val actualTrees = irFile.dumpTreesFromLineNumber(irTreeFileLabel.lineNumber) KotlinTestUtils.assertEqualsToFile(irTreeFileLabel.expectedTextFile, actualTrees) - verify(irFile, irFileDump) + verify(irFile) // Check that deep copy produces an equivalent result val irFileCopy = irFile.deepCopy() val copiedTrees = irFileCopy.dumpTreesFromLineNumber(irTreeFileLabel.lineNumber) TestCase.assertEquals("IR dump mismatch after deep copy", actualTrees, copiedTrees) - verify(irFileCopy, irFileCopy.dump()) + verify(irFileCopy) } try { @@ -88,10 +94,8 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { } } - private fun verify(irFile: IrFile, dump: String) { - val irVerifier = IrVerifier() - irVerifier.verify(irFile) - TestCase.assertFalse(irVerifier.errorsAsMessage + "\n\n\n" + dump, irVerifier.hasErrors) + private fun verify(irFile: IrFile) { + IrVerifier().verifyWithAssert(irFile) } private class IrVerifier : IrElementVisitorVoid { @@ -105,15 +109,28 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { errors.add(message) } - fun verify(irFile: IrFile) { + fun verifyWithAssert(irFile: IrFile) { irFile.acceptChildrenVoid(this) + TestCase.assertFalse(errorsAsMessage + "\n\n\n" + irFile.dump(), hasErrors) } override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } + override fun visitDeclaration(declaration: IrDeclaration) { + if (declaration is IrSymbolOwner) { + declaration.symbol.checkBinding("decl", declaration) + + if (declaration.symbol.owner != declaration) { + error("Symbol is not bound to declaration: ${declaration.render()}") + } + } + } + override fun visitFunction(declaration: IrFunction) { + visitDeclaration(declaration) + val functionDescriptor = declaration.descriptor checkTypeParameters(functionDescriptor, declaration, functionDescriptor.typeParameters) @@ -146,7 +163,35 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { } } + override fun visitDeclarationReference(expression: IrDeclarationReference) { + expression.symbol.checkBinding("ref", expression) + } + + override fun visitFunctionReference(expression: IrFunctionReference) { + expression.symbol.checkBinding("ref", expression) + } + + override fun visitPropertyReference(expression: IrPropertyReference) { + expression.field?.checkBinding("field", expression) + expression.getter?.checkBinding("getter", expression) + expression.setter?.checkBinding("setter", expression) + } + + override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) { + expression.delegate.checkBinding("delegate", expression) + expression.getter.checkBinding("getter", expression) + expression.setter?.checkBinding("setter", expression) + } + + private fun IrSymbol.checkBinding(kind: String, owner: IrElement) { + if (!isBound) { + error("$kind ${javaClass.simpleName} ${descriptor} is unbound: ${owner.render()}") + } + } + override fun visitClass(declaration: IrClass) { + visitDeclaration(declaration) + checkTypeParameters(declaration.descriptor, declaration, declaration.descriptor.declaredTypeParameters) }