From 1e712f8398d88b6547fb6eb1b04c798c0f950ade Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 26 Aug 2020 17:51:35 +0200 Subject: [PATCH] IR: remove IrElementVisitorVoidWithContext It was only used as a superclass in IrInlineReferenceLocator and LocalDeclarationsLowering. In both cases it's clearer and more optimal to pass the necessary data via the visitor 'data' variable. --- .../IrElementTransformerVoidWithContext.kt | 101 +----------------- .../common/lower/LocalDeclarationsLowering.kt | 72 +++++++------ .../jvm/ir/IrInlineReferenceLocator.kt | 20 ++-- .../jvm/lower/AddContinuationLowering.kt | 9 +- .../FakeInliningLocalVariablesLowering.kt | 8 +- 5 files changed, 62 insertions(+), 148 deletions(-) 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 index de4b4a23fd5..0b58a9b943f 100644 --- 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 @@ -21,9 +21,11 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol +import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid open class ScopeWithIr(val scope: Scope, val irElement: IrElement) @@ -139,98 +141,3 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() return super.visitScript(declaration) } } - -@OptIn(ObsoleteDescriptorBasedAPI::class) -abstract class IrElementVisitorVoidWithContext : IrElementVisitorVoid { - - private val scopeStack = mutableListOf() - - protected open fun createScope(declaration: IrSymbolOwner): ScopeWithIr = - ScopeWithIr(Scope(declaration.symbol), declaration) - - final override fun visitFile(declaration: IrFile) { - scopeStack.push(createScope(declaration)) - visitFileNew(declaration) - scopeStack.pop() - } - - final override fun visitClass(declaration: IrClass) { - scopeStack.push(createScope(declaration)) - visitClassNew(declaration) - scopeStack.pop() - } - - final override fun visitProperty(declaration: IrProperty) { - scopeStack.push(createScope(declaration)) - visitPropertyNew(declaration) - scopeStack.pop() - } - - final override fun visitField(declaration: IrField) { - val isDelegated = declaration.descriptor.isDelegated - if (isDelegated) scopeStack.push(createScope(declaration)) - visitFieldNew(declaration) - if (isDelegated) scopeStack.pop() - } - - final override fun visitFunction(declaration: IrFunction) { - scopeStack.push(createScope(declaration)) - visitFunctionNew(declaration) - scopeStack.pop() - } - - final override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) { - scopeStack.push(createScope(declaration)) - visitAnonymousInitializerNew(declaration) - scopeStack.pop() - } - - final override fun visitValueParameter(declaration: IrValueParameter) { - scopeStack.push(createScope(declaration)) - visitValueParameterNew(declaration) - scopeStack.pop() - } - - protected val currentFile get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrFileSymbol } - protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrClassSymbol } - protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrFunctionSymbol } - protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrPropertySymbol } - protected val currentAnonymousInitializer get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrAnonymousInitializer } - protected val currentValueParameter get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrValueParameter } - 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 - - @ObsoleteDescriptorBasedAPI - 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) - } - - open fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer) { - super.visitAnonymousInitializer(declaration) - } - - open fun visitValueParameterNew(declaration: IrValueParameter) { - super.visitValueParameter(declaration) - } -} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index e4b3c560cbc..d28d64017f7 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -5,15 +5,16 @@ package org.jetbrains.kotlin.backend.common.lower -import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.BodyLoweringPass +import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.ir.* +import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.* -import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildFun @@ -33,8 +34,7 @@ import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.acceptVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -109,7 +109,7 @@ class LocalDeclarationsLowering( LocalDeclarationsTransformer(irElement, container, classesToLower).lowerLocalDeclarations() } - internal class ScopeWithCounter(scope: Scope, irElement: IrElement) : ScopeWithIr(scope, irElement) { + internal class ScopeWithCounter(val irElement: IrElement) { // Continuous numbering across all declarations in the container. var counter: Int = 0 val usedLocalFunctionNames: MutableSet = hashSetOf() @@ -122,7 +122,7 @@ class LocalDeclarationsLowering( // Need to keep LocalFunctionContext.index private val IrSymbolOwner.scopeWithCounter: ScopeWithCounter get() = context.ir.localScopeWithCounterMap.scopeMap.getOrPut(this) { - ScopeWithCounter(Scope(symbol), this) + ScopeWithCounter(this) } private abstract class LocalContext { @@ -857,66 +857,70 @@ class LocalDeclarationsLowering( currentParent as? IrClass } - irElement.acceptVoid(object : IrElementVisitorVoidWithContext() { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) + class Data(val currentClass: ScopeWithCounter?, val isInInlineFunction: Boolean) { + fun withCurrentClass(currentClass: IrClass): Data = + // Don't cache local declarations + Data(ScopeWithCounter(currentClass), isInInlineFunction) + + fun withInline(isInline: Boolean): Data = + if (isInline && !isInInlineFunction) Data(currentClass, true) else this + } + + irElement.accept(object : IrElementVisitor { + override fun visitElement(element: IrElement, data: Data) { + element.acceptChildren(this, data) } - override fun createScope(declaration: IrSymbolOwner): ScopeWithIr { - return ScopeWithCounter(Scope(declaration.symbol), declaration) // Don't cache local declarations - } - - override fun visitFunctionExpression(expression: IrFunctionExpression) { + override fun visitFunctionExpression(expression: IrFunctionExpression, data: Data) { // TODO: For now IrFunctionExpression can only be encountered here if this was called from the inliner, // then all IrFunctionExpression will be replaced by IrFunctionReferenceExpression. // Don't forget to fix this when that replacement has been dropped. // Also, a note: even if a lambda is not an inline one, there still cannot be a reference to it // from an outside declaration, so it is safe to skip them here and correctly handle later, after the above conversion. - expression.function.acceptChildrenVoid(this) + expression.function.acceptChildren(this, data) } - override fun visitSimpleFunction(declaration: IrSimpleFunction) { - super.visitSimpleFunction(declaration) + override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Data) { + super.visitSimpleFunction(declaration, data.withInline(declaration.isInline)) if (declaration.visibility == Visibilities.LOCAL) { - val enclosingScope = + val enclosingScope = data.currentClass + ?: enclosingClass?.scopeWithCounter // File is required for K/N because file declarations are not split by classes. - currentClass ?: enclosingClass?.scopeWithCounter ?: enclosingFile.scopeWithCounter + ?: enclosingFile.scopeWithCounter val index = - if (enclosingScope is ScopeWithCounter && - (declaration.name.isSpecial || declaration.name in enclosingScope.usedLocalFunctionNames) - ) enclosingScope.counter++ else -1 + if (declaration.name.isSpecial || declaration.name in enclosingScope.usedLocalFunctionNames) + enclosingScope.counter++ + else -1 localFunctions[declaration] = LocalFunctionContext(declaration, index, enclosingScope.irElement as IrDeclarationContainer) - (enclosingScope as? ScopeWithCounter)?.usedLocalFunctionNames?.add(declaration.name) + enclosingScope.usedLocalFunctionNames.add(declaration.name) } } - override fun visitConstructor(declaration: IrConstructor) { - super.visitConstructor(declaration) + override fun visitConstructor(declaration: IrConstructor, data: Data) { + super.visitConstructor(declaration, data) if (!declaration.constructedClass.isLocalNotInner()) return - localClassConstructors[declaration] = LocalClassConstructorContext(declaration, inInlineFunctionScope) + localClassConstructors[declaration] = LocalClassConstructorContext(declaration, data.inInlineFunctionScope) } - override fun visitClassNew(declaration: IrClass) { + override fun visitClass(declaration: IrClass, data: Data) { if (classesToLower?.contains(declaration) == false) return - super.visitClassNew(declaration) + super.visitClass(declaration, data.withCurrentClass(declaration)) if (!declaration.isLocalNotInner()) return - val localClassContext = LocalClassContext(declaration, inInlineFunctionScope) - localClasses[declaration] = localClassContext + localClasses[declaration] = LocalClassContext(declaration, data.inInlineFunctionScope) } - private val inInlineFunctionScope: Boolean - get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false } || + private val Data.inInlineFunctionScope: Boolean + get() = isInInlineFunction || generateSequence(container) { it.parent as? IrDeclaration }.any { it is IrFunction && it.isInline } - }) + }, Data(null, false)) } } - } // Local inner classes capture anything through outer diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrInlineReferenceLocator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrInlineReferenceLocator.kt index 127dfe97e1b..0f735be5530 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrInlineReferenceLocator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrInlineReferenceLocator.kt @@ -5,25 +5,31 @@ package org.jetbrains.kotlin.backend.jvm.ir -import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression import org.jetbrains.kotlin.ir.util.isLambda import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrCallableReference import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor -internal open class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitorVoidWithContext() { - override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) +internal open class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitor { + override fun visitElement(element: IrElement, data: IrDeclaration?) { + element.acceptChildren(this, data) + } - override fun visitFunctionAccess(expression: IrFunctionAccessExpression) { + override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclaration?) { + declaration.acceptChildren(this, declaration) + } + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrDeclaration?) { val function = expression.symbol.owner if (function.isInlineFunctionCall(context)) { for (parameter in function.valueParameters) { @@ -36,13 +42,13 @@ internal open class IrInlineReferenceLocator(private val context: JvmBackendCont if (valueArgument is IrBlock && valueArgument.origin.isLambda) { val reference = valueArgument.statements.last() as IrFunctionReference - visitInlineLambda(reference, function, parameter, currentScope!!.irElement as IrDeclaration) + visitInlineLambda(reference, function, parameter, data!!) } else if (valueArgument is IrCallableReference<*>) { visitInlineReference(valueArgument) } } } - return super.visitFunctionAccess(expression) + return super.visitFunctionAccess(expression, data) } open fun visitInlineReference(argument: IrCallableReference<*>) {} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index 36c9118dc6e..e7e99b5b49f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -41,7 +41,6 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.name.Name @@ -96,13 +95,13 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : private fun transformSuspendLambdasIntoContinuations(irFile: IrFile) { val inlineReferences = mutableSetOf>() val suspendLambdas = mutableMapOf() - irFile.acceptChildrenVoid(object : IrInlineReferenceLocator(context) { + irFile.acceptChildren(object : IrInlineReferenceLocator(context) { override fun visitInlineReference(argument: IrCallableReference<*>) { inlineReferences.add(argument) } - override fun visitFunctionReference(expression: IrFunctionReference) { - expression.acceptChildrenVoid(this) + override fun visitFunctionReference(expression: IrFunctionReference, data: IrDeclaration?) { + expression.acceptChildren(this, data) if (expression.isSuspend && expression.shouldBeTreatedAsSuspendLambda() && expression !in inlineReferences) { val isRestricted = expression.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any { it.type.classOrNull?.signature == IdSignature.PublicSignature("kotlin.coroutines", "RestrictsSuspension", null, 0) @@ -115,7 +114,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : origin == IrStatementOrigin.LAMBDA || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE || origin == IrStatementOrigin.SUSPEND_CONVERSION - }) + }, null) for (lambda in suspendLambdas.values) { (lambda.function.parent as IrDeclarationContainer).declarations.remove(lambda.function) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FakeInliningLocalVariablesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FakeInliningLocalVariablesLowering.kt index aceb791ba04..1393c400322 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FakeInliningLocalVariablesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FakeInliningLocalVariablesLowering.kt @@ -19,8 +19,6 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.load.java.JvmAbi internal val fakeInliningLocalVariablesLowering = makeIrFilePhase( @@ -31,11 +29,11 @@ internal val fakeInliningLocalVariablesLowering = makeIrFilePhase( internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext) : IrInlineReferenceLocator(context), FileLoweringPass { override fun lower(irFile: IrFile) { - irFile.acceptVoid(this) + irFile.accept(this, null) } - override fun visitFunctionNew(declaration: IrFunction) { - declaration.acceptChildrenVoid(this) + override fun visitFunction(declaration: IrFunction, data: IrDeclaration?) { + super.visitFunction(declaration, data) if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null) { declaration.addFakeInliningLocalVariables() }