Expand default parameters conditions on inlining default function
#KT-14564 Fixed #KT-10848 Fixed #KT-12497 Fixed
This commit is contained in:
@@ -21,6 +21,12 @@ import org.jetbrains.kotlin.psi.KtExpression
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
enum class ValueKind {
|
||||||
|
GENERAL,
|
||||||
|
DEFAULT_MASK,
|
||||||
|
METHOD_HANDLE_IN_DEFAULT
|
||||||
|
}
|
||||||
|
|
||||||
abstract class CallGenerator {
|
abstract class CallGenerator {
|
||||||
|
|
||||||
internal class DefaultCallGenerator(private val codegen: ExpressionCodegen) : CallGenerator() {
|
internal class DefaultCallGenerator(private val codegen: ExpressionCodegen) : CallGenerator() {
|
||||||
@@ -67,8 +73,7 @@ abstract class CallGenerator {
|
|||||||
stackValue.put(stackValue.type, codegen.v)
|
stackValue.put(stackValue.type, codegen.v)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putValueIfNeeded(
|
override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind) {
|
||||||
parameterType: Type, value: StackValue) {
|
|
||||||
value.put(value.type, codegen.v)
|
value.put(value.type, codegen.v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,9 +122,16 @@ abstract class CallGenerator {
|
|||||||
parameterType: Type,
|
parameterType: Type,
|
||||||
parameterIndex: Int)
|
parameterIndex: Int)
|
||||||
|
|
||||||
|
fun putValueIfNeeded(
|
||||||
|
parameterType: Type,
|
||||||
|
value: StackValue) {
|
||||||
|
putValueIfNeeded(parameterType, value, ValueKind.GENERAL)
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun putValueIfNeeded(
|
abstract fun putValueIfNeeded(
|
||||||
parameterType: Type,
|
parameterType: Type,
|
||||||
value: StackValue)
|
value: StackValue,
|
||||||
|
kind: ValueKind)
|
||||||
|
|
||||||
abstract fun putCapturedValueOnStack(
|
abstract fun putCapturedValueOnStack(
|
||||||
stackValue: StackValue,
|
stackValue: StackValue,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class DefaultCallArgs(val size: Int) {
|
|||||||
bits.set(index)
|
bits.set(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toInts(): List<Int> {
|
private fun toInts(): List<Int> {
|
||||||
if (bits.isEmpty || size == 0) {
|
if (bits.isEmpty || size == 0) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
@@ -56,11 +56,11 @@ class DefaultCallArgs(val size: Int) {
|
|||||||
val toInts = toInts()
|
val toInts = toInts()
|
||||||
if (!toInts.isEmpty()) {
|
if (!toInts.isEmpty()) {
|
||||||
for (mask in toInts) {
|
for (mask in toInts) {
|
||||||
callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE))
|
callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE), ValueKind.DEFAULT_MASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else AsmTypes.OBJECT_TYPE
|
val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else AsmTypes.OBJECT_TYPE
|
||||||
callGenerator.putValueIfNeeded(parameterType, StackValue.constant(null, parameterType))
|
callGenerator.putValueIfNeeded(parameterType, StackValue.constant(null, parameterType), ValueKind.METHOD_HANDLE_IN_DEFAULT)
|
||||||
}
|
}
|
||||||
return toInts.isNotEmpty()
|
return toInts.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -741,9 +741,9 @@ public abstract class StackValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Constant extends StackValue {
|
public static class Constant extends StackValue {
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Object value;
|
public final Object value;
|
||||||
|
|
||||||
public Constant(@Nullable Object value, Type type) {
|
public Constant(@Nullable Object value, Type type) {
|
||||||
super(type, false);
|
super(type, false);
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
|
|
||||||
private Runnable delayedHiddenWriting;
|
private Runnable delayedHiddenWriting;
|
||||||
|
|
||||||
|
private List<Integer> maskValues = new ArrayList<>();
|
||||||
|
private int maskStartIndex = -1;
|
||||||
|
private int methodHandleInDefaultMethodIndex = -1;
|
||||||
|
|
||||||
public InlineCodegen(
|
public InlineCodegen(
|
||||||
@NotNull ExpressionCodegen codegen,
|
@NotNull ExpressionCodegen codegen,
|
||||||
@NotNull GenerationState state,
|
@NotNull GenerationState state,
|
||||||
@@ -177,7 +181,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
SMAPAndMethodNode nodeAndSmap = null;
|
SMAPAndMethodNode nodeAndSmap = null;
|
||||||
try {
|
try {
|
||||||
nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall);
|
nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall);
|
||||||
endCall(inlineCall(nodeAndSmap));
|
endCall(inlineCall(nodeAndSmap, callDefault));
|
||||||
}
|
}
|
||||||
catch (CompilationException e) {
|
catch (CompilationException e) {
|
||||||
throw e;
|
throw e;
|
||||||
@@ -378,7 +382,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
implementationOwner.getInternalName()
|
implementationOwner.getInternalName()
|
||||||
);
|
);
|
||||||
if (!(element instanceof KtNamedFunction)) {
|
if (!(element instanceof KtNamedFunction)) {
|
||||||
throw new IllegalStateException("Propertiy accessors with default parameters not supported " + callableDescriptor);
|
throw new IllegalStateException("Property accessors with default parameters not supported " + callableDescriptor);
|
||||||
}
|
}
|
||||||
FunctionCodegen.generateDefaultImplBody(
|
FunctionCodegen.generateDefaultImplBody(
|
||||||
methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
|
methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
|
||||||
@@ -404,11 +408,14 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private InlineResult inlineCall(@NotNull SMAPAndMethodNode nodeAndSmap) {
|
private InlineResult inlineCall(@NotNull SMAPAndMethodNode nodeAndSmap, boolean callDefault) {
|
||||||
assert delayedHiddenWriting == null : "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'";
|
assert delayedHiddenWriting == null : "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'";
|
||||||
DefaultSourceMapper defaultSourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
|
DefaultSourceMapper defaultSourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
|
||||||
defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber()));
|
defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber()));
|
||||||
MethodNode node = nodeAndSmap.getNode();
|
MethodNode node = nodeAndSmap.getNode();
|
||||||
|
if (callDefault) {
|
||||||
|
MethodInlinerUtilKt.expandMaskConditions(node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex);
|
||||||
|
}
|
||||||
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
|
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
|
||||||
generateClosuresBodies();
|
generateClosuresBodies();
|
||||||
|
|
||||||
@@ -676,7 +683,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
) {
|
) {
|
||||||
if (!asFunctionInline && Type.VOID_TYPE != type) {
|
if (!asFunctionInline && Type.VOID_TYPE != type) {
|
||||||
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
||||||
boolean couldBeRemapped = !shouldPutValue(type, stackValue);
|
boolean couldBeRemapped = !shouldPutGeneralValue(type, stackValue);
|
||||||
StackValue remappedValue = couldBeRemapped ? stackValue : null;
|
StackValue remappedValue = couldBeRemapped ? stackValue : null;
|
||||||
|
|
||||||
ParameterInfo info;
|
ParameterInfo info;
|
||||||
@@ -694,7 +701,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*descriptor is null for captured vars*/
|
/*descriptor is null for captured vars*/
|
||||||
private static boolean shouldPutValue(@NotNull Type type, @Nullable StackValue stackValue) {
|
private static boolean shouldPutGeneralValue(@NotNull Type type, @Nullable StackValue stackValue) {
|
||||||
if (stackValue == null) {
|
if (stackValue == null) {
|
||||||
//default or vararg
|
//default or vararg
|
||||||
return true;
|
return true;
|
||||||
@@ -899,7 +906,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
StackValue value = codegen.gen(argumentExpression);
|
StackValue value = codegen.gen(argumentExpression);
|
||||||
putValueIfNeeded(parameterType, value, valueParameterDescriptor.getIndex());
|
putValueIfNeeded(parameterType, value, valueParameterDescriptor.getIndex(), ValueKind.GENERAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,20 +925,44 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value) {
|
public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, @NotNull ValueKind kind) {
|
||||||
putValueIfNeeded(parameterType, value, -1);
|
putValueIfNeeded(parameterType, value, -1, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, int index) {
|
private void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, int index, @NotNull ValueKind kind) {
|
||||||
if (shouldPutValue(parameterType, value)) {
|
if (processDefaultMaskOrMethodHandler(value, kind)) return;
|
||||||
|
|
||||||
|
assert maskValues.isEmpty() : "Additional default call arguments should be last ones, but " + value;
|
||||||
|
|
||||||
|
if (shouldPutGeneralValue(parameterType, value)) {
|
||||||
value.put(parameterType, codegen.v);
|
value.put(parameterType, codegen.v);
|
||||||
}
|
}
|
||||||
afterParameterPut(parameterType, value, index);
|
afterParameterPut(parameterType, value, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) {
|
||||||
|
if (kind != ValueKind.DEFAULT_MASK && kind != ValueKind.METHOD_HANDLE_IN_DEFAULT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert value instanceof StackValue.Constant : "Additional default method argument should be constant, but " + value;
|
||||||
|
Object constantValue = ((StackValue.Constant) value).value;
|
||||||
|
if (kind == ValueKind.DEFAULT_MASK) {
|
||||||
|
assert constantValue instanceof Integer : "Mask should be of Integer type, but " + constantValue;
|
||||||
|
maskValues.add((Integer) constantValue);
|
||||||
|
if (maskStartIndex == -1) {
|
||||||
|
maskStartIndex = invocationParamBuilder.getNextParameterOffset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert constantValue == null : "Additional method handle for default argument should be null, but " + constantValue;
|
||||||
|
methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
|
public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
|
||||||
if (shouldPutValue(stackValue.type, stackValue)) {
|
if (shouldPutGeneralValue(stackValue.type, stackValue)) {
|
||||||
stackValue.put(stackValue.type, codegen.v);
|
stackValue.put(stackValue.type, codegen.v);
|
||||||
}
|
}
|
||||||
putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
|
putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@ class InlineCodegenForDefaultBody(
|
|||||||
throw UnsupportedOperationException("Shouldn't be called")
|
throw UnsupportedOperationException("Shouldn't be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putValueIfNeeded(parameterType: Type, value: StackValue) {
|
override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind) {
|
||||||
//original method would be inlined directly into default impl body without any inline magic
|
//original method would be inlined directly into default impl body without any inline magic
|
||||||
//so we no need to load variables on stack to further method call
|
//so we no need to load variables on stack to further method call
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.inline
|
package org.jetbrains.kotlin.codegen.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||||
import org.jetbrains.kotlin.utils.SmartSet
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||||
|
|
||||||
@@ -88,3 +88,63 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun SourceValue.singleOrNullInsn() = insns.singleOrNull()
|
fun SourceValue.singleOrNullInsn() = insns.singleOrNull()
|
||||||
|
|
||||||
|
fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>, methodHandlerIndex: Int) {
|
||||||
|
class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode) {
|
||||||
|
val expandNotDelete = mask and constant != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val maskProcessingHeader = node.instructions.asSequence().takeWhile {
|
||||||
|
if (it is VarInsnNode) {
|
||||||
|
if (isMaskIndex(it, maskStartIndex, masks)) {
|
||||||
|
/*if slot for default mask is updated than we occurred in actual function body*/
|
||||||
|
return@takeWhile it.opcode == Opcodes.ILOAD
|
||||||
|
}
|
||||||
|
else if (isMethodHandleIndex(methodHandlerIndex, it)) {
|
||||||
|
return@takeWhile it.opcode == Opcodes.ALOAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val conditions = maskProcessingHeader.filterIsInstance<VarInsnNode>().mapNotNull {
|
||||||
|
if (isMaskIndex(it, maskStartIndex, masks) &&
|
||||||
|
it.next?.next?.opcode == Opcodes.IAND &&
|
||||||
|
it.next.next.next?.opcode == Opcodes.IFEQ) {
|
||||||
|
Condition(
|
||||||
|
masks[it.`var` - maskStartIndex],
|
||||||
|
InlineCodegenUtil.getConstant(it.next),
|
||||||
|
it,
|
||||||
|
it.next?.next?.next as JumpInsnNode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if (isMethodHandleIndex(methodHandlerIndex, it) &&
|
||||||
|
it.next?.opcode == Opcodes.IFNULL &&
|
||||||
|
it.next.next?.opcode == Opcodes.NEW) {
|
||||||
|
//Always delete method handle for now
|
||||||
|
//This logic should be updated when method handles would be supported
|
||||||
|
Condition(0, 0, it,it.next as JumpInsnNode)
|
||||||
|
}
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
|
||||||
|
val toDelete = arrayListOf<AbstractInsnNode>()
|
||||||
|
conditions.forEach {
|
||||||
|
val jumpInstruction = it.jumpInstruction
|
||||||
|
InsnSequence(it.maskInstruction, (if (it.expandNotDelete) jumpInstruction.next else jumpInstruction.label)).forEach {
|
||||||
|
toDelete.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toDelete.forEach {
|
||||||
|
node.instructions.remove(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var`
|
||||||
|
|
||||||
|
private fun isMaskIndex(variable: VarInsnNode, maskStartIndex: Int, masks: List<Int>): Boolean {
|
||||||
|
val varIndex = variable.`var`
|
||||||
|
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
//NO_CHECK_LAMBDA_INLINING
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
object TimeUtil {
|
||||||
|
inline fun waitForEx(retryWait: Int = 200,
|
||||||
|
action: () -> Boolean) {
|
||||||
|
var now = 1L
|
||||||
|
if (now++ <= 3) {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
var result = "fail"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
TimeUtil.waitForEx(
|
||||||
|
action = {
|
||||||
|
try {
|
||||||
|
result = "OK"
|
||||||
|
true
|
||||||
|
}
|
||||||
|
catch (t: Throwable) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
var result = "fail"
|
||||||
|
|
||||||
|
object TimeUtil {
|
||||||
|
|
||||||
|
fun waitForAssert(z: String) {
|
||||||
|
waitForEx(
|
||||||
|
action = {
|
||||||
|
result = z
|
||||||
|
result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun waitForEx(retryWait: Int = 200,
|
||||||
|
action: () -> String) {
|
||||||
|
var now = 1L
|
||||||
|
now++
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
TimeUtil.waitForAssert("OK")
|
||||||
|
return result
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
fun calc() = "OK"
|
||||||
|
|
||||||
|
inline fun test(
|
||||||
|
p1: String = "1",
|
||||||
|
p2: String = "2",
|
||||||
|
p3: String = "3",
|
||||||
|
p4: String = "4",
|
||||||
|
p5: String = "5",
|
||||||
|
p6: String = "6",
|
||||||
|
p7: String = "7",
|
||||||
|
p8: String = "8",
|
||||||
|
p9: String = "9",
|
||||||
|
p10: String = "10",
|
||||||
|
p11: String = "11",
|
||||||
|
p12: String = "12",
|
||||||
|
p13: String = "13",
|
||||||
|
p14: String = "14",
|
||||||
|
p15: String = "15",
|
||||||
|
p16: String = "16",
|
||||||
|
p17: String = "17",
|
||||||
|
p18: String = "18",
|
||||||
|
p19: String = "19",
|
||||||
|
p20: String = "20",
|
||||||
|
p21: String = "21",
|
||||||
|
p22: String = "22",
|
||||||
|
p23: String = "23",
|
||||||
|
p24: String = "24",
|
||||||
|
p25: String = "25",
|
||||||
|
p26: String = "26",
|
||||||
|
p27: String = "27",
|
||||||
|
p28: String = "28",
|
||||||
|
p29: String = "29",
|
||||||
|
p30: String = "30",
|
||||||
|
p31: String = "31",
|
||||||
|
p32: String = "32"
|
||||||
|
): String {
|
||||||
|
return p1 + " " + p2 + " " + p3 + " " + p4 + " " + p5 + " " + p6 + " " +
|
||||||
|
p7 + " " + p8 + " " + p9 + " " + p10 + " " + p11 + " " + p12 + " " + p13 + " " + p14 + " " +
|
||||||
|
p15 + " " + p16 + " " + p17 + " " + p18 + " " + p19 + " " + p20 + " " + p21 + " " +
|
||||||
|
p22 + " " + p23 + " " + p24 + " " + p25 + " " + p26 + " " + p27 + " " + p28 + " " +
|
||||||
|
p29 + " " + p30 + " " + p31 + " " + p32
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (test() != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32")
|
||||||
|
return "fail 1: ${test()}"
|
||||||
|
|
||||||
|
if (test(p20 = "OK") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 OK 21 22 23 24 25 26 27 28 29 30 31 32")
|
||||||
|
return "fail 2: ${test(p20 = "OK")}"
|
||||||
|
|
||||||
|
if (test(p20 = "O", p22 = "K") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 O 21 K 23 24 25 26 27 28 29 30 31 32")
|
||||||
|
return "fail 3: ${test(p20 = "O", p22 = "K")}"
|
||||||
|
|
||||||
|
if (test(p20 = "O", p22 = "K", p32 = "23") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 O 21 K 23 24 25 26 27 28 29 30 31 23")
|
||||||
|
return "fail 4: ${test(p20 = "O", p22 = "K", p32 = "23")}"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
fun calc() = "OK"
|
||||||
|
|
||||||
|
inline fun test(
|
||||||
|
p1: String = "1",
|
||||||
|
p2: String = "2",
|
||||||
|
p3: String = "3",
|
||||||
|
p4: String = "4",
|
||||||
|
p5: String = "5",
|
||||||
|
p6: String = "6",
|
||||||
|
p7: String = "7",
|
||||||
|
p8: String = "8",
|
||||||
|
p9: String = "9",
|
||||||
|
p10: String = "10",
|
||||||
|
p11: String = "11",
|
||||||
|
p12: String = "12",
|
||||||
|
p13: String = "13",
|
||||||
|
p14: String = "14",
|
||||||
|
p15: String = "15",
|
||||||
|
p16: String = "16",
|
||||||
|
p17: String = "17",
|
||||||
|
p18: String = "18",
|
||||||
|
p19: String = "19",
|
||||||
|
p20: String = "20",
|
||||||
|
p21: String = "21",
|
||||||
|
p22: String = "22",
|
||||||
|
p23: String = "23",
|
||||||
|
p24: String = "24",
|
||||||
|
p25: String = "25",
|
||||||
|
p26: String = "26",
|
||||||
|
p27: String = "27",
|
||||||
|
p28: String = "28",
|
||||||
|
p29: String = "29",
|
||||||
|
p30: String = "30",
|
||||||
|
p31: String = "31",
|
||||||
|
p32: String = "32",
|
||||||
|
p33: String = "33"
|
||||||
|
): String {
|
||||||
|
return p1 + " " + p2 + " " + p3 + " " + p4 + " " + p5 + " " + p6 + " " +
|
||||||
|
p7 + " " + p8 + " " + p9 + " " + p10 + " " + p11 + " " + p12 + " " + p13 + " " + p14 + " " +
|
||||||
|
p15 + " " + p16 + " " + p17 + " " + p18 + " " + p19 + " " + p20 + " " + p21 + " " +
|
||||||
|
p22 + " " + p23 + " " + p24 + " " + p25 + " " + p26 + " " + p27 + " " + p28 + " " +
|
||||||
|
p29 + " " + p30 + " " + p31 + " " + p32 + " " + p33
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (test() != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33")
|
||||||
|
return "fail 1: ${test()}"
|
||||||
|
|
||||||
|
if (test(p20 = "OK") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 OK 21 22 23 24 25 26 27 28 29 30 31 32 33")
|
||||||
|
return "fail 2: ${test(p20 = "OK")}"
|
||||||
|
|
||||||
|
if (test(p20 = "O", p22 = "K") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 O 21 K 23 24 25 26 27 28 29 30 31 32 33")
|
||||||
|
return "fail 3: ${test(p20 = "O", p22 = "K")}"
|
||||||
|
|
||||||
|
if (test(p20 = "O", p22 = "K", p32 = "23") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 O 21 K 23 24 25 26 27 28 29 30 31 23 33")
|
||||||
|
return "fail 4: ${test(p20 = "O", p22 = "K", p32 = "23")}"
|
||||||
|
|
||||||
|
if (test(p20 = "O", p22 = "K", p32 = "33", p33 ="32") != "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 O 21 K 23 24 25 26 27 28 29 30 31 33 32")
|
||||||
|
return "fail 4: ${test(p20 = "O", p22 = "K", p32 = "33", p33 ="32")}"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
fun calc() = "OK"
|
||||||
|
|
||||||
|
/*open modifier for method handle check in default method*/
|
||||||
|
open class A {
|
||||||
|
inline fun test(p: String = calc()): String {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun String.testExt(p: String = "K"): String {
|
||||||
|
return this + p
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callExt(): String {
|
||||||
|
return "O".testExt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callExt(arg: String): String {
|
||||||
|
return "O".testExt(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
if (A().callExt() != "OK") return "fail 1: ${A().callExt()}"
|
||||||
|
if (A().callExt("O") != "OO") return "fail 2: ${A().callExt("O")}"
|
||||||
|
if (A().test("KK") != "KK") return "fail 3: ${A().test("KK")}"
|
||||||
|
|
||||||
|
return A().test()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
inline fun test(p: String = "OK"): String {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
return test()
|
||||||
|
}
|
||||||
|
|
||||||
|
//mask check in test$default
|
||||||
|
// 1 IFEQ
|
||||||
|
// 1 IF
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
open class A {
|
||||||
|
inline fun test(p: String = "OK"): String {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return A().test()
|
||||||
|
}
|
||||||
|
|
||||||
|
//handler check in test$default
|
||||||
|
// 1 IFNULL
|
||||||
|
//mask check in test$default
|
||||||
|
// 1 IFEQ
|
||||||
|
// 2 IF
|
||||||
@@ -905,6 +905,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt14564.kt")
|
||||||
|
public void testKt14564() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt14564.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt14564_2.kt")
|
||||||
|
public void testKt14564_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt14564_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt5685.kt")
|
@TestMetadata("kt5685.kt")
|
||||||
public void testKt5685() throws Exception {
|
public void testKt5685() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt5685.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt5685.kt");
|
||||||
@@ -916,6 +928,33 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/simpleDefaultMethod.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/simpleDefaultMethod.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class MaskElumination extends AbstractBlackBoxInlineCodegenTest {
|
||||||
|
@TestMetadata("32Parameters.kt")
|
||||||
|
public void test32Parameters() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("33Parameters.kt")
|
||||||
|
public void test33Parameters() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInMaskElumination() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/delegatedProperty")
|
@TestMetadata("compiler/testData/codegen/boxInline/delegatedProperty")
|
||||||
|
|||||||
@@ -1090,6 +1090,18 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("maskElumination.kt")
|
||||||
|
public void testMaskElumination() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("methodHandlerElumination.kt")
|
||||||
|
public void testMethodHandlerElumination() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/bytecodeText/directInvoke")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/directInvoke")
|
||||||
|
|||||||
+39
@@ -905,6 +905,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt14564.kt")
|
||||||
|
public void testKt14564() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt14564.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt14564_2.kt")
|
||||||
|
public void testKt14564_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt14564_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt5685.kt")
|
@TestMetadata("kt5685.kt")
|
||||||
public void testKt5685() throws Exception {
|
public void testKt5685() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt5685.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/kt5685.kt");
|
||||||
@@ -916,6 +928,33 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/simpleDefaultMethod.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/simpleDefaultMethod.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class MaskElumination extends AbstractCompileKotlinAgainstInlineKotlinTest {
|
||||||
|
@TestMetadata("32Parameters.kt")
|
||||||
|
public void test32Parameters() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("33Parameters.kt")
|
||||||
|
public void test33Parameters() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInMaskElumination() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/delegatedProperty")
|
@TestMetadata("compiler/testData/codegen/boxInline/delegatedProperty")
|
||||||
|
|||||||
Reference in New Issue
Block a user