[JVM] Migrate JVM lowerings to IrLeafVisitor and friends

KT-74068
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
index 62ca1dd..0c69277 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
@@ -44,8 +44,8 @@
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.util.isNullable
 import org.jetbrains.kotlin.ir.util.isSubtypeOfClass
-import org.jetbrains.kotlin.ir.visitors.IrVisitor
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitor
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.load.java.JvmAbi
@@ -140,7 +140,7 @@
     val classCodegen: ClassCodegen,
     val smap: SourceMapper,
     val reifiedTypeParametersUsages: ReifiedTypeParametersUsages,
-) : IrVisitor<PromisedValue, BlockInfo>(), BaseExpressionCodegen {
+) : IrLeafVisitor<PromisedValue, BlockInfo>(), BaseExpressionCodegen {
     override fun toString(): String = signature.toString()
 
     var finallyDepth = 0
@@ -399,11 +399,9 @@
             expression.markLineNumber(startOffset = true)
             mv.nop()
         }
-        if (expression.isTransparentScope)
-            return super.visitBlock(expression, data)
         val info = BlockInfo(data)
         // Force materialization to avoid reading from out-of-scope variables.
-        val value = super.visitBlock(expression, info).materialized().also {
+        val value = visitContainerExpression(expression, info).materialized().also {
             if (info.variables.isNotEmpty()) {
                 writeLocalVariablesInTable(info, markNewLabel())
             }
@@ -526,7 +524,7 @@
         return unitValue
     }
 
-    override fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo) =
+    private fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo): PromisedValue =
         if (expression.origin == JvmLoweredStatementOrigin.FAKE_CONTINUATION) {
             addFakeContinuationMarker(mv)
             expression.onStack
@@ -534,6 +532,9 @@
             visitStatementContainer(expression, data)
         }
 
+    override fun visitComposite(expression: IrComposite, data: BlockInfo): PromisedValue =
+        visitContainerExpression(expression, data)
+
     override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue {
         val intrinsic = classCodegen.context.getIntrinsic(expression.symbol) as IntrinsicMethod?
         if (intrinsic != null) {
@@ -809,7 +810,7 @@
                 }
     }
 
