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:
Michael Bogdanov
2015-04-22 15:45:14 +03:00
parent 72648d305e
commit 53b8a1d56e
20 changed files with 234 additions and 30 deletions
@@ -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()
@@ -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");
@@ -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");