From 6be9101675e38fca41c4f767c6796b60824c0374 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 31 Oct 2019 16:56:04 +0100 Subject: [PATCH] JVM IR: add jvmLocalClassExtractionPhase to lift out local classes from initializers Otherwise a local class in a field initializer or anonymous init block is copied into each constructor of the containing class (because InitializersLowering calls deepCopy). Since the code structure no longer resembles the original source code here, record a custom EnclosingMethod mapping before moving such classes, and use it in codegen. --- .../common/lower/LocalClassPopupLowering.kt | 21 ++++++--- .../kotlin/backend/jvm/JvmBackendContext.kt | 9 ++-- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 11 ++++- .../backend/jvm/codegen/ClassCodegen.kt | 8 ++-- .../backend/jvm/codegen/irCodegenUtils.kt | 7 +-- .../jvm/lower/JvmLocalClassPopupLowering.kt | 47 +++++++++++++++++++ .../enclosing/lambdaInPropertyDelegate.kt | 47 +++++++++++++++++++ ...dataForMembersInLocalClassInInitializer.kt | 27 +++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 ++ ...mpileKotlinAgainstKotlinTestGenerated.java | 5 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 ++ ...mpileKotlinAgainstKotlinTestGenerated.java | 5 ++ 13 files changed, 182 insertions(+), 20 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmLocalClassPopupLowering.kt create mode 100644 compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalClassPopupLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalClassPopupLowering.kt index 42d96652902..e4c55f0dbdf 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalClassPopupLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalClassPopupLowering.kt @@ -1,8 +1,14 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ScopeWithIr import org.jetbrains.kotlin.backend.common.ir.addChild import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass @@ -12,8 +18,7 @@ import org.jetbrains.kotlin.ir.declarations.IrScript import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl //This lower takes part of old LocalDeclarationLowering job to pop up local classes from functions -class LocalClassPopupLowering(val context: BackendContext) : FileLoweringPass { - +open class LocalClassPopupLowering(val context: BackendContext) : FileLoweringPass { override fun lower(irFile: IrFile) { val extractedLocalClasses = arrayListOf>() @@ -21,9 +26,10 @@ class LocalClassPopupLowering(val context: BackendContext) : FileLoweringPass { override fun visitClassNew(declaration: IrClass): IrStatement { val newDeclaration = super.visitClassNew(declaration) - if (newDeclaration !is IrClass || !newDeclaration.isLocalNotInner()) { - return newDeclaration - } + if (newDeclaration !is IrClass) return newDeclaration + + val currentScope = allScopes[allScopes.lastIndex - 1] + if (!shouldPopUp(declaration, currentScope)) return newDeclaration val newContainer = allScopes.asReversed().drop(1/*skip self*/).firstOrNull { //find first class local or not; @@ -39,4 +45,7 @@ class LocalClassPopupLowering(val context: BackendContext) : FileLoweringPass { newContainer.addChild(local) } } -} \ No newline at end of file + + protected open fun shouldPopUp(klass: IrClass, currentScope: ScopeWithIr?): Boolean = + klass.isLocalNotInner() +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index b3c87e01859..70fcbeef58d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -27,12 +27,8 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol -import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol +import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName @@ -65,7 +61,6 @@ class JvmBackendContext( val irIntrinsics = IrIntrinsicMethods(irBuiltIns, ir.symbols) - // TODO: also store info for EnclosingMethod internal class LocalClassInfo(val internalName: String) private val localClassInfo = mutableMapOf() @@ -77,6 +72,8 @@ class JvmBackendContext( localClassInfo[container.attributeOwnerId] = value } + internal val customEnclosingFunction = mutableMapOf() + // TODO cache these at ClassCodegen level. Currently, sharing this map between classes in a module is required // because IrSourceCompilerForInline constructs a new (Fake)ClassCodegen for every call to // an inline function in the same module. Thus, if two inline functions happen to have the same name diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 5cfb6806d9f..68d4f74bb01 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -145,6 +145,12 @@ internal val localDeclarationsPhase = makeIrFilePhase( prerequisite = setOf(callableReferencePhase, sharedVariablesPhase) ) +private val jvmLocalClassExtractionPhase = makeIrFilePhase( + ::JvmLocalClassPopupLowering, + name = "JvmLocalClassExtraction", + description = "Move local classes from field initializers and anonymous init blocks into the containing class" +) + private val defaultArgumentStubPhase = makeIrFilePhase( ::JvmDefaultArgumentStubGenerator, name = "DefaultArgumentsStubGenerator", @@ -193,7 +199,9 @@ private val initializersPhase = makeIrFilePhase( error("No anonymous initializers should remain at this stage") } }) - }) + }), + // Depends on local class extraction, because otherwise local classes in initializers will be copied into each constructor. + prerequisite = setOf(jvmLocalClassExtractionPhase) ) private val returnableBlocksPhase = makeIrFilePhase( @@ -248,6 +256,7 @@ private val jvmFilePhases = assertionPhase then returnableBlocksPhase then localDeclarationsPhase then + jvmLocalClassExtractionPhase then jvmOverloadsAnnotationPhase then jvmDefaultConstructorPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 960a7a4100c..cc5e6762377 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -122,7 +122,7 @@ open class ClassCodegen protected constructor( val nestedClasses = irClass.declarations.mapNotNull { declaration -> if (declaration is IrClass) { - ClassCodegen(declaration, context, this) + ClassCodegen(declaration, context, this, withinInline = withinInline) } else null } @@ -411,9 +411,9 @@ open class ClassCodegen protected constructor( // or constructor, the name and type of the function is recorded as well. if (parentClassCodegen != null) { val outerClassName = parentClassCodegen.type.internalName - // TODO: LocalDeclarationsLowering could have moved this class out of its enclosing method. - if (parentFunction != null) { - val method = methodSignatureMapper.mapAsmMethod(parentFunction) + val enclosingFunction = context.customEnclosingFunction[irClass.attributeOwnerId] ?: parentFunction + if (enclosingFunction != null) { + val method = methodSignatureMapper.mapAsmMethod(enclosingFunction) visitor.visitOuterClass(outerClassName, method.name, method.descriptor) } else if (irClass.isAnonymousObject) { visitor.visitOuterClass(outerClassName, null, null) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index d175a2502cf..fbe42c7a02e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature @@ -110,10 +109,12 @@ val IrType.isExtensionFunctionType: Boolean get() = isFunctionTypeOrSubtype() && hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) -/* Borrowed from MemberCodegen.java */ +/* Borrowed with modifications from MemberCodegen.java */ fun writeInnerClass(innerClass: IrClass, typeMapper: IrTypeMapper, context: JvmBackendContext, v: ClassBuilder) { - val outerClassInternalName = innerClass.parent.safeAs()?.let { typeMapper.classInternalName(it) } + val outerClassInternalName = + if (context.customEnclosingFunction[innerClass.attributeOwnerId] != null) null + else innerClass.parent.safeAs()?.let(typeMapper::classInternalName) val innerName = innerClass.name.takeUnless { it.isSpecial }?.asString() val innerClassInternalName = typeMapper.classInternalName(innerClass) v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, innerClass.calculateInnerClassAccessFlags(context)) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmLocalClassPopupLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmLocalClassPopupLowering.kt new file mode 100644 index 00000000000..fbe06f50e84 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmLocalClassPopupLowering.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.lower.LocalClassPopupLowering +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.primaryConstructor +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull + +class JvmLocalClassPopupLowering(context: JvmBackendContext) : LocalClassPopupLowering(context) { + // On JVM, we only pop up local classes in field initializers and anonymous init blocks, so that InitializersLowering would not copy + // them to each constructor. (Moving all local classes is not possible because of cases where they use reified type parameters, + // or capture crossinline lambdas.) + // Upon moving such class, we record customEnclosingFunction for it to be the class constructor. This is needed because otherwise + // the class will not get any EnclosingMethod in the codegen later, since it won't be local anymore. + override fun shouldPopUp(klass: IrClass, currentScope: ScopeWithIr?): Boolean { + // On JVM, lambdas have package-private visibility after LocalDeclarationsLowering, so we have to check something else. + val isLocal = super.shouldPopUp(klass, currentScope) || + klass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL || + klass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL || + klass.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE + if (!isLocal) return false + + val container = when (val element = currentScope?.irElement) { + is IrAnonymousInitializer -> element.parentAsClass.takeUnless { element.isStatic } + is IrField -> element.parentAsClass.takeUnless { element.isStatic } + else -> null + } ?: return false + + // In case there's no primary constructor, it's unclear which constructor should be the enclosing one, so we select the first. + (context as JvmBackendContext).customEnclosingFunction[klass.attributeOwnerId] = + container.primaryConstructor ?: container.declarations.firstIsInstanceOrNull() + ?: error("Class in a non-static initializer found, but container has no constructors: ${container.render()}") + + return true + } +} diff --git a/compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt b/compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt new file mode 100644 index 00000000000..bb87f24898b --- /dev/null +++ b/compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt @@ -0,0 +1,47 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME + +class C { + val f by foo { + {} + } +} + +fun foo(f: () -> Any): Any = f() + +operator fun Any.getValue(thiz: Any?, metadata: Any?): Any = this + +fun box(): String { + // This is the class for lambda inside the `foo` call (`{}`) + val innerLambda = C().f.javaClass + + val emInner = innerLambda.getEnclosingMethod() + if (emInner?.getName() != "invoke") return "Fail: incorrect enclosing method for inner lambda: $emInner" + + val ecInner = innerLambda.getEnclosingClass() + if (ecInner?.getName() != "C\$f\$2") return "Fail: incorrect enclosing class for inner lambda: $ecInner" + + val ectorInner = innerLambda.getEnclosingConstructor() + if (ectorInner != null) return "Fail: inner lambda should not have enclosing constructor: $ectorInner" + + val dcInner = innerLambda.getDeclaringClass() + if (dcInner != null) return "Fail: inner lambda should not have declaring class: $dcInner" + + + // This is the class for lambda that is passed as an argument to `foo` + val outerLambda = ecInner + + val emOuter = outerLambda.getEnclosingMethod() + if (emOuter != null) return "Fail: outer lambda should not have enclosing method: $emOuter" + + val ecOuter = outerLambda.getEnclosingClass() + if (ecOuter?.getName() != "C") return "Fail: incorrect enclosing class for outer lambda: $ecOuter" + + val ectorOuter = outerLambda.getEnclosingConstructor() + if (ectorOuter == null) return "Fail: outer lambda _should_ have enclosing constructor" + + val dcOuter = outerLambda.getDeclaringClass() + if (dcOuter != null) return "Fail: outer lambda should not have declaring class: $dcOuter" + + return "OK" +} diff --git a/compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt b/compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt new file mode 100644 index 00000000000..97a5a63ccaf --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt @@ -0,0 +1,27 @@ +// TARGET_BACKEND: JVM +// FILE: A.kt + +class A { + val o = object { + @JvmName("jvmGetO") + fun getO(): String = "O" + } + + val k = object { + @get:JvmName("jvmGetK") + val k: String = "K" + } +} + +// FILE: B.kt + +import kotlin.reflect.full.* + +fun box(): String { + val a = A() + val obj1 = a.o + val o = obj1::class.declaredMemberFunctions.single().call(obj1) as String + val obj2 = a.k + val k = obj2::class.declaredMemberProperties.single().call(obj2) as String + return o + k +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index db331fa215b..743ebcb6c59 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -23105,6 +23105,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPackage.kt"); } + @TestMetadata("lambdaInPropertyDelegate.kt") + public void testLambdaInPropertyDelegate() throws Exception { + runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt"); + } + @TestMetadata("lambdaInPropertyGetter.kt") public void testLambdaInPropertyGetter() throws Exception { runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyGetter.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java index d76d36451b8..6911f4f087e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java @@ -223,6 +223,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl runTest("compiler/testData/compileKotlinAgainstKotlin/kt21775.kt"); } + @TestMetadata("metadataForMembersInLocalClassInInitializer.kt") + public void testMetadataForMembersInLocalClassInInitializer() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt"); + } + @TestMetadata("multifileClassInlineFunctionAccessingProperty.kt") public void testMultifileClassInlineFunctionAccessingProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/multifileClassInlineFunctionAccessingProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index cf37f5f1a2f..1f19a9d81d1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -21922,6 +21922,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPackage.kt"); } + @TestMetadata("lambdaInPropertyDelegate.kt") + public void testLambdaInPropertyDelegate() throws Exception { + runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt"); + } + @TestMetadata("lambdaInPropertyGetter.kt") public void testLambdaInPropertyGetter() throws Exception { runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyGetter.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index b044eaa98b0..b9ffc252afe 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -21670,6 +21670,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPackage.kt"); } + @TestMetadata("lambdaInPropertyDelegate.kt") + public void testLambdaInPropertyDelegate() throws Exception { + runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyDelegate.kt"); + } + @TestMetadata("lambdaInPropertyGetter.kt") public void testLambdaInPropertyGetter() throws Exception { runTest("compiler/testData/codegen/box/reflection/enclosing/lambdaInPropertyGetter.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java index 4df8ce1c475..49effe78ca9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java @@ -218,6 +218,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile runTest("compiler/testData/compileKotlinAgainstKotlin/kt21775.kt"); } + @TestMetadata("metadataForMembersInLocalClassInInitializer.kt") + public void testMetadataForMembersInLocalClassInInitializer() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/metadataForMembersInLocalClassInInitializer.kt"); + } + @TestMetadata("multifileClassInlineFunctionAccessingProperty.kt") public void testMultifileClassInlineFunctionAccessingProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/multifileClassInlineFunctionAccessingProperty.kt");