diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 32b2568f2cb..8232d4a272e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2849,7 +2849,9 @@ public class ExpressionCodegen extends JetVisitor 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 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++; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java index da5904adfd4..bd025258beb 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/binding/CodegenAnnotatingVisitor.java @@ -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 indexExpressions = expression.getIndexExpressions(); + List 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)) { diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.java b/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.java new file mode 100644 index 00000000000..4cda5428442 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.java @@ -0,0 +1,6 @@ +class JavaClass { + int get(Runnable i) { + i.run(); + return 239; + } +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.kt b/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.kt new file mode 100644 index 00000000000..c4bad79f808 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/get.kt @@ -0,0 +1,7 @@ +fun box(): String { + val obj = JavaClass() + + var v = "FAIL" + obj[{ v = "OK" }] + return v +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.java b/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.java new file mode 100644 index 00000000000..75c0ddc46a9 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.java @@ -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(); + } +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.kt b/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.kt new file mode 100644 index 00000000000..74d21d6b861 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/multiGetSet.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.java b/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.java new file mode 100644 index 00000000000..037f17f3870 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.java @@ -0,0 +1,6 @@ +class JavaClass { + void set(Runnable i, Runnable value) { + i.run(); + value.run(); + } +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.kt b/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.kt new file mode 100644 index 00000000000..ccb81a8cd8f --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/operators/set.kt @@ -0,0 +1,7 @@ +fun box(): String { + val obj = JavaClass() + + var v = "FAIL" + obj[{ v = "O" }] = { v += "K" } + return v +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index d6e6f8b39bf..e58f94bc8cb 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -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());