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.google.common.collect.Lists;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.asm4.MethodVisitor;
|
import org.jetbrains.asm4.MethodVisitor;
|
||||||
import org.jetbrains.asm4.Type;
|
import org.jetbrains.asm4.Type;
|
||||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
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.BindingContextUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
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.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
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 {
|
public class ClosureCodegen extends GenerationStateAware {
|
||||||
|
|
||||||
private final MutableClosure closure;
|
private final MutableClosure closure;
|
||||||
|
@Nullable
|
||||||
|
private final ClassDescriptor samInterface;
|
||||||
|
|
||||||
Method constructor;
|
Method constructor;
|
||||||
JvmClassName name;
|
JvmClassName name;
|
||||||
|
|
||||||
public ClosureCodegen(GenerationState state, MutableClosure closure) {
|
public ClosureCodegen(GenerationState state, MutableClosure closure, @Nullable ClassDescriptor samInterface) {
|
||||||
super(state);
|
super(state);
|
||||||
this.closure = closure;
|
this.closure = closure;
|
||||||
|
this.samInterface = samInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClosureCodegen gen(JetDeclarationWithBody fun, CodegenContext context, ExpressionCodegen expressionCodegen) {
|
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);
|
FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun);
|
||||||
assert funDescriptor != null;
|
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();
|
SignatureWriter signatureWriter = new SignatureWriter();
|
||||||
|
|
||||||
@@ -83,18 +94,24 @@ public class ClosureCodegen extends GenerationStateAware {
|
|||||||
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
|
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
|
||||||
signatureWriter.visitEnd();
|
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,
|
cv.defineClass(fun,
|
||||||
V1_6,
|
V1_6,
|
||||||
ACC_PUBLIC|ACC_FINAL/*|ACC_SUPER*/,
|
ACC_PUBLIC | ACC_FINAL/*|ACC_SUPER*/,
|
||||||
name.getInternalName(),
|
name.getInternalName(),
|
||||||
null,
|
null,
|
||||||
funClass.getInternalName(),
|
superclass.getInternalName(),
|
||||||
new String[0]
|
superInterfaces
|
||||||
);
|
);
|
||||||
cv.visitSource(fun.getContainingFile().getName(), null);
|
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);
|
generateBody(interfaceFunctionName, funDescriptor, cv, fun, context, expressionCodegen);
|
||||||
|
|
||||||
constructor = generateConstructor(funClass, fun, cv, closure);
|
constructor = generateConstructor(funClass, fun, cv, closure);
|
||||||
@@ -213,8 +230,10 @@ public class ClosureCodegen extends GenerationStateAware {
|
|||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
|
|
||||||
iv.load(0, funClass.getAsmType());
|
Type superAsmType = samInterface == null ? funClass.getAsmType() : OBJECT_TYPE;
|
||||||
iv.invokespecial(funClass.getInternalName(), "<init>", "()V");
|
|
||||||
|
iv.load(0, superAsmType);
|
||||||
|
iv.invokespecial(superAsmType.getInternalName(), "<init>", "()V");
|
||||||
|
|
||||||
int k = 1;
|
int k = 1;
|
||||||
for (FieldInfo fieldInfo : args) {
|
for (FieldInfo fieldInfo : args) {
|
||||||
|
|||||||
@@ -1230,7 +1230,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
return StackValue.none();
|
return StackValue.none();
|
||||||
}
|
}
|
||||||
|
|
||||||
StackValue closure = genClosure(function);
|
StackValue closure = genClosure(function, null);
|
||||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
|
||||||
int index = lookupLocalIndex(descriptor);
|
int index = lookupLocalIndex(descriptor);
|
||||||
closure.put(OBJECT_TYPE, v);
|
closure.put(OBJECT_TYPE, v);
|
||||||
@@ -1246,18 +1246,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
return gen(expression.getFunctionLiteral().getBodyExpression());
|
return gen(expression.getFunctionLiteral().getBodyExpression());
|
||||||
}
|
}
|
||||||
else {
|
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);
|
FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, declaration);
|
||||||
ClassDescriptor classDescriptor =
|
ClassDescriptor classDescriptor =
|
||||||
bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
|
bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
|
||||||
//noinspection SuspiciousMethodCalls
|
//noinspection SuspiciousMethodCalls
|
||||||
CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
|
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;
|
JvmClassName className = closureCodegen.name;
|
||||||
Type asmType = className.getAsmType();
|
Type asmType = className.getAsmType();
|
||||||
@@ -1886,6 +1886,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
return invokeFunction(call, receiver, functionCall);
|
return invokeFunction(call, receiver, functionCall);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
return invokeFunction(call, receiver, resolvedCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -72,7 +72,7 @@ public class SingleAbstractMethodUtils {
|
|||||||
CallableMemberDescriptor.Kind.SYNTHESIZED
|
CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||||
);
|
);
|
||||||
|
|
||||||
JetType parameterType = getFunctionalTypeForFunction((SimpleFunctionDescriptor) getAbstractMembers(klass).get(0));
|
JetType parameterType = getFunctionalTypeForFunction(getAbstractMethodOfFunctionalInterface(klass));;
|
||||||
ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
|
ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
|
||||||
result, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("function"), parameterType, false, null);
|
result, 0, Collections.<AnnotationDescriptor>emptyList(), Name.identifier("function"), parameterType, false, null);
|
||||||
|
|
||||||
@@ -90,6 +90,11 @@ public class SingleAbstractMethodUtils {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static SimpleFunctionDescriptor getAbstractMethodOfFunctionalInterface(@NotNull ClassDescriptor klass) {
|
||||||
|
return (SimpleFunctionDescriptor) getAbstractMembers(klass).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
private SingleAbstractMethodUtils() {
|
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 */
|
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("compiler/testData/codegen/box")
|
@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 class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||||
public void testAllFilesPresentInBox() throws Exception {
|
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);
|
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")
|
@TestMetadata("compiler/testData/codegen/box/strings")
|
||||||
public static class Strings extends AbstractBlackBoxCodegenTest {
|
public static class Strings extends AbstractBlackBoxCodegenTest {
|
||||||
public void testAllFilesPresentInStrings() throws Exception {
|
public void testAllFilesPresentInStrings() throws Exception {
|
||||||
@@ -3507,6 +3530,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
suite.addTestSuite(PrimitiveTypes.class);
|
suite.addTestSuite(PrimitiveTypes.class);
|
||||||
suite.addTestSuite(Properties.class);
|
suite.addTestSuite(Properties.class);
|
||||||
suite.addTestSuite(SafeCall.class);
|
suite.addTestSuite(SafeCall.class);
|
||||||
|
suite.addTestSuite(Sam.class);
|
||||||
suite.addTestSuite(Strings.class);
|
suite.addTestSuite(Strings.class);
|
||||||
suite.addTestSuite(Super.class);
|
suite.addTestSuite(Super.class);
|
||||||
suite.addTestSuite(Traits.class);
|
suite.addTestSuite(Traits.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user