From 9d1d6a7b1ff11a1d89c047c535bd724065604141 Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Tue, 1 Oct 2019 12:35:04 +0200 Subject: [PATCH] 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. --- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 14 ++ .../jvm/lower/InterfaceDelegationLowering.kt | 120 +++++++-------- .../backend/jvm/lower/InterfaceLowering.kt | 140 +++++++++++++----- .../jvm/lower/SyntheticAccessorLowering.kt | 9 +- .../ir/declarations/impl/IrFunctionImpl.kt | 2 - .../compatibility/defaultImplementations.kt | 22 +++ .../defaults/onlyJvmDefaultsOnInterface.kt | 20 +++ .../flags/WriteFlagsTestGenerated.java | 10 ++ .../codegen/ir/IrWriteFlagsTestGenerated.java | 10 ++ 9 files changed, 228 insertions(+), 119 deletions(-) create mode 100644 compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt create mode 100644 compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt 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 91e199248a1..1a798b1201f 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 @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt index 8fe274dccd7..6bfe8d07bca 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt @@ -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() - 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()?.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) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt index 48de8e6f727..bc5bef6200e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt @@ -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() + private val removedFunctions = hashMapOf() 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): 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( diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 2db2d699d5e..b1ceed403ef 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -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>() private val inlineLambdaToCallSite = mutableMapOf() diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt index a4c52ae6097..11b61f28234 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt @@ -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 diff --git a/compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt b/compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt new file mode 100644 index 00000000000..59c79abb5d5 --- /dev/null +++ b/compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt b/compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt new file mode 100644 index 00000000000..52c0a3599d5 --- /dev/null +++ b/compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java index 86faacbe235..505846bc039 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/flags/WriteFlagsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java index 7c78ee96a47..a4540d053f2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrWriteFlagsTestGenerated.java @@ -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");