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.
This commit is contained in:
Alexander Udalov
2020-08-26 17:51:35 +02:00
parent 5e48be3d11
commit 1e712f8398
5 changed files with 62 additions and 148 deletions
@@ -21,9 +21,11 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.builders.Scope
import org.jetbrains.kotlin.ir.declarations.* 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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
open class ScopeWithIr(val scope: Scope, val irElement: IrElement) open class ScopeWithIr(val scope: Scope, val irElement: IrElement)
@@ -139,98 +141,3 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid()
return super.visitScript(declaration) return super.visitScript(declaration)
} }
} }
@OptIn(ObsoleteDescriptorBasedAPI::class)
abstract class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
private val scopeStack = mutableListOf<ScopeWithIr>()
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)
}
}
@@ -5,15 +5,16 @@
package org.jetbrains.kotlin.backend.common.lower 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.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.common.ir.* 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.Modality
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.* 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.buildConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.declarations.buildFun 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.parentAsClass
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -109,7 +109,7 @@ class LocalDeclarationsLowering(
LocalDeclarationsTransformer(irElement, container, classesToLower).lowerLocalDeclarations() 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. // Continuous numbering across all declarations in the container.
var counter: Int = 0 var counter: Int = 0
val usedLocalFunctionNames: MutableSet<Name> = hashSetOf() val usedLocalFunctionNames: MutableSet<Name> = hashSetOf()
@@ -122,7 +122,7 @@ class LocalDeclarationsLowering(
// Need to keep LocalFunctionContext.index // Need to keep LocalFunctionContext.index
private val IrSymbolOwner.scopeWithCounter: ScopeWithCounter private val IrSymbolOwner.scopeWithCounter: ScopeWithCounter
get() = context.ir.localScopeWithCounterMap.scopeMap.getOrPut(this) { get() = context.ir.localScopeWithCounterMap.scopeMap.getOrPut(this) {
ScopeWithCounter(Scope(symbol), this) ScopeWithCounter(this)
} }
private abstract class LocalContext { private abstract class LocalContext {
@@ -857,66 +857,70 @@ class LocalDeclarationsLowering(
currentParent as? IrClass currentParent as? IrClass
} }
irElement.acceptVoid(object : IrElementVisitorVoidWithContext() { class Data(val currentClass: ScopeWithCounter?, val isInInlineFunction: Boolean) {
override fun visitElement(element: IrElement) { fun withCurrentClass(currentClass: IrClass): Data =
element.acceptChildrenVoid(this) // 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<Unit, Data> {
override fun visitElement(element: IrElement, data: Data) {
element.acceptChildren(this, data)
} }
override fun createScope(declaration: IrSymbolOwner): ScopeWithIr { override fun visitFunctionExpression(expression: IrFunctionExpression, data: Data) {
return ScopeWithCounter(Scope(declaration.symbol), declaration) // Don't cache local declarations
}
override fun visitFunctionExpression(expression: IrFunctionExpression) {
// TODO: For now IrFunctionExpression can only be encountered here if this was called from the inliner, // TODO: For now IrFunctionExpression can only be encountered here if this was called from the inliner,
// then all IrFunctionExpression will be replaced by IrFunctionReferenceExpression. // then all IrFunctionExpression will be replaced by IrFunctionReferenceExpression.
// Don't forget to fix this when that replacement has been dropped. // 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 // 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. // 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) { override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Data) {
super.visitSimpleFunction(declaration) super.visitSimpleFunction(declaration, data.withInline(declaration.isInline))
if (declaration.visibility == Visibilities.LOCAL) { 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. // File is required for K/N because file declarations are not split by classes.
currentClass ?: enclosingClass?.scopeWithCounter ?: enclosingFile.scopeWithCounter ?: enclosingFile.scopeWithCounter
val index = val index =
if (enclosingScope is ScopeWithCounter && if (declaration.name.isSpecial || declaration.name in enclosingScope.usedLocalFunctionNames)
(declaration.name.isSpecial || declaration.name in enclosingScope.usedLocalFunctionNames) enclosingScope.counter++
) enclosingScope.counter++ else -1 else -1
localFunctions[declaration] = localFunctions[declaration] =
LocalFunctionContext(declaration, index, enclosingScope.irElement as IrDeclarationContainer) LocalFunctionContext(declaration, index, enclosingScope.irElement as IrDeclarationContainer)
(enclosingScope as? ScopeWithCounter)?.usedLocalFunctionNames?.add(declaration.name) enclosingScope.usedLocalFunctionNames.add(declaration.name)
} }
} }
override fun visitConstructor(declaration: IrConstructor) { override fun visitConstructor(declaration: IrConstructor, data: Data) {
super.visitConstructor(declaration) super.visitConstructor(declaration, data)
if (!declaration.constructedClass.isLocalNotInner()) return 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 if (classesToLower?.contains(declaration) == false) return
super.visitClassNew(declaration) super.visitClass(declaration, data.withCurrentClass(declaration))
if (!declaration.isLocalNotInner()) return if (!declaration.isLocalNotInner()) return
val localClassContext = LocalClassContext(declaration, inInlineFunctionScope) localClasses[declaration] = LocalClassContext(declaration, data.inInlineFunctionScope)
localClasses[declaration] = localClassContext
} }
private val inInlineFunctionScope: Boolean private val Data.inInlineFunctionScope: Boolean
get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false } || get() = isInInlineFunction ||
generateSequence(container) { it.parent as? IrDeclaration }.any { it is IrFunction && it.isInline } generateSequence(container) { it.parent as? IrDeclaration }.any { it is IrFunction && it.isInline }
}) }, Data(null, false))
} }
} }
} }
// Local inner classes capture anything through outer // Local inner classes capture anything through outer
@@ -5,25 +5,31 @@
package org.jetbrains.kotlin.backend.jvm.ir 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.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.ir.util.isLambda import org.jetbrains.kotlin.ir.util.isLambda
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration 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.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrCallableReference import org.jetbrains.kotlin.ir.expressions.IrCallableReference
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference 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() { internal open class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitor<Unit, IrDeclaration?> {
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) 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 val function = expression.symbol.owner
if (function.isInlineFunctionCall(context)) { if (function.isInlineFunctionCall(context)) {
for (parameter in function.valueParameters) { for (parameter in function.valueParameters) {
@@ -36,13 +42,13 @@ internal open class IrInlineReferenceLocator(private val context: JvmBackendCont
if (valueArgument is IrBlock && valueArgument.origin.isLambda) { if (valueArgument is IrBlock && valueArgument.origin.isLambda) {
val reference = valueArgument.statements.last() as IrFunctionReference 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<*>) { } else if (valueArgument is IrCallableReference<*>) {
visitInlineReference(valueArgument) visitInlineReference(valueArgument)
} }
} }
} }
return super.visitFunctionAccess(expression) return super.visitFunctionAccess(expression, data)
} }
open fun visitInlineReference(argument: IrCallableReference<*>) {} open fun visitInlineReference(argument: IrCallableReference<*>) {}
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -96,13 +95,13 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
private fun transformSuspendLambdasIntoContinuations(irFile: IrFile) { private fun transformSuspendLambdasIntoContinuations(irFile: IrFile) {
val inlineReferences = mutableSetOf<IrCallableReference<*>>() val inlineReferences = mutableSetOf<IrCallableReference<*>>()
val suspendLambdas = mutableMapOf<IrFunctionReference, SuspendLambdaInfo>() val suspendLambdas = mutableMapOf<IrFunctionReference, SuspendLambdaInfo>()
irFile.acceptChildrenVoid(object : IrInlineReferenceLocator(context) { irFile.acceptChildren(object : IrInlineReferenceLocator(context) {
override fun visitInlineReference(argument: IrCallableReference<*>) { override fun visitInlineReference(argument: IrCallableReference<*>) {
inlineReferences.add(argument) inlineReferences.add(argument)
} }
override fun visitFunctionReference(expression: IrFunctionReference) { override fun visitFunctionReference(expression: IrFunctionReference, data: IrDeclaration?) {
expression.acceptChildrenVoid(this) expression.acceptChildren(this, data)
if (expression.isSuspend && expression.shouldBeTreatedAsSuspendLambda() && expression !in inlineReferences) { if (expression.isSuspend && expression.shouldBeTreatedAsSuspendLambda() && expression !in inlineReferences) {
val isRestricted = expression.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any { val isRestricted = expression.symbol.owner.extensionReceiverParameter?.type?.classOrNull?.owner?.annotations?.any {
it.type.classOrNull?.signature == IdSignature.PublicSignature("kotlin.coroutines", "RestrictsSuspension", null, 0) 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.LAMBDA ||
origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE || origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE ||
origin == IrStatementOrigin.SUSPEND_CONVERSION origin == IrStatementOrigin.SUSPEND_CONVERSION
}) }, null)
for (lambda in suspendLambdas.values) { for (lambda in suspendLambdas.values) {
(lambda.function.parent as IrDeclarationContainer).declarations.remove(lambda.function) (lambda.function.parent as IrDeclarationContainer).declarations.remove(lambda.function)
@@ -19,8 +19,6 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference 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 import org.jetbrains.kotlin.load.java.JvmAbi
internal val fakeInliningLocalVariablesLowering = makeIrFilePhase( internal val fakeInliningLocalVariablesLowering = makeIrFilePhase(
@@ -31,11 +29,11 @@ internal val fakeInliningLocalVariablesLowering = makeIrFilePhase(
internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext) : IrInlineReferenceLocator(context), FileLoweringPass { internal class FakeInliningLocalVariablesLowering(val context: JvmBackendContext) : IrInlineReferenceLocator(context), FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.acceptVoid(this) irFile.accept(this, null)
} }
override fun visitFunctionNew(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction, data: IrDeclaration?) {
declaration.acceptChildrenVoid(this) super.visitFunction(declaration, data)
if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null) { if (declaration.isInline && !declaration.origin.isSynthetic && declaration.body != null) {
declaration.addFakeInliningLocalVariables() declaration.addFakeInliningLocalVariables()
} }