Supported SAM constructors in codegen (simplest case).

This commit is contained in:
Evgeny Gerashchenko
2013-03-13 20:57:46 +04:00
parent 8f34dea4c8
commit 835c0f85c7
7 changed files with 99 additions and 14 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.jet.codegen;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
@@ -38,6 +39,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
@@ -53,13 +55,16 @@ import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public class ClosureCodegen extends GenerationStateAware {
private final MutableClosure closure;
@Nullable
private final ClassDescriptor samInterface;
Method constructor;
JvmClassName name;
public ClosureCodegen(GenerationState state, MutableClosure closure) {
public ClosureCodegen(GenerationState state, MutableClosure closure, @Nullable ClassDescriptor samInterface) {
super(state);
this.closure = closure;
this.samInterface = samInterface;
}
public ClosureCodegen gen(JetDeclarationWithBody fun, CodegenContext context, ExpressionCodegen expressionCodegen) {
@@ -69,7 +74,13 @@ public class ClosureCodegen extends GenerationStateAware {
FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun);
assert funDescriptor != null;
Name interfaceFunctionName = Name.identifier("invoke");
Name interfaceFunctionName;
if (samInterface == null) {
interfaceFunctionName = Name.identifier("invoke");
}
else {
interfaceFunctionName = SingleAbstractMethodUtils.getAbstractMethodOfFunctionalInterface(samInterface).getName();
}
SignatureWriter signatureWriter = new SignatureWriter();
@@ -83,18 +94,24 @@ public class ClosureCodegen extends GenerationStateAware {
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
signatureWriter.visitEnd();
JvmClassName superclass = samInterface == null ? funClass : JvmClassName.byType(OBJECT_TYPE);
String[] superInterfaces = samInterface == null
? new String[0]
: new String[] {JvmClassName.byClassDescriptor(samInterface).getInternalName()};
cv.defineClass(fun,
V1_6,
ACC_PUBLIC|ACC_FINAL/*|ACC_SUPER*/,
ACC_PUBLIC | ACC_FINAL/*|ACC_SUPER*/,
name.getInternalName(),
null,
funClass.getInternalName(),
new String[0]
superclass.getInternalName(),
superInterfaces
);
cv.visitSource(fun.getContainingFile().getName(), null);
generateBridge(interfaceFunctionName, name.getInternalName(), funDescriptor, fun, cv);
if (samInterface == null) { // TODO temporary: if SAM interface is generic, we'll need bridge
generateBridge(interfaceFunctionName, name.getInternalName(), funDescriptor, fun, cv);
}
generateBody(interfaceFunctionName, funDescriptor, cv, fun, context, expressionCodegen);
constructor = generateConstructor(funClass, fun, cv, closure);
@@ -213,8 +230,10 @@ public class ClosureCodegen extends GenerationStateAware {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, funClass.getAsmType());
iv.invokespecial(funClass.getInternalName(), "<init>", "()V");
Type superAsmType = samInterface == null ? funClass.getAsmType() : OBJECT_TYPE;
iv.load(0, superAsmType);
iv.invokespecial(superAsmType.getInternalName(), "<init>", "()V");
int k = 1;
for (FieldInfo fieldInfo : args) {
@@ -1230,7 +1230,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return StackValue.none();
}
StackValue closure = genClosure(function);
StackValue closure = genClosure(function, null);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
int index = lookupLocalIndex(descriptor);
closure.put(OBJECT_TYPE, v);
@@ -1246,18 +1246,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return gen(expression.getFunctionLiteral().getBodyExpression());
}
else {
return genClosure(expression.getFunctionLiteral());
return genClosure(expression.getFunctionLiteral(), null);
}
}
private StackValue genClosure(JetDeclarationWithBody declaration) {
private StackValue genClosure(JetDeclarationWithBody declaration, @Nullable ClassDescriptor samInterfaceClass) {
FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, declaration);
ClassDescriptor classDescriptor =
bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
//noinspection SuspiciousMethodCalls
CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
ClosureCodegen closureCodegen = new ClosureCodegen(state, (MutableClosure) closure).gen(declaration, context, this);
ClosureCodegen closureCodegen = new ClosureCodegen(state, (MutableClosure) closure, samInterfaceClass).gen(declaration, context, this);
JvmClassName className = closureCodegen.name;
Type asmType = className.getAsmType();
@@ -1886,6 +1886,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return invokeFunction(call, receiver, functionCall);
}
else {
if (funDescriptor instanceof SimpleFunctionDescriptor) {
ClassDescriptor samTrait = bindingContext.get(
BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, (SimpleFunctionDescriptor) funDescriptor);
if (samTrait != null) {
JetFunctionLiteralExpression argumentExpression = (JetFunctionLiteralExpression) ((ExpressionValueArgument) resolvedCall.getValueArgumentsByIndex().get(0)).getValueArgument()
.getArgumentExpression(); // TODO this will fail for Runnable(f) expression
return genClosure(argumentExpression.getFunctionLiteral(), samTrait);
}
}
return invokeFunction(call, receiver, resolvedCall);
}
}
@@ -72,7 +72,7 @@ public class SingleAbstractMethodUtils {
CallableMemberDescriptor.Kind.SYNTHESIZED
);
JetType parameterType = getFunctionalTypeForFunction((SimpleFunctionDescriptor) getAbstractMembers(klass).get(0));
JetType parameterType = getFunctionalTypeForFunction(getAbstractMethodOfFunctionalInterface(klass));;
ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
result, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("function"), parameterType, false, null);
@@ -90,6 +90,11 @@ public class SingleAbstractMethodUtils {
return result;
}
@NotNull
public static SimpleFunctionDescriptor getAbstractMethodOfFunctionalInterface(@NotNull ClassDescriptor klass) {
return (SimpleFunctionDescriptor) getAbstractMembers(klass).get(0);
}
private SingleAbstractMethodUtils() {
}
}
@@ -0,0 +1,7 @@
var result = "FAIL"
fun box(): String {
val r = Runnable { result = "OK" }
r.run()
return result
}
@@ -0,0 +1,8 @@
fun box(): String {
val o = "O"
var result = ""
val r = Runnable { result = o + "K" } //capturing local vals and local var
r.run()
return result
}
@@ -0,0 +1,11 @@
class Box(val s: String) {
fun extract(): String {
var result = ""
Runnable { result = s }.run() // capturing this and local var
return result
}
}
fun box(): String {
return Box("OK").extract()
}
@@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/box")
@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Namespace.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class})
@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Namespace.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.Sam.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class})
public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInBox() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -3153,6 +3153,29 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
@TestMetadata("compiler/testData/codegen/box/sam")
public static class Sam extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInSam() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("runnable.kt")
public void testRunnable() throws Exception {
doTest("compiler/testData/codegen/box/sam/runnable.kt");
}
@TestMetadata("runnableAccessingClosure1.kt")
public void testRunnableAccessingClosure1() throws Exception {
doTest("compiler/testData/codegen/box/sam/runnableAccessingClosure1.kt");
}
@TestMetadata("runnableAccessingClosure2.kt")
public void testRunnableAccessingClosure2() throws Exception {
doTest("compiler/testData/codegen/box/sam/runnableAccessingClosure2.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/strings")
public static class Strings extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInStrings() throws Exception {
@@ -3507,6 +3530,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
suite.addTestSuite(PrimitiveTypes.class);
suite.addTestSuite(Properties.class);
suite.addTestSuite(SafeCall.class);
suite.addTestSuite(Sam.class);
suite.addTestSuite(Strings.class);
suite.addTestSuite(Super.class);
suite.addTestSuite(Traits.class);