-    override fun visitFieldAccess(expression: IrFieldAccessExpression, data: BlockInfo): PromisedValue {
+    private fun visitFieldAccess(expression: IrFieldAccessExpression, data: BlockInfo): PromisedValue {
         val callee = expression.symbol.owner
         if (context.config.shouldInlineConstVals) {
             // Const fields should only have reads, and those should have been transformed by ConstLowering.
@@ -853,6 +854,9 @@
         }
     }
 
+    override fun visitGetField(expression: IrGetField, data: BlockInfo): PromisedValue =
+        visitFieldAccess(expression, data)
+
     override fun visitSetField(expression: IrSetField, data: BlockInfo): PromisedValue {
         val expressionValue = expression.value
         // Do not add redundant field initializers that initialize to default values.
@@ -860,7 +864,7 @@
         val isFieldInitializer = expression.origin == IrStatementOrigin.INITIALIZE_FIELD
         val skip = (irFunction is IrConstructor || inClassInit) && isFieldInitializer && expressionValue is IrConst &&
                 isDefaultValueForType(expression.symbol.owner.type.asmType, expressionValue.value)
-        return if (skip) unitValue else super.visitSetField(expression, data)
+        return if (skip) unitValue else visitFieldAccess(expression, data)
     }
 
     /**
@@ -1216,7 +1220,7 @@
     // such as D8 will see locals information that makes no sense.
     private fun endUnreferencedDoWhileLocals(blockInfo: BlockInfo, loop: IrDoWhileLoop, continueLabel: Label) {
         val referencedValues = hashSetOf<IrValueSymbol>()
-        loop.condition.acceptVoid(object : IrVisitorVoid() {
+        loop.condition.acceptVoid(object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 element.acceptChildrenVoid(this)
             }
@@ -1253,7 +1257,7 @@
         }
     }
 
-    override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue {
+    private fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue {
         jump.markLineNumber(startOffset = true)
         // Make sure that the line number has an instruction so that the debugger can always
         // break on the break/continue. As an example, unwindBlockStack could otherwise
@@ -1276,6 +1280,12 @@
         return unitValue
     }
 
+    override fun visitBreak(jump: IrBreak, data: BlockInfo): PromisedValue =
+        visitBreakContinue(jump, data)
+
+    override fun visitContinue(jump: IrContinue, data: BlockInfo): PromisedValue =
+        visitBreakContinue(jump, data)
+
     override fun visitTry(aTry: IrTry, data: BlockInfo): PromisedValue {
         aTry.markLineNumber(startOffset = true)
         return data.withBlock(if (aTry.finallyExpression != null) TryWithFinallyInfo(aTry.finallyExpression!!) else TryInfo()) {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt
index 543563e..577d31c 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt
@@ -56,14 +56,20 @@
     }
 
     private fun addContinuationParameterToSuspendCalls(irFile: IrFile) {
-        irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
+        irFile.transformChildrenVoid(object : IrLeafTransformerVoid() {
             val functionStack = mutableListOf<IrFunction>()
 
-            override fun visitFunction(declaration: IrFunction): IrStatement {
+            private fun visitFunction(declaration: IrFunction): IrStatement {
                 functionStack.push(declaration)
-                return super.visitFunction(declaration).also { functionStack.pop() }
+                return transformElement(declaration).also { functionStack.pop() }
             }
 
+            override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement =
+                visitFunction(declaration)
+
+            override fun visitConstructor(declaration: IrConstructor): IrStatement =
+                visitFunction(declaration)
+
             override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
                 val transformed = super.visitFunctionReference(expression) as IrFunctionReference
                 // The only references not yet transformed into objects are inline lambdas; the continuation
@@ -235,7 +241,7 @@
             assert(movedDispatchParameter.origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER) {
                 "MOVED_DISPATCH_RECEIVER should be the first parameter in ${static.render()}"
             }
-            static.body!!.transformChildrenVoid(object : IrElementTransformerVoid() {
+            static.body!!.transformChildrenVoid(object : IrLeafTransformerVoid() {
                 override fun visitGetValue(expression: IrGetValue): IrExpression {
                     val owner = expression.symbol.owner
                     if (owner is IrValueParameter && isInstanceReceiverOfOuterClass(owner)) {
@@ -290,7 +296,7 @@
     }
 
     private fun addContinuationObjectAndContinuationParameterToSuspendFunctions(irFile: IrFile) {
-        irFile.accept(object : IrElementTransformerVoid() {
+        irFile.accept(object : IrLeafTransformerVoid() {
             override fun visitClass(declaration: IrClass): IrStatement {
                 declaration.transformDeclarationsFlat {
                     if (it is IrSimpleFunction && it.isSuspend)
@@ -370,17 +376,25 @@
 
             private fun IrSimpleFunction.isCapturingCrossinline(): Boolean {
                 var capturesCrossinline = false
-                (this.originalBeforeInline ?: this).acceptVoid(object : IrVisitorVoid() {
+                (this.originalBeforeInline ?: this).acceptVoid(object : IrLeafVisitorVoid() {
                     override fun visitElement(element: IrElement) {
                         element.acceptChildrenVoid(this)
                     }
 
-                    override fun visitFieldAccess(expression: IrFieldAccessExpression) {
+                    private fun visitFieldAccess(expression: IrFieldAccessExpression) {
                         if (expression.symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE) {
                             capturesCrossinline = true
                             return
                         }
-                        super.visitFieldAccess(expression)
+                        expression.acceptChildrenVoid(this)
+                    }
+
+                    override fun visitGetField(expression: IrGetField) {
+                        visitFieldAccess(expression)
+                    }
+
+                    override fun visitSetField(expression: IrSetField) {
+                        visitFieldAccess(expression)
                     }
 
                     override fun visitClass(declaration: IrClass) {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/CreateSeparateCallForInlinedLambdasLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/CreateSeparateCallForInlinedLambdasLowering.kt
index a54ae64..4d3f5ba 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/CreateSeparateCallForInlinedLambdasLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/CreateSeparateCallForInlinedLambdasLowering.kt
@@ -16,7 +16,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
 import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 
 /**
  * Creates a separate call to `singleArgumentInlineFunction` with previously inlined lambda as argument.
@@ -25,7 +25,7 @@
     name = "CreateSeparateCallForInlinedLambdasLowering",
     prerequisite = [JvmIrInliner::class]
 )
-class CreateSeparateCallForInlinedLambdasLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
+class CreateSeparateCallForInlinedLambdasLowering(val context: JvmBackendContext) : IrLeafTransformerVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         if (context.config.enableIrInliner) {
             irFile.transformChildrenVoid()
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt
index 76e8836..35db9172 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt
@@ -33,7 +33,7 @@
 import org.jetbrains.kotlin.ir.types.defaultType
 import org.jetbrains.kotlin.ir.types.typeWith
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.name.SpecialNames
@@ -191,7 +191,7 @@
 
         private inner class EnumClassDeclarationsTransformer(
             private val valuesField: IrField, private val entriesField: IrField?
-        ) : IrElementTransformerVoid() {
+        ) : IrLeafTransformerVoid() {
 
             override fun visitClass(declaration: IrClass): IrStatement =
                 if (declaration.isEnumEntry) super.visitClass(declaration) else declaration
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FakeLocalVariablesForIrInlinerLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FakeLocalVariablesForIrInlinerLowering.kt
index f93d9c7..c804d4c 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FakeLocalVariablesForIrInlinerLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FakeLocalVariablesForIrInlinerLowering.kt
@@ -27,8 +27,8 @@
 import org.jetbrains.kotlin.ir.expressions.*
 import org.jetbrains.kotlin.ir.originalBeforeInline
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrVisitor
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitor
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.load.java.JvmAbi
@@ -41,7 +41,7 @@
 @PhaseDescription(name = "FakeLocalVariablesForIrInlinerLowering")
 internal class FakeLocalVariablesForIrInlinerLowering(
     override val context: JvmBackendContext
-) : IrVisitorVoid(), FakeInliningLocalVariables<IrInlinedFunctionBlock>, FileLoweringPass {
+) : IrLeafVisitorVoid(), FakeInliningLocalVariables<IrInlinedFunctionBlock>, FileLoweringPass {
     private val inlinedStack = mutableListOf<IrInlinedFunctionBlock>()
     private var container: IrDeclaration? = null
 
@@ -105,7 +105,7 @@
     }
 }
 
-private class LocalVariablesProcessor : IrVisitor<Unit, LocalVariablesProcessor.Data>() {
+private class LocalVariablesProcessor : IrLeafVisitor<Unit, LocalVariablesProcessor.Data>() {
     data class Data(val processingOriginalDeclarations: Boolean)
 
     private val inlinedStack = mutableListOf<IrInlinedFunctionBlock>()
@@ -165,7 +165,7 @@
     }
 }
 
-private class FunctionParametersProcessor : IrVisitorVoid() {
+private class FunctionParametersProcessor : IrLeafVisitorVoid() {
     override fun visitElement(element: IrElement) {
         element.acceptChildrenVoid(this)
     }
@@ -185,7 +185,7 @@
     }
 }
 
-private class ScopeNumberVariableProcessor : IrVisitorVoid() {
+private class ScopeNumberVariableProcessor : IrLeafVisitorVoid() {
     private val inlinedStack = mutableListOf<Pair<IrInlinedFunctionBlock, Int>>()
     private var lastInlineScopeNumber = 0
 
@@ -200,7 +200,12 @@
         element.acceptChildrenVoid(this)
     }
 
-    override fun visitFunction(declaration: IrFunction) {
+    override fun visitSimpleFunction(declaration: IrSimpleFunction) {
+        val processor = ScopeNumberVariableProcessor()
+        declaration.acceptChildrenVoid(processor)
+    }
+
+    override fun visitConstructor(declaration: IrConstructor) {
         val processor = ScopeNumberVariableProcessor()
         declaration.acceptChildrenVoid(processor)
     }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FragmentSharedVariablesLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FragmentSharedVariablesLowering.kt
index d182af3..1b153f9 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FragmentSharedVariablesLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/FragmentSharedVariablesLowering.kt
@@ -18,7 +18,7 @@
 import org.jetbrains.kotlin.ir.expressions.IrSetValue
 import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
 import org.jetbrains.kotlin.ir.util.copyTo
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 
 /**
@@ -89,7 +89,7 @@
         declaration: IrFunction,
         promotedParameters: Map<IrValueParameterSymbol, IrValueParameterSymbol>
     ) {
-        declaration.body!!.transformChildrenVoid(object : IrElementTransformerVoid() {
+        declaration.body!!.transformChildrenVoid(object : IrLeafTransformerVoid() {
             override fun visitGetValue(expression: IrGetValue): IrExpression {
                 expression.transformChildrenVoid(this)
                 val newDeclaration = promotedParameters[expression.symbol] ?: return expression
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt
index f6d0b24..29bb5e4 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt
@@ -31,8 +31,8 @@
 import org.jetbrains.kotlin.ir.types.defaultType
 import org.jetbrains.kotlin.ir.types.typeWith
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
-import org.jetbrains.kotlin.ir.visitors.IrVisitor
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitor
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
 import org.jetbrains.kotlin.name.JvmStandardClassIds
@@ -300,7 +300,7 @@
 
 private class UpdateFunctionCallSites(
     private val functionDelegates: MutableMap<IrSimpleFunction, IrSimpleFunction>
-) : IrVisitor<Unit, IrFunction?>(), FileLoweringPass {
+) : IrLeafVisitor<Unit, IrFunction?>(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.acceptChildren(this, null)
     }
@@ -309,8 +309,11 @@
         element.acceptChildren(this, data)
     }
 
-    override fun visitFunction(declaration: IrFunction, data: IrFunction?): Unit =
-        super.visitFunction(declaration, declaration)
+    override fun visitSimpleFunction(declaration: IrSimpleFunction, data: IrFunction?): Unit =
+        declaration.acceptChildren(this, declaration)
+
+    override fun visitConstructor(declaration: IrConstructor, data: IrFunction?): Unit =
+        declaration.acceptChildren(this, declaration)
 
     override fun visitCall(expression: IrCall, data: IrFunction?) {
         expression.acceptChildren(this, data)
@@ -331,7 +334,7 @@
         val facadeClass = getReplacementFacadeClassOrNull(irClass) ?: return
 
         // Replace the class reference in the body of the property reference class (in getOwner) to refer to the facade class instead.
-        irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
+        irClass.transformChildrenVoid(object : IrLeafTransformerVoid() {
             override fun visitClass(declaration: IrClass): IrStatement = declaration
 
             override fun visitClassReference(expression: IrClassReference): IrExpression = IrClassReferenceImpl(
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt
index f212e7a..bc33be9 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt
@@ -28,8 +28,8 @@
 import org.jetbrains.kotlin.ir.expressions.putArgument
 import org.jetbrains.kotlin.ir.types.IrType
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 
 /**
@@ -121,7 +121,7 @@
  * Redirects super interface calls to DefaultImpls.
  */
 @PhaseDescription(name = "InterfaceSuperCalls")
-internal class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
+internal class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrLeafTransformerVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.transformChildrenVoid(this)
     }
