IR: Align Interface Defaults with Old Backend
Change the treatment of default implementations on interfaces in JVM compatibility mode. Previously, the IR backend moved the actual default implementation to the DefaultImpls class, and then bridged to it from the interface default. The old backend did the reverse, at the cost of an additional accessor, in order to gain better binary compatibility properties. See #2612 for discussion. The accessor needs to call a specific implementation, so must be performed through an `invokespecial`. We trick the SyntheticAccessorLowering into doing this for us, by marking the bridging call as a super call. We do this in want of an explicit `invokespecial` Ir Node. InterfaceDefaultCallsPhase previously assumed the old behaviour of the IR backend (that calls to default implementations, e.g. `foo$default` should target `DefaultImpls.foo$default`). But now the bridge to foo$default resides on `DefaultImpls` already, causing that pass to create a recursive loop. We cut that loop with a simple check.
This commit is contained in:
committed by
max-kammerer
parent
b5de625350
commit
d1c2862e27
+8
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
@@ -164,7 +165,7 @@ internal val interfaceDefaultCallsPhase = makeIrFilePhase(
|
||||
description = "Redirect interface calls with default arguments to DefaultImpls"
|
||||
)
|
||||
|
||||
private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
// TODO If there are no default _implementations_ we can avoid generating defaultImpls class entirely by moving default arg dispatchers to the interface class
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
@@ -181,6 +182,12 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
|
||||
}
|
||||
|
||||
val redirectTarget = context.declarationFactory.getDefaultImplsFunction(callee as IrSimpleFunction)
|
||||
|
||||
// InterfaceLowering bridges from DefaultImpls in compatibility mode -- if that's the case,
|
||||
// this phase will inadvertently cause a recursive loop as the bridge on the DefaultImpls
|
||||
// gets redirected to call itself.
|
||||
if (redirectTarget == currentFunction?.irElement) return super.visitCall(expression)
|
||||
|
||||
val newCall = irCall(expression, redirectTarget, receiversAsArguments = true)
|
||||
|
||||
return super.visitCall(newCall)
|
||||
|
||||
+62
-38
@@ -9,7 +9,6 @@ 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.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
@@ -17,10 +16,6 @@ import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
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.irExprBody
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
@@ -74,7 +69,12 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
|
||||
/**
|
||||
* 2) They inherit a default implementation from an interface this interface
|
||||
* extends: create a bridge from companion to companion, if necessary:
|
||||
* extends: create a bridge from companion to companion, unless
|
||||
* - the implementation is private or belongs to java.lang.Object
|
||||
* - we're in JVM Compatibility Default mode, in which case we go via
|
||||
* accessors on the parent class rather than the DefaultImpls
|
||||
* - we're in JVM Default mode, and we have that default implementation,
|
||||
* in which case we simply leave it.
|
||||
*
|
||||
* ```
|
||||
* interface A { fun foo() = 0 }
|
||||
@@ -91,11 +91,20 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
function.origin == IrDeclarationOrigin.FAKE_OVERRIDE -> {
|
||||
val implementation = function.resolveFakeOverride()!!
|
||||
|
||||
if (!Visibilities.isPrivate(implementation.visibility)
|
||||
&& !implementation.isMethodOfAny()
|
||||
&& (!implementation.hasJvmDefault() || context.state.jvmDefaultMode.isCompatibility)
|
||||
) {
|
||||
delegateInheritedDefaultImplementationToDefaultImpls(function, implementation)
|
||||
when {
|
||||
Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() ->
|
||||
continue@loop
|
||||
context.state.jvmDefaultMode.isCompatibility -> {
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
defaultImpl.bridgeViaAccessorTo(function)
|
||||
}
|
||||
!implementation.hasJvmDefault() -> {
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
context.declarationFactory.getDefaultImplsFunction(implementation).also {
|
||||
defaultImpl.bridgeToStatic(it)
|
||||
}
|
||||
}
|
||||
// else -> Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +115,9 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
Visibilities.isPrivate(function.visibility)
|
||||
|| (function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && !function.hasJvmDefault())
|
||||
|| function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS -> {
|
||||
removedFunctions[function.symbol] = createDefaultImpl(function).symbol
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
function.copyImplementationTo(defaultImpl)
|
||||
removedFunctions[function.symbol] = defaultImpl.symbol
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +125,8 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
* an abstract stub is left.
|
||||
*/
|
||||
!function.hasJvmDefault() -> {
|
||||
createDefaultImpl(function)
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
function.copyImplementationTo(defaultImpl)
|
||||
function.body = null
|
||||
//TODO reset modality to abstract
|
||||
}
|
||||
@@ -124,7 +136,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
*/
|
||||
context.state.jvmDefaultMode.isCompatibility -> {
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
function.body = createDelegatingCall(defaultImpl, function)
|
||||
defaultImpl.bridgeViaAccessorTo(function)
|
||||
}
|
||||
|
||||
// 6) ... otherwise we simply leave the default function implementation on the interface.
|
||||
@@ -163,40 +175,52 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
}
|
||||
|
||||
private fun createDefaultImpl(function: IrSimpleFunction): IrSimpleFunction =
|
||||
context.declarationFactory.getDefaultImplsFunction(function).also { newFunction ->
|
||||
context.declarationFactory.getDefaultImplsFunction(function).also {newFunction ->
|
||||
newFunction.body = function.body?.patchDeclarationParents(newFunction)
|
||||
copyBodyToStatic(function, newFunction)
|
||||
newFunction.parentAsClass.declarations.add(newFunction)
|
||||
}
|
||||
|
||||
private fun createDelegatingCall(defaultImpls: IrFunction, interfaceMethod: IrFunction): IrExpressionBody {
|
||||
val startOffset = interfaceMethod.startOffset
|
||||
val endOffset = interfaceMethod.endOffset
|
||||
private fun IrSimpleFunction.copyImplementationTo(target: IrSimpleFunction) {
|
||||
copyBodyToStatic(this, target)
|
||||
}
|
||||
|
||||
return IrExpressionBodyImpl(IrCallImpl(startOffset, endOffset, interfaceMethod.returnType, defaultImpls.symbol).apply {
|
||||
passTypeArgumentsFrom(interfaceMethod)
|
||||
|
||||
var offset = 0
|
||||
interfaceMethod.dispatchReceiverParameter?.let {
|
||||
putValueArgument(offset++, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
||||
}
|
||||
interfaceMethod.extensionReceiverParameter?.let {
|
||||
putValueArgument(offset++, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
||||
}
|
||||
interfaceMethod.valueParameters.forEachIndexed { i, it ->
|
||||
putValueArgument(i + offset, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
||||
// Bridge from static to static method - simply fill the arguments to the parameters.
|
||||
// By nature of the generation of both source and target of bridge, they line up.
|
||||
private fun IrFunction.bridgeToStatic(callTarget: IrFunction) {
|
||||
body = IrExpressionBodyImpl(IrCallImpl(startOffset, endOffset, returnType, callTarget.symbol).also { call ->
|
||||
call.passTypeArgumentsFrom(this)
|
||||
valueParameters.forEachIndexed { i, it ->
|
||||
call.putValueArgument(i, IrGetValueImpl(startOffset, endOffset, it.symbol))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun delegateInheritedDefaultImplementationToDefaultImpls(fakeOverride: IrSimpleFunction, implementation: IrSimpleFunction) {
|
||||
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(implementation)
|
||||
val irFunction = context.declarationFactory.getDefaultImplsFunction(fakeOverride)
|
||||
// Bridge from static DefaultImpl method to the interface method. Arguments need to
|
||||
// be shifted in presence of dispatch and extension receiver.
|
||||
private fun IrFunction.bridgeViaAccessorTo(callTarget: IrFunction) {
|
||||
body = IrExpressionBodyImpl(
|
||||
IrCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
returnType,
|
||||
callTarget.symbol,
|
||||
superQualifierSymbol = callTarget.parentAsClass.symbol
|
||||
).also { call ->
|
||||
call.passTypeArgumentsFrom(this)
|
||||
|
||||
irFunction.parentAsClass.declarations.add(irFunction)
|
||||
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
||||
irFunction.body = createDelegatingCall(defaultImplFun, irFunction)
|
||||
}
|
||||
var offset = 0
|
||||
callTarget.dispatchReceiverParameter?.let {
|
||||
call.dispatchReceiver = IrGetValueImpl(startOffset, endOffset, valueParameters[offset].symbol)
|
||||
offset += 1
|
||||
}
|
||||
callTarget.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = IrGetValueImpl(startOffset, endOffset, valueParameters[offset].symbol)
|
||||
offset += 1
|
||||
}
|
||||
for (i in offset until valueParameters.size) {
|
||||
call.putValueArgument(i - 1, IrGetValueImpl(startOffset, endOffset, valueParameters[i].symbol))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
|
||||
+41
-36
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters
|
||||
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.intrinsics.receiverAndArgs
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
|
||||
@@ -187,48 +188,52 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
|
||||
private fun IrSimpleFunction.makeSimpleFunctionAccessor(expression: IrCall): IrSimpleFunction {
|
||||
val source = this
|
||||
|
||||
// Find the right container to insert the accessor. Simply put, when we call a function on a class A,
|
||||
// we also need to put its accessor into A. However, due to the way that calls are implemented in the
|
||||
// IR we generally need to look at the type of the dispatchReceiver *argument* in order to find the
|
||||
// correct class. Consider the following code:
|
||||
//
|
||||
// fun run(f : () -> Int): Int = f()
|
||||
//
|
||||
// open class A {
|
||||
// private fun f() = 0
|
||||
// fun g() = run { this.f() }
|
||||
// }
|
||||
//
|
||||
// class B : A {
|
||||
// override fun g() = 1
|
||||
// fun h() = run { super.g() }
|
||||
// }
|
||||
//
|
||||
// We have calls to the private methods A.f from a generated Lambda subclass for the argument to `run`
|
||||
// in class A and a super call to A.g from a generated Lambda subclass in class B.
|
||||
//
|
||||
// In the first case, we need to produce an accessor in class A to access the private member of A.
|
||||
// Both the parent of the function f and the type of the dispatch receiver point to the correct class.
|
||||
// In the second case we need to call A.g from within class B, since this is the only way to invoke
|
||||
// a method of a superclass on the JVM. However, the IR for the call to super.g points directly to the
|
||||
// function g in class A. Confusingly, the `superQualifier` on this call also points to class A.
|
||||
// The only way to compute the actual enclosing class for the call is by looking at the type of the
|
||||
// dispatch receiver argument, which points to B.
|
||||
//
|
||||
// Beyond this, there can be accessors that are needed because other lowerings produce code calling
|
||||
// private methods (e.g., local functions for lambdas are private and called from generated
|
||||
// SAM wrapper classes). In this case we rely on the parent field of the called function.
|
||||
//
|
||||
// Finally, we need to produce accessors for calls to protected static methods coming from Java,
|
||||
// which we put in the closest enclosing class which has access to the method in question.
|
||||
val dispatchReceiverType = expression.dispatchReceiver?.type
|
||||
val parent = source.accessorParent(dispatchReceiverType?.classOrNull?.owner ?: source.parent)
|
||||
|
||||
return buildFun {
|
||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
|
||||
name = source.accessorName()
|
||||
visibility = Visibilities.PUBLIC
|
||||
modality = if (parent is IrClass && parent.isJvmInterface) Modality.OPEN else Modality.FINAL
|
||||
isSuspend = source.isSuspend // synthetic accessors of suspend functions are handled in codegen
|
||||
}.also { accessor ->
|
||||
// Find the right container to insert the accessor. Simply put, when we call a function on a class A,
|
||||
// we also need to put its accessor into A. However, due to the way that calls are implemented in the
|
||||
// IR we generally need to look at the type of the dispatchReceiver *argument* in order to find the
|
||||
// correct class. Consider the following code:
|
||||
//
|
||||
// fun run(f : () -> Int): Int = f()
|
||||
//
|
||||
// open class A {
|
||||
// private fun f() = 0
|
||||
// fun g() = run { this.f() }
|
||||
// }
|
||||
//
|
||||
// class B : A {
|
||||
// override fun g() = 1
|
||||
// fun h() = run { super.g() }
|
||||
// }
|
||||
//
|
||||
// We have calls to the private methods A.f from a generated Lambda subclass for the argument to `run`
|
||||
// in class A and a super call to A.g from a generated Lambda subclass in class B.
|
||||
//
|
||||
// In the first case, we need to produce an accessor in class A to access the private member of A.
|
||||
// Both the parent of the function f and the type of the dispatch receiver point to the correct class.
|
||||
// In the second case we need to call A.g from within class B, since this is the only way to invoke
|
||||
// a method of a superclass on the JVM. However, the IR for the call to super.g points directly to the
|
||||
// function g in class A. Confusingly, the `superQualifier` on this call also points to class A.
|
||||
// The only way to compute the actual enclosing class for the call is by looking at the type of the
|
||||
// dispatch receiver argument, which points to B.
|
||||
//
|
||||
// Beyond this, there can be accessors that are needed because other lowerings produce code calling
|
||||
// private methods (e.g., local functions for lambdas are private and called from generated
|
||||
// SAM wrapper classes). In this case we rely on the parent field of the called function.
|
||||
//
|
||||
// Finally, we need to produce accessors for calls to protected static methods coming from Java,
|
||||
// which we put in the closest enclosing class which has access to the method in question.
|
||||
val dispatchReceiverType = expression.dispatchReceiver?.type
|
||||
accessor.parent = source.accessorParent(dispatchReceiverType?.classOrNull?.owner ?: source.parent)
|
||||
accessor.parent = parent
|
||||
pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) }
|
||||
|
||||
accessor.copyTypeParametersFrom(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR)
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
interface A {
|
||||
@JvmDefault
|
||||
fun String.foo() = "OK"
|
||||
}
|
||||
|
||||
fun box(): String =
|
||||
object : A { fun box() = "FAIL".foo() }.box()
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
// FULL_JDK
|
||||
|
||||
@@ -10,7 +9,7 @@ interface KInterface {
|
||||
}
|
||||
}
|
||||
|
||||
// 1 INVOKESTATIC KInterface.access\$test\$jd
|
||||
// 1 INVOKESTATIC KInterface.access\$test\$
|
||||
// 1 INVOKESTATIC KInterface.test\$default
|
||||
|
||||
// from $default
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
interface A {
|
||||
@JvmDefault
|
||||
fun foo() = "FAIL"
|
||||
}
|
||||
|
||||
interface Left : A { }
|
||||
interface Right : A {
|
||||
@JvmDefault
|
||||
override fun foo() = "OK"
|
||||
}
|
||||
|
||||
interface C : Left, Right {}
|
||||
|
||||
fun box(): String {
|
||||
val x = object : C {}
|
||||
return x.foo()
|
||||
}
|
||||
|
||||
// 0 INVOKESTATIC .*\$DefaultImpls\.foo
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
interface KInterface {
|
||||
@@ -13,8 +12,8 @@ interface KInterface2 : KInterface {
|
||||
|
||||
}
|
||||
|
||||
// 1 INVOKESTATIC KInterface2.access\$test2\$jd
|
||||
// 1 INVOKESTATIC KInterface.access\$test2\$jd
|
||||
// 1 INVOKESTATIC KInterface2.access\$test2\$
|
||||
// 1 INVOKESTATIC KInterface.access\$test2\$
|
||||
|
||||
// 1 INVOKESPECIAL KInterface2.test2
|
||||
// 1 INVOKESPECIAL KInterface.test2
|
||||
|
||||
+6
-7
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
interface KInterface {
|
||||
@@ -14,11 +13,11 @@ interface KInterface2 : KInterface {
|
||||
abstract override fun test2(): String
|
||||
}
|
||||
|
||||
// 1 INVOKESTATIC KInterface.access\$test2\$jd
|
||||
// +
|
||||
// 0 INVOKESTATIC KInterface2.access\$test2\$jd
|
||||
// =
|
||||
// 1 INVOKESTATIC
|
||||
|
||||
// 1 INVOKESPECIAL KInterface.test2
|
||||
// 0 INVOKESPECIAL KInterface2.test2
|
||||
|
||||
// 1 INVOKESTATIC KInterface.access\$test2\$
|
||||
// +
|
||||
// 0 INVOKESTATIC KInterface2.access\$test2\$
|
||||
// =
|
||||
// 1 INVOKESTATIC KInterface
|
||||
+4
-5
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
interface KInterface {
|
||||
@@ -14,10 +13,10 @@ interface KInterface2 : KInterface {
|
||||
|
||||
}
|
||||
|
||||
// 1 INVOKESTATIC KInterface2.access\$getBar\$jd
|
||||
// 1 INVOKESTATIC KInterface2.access\$setBar\$jd
|
||||
// 1 INVOKESTATIC KInterface.access\$getBar\$jd
|
||||
// 1 INVOKESTATIC KInterface.access\$setBar\$jd
|
||||
// 1 INVOKESTATIC KInterface2.access\$getBar\$
|
||||
// 1 INVOKESTATIC KInterface2.access\$setBar\$
|
||||
// 1 INVOKESTATIC KInterface.access\$getBar\$
|
||||
// 1 INVOKESTATIC KInterface.access\$setBar\$
|
||||
|
||||
// 1 INVOKESPECIAL KInterface2.getBar
|
||||
// 1 INVOKESPECIAL KInterface2.setBar
|
||||
|
||||
+5
@@ -14863,6 +14863,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceExtension.kt")
|
||||
public void testInterfaceExtension() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/interfaceExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAnnotation.kt")
|
||||
public void testPropertyAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/propertyAnnotation.kt");
|
||||
|
||||
@@ -3002,6 +3002,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/defaultArgs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleDiamond.kt")
|
||||
public void testSimpleDiamond() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/simpleDiamond.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleFunction.kt")
|
||||
public void testSimpleFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/simpleFunction.kt");
|
||||
|
||||
+5
@@ -14863,6 +14863,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceExtension.kt")
|
||||
public void testInterfaceExtension() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/interfaceExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAnnotation.kt")
|
||||
public void testPropertyAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/propertyAnnotation.kt");
|
||||
|
||||
+5
@@ -13713,6 +13713,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceExtension.kt")
|
||||
public void testInterfaceExtension() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/interfaceExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAnnotation.kt")
|
||||
public void testPropertyAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/propertyAnnotation.kt");
|
||||
|
||||
+5
@@ -13713,6 +13713,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceExtension.kt")
|
||||
public void testInterfaceExtension() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/interfaceExtension.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAnnotation.kt")
|
||||
public void testPropertyAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/propertyAnnotation.kt");
|
||||
|
||||
+5
@@ -3047,6 +3047,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/defaultArgs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleDiamond.kt")
|
||||
public void testSimpleDiamond() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/simpleDiamond.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleFunction.kt")
|
||||
public void testSimpleFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/jvm8/jvmDefault/compatibility/simpleFunction.kt");
|
||||
|
||||
Reference in New Issue
Block a user