Supported SAM constructors in codegen (simplest case).
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -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()
|
||||
}
|
||||
+25
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user