@@ -220,7 +220,7 @@
  * Resolves calls to Object methods on interface types to virtual methods.
  */
 @PhaseDescription(name = "InterfaceObjectCalls")
-internal class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) = irFile.acceptChildren(this, null)
 
     override fun visitElement(element: IrElement) {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt
index 634ece7..878e212 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt
@@ -16,7 +16,7 @@
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
 import org.jetbrains.kotlin.ir.util.render
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 
 /**
@@ -26,7 +26,7 @@
     name = "InlinedClassReferencesBoxingLowering",
     prerequisite = [JvmIrInliner::class, MarkNecessaryInlinedClassesAsRegeneratedLowering::class]
 )
-internal class InlinedClassReferencesBoxingLowering(val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class InlinedClassReferencesBoxingLowering(val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         if (context.config.enableIrInliner) {
             irFile.acceptChildrenVoid(this)
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt
index 0b39b0f..7590ecf 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt
@@ -32,7 +32,7 @@
 import org.jetbrains.kotlin.ir.util.isMethodOfAny
 import org.jetbrains.kotlin.ir.util.parentAsClass
 import org.jetbrains.kotlin.ir.util.resolveFakeOverrideOrFail
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 
 /**
@@ -43,7 +43,7 @@
     name = "Interface",
     prerequisite = [JvmDefaultParameterInjector::class]
 )
-internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
+internal class InterfaceLowering(val context: JvmBackendContext) : IrLeafTransformerVoid(), ClassLoweringPass {
     private val removedFunctions = hashMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
     private val removedFunctionsWithoutRemapping = mutableSetOf<IrSimpleFunctionSymbol>()
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
index cfc2ced..b3e8181 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
@@ -27,7 +27,7 @@
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.util.isNullable
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
 
@@ -153,7 +153,7 @@
 
             constructor.body?.statements?.forEach { statement ->
                 +statement
-                    .transformStatement(object : IrElementTransformerVoid() {
+                    .transformStatement(object : IrLeafTransformerVoid() {
                         // Don't recurse under nested class declarations
                         override fun visitClass(declaration: IrClass): IrStatement {
                             return declaration
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
index 6f5aa9f..c7f9aac 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
@@ -463,7 +463,7 @@
         replacement.body = context.createJvmIrBuilder(replacement.symbol).irBlockBody {
             val thisVar = irTemporary(irType = replacement.returnType, nameHint = "\$this")
             constructor.body?.statements?.forEach { statement ->
-                +statement.transformStatement(object : IrElementTransformerVoid() {
+                +statement.transformStatement(object : IrLeafTransformerVoid() {
                     override fun visitClass(declaration: IrClass): IrStatement = declaration
 
                     override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
@@ -1122,17 +1122,25 @@
                         standaloneExpressions.add(statement.value)
                         resultVariables.removeLast()
                         block.statements.removeLast()
-                        statement.value.acceptVoid(object : IrVisitorVoid() {
+                        statement.value.acceptVoid(object : IrLeafVisitorVoid() {
                             override fun visitElement(element: IrElement) {
                                 element.acceptChildrenVoid(this)
                             }
 
-                            override fun visitValueAccess(expression: IrValueAccessExpression) {
+                            private fun visitValueAccess(expression: IrValueAccessExpression) {
                                 val valueDeclaration = expression.symbol.owner
                                 if (valueDeclaration is IrVariable && valueDeclaration in variablesSet) {
                                     forbiddenVariables.add(valueDeclaration)
                                 }
-                                super.visitValueAccess(expression)
+                                expression.acceptChildrenVoid(this)
+                            }
+
+                            override fun visitGetValue(expression: IrGetValue) {
+                                visitValueAccess(expression)
+                            }
+
+                            override fun visitSetValue(expression: IrSetValue) {
+                                visitValueAccess(expression)
                             }
                         })
                     }
@@ -1326,7 +1334,7 @@
      */
     private fun IrBody.removeAllExtraBoxes() {
         // data is whether the expression result is used
-        accept(object : IrVisitor<Unit, Boolean>() {
+        accept(object : IrLeafVisitor<Unit, Boolean>() {
             override fun visitElement(element: IrElement, data: Boolean) {
                 element.acceptChildren(this, true) // uses what is inside
             }
@@ -1342,12 +1350,16 @@
             }
 
             // inner functions will be handled separately, no need to do it now
-            override fun visitFunction(declaration: IrFunction, data: Boolean) = Unit
+            override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Boolean) = Unit
 
             // inner classes will be handled separately, no need to do it now
             override fun visitClass(declaration: IrClass, data: Boolean) = Unit
 
-            override fun visitContainerExpression(expression: IrContainerExpression, data: Boolean) {
+            override fun visitBlock(expression: IrBlock, data: Boolean) {
+                handleStatementContainer(expression, data)
+            }
+
+            override fun visitComposite(expression: IrComposite, data: Boolean) {
                 handleStatementContainer(expression, data)
             }
 
@@ -1418,41 +1430,62 @@
     val variableUsages = mutableMapOf<BlockOrBody, MutableSet<IrVariable>>()
     val childrenBlocks = mutableMapOf<BlockOrBody, MutableList<BlockOrBody>>()
 
-    body.element.acceptVoid(object : IrVisitorVoid() {
+    body.element.acceptVoid(object : IrLeafVisitorVoid() {
         private val stack = mutableListOf<BlockOrBody>()
         override fun visitElement(element: IrElement) {
-            element.acceptChildren(this, null)
+            element.acceptChildrenVoid(this)
         }
 
-        override fun visitBody(body: IrBody) {
+        private fun visitBody(body: IrBody) {
             currentStackElement()?.let { childrenBlocks.getOrPut(it) { mutableListOf() }.add(BlockOrBody.Body(body)) }
             stack.add(BlockOrBody.Body(body))
-            super.visitBody(body)
+            body.acceptChildrenVoid(this)
             require(stack.removeLast() == BlockOrBody.Body(body)) { "Invalid stack" }
         }
 
-        override fun visitBlock(expression: IrBlock) {
+        override fun visitBlockBody(body: IrBlockBody) {
+            visitBody(body)
+        }
+
+        override fun visitExpressionBody(body: IrExpressionBody) {
+            visitBody(body)
+        }
+
+        override fun visitSyntheticBody(body: IrSyntheticBody) {
+            visitBody(body)
+        }
+
+        override fun visitInlinedFunctionBlock(inlinedBlock: IrInlinedFunctionBlock) {
             // This is a workaround.
             // We process IrInlinedFunctionBlock on codegen in a special way by processing composite blocks with arguments evaluation first.
             // Thus, we don't want IrInlinedFunctionBlock to contain variable declarations before this composite blocks.
             // That is why we move variable declarations from IrInlinedFunctionBlock to the outer block.
-            if (expression is IrInlinedFunctionBlock) {
-                return super.visitBlock(expression)
-            }
+            inlinedBlock.acceptChildrenVoid(this)
+        }
+
+        override fun visitBlock(expression: IrBlock) {
             currentStackElement()?.let { childrenBlocks.getOrPut(it) { mutableListOf() }.add(Block(expression)) }
             stack.add(Block(expression))
-            super.visitBlock(expression)
+            expression.acceptChildrenVoid(this)
             require(stack.removeLast() == Block(expression)) { "Invalid stack" }
         }
 
         private fun currentStackElement() = stack.lastOrNull()
 
-        override fun visitValueAccess(expression: IrValueAccessExpression) {
+        private fun visitValueAccess(expression: IrValueAccessExpression) {
             val valueDeclaration = expression.symbol.owner
             if (valueDeclaration is IrVariable && valueDeclaration in variables) {
                 variableUsages.getOrPut(currentStackElement()!!) { mutableSetOf() }.add(valueDeclaration)
             }
-            super.visitValueAccess(expression)
+            expression.acceptChildrenVoid(this)
+        }
+
+        override fun visitGetValue(expression: IrGetValue) {
+            visitValueAccess(expression)
+        }
+
+        override fun visitSetValue(expression: IrSetValue) {
+            visitValueAccess(expression)
         }
     })
 
@@ -1471,18 +1504,26 @@
 
 private fun IrStatement.containsUsagesOf(variablesSet: Set<IrVariable>): Boolean {
     var used = false
-    acceptVoid(object : IrVisitorVoid() {
+    acceptVoid(object : IrLeafVisitorVoid() {
         override fun visitElement(element: IrElement) {
             if (!used) {
                 element.acceptChildrenVoid(this)
             }
         }
 
-        override fun visitValueAccess(expression: IrValueAccessExpression) {
+        private fun visitValueAccess(expression: IrValueAccessExpression) {
             if (expression.symbol.owner in variablesSet) {
                 used = true
             }
-            super.visitValueAccess(expression)
+            visitElement(expression)
+        }
+
+        override fun visitGetValue(expression: IrGetValue) {
+            visitValueAccess(expression)
+        }
+
+        override fun visitSetValue(expression: IrSetValue) {
+            visitValueAccess(expression)
         }
     })
     return used
@@ -1502,7 +1543,7 @@
     val containingVariables: Map<BlockOrBody, List<IrVariable>> = nearestBlocks.entries
         .mapNotNull { (k, v) -> if (v != null) k to v else null }
         .groupBy({ (_, v) -> v }, { (k, _) -> k })
-    return element.transform(object : IrElementTransformerVoid() {
+    return element.transform(object : IrLeafTransformerVoid() {
         private fun getFirstInnerStatement(statement: IrStatement): IrStatement? =
             if (statement is IrStatementContainer) statement.statements.first().let(::getFirstInnerStatement) else statement
 
@@ -1588,13 +1629,18 @@
 }
 
 private fun BlockOrBody.extractVariablesSettersToOuterPossibleBlock(variables: Set<IrVariable>) {
-    element.acceptVoid(object : IrVisitorVoid() {
+    element.acceptVoid(object : IrLeafVisitorVoid() {
         override fun visitElement(element: IrElement) {
             element.acceptChildrenVoid(this)
         }
 
-        override fun visitContainerExpression(expression: IrContainerExpression) {
-            super.visitContainerExpression(expression)
+        override fun visitBlock(expression: IrBlock) {
+            expression.acceptChildrenVoid(this)
+            visitStatementContainer(expression)
+        }
+
+        override fun visitComposite(expression: IrComposite) {
+            expression.acceptChildrenVoid(this)
             visitStatementContainer(expression)
         }
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt
index 4a2b85a..7366d37 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt
@@ -29,7 +29,7 @@
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.util.isNullable
-import org.jetbrains.kotlin.ir.visitors.IrTransformer
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformer
 import org.jetbrains.kotlin.util.OperatorNameConventions
 
 @PhaseDescription(name = "JvmOptimizationLowering")
@@ -78,12 +78,14 @@
     private inner class Transformer(
         private val fileEntry: IrFileEntry,
         private val inlineScopeResolver: IrInlineScopeResolver
-    ) : IrTransformer<IrDeclaration?>() {
+    ) : IrLeafTransformer<IrDeclaration?>() {
 
         private val dontTouchTemporaryVals = HashSet<IrVariable>()
 
-        override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclaration?): IrStatement =
-            super.visitDeclaration(declaration, declaration)
+        override fun <E : IrElement> transformElement(element: E, data: IrDeclaration?): E {
+            element.transformChildren(this, element as? IrDeclaration ?: data)
+            return element
+        }
 
         override fun visitCall(expression: IrCall, data: IrDeclaration?): IrExpression {
             expression.transformChildren(this, data)
@@ -290,7 +292,7 @@
             return body
         }
 
-        override fun visitContainerExpression(expression: IrContainerExpression, data: IrDeclaration?): IrExpression {
+        private fun visitContainerExpression(expression: IrContainerExpression, data: IrDeclaration?): IrExpression {
             if (expression.origin == IrStatementOrigin.WHEN) {
                 // Don't optimize out 'when' subject initialized with a variable,
                 // otherwise we might get somewhat weird debugging behavior.
@@ -313,6 +315,12 @@
             return expression
         }
 
+        override fun visitBlock(expression: IrBlock, data: IrDeclaration?): IrExpression =
+            visitContainerExpression(expression, data)
+
+        override fun visitComposite(expression: IrComposite, data: IrDeclaration?): IrExpression =
+            visitContainerExpression(expression, data)
+
         private fun reuseLoopVariableAsInductionVariableIfPossible(irForLoopBlock: IrContainerExpression) {
             if (irForLoopBlock.statements.size != 2) return
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt
index cc0a129..f4d70ac 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSafeCallChainFoldingLowering.kt
@@ -19,7 +19,7 @@
 import org.jetbrains.kotlin.ir.util.hasAnnotation
 import org.jetbrains.kotlin.ir.util.isConstantLike
 import org.jetbrains.kotlin.ir.util.isNullable
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JvmAnnotationNames
 
@@ -130,7 +130,7 @@
         (isBoolean() || isByte() || isShort() || isInt() || isLong() || isChar() || isFloat() || isDouble()) &&
                 !hasAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION)
 
-    private inner class Transformer : IrElementTransformerVoid() {
+    private inner class Transformer : IrLeafTransformerVoid() {
         override fun visitBlock(expression: IrBlock): IrExpression {
             expression.transformChildrenVoid()
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt
index 085c786..e50d054 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt
@@ -24,6 +24,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
 
@@ -124,7 +125,7 @@
     }
 }
 
-private class CompanionObjectJvmStaticTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() {
+private class CompanionObjectJvmStaticTransformer(val context: JvmBackendContext) : IrLeafTransformerVoid() {
     // TODO: would be nice to add a mode that *only* leaves static versions for all annotated methods, with nothing
     //  in companions - this would reduce the number of classes if the companion only has `@JvmStatic` declarations.
     private fun IrSimpleFunction.needsStaticProxy(): Boolean = when {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MakePropertyDelegateMethodsStaticLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MakePropertyDelegateMethodsStaticLowering.kt
index 0fc7590..38bc835 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MakePropertyDelegateMethodsStaticLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MakePropertyDelegateMethodsStaticLowering.kt
@@ -17,7 +17,7 @@
 import org.jetbrains.kotlin.ir.expressions.IrExpression
 import org.jetbrains.kotlin.ir.util.copyTo
 import org.jetbrains.kotlin.ir.util.render
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.load.java.JvmAbi
 
 /**
@@ -35,7 +35,7 @@
     name = "MakePropertyDelegateMethodsStatic",
     prerequisite = [PropertyReferenceDelegationLowering::class, JvmLocalDeclarationsLowering::class]
 )
-internal class MakePropertyDelegateMethodsStaticLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
+internal class MakePropertyDelegateMethodsStaticLowering(val context: JvmBackendContext) : IrLeafTransformerVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.transform(this, null)
     }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MarkNecessaryInlinedClassesAsRegeneratedLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MarkNecessaryInlinedClassesAsRegeneratedLowering.kt
index f20d51f..3773c02 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MarkNecessaryInlinedClassesAsRegeneratedLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/MarkNecessaryInlinedClassesAsRegeneratedLowering.kt
@@ -23,7 +23,7 @@
 import org.jetbrains.kotlin.ir.util.isFunctionInlining
 import org.jetbrains.kotlin.ir.util.isLambdaBlock
 import org.jetbrains.kotlin.ir.util.isLambdaInlining
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 
@@ -34,7 +34,7 @@
     name = "MarkNecessaryInlinedClassesAsRegeneratedLowering",
     prerequisite = [JvmIrInliner::class, CreateSeparateCallForInlinedLambdasLowering::class]
 )
-internal class MarkNecessaryInlinedClassesAsRegeneratedLowering(val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class MarkNecessaryInlinedClassesAsRegeneratedLowering(val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     private var IrDeclaration.wasVisitedForRegenerationLowering: Boolean by irFlag(false)
 
     override fun lower(irFile: IrFile) {
@@ -67,7 +67,7 @@
 
     private fun IrInlinedFunctionBlock.collectDeclarationsThatMustBeRegenerated(): Set<IrElement> {
         val classesToRegenerate = mutableSetOf<IrElement>()
-        this.acceptVoid(object : IrVisitorVoid() {
+        this.acceptVoid(object : IrLeafVisitorVoid() {
             private val containersStack = mutableListOf<IrElement>()
             private val inlinableParameters = mutableListOf<IrValueParameter>()
             private val reifiedArguments = mutableListOf<IrType>()
@@ -175,7 +175,7 @@
 
                 inlinableParameters.addAll(additionalInlinableParameters)
                 reifiedArguments.addAll(additionalTypeArguments)
-                super.visitContainerExpression(inlinedBlock)
+                inlinedBlock.acceptChildrenVoid(this)
                 inlinableParameters.dropLast(additionalInlinableParameters.size)
                 reifiedArguments.dropLast(additionalTypeArguments.size)
             }
@@ -186,12 +186,12 @@
     private fun IrElement.hasReifiedTypeArguments(reifiedArguments: List<IrType>): Boolean {
         var hasReified = false
 
-        fun IrType.recursiveWalkDown(visitor: IrVisitorVoid) {
+        fun IrType.recursiveWalkDown(visitor: IrLeafVisitorVoid) {
             hasReified = hasReified || this@recursiveWalkDown in reifiedArguments
             (this@recursiveWalkDown as? IrSimpleType)?.arguments?.forEach { it.typeOrNull?.recursiveWalkDown(visitor) }
         }
 
-        this.acceptVoid(object : IrVisitorVoid() {
+        this.acceptVoid(object : IrLeafVisitorVoid() {
             private val visitedClasses = mutableSetOf<IrClass>()
 
             override fun visitElement(element: IrElement) {
@@ -226,7 +226,7 @@
     }
 
     private fun IrElement.setUpCorrectAttributesForAllInnerElements(mustBeRegenerated: Set<IrElement>) {
-        this.acceptChildrenVoid(object : IrVisitorVoid() {
+        this.acceptChildrenVoid(object : IrLeafVisitorVoid() {
             private fun checkAndSetUpCorrectAttributes(element: IrElement) {
                 when {
                     element !in mustBeRegenerated && element.originalBeforeInline != null -> element.setUpOriginalAttributes()
@@ -253,7 +253,7 @@
     }
 
     private fun IrElement.setUpOriginalAttributes() {
-        acceptVoid(object : IrVisitorVoid() {
+        acceptVoid(object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 if (element.originalBeforeInline != null) {
                     // Basically we need to generate SEQUENCE of `element.originalBeforeInline` and find the original one.
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PolymorphicSignatureLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PolymorphicSignatureLowering.kt
index d79a7b8..ee2f5a0 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PolymorphicSignatureLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PolymorphicSignatureLowering.kt
@@ -24,7 +24,7 @@
 import org.jetbrains.kotlin.ir.util.dump
 import org.jetbrains.kotlin.ir.util.hasAnnotation
 import org.jetbrains.kotlin.ir.util.transformInPlace
-import org.jetbrains.kotlin.ir.visitors.IrTransformer
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformer
 import org.jetbrains.kotlin.resolve.jvm.checkers.PolymorphicSignatureCallChecker
 
 /**
@@ -46,7 +46,7 @@
  * types and return type.
  */
 @PhaseDescription(name = "PolymorphicSignature")
-internal class PolymorphicSignatureLowering(val context: JvmBackendContext) : IrTransformer<PolymorphicSignatureLowering.Data>(),
+internal class PolymorphicSignatureLowering(val context: JvmBackendContext) : IrLeafTransformer<PolymorphicSignatureLowering.Data>(),
     FileLoweringPass {
     override fun lower(irFile: IrFile) {
         if (context.config.languageVersionSettings.supportsFeature(LanguageFeature.PolymorphicSignature))
@@ -92,7 +92,7 @@
         return expression
     }
 
-    override fun visitContainerExpression(expression: IrContainerExpression, data: Data): IrExpression {
+    private fun visitContainerExpression(expression: IrContainerExpression, data: Data): IrExpression {
         val statements = expression.statements
         for (i in 0 until statements.size) {
             val newData = if (i == statements.lastIndex) data else Data.NO_COERCION
@@ -101,6 +101,12 @@
         return expression
     }
 
+    override fun visitBlock(expression: IrBlock, data: Data): IrExpression =
+        visitContainerExpression(expression, data)
+
+    override fun visitComposite(expression: IrComposite, data: Data): IrExpression =
+        visitContainerExpression(expression, data)
+
     override fun visitCall(expression: IrCall, data: Data): IrElement =
         if (expression.isPolymorphicCall()) {
             expression.transform(data.coerceToType)
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceDelegationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceDelegationLowering.kt
index ad8dbb8..1d9804a 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceDelegationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceDelegationLowering.kt
@@ -23,7 +23,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImplWithShape
 import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.name.Name
 
 /**
@@ -53,7 +53,7 @@
     }
 }
 
-private class PropertyReferenceDelegationTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() {
+private class PropertyReferenceDelegationTransformer(val context: JvmBackendContext) : IrLeafTransformerVoid() {
     private fun IrSimpleFunction.accessorBody(delegate: IrPropertyReference, receiverFieldOrExpression: IrStatement?): IrBody =
         context.createIrBuilder(symbol, startOffset, endOffset).run {
             val value = valueParameters.singleOrNull()?.let(::irGet)
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDuplicatedInlinedLocalClassesLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDuplicatedInlinedLocalClassesLowering.kt
index c9b4363e..0a8e7de 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDuplicatedInlinedLocalClassesLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDuplicatedInlinedLocalClassesLowering.kt
@@ -19,7 +19,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner
 import org.jetbrains.kotlin.ir.originalBeforeInline
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrTransformer
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformer
 import org.jetbrains.kotlin.name.NameUtils
 
 /**
@@ -51,7 +51,7 @@
     var modifyTree: Boolean = true,
 )
 
-private class RemoveDuplicatedInlinedLocalClassesTransformer(val context: JvmBackendContext) : IrTransformer<Data>() {
+private class RemoveDuplicatedInlinedLocalClassesTransformer(val context: JvmBackendContext) : IrLeafTransformer<Data>() {
     private val visited = mutableSetOf<IrElement>()
     private val capturedConstructors = context.mapping.capturedConstructors
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RepeatedAnnotationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RepeatedAnnotationLowering.kt
index 95c8b6d..2856025 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RepeatedAnnotationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/RepeatedAnnotationLowering.kt
@@ -13,8 +13,8 @@
 import org.jetbrains.kotlin.ir.IrElement
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.declarations.IrClass
-import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
 import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer
 import org.jetbrains.kotlin.ir.expressions.IrClassReference
 import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
 import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
@@ -23,7 +23,7 @@
 import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
 import org.jetbrains.kotlin.ir.types.typeWith
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.load.java.JvmAnnotationNames
@@ -50,25 +50,18 @@
  *     fun f() {}
  */
 @PhaseDescription(name = "RepeatedAnnotation")
-internal class RepeatedAnnotationLowering(private val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class RepeatedAnnotationLowering(private val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.acceptVoid(this)
     }
 
     override fun visitElement(element: IrElement) {
+        if (element is IrMutableAnnotationContainer) {
+            element.annotations = transformAnnotations(element.annotations)
+        }
         element.acceptChildrenVoid(this)
     }
 
-    override fun visitFile(declaration: IrFile) {
-        declaration.annotations = transformAnnotations(declaration.annotations)
-        super.visitFile(declaration)
-    }
-
-    override fun visitDeclaration(declaration: IrDeclarationBase) {
-        declaration.annotations = transformAnnotations(declaration.annotations)
-        super.visitDeclaration(declaration)
-    }
-
     override fun visitClass(declaration: IrClass) {
         if (declaration.kind == ClassKind.ANNOTATION_CLASS &&
             declaration.hasAnnotation(StandardNames.FqNames.repeatable) &&
@@ -76,7 +69,8 @@
         ) {
             declaration.declarations.add(context.cachedDeclarations.getRepeatedAnnotationSyntheticContainer(declaration))
         }
-        super.visitClass(declaration)
+        declaration.annotations = transformAnnotations(declaration.annotations)
+        declaration.acceptChildrenVoid(this)
     }
 
     private fun transformAnnotations(annotations: List<IrConstructorCall>): List<IrConstructorCall> {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReplaceNumberToCharCallSitesLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReplaceNumberToCharCallSitesLowering.kt
index 3490b1a..6a48526 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReplaceNumberToCharCallSitesLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReplaceNumberToCharCallSitesLowering.kt
@@ -15,7 +15,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
 import org.jetbrains.kotlin.ir.types.isNumber
 import org.jetbrains.kotlin.ir.util.resolveFakeOverride
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.types.expressions.OperatorConventions
 
 /**
@@ -28,7 +28,7 @@
  * compiler sees it there because `java.lang.Number` is mapped to `kotlin.Number`.
  */
 @PhaseDescription(name = "ReplaceNumberToCharCallSites")
-internal class ReplaceNumberToCharCallSitesLowering(val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class ReplaceNumberToCharCallSitesLowering(val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.acceptChildren(this, null)
     }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt
index 11e97e9..d8dab47 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ResolveInlineCalls.kt
@@ -21,13 +21,13 @@
 import org.jetbrains.kotlin.ir.util.defaultType
 import org.jetbrains.kotlin.ir.util.parentAsClass
 import org.jetbrains.kotlin.ir.util.resolveFakeOverride
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 
 /**
  * Statically resolves calls to inline methods to particular implementations.
  */
 @PhaseDescription(name = "ResolveInlineCalls")
-internal class ResolveInlineCalls(val context: JvmBackendContext) : IrVisitorVoid(), FileLoweringPass {
+internal class ResolveInlineCalls(val context: JvmBackendContext) : IrLeafVisitorVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) = irFile.acceptChildren(this, null)
 
     override fun visitElement(element: IrElement) {
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonOrConstantDelegationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonOrConstantDelegationLowering.kt
index 885c763..4c68bcd 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonOrConstantDelegationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonOrConstantDelegationLowering.kt
@@ -21,7 +21,7 @@
 import org.jetbrains.kotlin.ir.util.parentAsClass
 import org.jetbrains.kotlin.ir.util.remapReceiver
 import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 
 /**
  * Optimizes `val x by C` where `C` is either a constant or singleton: instead of storing the value `C` in a field, we access it every time
@@ -34,7 +34,7 @@
     }
 }
 
-private class SingletonOrConstantDelegationTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() {
+private class SingletonOrConstantDelegationTransformer(val context: JvmBackendContext) : IrLeafTransformerVoid() {
     override fun visitClass(declaration: IrClass): IrClass {
         declaration.transformChildren(this, null)
         declaration.transformDeclarationsFlat {
@@ -47,7 +47,7 @@
         val delegate = getSingletonOrConstantForOptimizableDelegatedProperty() ?: return null
         val originalThis = parentAsClass.thisReceiver
 
-        class DelegateFieldAccessTransformer(val newReceiver: IrExpression) : IrElementTransformerVoid() {
+        class DelegateFieldAccessTransformer(val newReceiver: IrExpression) : IrLeafTransformerVoid() {
             override fun visitGetField(expression: IrGetField): IrExpression =
                 if (expression.symbol == backingField?.symbol) newReceiver else super.visitGetField(expression)
         }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt
index abdc9b1..0783a8a 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt
@@ -31,7 +31,7 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
 import org.jetbrains.kotlin.ir.util.createStaticFunctionWithReceivers
 import org.jetbrains.kotlin.ir.util.irCall
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
 import org.jetbrains.kotlin.utils.addToStdlib.getOrSetIfNull
 
 /**
@@ -41,12 +41,12 @@
     name = "StaticDefaultFunction",
     prerequisite = [/* JvmStaticInObjectLowering::class */]
 )
-internal class StaticDefaultFunctionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
+internal class StaticDefaultFunctionLowering(val context: JvmBackendContext) : IrLeafTransformerVoid(), FileLoweringPass {
     override fun lower(irFile: IrFile) {
         irFile.accept(this, null)
     }
 
-    override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement = super.visitFunction(
+    override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement = transformElement(
         if (declaration.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && declaration.dispatchReceiverParameter != null)
             getStaticFunctionWithReceivers(declaration).also {
                 it.body = declaration.moveBodyTo(it)
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt
index 0f6f4e6..852d375 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/SuspendLambdaLowering.kt
@@ -37,8 +37,8 @@
 import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
@@ -162,7 +162,7 @@
 
             // marking the parameters referenced in the function
             function.acceptChildrenVoid(
-                object : IrVisitorVoid() {
+                object : IrLeafVisitorVoid() {
                     override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
 
                     override fun visitGetValue(expression: IrGetValue) {
@@ -244,7 +244,7 @@
             }
 
             body = irFunction.moveBodyTo(this, mapOf())?.let { body ->
-                body.transform(object : IrElementTransformerVoid() {
+                body.transform(object : IrLeafTransformerVoid() {
                     override fun visitGetValue(expression: IrGetValue): IrExpression {
                         val parameter = (expression.symbol.owner as? IrValueParameter)?.takeIf { it.parent == irFunction }
                             ?: return expression
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt
index 0160f27..cbbc3a4 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TailCallOptimizationLowering.kt
@@ -19,7 +19,7 @@
 import org.jetbrains.kotlin.ir.util.isFunctionInlining
 import org.jetbrains.kotlin.ir.util.isSuspend
 import org.jetbrains.kotlin.ir.util.parentAsClass
-import org.jetbrains.kotlin.ir.visitors.IrTransformer
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformer
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.name.Name
 
@@ -31,7 +31,7 @@
 @PhaseDescription(name = "TailCallOptimization")
 internal class TailCallOptimizationLowering(private val context: JvmBackendContext) : FileLoweringPass {
     override fun lower(irFile: IrFile) {
-        irFile.transformChildren(object : IrTransformer<TailCallOptimizationData?>() {
+        irFile.transformChildren(object : IrLeafTransformer<TailCallOptimizationData?>() {
             override fun visitSimpleFunction(declaration: IrSimpleFunction, data: TailCallOptimizationData?) =
                 super.visitSimpleFunction(declaration, if (declaration.isSuspend) TailCallOptimizationData(declaration) else null)
 
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt
index acc085a..256f578 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt
@@ -37,7 +37,7 @@
 import org.jetbrains.kotlin.ir.util.isNullable
 import org.jetbrains.kotlin.ir.util.isSubtypeOf
 import org.jetbrains.kotlin.ir.util.isSubtypeOfClass
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.name.Name
@@ -801,7 +801,7 @@
     private fun IrElement.extents(): Pair<Int, Int> {
         var startOffset = Int.MAX_VALUE
         var endOffset = 0
-        acceptVoid(object : IrVisitorVoid() {
+        acceptVoid(object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 element.acceptChildrenVoid(this)
                 if (element.startOffset in 0 until startOffset)
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/UniqueLoopLabelsLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/UniqueLoopLabelsLowering.kt
index 73e16b3..50d13ff 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/UniqueLoopLabelsLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/UniqueLoopLabelsLowering.kt
@@ -11,8 +11,10 @@
 import org.jetbrains.kotlin.ir.IrElement
 import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
 import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.expressions.IrDoWhileLoop
 import org.jetbrains.kotlin.ir.expressions.IrLoop
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.name.Name
@@ -23,7 +25,7 @@
 @PhaseDescription(name = "UniqueLoopLabels")
 internal class UniqueLoopLabelsLowering(@Suppress("UNUSED_PARAMETER", "unused") context: JvmBackendContext) : FileLoweringPass {
     override fun lower(irFile: IrFile) {
-        irFile.acceptVoid(object : IrVisitorVoid() {
+        irFile.acceptVoid(object : IrLeafVisitorVoid() {
             // This counter is intentionally not local to every declaration because their names might clash.
             private var counter = 0
             private val stack = ArrayList<Name>()
@@ -38,11 +40,19 @@
                 }
             }
 
-            override fun visitLoop(loop: IrLoop) {
+            private fun visitLoop(loop: IrLoop) {
                 // Give all loops unique labels so that we can generate unambiguous instructions for non-local
                 // `break`/`continue` statements.
                 loop.label = stack.joinToString("$", postfix = (++counter).toString())
-                super.visitLoop(loop)
+                visitElement(loop)
+            }
+
+            override fun visitWhileLoop(loop: IrWhileLoop) {
+                visitLoop(loop)
+            }
+
+            override fun visitDoWhileLoop(loop: IrDoWhileLoop) {
+                visitLoop(loop)
             }
         })
     }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
index c045ad4..376db29 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
@@ -30,7 +30,7 @@
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.util.isNullable
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
 import org.jetbrains.kotlin.load.java.JvmAnnotationNames
@@ -427,7 +427,7 @@
 
     private fun makeLambdaParameterNullable(function: IrFunction, parameter: IrValueParameter) {
         parameter.type = parameter.type.makeNullable()
-        function.body?.accept(object : IrVisitorVoid() {
+        function.body?.accept(object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 element.acceptChildren(this, null)
             }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/irValidation.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/irValidation.kt
index 2005ec6..4b2f431 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/irValidation.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/irValidation.kt
@@ -17,7 +17,7 @@
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
 import org.jetbrains.kotlin.ir.declarations.IrProperty
 import org.jetbrains.kotlin.ir.util.fileOrNull
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 
@@ -58,7 +58,7 @@
             }
         }
 
-        val validator = object : IrVisitorVoid() {
+        val validator = object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 element.acceptChildrenVoid(this)
             }
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
index aae2649..5432d7c 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
@@ -46,8 +46,8 @@
 import org.jetbrains.kotlin.ir.util.getArrayElementType
 import org.jetbrains.kotlin.ir.util.isBoxedArray
 import org.jetbrains.kotlin.ir.util.isSubtypeOf
-import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
 import org.jetbrains.kotlin.load.java.JvmAbi
@@ -138,7 +138,7 @@
     irClass: IrClass,
     oldThisReceiverParameter: IrValueParameter
 ) {
-    transformChildrenVoid(object : IrElementTransformerVoid() {
+    transformChildrenVoid(object : IrLeafTransformerVoid() {
         override fun visitGetValue(expression: IrGetValue): IrExpression =
             if (expression.symbol == oldThisReceiverParameter.symbol) {
                 IrGetFieldImpl(
@@ -294,7 +294,7 @@
 
 inline fun IrElement.hasChild(crossinline block: (IrElement) -> Boolean): Boolean {
     var result = false
-    acceptChildren(object : IrVisitorVoid() {
+    acceptChildren(object : IrLeafVisitorVoid() {
         override fun visitElement(element: IrElement) = when {
             result -> Unit
             block(element) -> result = true
diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt
index 5289d5c..471cce1 100644
--- a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt
+++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt
@@ -26,7 +26,7 @@
 import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl
 import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
 import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.IrLeafVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
@@ -108,10 +108,10 @@
     // which would throw ConcurrentModificationException.
     // The workaround is to traverse the subtree over snapshots first.
 
-    acceptVoid(object : IrVisitorVoid() {
+    acceptVoid(object : IrLeafVisitorVoid() {
         override fun visitElement(element: IrElement) {
             val directChildrenSnapshot = mutableListOf<IrElement>()
-            element.acceptChildrenVoid(object : IrVisitorVoid() {
+            element.acceptChildrenVoid(object : IrLeafVisitorVoid() {
                 override fun visitElement(element: IrElement) {
                     directChildrenSnapshot += element
                 }
@@ -201,7 +201,7 @@
 ) {
     val builder = makeSimpleFakeOverrideBuilder(symbolTable, typeSystemContext, symbolDeserializer)
     toplevel.acceptChildrenVoid(
-        object : IrVisitorVoid() {
+        object : IrLeafVisitorVoid() {
             override fun visitElement(element: IrElement) {
                 element.acceptChildrenVoid(this)
             }