Fix for KT-7544: Backend fails when inlining nested calls with reified type parameter and default value parameter
#KT-7544 Fixed
This commit is contained in:
@@ -1962,7 +1962,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
DeclarationDescriptor enumClass = classDescriptor.getContainingDeclaration();
|
||||
assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor;
|
||||
Type type = typeMapper.mapType((ClassDescriptor) enumClass);
|
||||
return StackValue.field(type, type, descriptor.getName().asString(), true, StackValue.none());
|
||||
return StackValue.field(type, type, descriptor.getName().asString(), true, StackValue.none(), classDescriptor);
|
||||
}
|
||||
ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
|
||||
if (companionObjectDescriptor != null) {
|
||||
@@ -1983,7 +1983,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
|
||||
StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false);
|
||||
Type fieldType = typeMapper.mapType(valueParameterDescriptor);
|
||||
return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false, script);
|
||||
return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false, script, valueParameterDescriptor);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
|
||||
@@ -2490,15 +2490,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
if (cur instanceof ScriptContext) {
|
||||
ScriptContext scriptContext = (ScriptContext) cur;
|
||||
|
||||
if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) {
|
||||
ScriptDescriptor receiverDeclarationDescriptor = receiver.getDeclarationDescriptor();
|
||||
if (scriptContext.getScriptDescriptor() == receiverDeclarationDescriptor) {
|
||||
//TODO lazy
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor());
|
||||
Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor());
|
||||
String fieldName = scriptContext.getScriptFieldName(receiver.getDeclarationDescriptor());
|
||||
return StackValue.field(classType, currentScriptType, fieldName, false, result);
|
||||
Type classType = asmTypeForScriptDescriptor(bindingContext, receiverDeclarationDescriptor);
|
||||
String fieldName = scriptContext.getScriptFieldName(receiverDeclarationDescriptor);
|
||||
return StackValue.field(classType, currentScriptType, fieldName, false, result, receiverDeclarationDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3440,7 +3441,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
|
||||
assert scriptPsi != null;
|
||||
Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi);
|
||||
storeTo = StackValue.field(varType, scriptClassType, variableDeclaration.getName(), false, StackValue.LOCAL_0);
|
||||
storeTo = StackValue.field(varType, scriptClassType, variableDeclaration.getName(), false, StackValue.LOCAL_0, variableDescriptor);
|
||||
}
|
||||
else if (sharedVarType == null) {
|
||||
storeTo = StackValue.local(index, varType);
|
||||
|
||||
@@ -1043,7 +1043,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) {
|
||||
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
||||
StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null, StackValue.none());
|
||||
StackValue.Field field = StackValue.field(property.type, classAsmType, propertyDescriptor.getName().asString(), true, StackValue.none());
|
||||
StackValue.Field field = StackValue
|
||||
.field(property.type, classAsmType, propertyDescriptor.getName().asString(), true, StackValue.none(), propertyDescriptor);
|
||||
field.store(property, codegen.v);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,12 +206,24 @@ public abstract class StackValue {
|
||||
|
||||
@NotNull
|
||||
public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
|
||||
return new Field(type, owner, name, isStatic, receiver);
|
||||
return field(type, owner, name, isStatic, receiver, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Field field(
|
||||
@NotNull Type type,
|
||||
@NotNull Type owner,
|
||||
@NotNull String name,
|
||||
boolean isStatic,
|
||||
@NotNull StackValue receiver,
|
||||
@Nullable DeclarationDescriptor descriptor
|
||||
) {
|
||||
return new Field(type, owner, name, isStatic, receiver, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Field field(@NotNull StackValue.Field field, @NotNull StackValue newReceiver) {
|
||||
return new Field(field.type, field.owner, field.name, field.isStaticPut, newReceiver);
|
||||
return field(field.type, field.owner, field.name, field.isStaticPut, newReceiver, field.descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -402,8 +414,14 @@ public abstract class StackValue {
|
||||
return None.INSTANCE;
|
||||
}
|
||||
|
||||
public static FieldForSharedVar fieldForSharedVar(@NotNull Type localType, @NotNull Type classType, @NotNull String fieldName, @NotNull StackValue receiver) {
|
||||
Field receiverWithRefWrapper = field(sharedTypeForType(localType), classType, fieldName, false, receiver);
|
||||
public static FieldForSharedVar fieldForSharedVar(
|
||||
@NotNull Type localType,
|
||||
@NotNull Type classType,
|
||||
@NotNull String fieldName,
|
||||
@NotNull StackValue receiver,
|
||||
@Nullable DeclarationDescriptor descriptor
|
||||
) {
|
||||
Field receiverWithRefWrapper = field(sharedTypeForType(localType), classType, fieldName, false, receiver, descriptor);
|
||||
return new FieldForSharedVar(localType, classType, fieldName, receiverWithRefWrapper);
|
||||
}
|
||||
|
||||
@@ -986,11 +1004,20 @@ public abstract class StackValue {
|
||||
public static class Field extends StackValueWithSimpleReceiver {
|
||||
public final Type owner;
|
||||
public final String name;
|
||||
public final DeclarationDescriptor descriptor;
|
||||
|
||||
public Field(Type type, Type owner, String name, boolean isStatic, StackValue receiver) {
|
||||
public Field(
|
||||
@NotNull Type type,
|
||||
@NotNull Type owner,
|
||||
@NotNull String name,
|
||||
boolean isStatic,
|
||||
@NotNull StackValue receiver,
|
||||
@Nullable DeclarationDescriptor descriptor
|
||||
) {
|
||||
super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,7 +56,8 @@ public class ClassContext extends FieldOwnerContext<ClassDescriptor> {
|
||||
typeMapper.mapType(getContextDescriptor()),
|
||||
CAPTURED_THIS_FIELD,
|
||||
/* isStatic = */ false,
|
||||
StackValue.LOCAL_0
|
||||
StackValue.LOCAL_0,
|
||||
enclosingClass
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ public interface LocalLookup {
|
||||
String fieldName = "$" + vd.getName();
|
||||
StackValue.Local thiz = StackValue.LOCAL_0;
|
||||
StackValue.StackValueWithSimpleReceiver innerValue = sharedVarType != null
|
||||
? StackValue.fieldForSharedVar(localType, classType, fieldName, thiz)
|
||||
: StackValue.field(type, classType, fieldName, false, thiz);
|
||||
? StackValue.fieldForSharedVar(localType, classType, fieldName, thiz, vd)
|
||||
: StackValue.field(type, classType, fieldName, false, thiz, vd);
|
||||
|
||||
closure.recordField(fieldName, type);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type));
|
||||
@@ -98,12 +98,12 @@ public interface LocalLookup {
|
||||
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
|
||||
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
|
||||
// (instead of passing this instance to the constructor and storing as a field)
|
||||
return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0);
|
||||
return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
|
||||
}
|
||||
|
||||
String fieldName = "$" + vd.getName();
|
||||
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
|
||||
StackValue.LOCAL_0);
|
||||
StackValue.LOCAL_0, vd);
|
||||
|
||||
closure.recordField(fieldName, localType);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
|
||||
@@ -133,7 +133,7 @@ public interface LocalLookup {
|
||||
JetType receiverType = closure.getEnclosingReceiverDescriptor().getType();
|
||||
Type type = state.getTypeMapper().mapType(receiverType);
|
||||
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false,
|
||||
StackValue.LOCAL_0);
|
||||
StackValue.LOCAL_0, d);
|
||||
closure.setCaptureReceiver();
|
||||
|
||||
return innerValue;
|
||||
|
||||
@@ -454,21 +454,21 @@ public class InlineCodegen extends CallGenerator {
|
||||
return false;
|
||||
}
|
||||
|
||||
//skip direct capturing fields
|
||||
StackValue receiver = null;
|
||||
if (stackValue instanceof StackValue.Field) {
|
||||
receiver = ((StackValue.Field) stackValue).receiver;
|
||||
}
|
||||
else if (stackValue instanceof StackValue.FieldForSharedVar) {
|
||||
receiver = ((StackValue.Field) ((StackValue.FieldForSharedVar) stackValue).receiver).receiver;
|
||||
StackValue field = stackValue;
|
||||
if (stackValue instanceof StackValue.FieldForSharedVar) {
|
||||
field = ((StackValue.FieldForSharedVar) stackValue).receiver;
|
||||
}
|
||||
|
||||
if (!(receiver instanceof StackValue.Local)) {
|
||||
return true;
|
||||
//check that value corresponds to captured inlining parameter
|
||||
if (field instanceof StackValue.Field) {
|
||||
DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
|
||||
//check that variable is inline function parameter
|
||||
return !(varDescriptor instanceof CallableDescriptor &&
|
||||
InlineUtil.isInlineLambdaParameter((CallableDescriptor) varDescriptor) &&
|
||||
InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
|
||||
}
|
||||
|
||||
//TODO: check type of context
|
||||
return !(codegen.getContext().isInliningLambda() && descriptor != null && !KotlinBuiltIns.isNoinline(descriptor));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void putParameterOnStack(ParameterInfo... infos) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return bar {"OK"} ()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
inline fun bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = {
|
||||
call(y)
|
||||
}
|
||||
|
||||
public inline fun <T> call(f: () -> T): T = f()
|
||||
@@ -0,0 +1,6 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return bar {"OK"} ()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
inline fun bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = {
|
||||
{ { call(y) }() }()
|
||||
}
|
||||
|
||||
public inline fun <T> call(f: () -> T): T = f()
|
||||
@@ -0,0 +1,12 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
val bar1 = bar {"123"} ()
|
||||
val bar2 = bar2 { "1234" } ()
|
||||
return if (bar1 == "123" && bar2 == "1234") "OK" else "fail: $bar1 $bar2"
|
||||
}
|
||||
|
||||
inline fun bar2(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = {
|
||||
{ { call(y) }() }()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
inline fun bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = {
|
||||
{ { call(y) }() }()
|
||||
}
|
||||
|
||||
public inline fun <T> call(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) f: () -> T): T = {{ f() }()}()
|
||||
@@ -0,0 +1,6 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return bar { "OK" }.run()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
trait A<T> {
|
||||
fun run(): T;
|
||||
}
|
||||
|
||||
inline fun bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = object : A<String> {
|
||||
override fun run() : String {
|
||||
return call(y)
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <T> call(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) f: () -> T): T = object : A<T> {
|
||||
override fun run() : T {
|
||||
return f()
|
||||
}
|
||||
}.run()
|
||||
@@ -0,0 +1,8 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
val x: () -> String = foo<String>()
|
||||
|
||||
fun box(): String {
|
||||
return x()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
inline fun <reified R> foo() = bar<R>() {"OK"}
|
||||
inline fun <reified E> bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) y: () -> String) = {
|
||||
null is E
|
||||
run(y)
|
||||
}
|
||||
|
||||
public inline fun <T> call(f: () -> T): T = f()
|
||||
@@ -0,0 +1,8 @@
|
||||
//NO_CHECK_LAMBDA_INLINING
|
||||
import test.*
|
||||
|
||||
inline fun <reified R> foo() = bar<R, String>() {"OK"}
|
||||
|
||||
fun box(): String {
|
||||
return foo<String>()()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
inline fun <reified R, T> bar(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) tasksFactory: () -> T) = {
|
||||
null is R
|
||||
run(tasksFactory)
|
||||
}
|
||||
|
||||
public inline fun <T> call(f: () -> T): T = f()
|
||||
|
||||
+36
@@ -66,6 +66,30 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/anonymousObjectOnDeclarationSiteSuperParams.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline.1.kt")
|
||||
public void testCapturedLambdaInInline() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline2.1.kt")
|
||||
public void testCapturedLambdaInInline2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline2.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline3.1.kt")
|
||||
public void testCapturedLambdaInInline3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline3.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInlineObject.1.kt")
|
||||
public void testCapturedLambdaInInlineObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInlineObject.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/builders")
|
||||
@@ -688,6 +712,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambda.1.kt")
|
||||
public void testCapturedLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/capturedLambda.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambda2.1.kt")
|
||||
public void testCapturedLambda2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/capturedLambda2.1.kt");
|
||||
doTestMultiFileWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("packages.1.kt")
|
||||
public void testPackages() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
||||
|
||||
+36
@@ -66,6 +66,30 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/anonymousObjectOnDeclarationSiteSuperParams.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline.1.kt")
|
||||
public void testCapturedLambdaInInline() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline2.1.kt")
|
||||
public void testCapturedLambdaInInline2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline2.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInline3.1.kt")
|
||||
public void testCapturedLambdaInInline3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInline3.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambdaInInlineObject.1.kt")
|
||||
public void testCapturedLambdaInInlineObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/capturedLambdaInInlineObject.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/builders")
|
||||
@@ -688,6 +712,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambda.1.kt")
|
||||
public void testCapturedLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/capturedLambda.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLambda2.1.kt")
|
||||
public void testCapturedLambda2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/capturedLambda2.1.kt");
|
||||
doBoxTestWithInlineCheck(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("packages.1.kt")
|
||||
public void testPackages() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
||||
|
||||
Reference in New Issue
Block a user