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.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<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
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<Name> = 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<Unit, Data> {
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
@@ -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<Unit, IrDeclaration?> {
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<*>) {}
@@ -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<IrCallableReference<*>>()
val suspendLambdas = mutableMapOf<IrFunctionReference, SuspendLambdaInfo>()
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)
@@ -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()
}