JVM IR: Do not generate DefaultImpls if it's empty. This revealed that InterfaceDelegationLowering was relying on the presence of DefaultImpls even when empty. Hence, simply dropping it from InterfaceLowering was not trivial. Moved default delegation in DefaultImpls to SuperType.DefaultImpls to InterfaceLowering. Clean up logic considerably, and document inter-phase dependencies.

This commit is contained in:
Kristoffer Andersen
2019-10-01 12:35:04 +02:00
committed by max-kammerer
parent cc6252098f
commit 9d1d6a7b1f
9 changed files with 228 additions and 119 deletions
@@ -144,6 +144,13 @@ private val defaultArgumentInjectorPhase = makeIrFilePhase(
prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase)
)
private val interfacePhase = makeIrFilePhase(
::InterfaceLowering,
name = "Interface",
description = "Move default implementations of interface members to DefaultImpls class",
prerequisite = setOf(defaultArgumentInjectorPhase)
)
private val innerClassesPhase = makeIrFilePhase(
::InnerClassesLowering,
name = "InnerClasses",
@@ -158,6 +165,13 @@ private val returnableBlocksPhase = makeIrFilePhase(
prerequisite = setOf(arrayConstructorPhase, assertionPhase)
)
private val syntheticAccessorPhase = makeIrFilePhase(
::SyntheticAccessorLowering,
name = "SyntheticAccessor",
description = "Introduce synthetic accessors",
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
)
@Suppress("Reformat")
private val jvmFilePhases =
typeAliasAnnotationMethodsPhase then
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
import org.jetbrains.kotlin.descriptors.Modality
@@ -39,7 +38,6 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.function.UnaryOperator
internal val interfaceDelegationPhase = makeIrFilePhase(
::InterfaceDelegationLowering,
@@ -68,95 +66,80 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
}
private fun generateInterfaceMethods(irClass: IrClass) {
val (actualClass, isDefaultImplsGeneration) = if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
Pair(irClass.parent as IrClass, true)
} else {
Pair(irClass, false)
}
val toRemove = mutableListOf<IrSimpleFunction>()
for (function in actualClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop
for (function in irClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop
if (function.origin !== IrDeclarationOrigin.FAKE_OVERRIDE) continue
// In classes, only generate interface delegation for functions immediately inherited from an interface.
// Only generate interface delegation for functions immediately inherited from an interface.
// (Otherwise, delegation will be present in the parent class)
if (!isDefaultImplsGeneration &&
function.overriddenSymbols.any {
(!it.owner.parentAsClass.isInterface || it.owner.hasJvmDefault()) &&
it.owner.modality != Modality.ABSTRACT
}
) {
if (function.overriddenSymbols.any { !it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT }) {
continue
}
val implementation = function.resolveFakeOverride() ?: continue
if (!implementation.hasInterfaceParent() ||
Visibilities.isPrivate(implementation.visibility) ||
implementation.isDefinitelyNotDefaultImplsMethod() ||
implementation.isMethodOfAny() ||
(!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault())
if (!implementation.hasInterfaceParent()
|| Visibilities.isPrivate(implementation.visibility)
|| implementation.isDefinitelyNotDefaultImplsMethod()
|| implementation.isMethodOfAny()
|| (!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault())
) {
continue
}
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function, isDefaultImplsGeneration)
if (!isDefaultImplsGeneration) {
toRemove.add(function)
replacementMap[function.symbol] = delegation.symbol
}
toRemove.add(function)
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function)
irClass.declarations.add(delegation)
replacementMap[function.symbol] = delegation.symbol
}
irClass.declarations.removeAll(toRemove)
}
private fun generateDelegationToDefaultImpl(
irClass: IrClass,
interfaceFun: IrSimpleFunction,
inheritedFun: IrSimpleFunction,
isDefaultImplsGeneration: Boolean
interfaceImplementation: IrSimpleFunction,
classOverride: IrSimpleFunction
): IrSimpleFunction {
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun)
val inheritedProperty = classOverride.correspondingPropertySymbol?.owner
val descriptor = DescriptorsToIrRemapper.remapDeclaredSimpleFunction(classOverride.descriptor)
val irFunction =
if (!isDefaultImplsGeneration) {
val inheritedProperty = inheritedFun.correspondingPropertySymbol?.owner
val descriptor = DescriptorsToIrRemapper.remapDeclaredSimpleFunction(inheritedFun.descriptor)
IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
inheritedFun.name,
Visibilities.PUBLIC,
inheritedFun.modality,
inheritedFun.returnType,
isInline = inheritedFun.isInline,
isExternal = false,
isTailrec = false,
isSuspend = inheritedFun.isSuspend
).apply {
descriptor.bind(this)
parent = irClass
overriddenSymbols.addAll(inheritedFun.overriddenSymbols)
copyParameterDeclarationsFrom(inheritedFun)
annotations.addAll(inheritedFun.annotations)
IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
classOverride.name,
Visibilities.PUBLIC,
classOverride.modality,
classOverride.returnType,
isInline = classOverride.isInline,
isExternal = false,
isTailrec = false,
isSuspend = classOverride.isSuspend
).apply {
descriptor.bind(this)
parent = irClass
overriddenSymbols.addAll(classOverride.overriddenSymbols)
copyParameterDeclarationsFrom(classOverride)
annotations.addAll(classOverride.annotations)
if (inheritedProperty != null) {
val propertyDescriptor = DescriptorsToIrRemapper.remapDeclaredProperty(inheritedProperty.descriptor)
IrPropertyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, IrPropertySymbolImpl(propertyDescriptor),
inheritedProperty.name, Visibilities.PUBLIC, inheritedProperty.modality, inheritedProperty.isVar,
inheritedProperty.isConst, inheritedProperty.isLateinit, inheritedProperty.isDelegated, isExternal = false
).apply {
propertyDescriptor.bind(this)
parent = irClass
correspondingPropertySymbol = symbol
}
if (inheritedProperty != null) {
val propertyDescriptor = DescriptorsToIrRemapper.remapDeclaredProperty(inheritedProperty.descriptor)
IrPropertyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, IrPropertySymbolImpl(propertyDescriptor),
inheritedProperty.name, Visibilities.PUBLIC, inheritedProperty.modality, inheritedProperty.isVar,
inheritedProperty.isConst, inheritedProperty.isLateinit, inheritedProperty.isDelegated, isExternal = false
).apply {
propertyDescriptor.bind(this)
parent = irClass
correspondingPropertySymbol = symbol
}
}
} else context.declarationFactory.getDefaultImplsFunction(inheritedFun)
irClass.declarations.add(irFunction)
}
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceImplementation)
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
irFunction.body = irBlockBody {
+irReturn(
@@ -182,7 +165,7 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
}
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
declaration.overriddenSymbols.replaceAll(UnaryOperator { symbol -> replacementMap[symbol] ?: symbol })
declaration.overriddenSymbols.replaceAll { symbol -> replacementMap[symbol] ?: symbol }
super.visitSimpleFunction(declaration)
}
}
@@ -234,7 +217,8 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
val callee = expression.symbol.owner
if (callee.parent.safeAs<IrClass>()?.isInterface != true ||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
(callee.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility)
) {
return super.visitCall(expression)
}
@@ -7,14 +7,17 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.ir.copyBodyToStatic
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering.Companion.clinitName
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -23,62 +26,95 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal val interfacePhase = makeIrFilePhase(
::InterfaceLowering,
name = "Interface",
description = "Move default implementations of interface members to DefaultImpls class"
)
/**
* This phase moves interface members with default implementations to the
* associated companion DefaultImpls with bridges, as appropriate. It then
* performs a traversal of any other code in this interface and redirects calls
* to the interface to the companion, if functions were moved completely.
*/
internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
private class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
val state = context.state
val removedFunctions = hashMapOf<IrFunctionSymbol, IrFunctionSymbol>()
private val removedFunctions = hashMapOf<IrFunctionSymbol, IrFunctionSymbol>()
override fun lower(irClass: IrClass) {
if (!irClass.isInterface) return
val defaultImplsIrClass = context.declarationFactory.getDefaultImplsClass(irClass)
//TODO: Don't add DefaultImpls if it's empty. Just like the old backend...?
irClass.declarations.add(defaultImplsIrClass)
val members = defaultImplsIrClass.declarations
for (function in irClass.declarations) {
if (function !is IrSimpleFunction) continue
// There are 6 cases for functions on interfaces:
loop@ for (function in irClass.functions) {
when {
/**
* 1) They are plain abstract interface functions, in which case we leave them:
*/
function.modality == Modality.ABSTRACT ->
continue@loop
if (function.modality != Modality.ABSTRACT && function.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
/**
* 2) They inherit a default implementation from an interface this interface
* extends: create a bridge from companion to companion, if necessary:
*
* ```
* interface A { fun foo() = 0 }
* interface B : A { }
* ```
*
* yields
*
* ```
* interface A { fun foo(); class DefaultImpls { fun foo() = 0 } } // !! by Case 4 !!
* interface B : A { class DefaultImpls { fun foo() = A.DefaultImpls.foo() } }
* ```
*/
function.origin == IrDeclarationOrigin.FAKE_OVERRIDE -> {
val implementation = function.resolveFakeOverride()!!
if(function.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility && !mustMoveToDefaultImpls(function)) continue
val element = context.declarationFactory.getDefaultImplsFunction(function).also {
if (mustMoveToDefaultImpls(function))
removedFunctions[function.symbol] = it.symbol
if (!Visibilities.isPrivate(implementation.visibility)
&& !implementation.isMethodOfAny()
&& (!implementation.hasJvmDefault() || context.state.jvmDefaultMode.isCompatibility)
) {
delegateInheritedDefaultImplementationToDefaultImpls(function, implementation, defaultImplsIrClass)
}
}
members.add(element)
copyBodyToStatic(function, element)
element.body = element.body?.patchDeclarationParents(element)
/**
* 3) Private methods, default parameter dispatchers (without @JvmDefault)
* and $annotation methods are always moved without bridges
*/
Visibilities.isPrivate(function.visibility)
|| (function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && !function.hasJvmDefault())
|| function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS -> {
val defaultImpl = createDefaultImpl(function, members)
removedFunctions[function.symbol] = defaultImpl.symbol
}
if (function.hasJvmDefault() &&
function.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
) {
function.body = IrExpressionBodyImpl(callDefaultImpls(element, function))
} else {
/**
* 4) _Without_ @JvmDefault, the default implementation is moved to DefaultImpls and
* an abstract stub is left.
*/
!function.hasJvmDefault() -> {
createDefaultImpl(function, members)
function.body = null
//TODO reset modality to abstract
}
/**
* 5) _With_ @JvmDefault, we move and bridge if in compatibility mode, ...
*/
context.state.jvmDefaultMode.isCompatibility -> {
val defaultImpl = createDefaultImpl(function, members)
function.body = IrExpressionBodyImpl(createDelegatingCall(defaultImpl, function))
}
// 6) ... otherwise we simply leave the default function implementation on the interface.
}
}
// Update IrElements (e.g., IrCalls) to point to the new functions.
irClass.transformChildrenVoid(this)
irClass.declarations.removeAll {
it is IrFunction && removedFunctions.containsKey(it.symbol)
}
@@ -99,14 +135,20 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
delegatedPropertyArray.parent = defaultImplsIrClass
delegatedPropertyArray.initializer?.patchDeclarationParents(defaultImplsIrClass)
}
if (defaultImplsIrClass.declarations.isNotEmpty()) irClass.declarations.add(defaultImplsIrClass)
// Update IrElements (e.g., IrCalls) to point to the new functions.
irClass.transformChildrenVoid(this)
}
private fun mustMoveToDefaultImpls(function: IrFunction): Boolean =
Visibilities.isPrivate(function.visibility) && function.name != clinitName ||
function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
private fun createDefaultImpl(function: IrSimpleFunction, members: MutableList<IrDeclaration>): IrSimpleFunction =
context.declarationFactory.getDefaultImplsFunction(function).also {
it.body = function.body?.patchDeclarationParents(it)
copyBodyToStatic(function, it)
members.add(it)
}
private fun callDefaultImpls(defaultImpls: IrFunction, interfaceMethod: IrFunction): IrCall {
private fun createDelegatingCall(defaultImpls: IrFunction, interfaceMethod: IrFunction): IrCall {
val startOffset = interfaceMethod.startOffset
val endOffset = interfaceMethod.endOffset
@@ -126,6 +168,22 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
}
}
private fun delegateInheritedDefaultImplementationToDefaultImpls(
fakeOverride: IrSimpleFunction,
implementation: IrSimpleFunction,
defaultImpls: IrClass
) {
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(implementation)
val irFunction = context.declarationFactory.getDefaultImplsFunction(fakeOverride)
defaultImpls.declarations.add(irFunction)
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
irFunction.body = irBlockBody {
+irReturn(createDelegatingCall(defaultImplFun, irFunction))
}
}
}
override fun visitReturn(expression: IrReturn): IrExpression {
val newFunction = removedFunctions[expression.returnTargetSymbol]?.owner
return super.visitReturn(
@@ -36,14 +36,7 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
internal val syntheticAccessorPhase = makeIrFilePhase(
::SyntheticAccessorLowering,
name = "SyntheticAccessor",
description = "Introduce synthetic accessors",
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase)
)
private class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
private val pendingTransformations = mutableListOf<Function0<Unit>>()
private val inlineLambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
@@ -11,12 +11,10 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.name
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartList
@@ -0,0 +1,22 @@
// !JVM_DEFAULT_MODE: compatibility
// JVM_TARGET: 1.8
// WITH_RUNTIME
interface A {
@JvmDefault
fun foo(x: Int = 0): Int {
return x
}
}
// TESTED_OBJECT_KIND: innerClass
// TESTED_OBJECTS: A, DefaultImpls
// FLAGS: ACC_FINAL, ACC_STATIC, ACC_PUBLIC
// TESTED_OBJECT_KIND: function
// TESTED_OBJECTS: A, foo$default
// FLAGS: ACC_PUBLIC, ACC_SYNTHETIC, ACC_STATIC
// TESTED_OBJECT_KIND: function
// TESTED_OBJECTS: A$DefaultImpls, foo$default
// FLAGS: ACC_PUBLIC, ACC_SYNTHETIC, ACC_STATIC
@@ -0,0 +1,20 @@
// !JVM_DEFAULT_MODE: enable
// JVM_TARGET: 1.8
// WITH_RUNTIME
interface Test {
@JvmDefault
fun foo(): String {
return "OK"
}
@JvmDefault
fun bar(x: String = "OK"): String {
return x
}
}
// TESTED_OBJECT_KIND: innerClass
// TESTED_OBJECTS: Test, DefaultImpls
// ABSENT: TRUE
@@ -756,6 +756,11 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
}
@TestMetadata("onlyJvmDefaultsOnInterface.kt")
public void testOnlyJvmDefaultsOnInterface() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt");
}
@TestMetadata("propertyAnnotation.kt")
public void testPropertyAnnotation() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
@@ -773,6 +778,11 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("defaultImplementations.kt")
public void testDefaultImplementations() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt");
}
@TestMetadata("propertyAccessors.kt")
public void testPropertyAccessors() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");
@@ -756,6 +756,11 @@ public class IrWriteFlagsTestGenerated extends AbstractIrWriteFlagsTest {
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
}
@TestMetadata("onlyJvmDefaultsOnInterface.kt")
public void testOnlyJvmDefaultsOnInterface() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt");
}
@TestMetadata("propertyAnnotation.kt")
public void testPropertyAnnotation() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
@@ -773,6 +778,11 @@ public class IrWriteFlagsTestGenerated extends AbstractIrWriteFlagsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("defaultImplementations.kt")
public void testDefaultImplementations() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt");
}
@TestMetadata("propertyAccessors.kt")
public void testPropertyAccessors() throws Exception {
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");