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(); DeclarationDescriptor enumClass = classDescriptor.getContainingDeclaration();
assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor; assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor;
Type type = typeMapper.mapType((ClassDescriptor) enumClass); 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(); ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
if (companionObjectDescriptor != null) { if (companionObjectDescriptor != null) {
@@ -1983,7 +1983,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor); ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false); StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false);
Type fieldType = typeMapper.mapType(valueParameterDescriptor); 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); 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) { if (cur instanceof ScriptContext) {
ScriptContext scriptContext = (ScriptContext) cur; ScriptContext scriptContext = (ScriptContext) cur;
if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) { ScriptDescriptor receiverDeclarationDescriptor = receiver.getDeclarationDescriptor();
if (scriptContext.getScriptDescriptor() == receiverDeclarationDescriptor) {
//TODO lazy //TODO lazy
return result; return result;
} }
else { else {
Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor()); Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor());
Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor()); Type classType = asmTypeForScriptDescriptor(bindingContext, receiverDeclarationDescriptor);
String fieldName = scriptContext.getScriptFieldName(receiver.getDeclarationDescriptor()); String fieldName = scriptContext.getScriptFieldName(receiverDeclarationDescriptor);
return StackValue.field(classType, currentScriptType, fieldName, false, result); 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); JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
assert scriptPsi != null; assert scriptPsi != null;
Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi); 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) { else if (sharedVarType == null) {
storeTo = StackValue.local(index, varType); storeTo = StackValue.local(index, varType);
@@ -1043,7 +1043,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) { private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) {
ExpressionCodegen codegen = createOrGetClInitCodegen(); ExpressionCodegen codegen = createOrGetClInitCodegen();
StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null, StackValue.none()); 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); field.store(property, codegen.v);
} }
@@ -206,12 +206,24 @@ public abstract class StackValue {
@NotNull @NotNull
public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) { 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 @NotNull
public static Field field(@NotNull StackValue.Field field, @NotNull StackValue newReceiver) { 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 @NotNull
@@ -402,8 +414,14 @@ public abstract class StackValue {
return None.INSTANCE; return None.INSTANCE;
} }
public static FieldForSharedVar fieldForSharedVar(@NotNull Type localType, @NotNull Type classType, @NotNull String fieldName, @NotNull StackValue receiver) { public static FieldForSharedVar fieldForSharedVar(
Field receiverWithRefWrapper = field(sharedTypeForType(localType), classType, fieldName, false, receiver); @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); return new FieldForSharedVar(localType, classType, fieldName, receiverWithRefWrapper);
} }
@@ -986,11 +1004,20 @@ public abstract class StackValue {
public static class Field extends StackValueWithSimpleReceiver { public static class Field extends StackValueWithSimpleReceiver {
public final Type owner; public final Type owner;
public final String name; 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()); super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
this.owner = owner; this.owner = owner;
this.name = name; this.name = name;
this.descriptor = descriptor;
} }
@Override @Override
@@ -56,7 +56,8 @@ public class ClassContext extends FieldOwnerContext<ClassDescriptor> {
typeMapper.mapType(getContextDescriptor()), typeMapper.mapType(getContextDescriptor()),
CAPTURED_THIS_FIELD, CAPTURED_THIS_FIELD,
/* isStatic = */ false, /* isStatic = */ false,
StackValue.LOCAL_0 StackValue.LOCAL_0,
enclosingClass
); );
} }
@@ -62,8 +62,8 @@ public interface LocalLookup {
String fieldName = "$" + vd.getName(); String fieldName = "$" + vd.getName();
StackValue.Local thiz = StackValue.LOCAL_0; StackValue.Local thiz = StackValue.LOCAL_0;
StackValue.StackValueWithSimpleReceiver innerValue = sharedVarType != null StackValue.StackValueWithSimpleReceiver innerValue = sharedVarType != null
? StackValue.fieldForSharedVar(localType, classType, fieldName, thiz) ? StackValue.fieldForSharedVar(localType, classType, fieldName, thiz, vd)
: StackValue.field(type, classType, fieldName, false, thiz); : StackValue.field(type, classType, fieldName, false, thiz, vd);
closure.recordField(fieldName, type); closure.recordField(fieldName, type);
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type)); closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type));
@@ -98,12 +98,12 @@ public interface LocalLookup {
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) { if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance // 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) // (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(); String fieldName = "$" + vd.getName();
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false, StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
StackValue.LOCAL_0); StackValue.LOCAL_0, vd);
closure.recordField(fieldName, localType); closure.recordField(fieldName, localType);
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType)); closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
@@ -133,7 +133,7 @@ public interface LocalLookup {
JetType receiverType = closure.getEnclosingReceiverDescriptor().getType(); JetType receiverType = closure.getEnclosingReceiverDescriptor().getType();
Type type = state.getTypeMapper().mapType(receiverType); Type type = state.getTypeMapper().mapType(receiverType);
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false, StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false,
StackValue.LOCAL_0); StackValue.LOCAL_0, d);
closure.setCaptureReceiver(); closure.setCaptureReceiver();
return innerValue; return innerValue;
@@ -454,21 +454,21 @@ public class InlineCodegen extends CallGenerator {
return false; return false;
} }
//skip direct capturing fields StackValue field = stackValue;
StackValue receiver = null; if (stackValue instanceof StackValue.FieldForSharedVar) {
if (stackValue instanceof StackValue.Field) { field = ((StackValue.FieldForSharedVar) stackValue).receiver;
receiver = ((StackValue.Field) stackValue).receiver;
}
else if (stackValue instanceof StackValue.FieldForSharedVar) {
receiver = ((StackValue.Field) ((StackValue.FieldForSharedVar) stackValue).receiver).receiver;
} }
if (!(receiver instanceof StackValue.Local)) { //check that value corresponds to captured inlining parameter
return true; 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 true;
return !(codegen.getContext().isInliningLambda() && descriptor != null && !KotlinBuiltIns.isNoinline(descriptor));
} }
private void putParameterOnStack(ParameterInfo... infos) { 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"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/anonymousObjectOnDeclarationSiteSuperParams.1.kt");
doTestMultiFileWithInlineCheck(fileName); 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") @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); 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") @TestMetadata("packages.1.kt")
public void testPackages() throws Exception { public void testPackages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt"); 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"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/anonymousObjectOnDeclarationSiteSuperParams.1.kt");
doBoxTestWithInlineCheck(fileName); 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") @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); 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") @TestMetadata("packages.1.kt")
public void testPackages() throws Exception { public void testPackages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");