Supported SAM adapters as get/set operators.

This commit is contained in:
Evgeny Gerashchenko
2013-06-26 00:17:14 +04:00
parent 779ea1d7b8
commit b1fb0aafea
9 changed files with 126 additions and 3 deletions
@@ -2849,7 +2849,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
StackValue stackValue = gen(expression.getLeft());
gen(expression.getRight(), stackValue.type);
JetExpression right = expression.getRight();
assert right != null : expression.getText();
samAwareGen(right, stackValue.type);
stackValue.store(stackValue.type, v);
return StackValue.none();
}
@@ -3374,7 +3376,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getSignature().getAsmMethod();
Type[] argumentTypes = asmMethod.getArgumentTypes();
for (JetExpression jetExpression : expression.getIndexExpressions()) {
gen(jetExpression, argumentTypes[index]);
samAwareGen(jetExpression, argumentTypes[index]);
index++;
}
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen.binding;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
import java.util.HashMap;
@@ -381,6 +383,43 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
}
}
@Override
public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
super.visitArrayAccessExpression(expression);
FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
if (operationDescriptor == null) {
return;
}
boolean isSetter = operationDescriptor.getName().asString().equals("set");
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter(bindingContext, operationDescriptor);
if (original == null) {
return;
}
List<JetExpression> indexExpressions = expression.getIndexExpressions();
List<ValueParameterDescriptor> parameters = original.getValueParameters();
for (ValueParameterDescriptor valueParameter : parameters) {
ClassDescriptorFromJvmBytecode samInterface = getInterfaceIfSamType(valueParameter.getType());
if (samInterface == null) {
continue;
}
if (isSetter && valueParameter.getIndex() == parameters.size() - 1) {
PsiElement parent = expression.getParent();
if (parent instanceof JetBinaryExpression && ((JetBinaryExpression) parent).getOperationToken() == JetTokens.EQ) {
JetExpression right = ((JetBinaryExpression) parent).getRight();
bindingTrace.record(CodegenBinding.SAM_VALUE, right, samInterface);
}
}
else {
JetExpression indexExpression = indexExpressions.get(valueParameter.getIndex());
bindingTrace.record(CodegenBinding.SAM_VALUE, indexExpression, samInterface);
}
}
}
@Nullable
private static ClassDescriptorFromJvmBytecode getInterfaceIfSamType(@NotNull JetType originalType) {
if (!SingleAbstractMethodUtils.isSamType(originalType)) {
@@ -0,0 +1,6 @@
class JavaClass {
int get(Runnable i) {
i.run();
return 239;
}
}
@@ -0,0 +1,7 @@
fun box(): String {
val obj = JavaClass()
var v = "FAIL"
obj[{ v = "OK" }]
return v
}
@@ -0,0 +1,13 @@
class JavaClass {
int get(Runnable i1, Runnable i2) {
i1.run();
i2.run();
return 239;
}
void set(Runnable i1, Runnable i2, Runnable value) {
i1.run();
i2.run();
value.run();
}
}
@@ -0,0 +1,13 @@
fun box(): String {
val obj = JavaClass()
var v1 = "FAIL"
obj[{ v1 = "O" }, { v1 += "K" }]
if (v1 != "OK") return "get: $v1"
var v2 = "FAIL"
obj[{ v2 = "" }, { v2 += "O" }] = { v2 += "K" }
if (v2 != "OK") return "set: $v2"
return "OK"
}
@@ -0,0 +1,6 @@
class JavaClass {
void set(Runnable i, Runnable value) {
i.run();
value.run();
}
}
@@ -0,0 +1,7 @@
fun box(): String {
val obj = JavaClass()
var v = "FAIL"
obj[{ v = "O" }] = { v += "K" }
return v
}
@@ -130,6 +130,7 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
}
@TestMetadata("compiler/testData/codegen/boxWithJava/samAdapters")
@InnerTestClasses({SamAdapters.Operators.class})
public static class SamAdapters extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInSamAdapters() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithJava/samAdapters"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -225,6 +226,35 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/typeParameterOfOuterClass.kt");
}
@TestMetadata("compiler/testData/codegen/boxWithJava/samAdapters/operators")
public static class Operators extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInOperators() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithJava/samAdapters/operators"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("get.kt")
public void testGet() throws Exception {
doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/operators/get.kt");
}
@TestMetadata("multiGetSet.kt")
public void testMultiGetSet() throws Exception {
doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.kt");
}
@TestMetadata("set.kt")
public void testSet() throws Exception {
doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/operators/set.kt");
}
}
public static Test innerSuite() {
TestSuite suite = new TestSuite("SamAdapters");
suite.addTestSuite(SamAdapters.class);
suite.addTestSuite(Operators.class);
return suite;
}
}
@TestMetadata("compiler/testData/codegen/boxWithJava/samWrappers")
@@ -401,7 +431,7 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
suite.addTestSuite(Enum.class);
suite.addTestSuite(Functions.class);
suite.addTestSuite(Property.class);
suite.addTestSuite(SamAdapters.class);
suite.addTest(SamAdapters.innerSuite());
suite.addTestSuite(SamWrappers.class);
suite.addTestSuite(StaticFun.class);
suite.addTest(Visibility.innerSuite());