From 3bd202de8473db1d8840a9724b1163cda76d157f Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 21 Mar 2013 21:20:52 +0400 Subject: [PATCH] Allow to call += on a val --- .../ExpressionTypingVisitorForStatements.java | 5 ++- .../assignmentOperations.kt | 36 +++++++++++++++++ .../AssignmentOperations.kt | 40 +++++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ .../BlackBoxCodegenTestGenerated.java | 5 +++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt create mode 100644 compiler/testData/diagnostics/tests/operatorsOverloading/AssignmentOperations.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 0b6b240a26f..622abc94faa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -238,6 +238,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; if (assignmentOperationType != null && binaryOperationType != null) { + // Both 'plus()' and 'plusAssign()' available => ambiguity OverloadResolutionResults ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors); context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls())); Collection descriptors = Sets.newHashSet(); @@ -248,12 +249,14 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } else if (assignmentOperationType != null) { + // There's 'plusAssign()', so we do a.plusAssign(b) assignmentOperationTrace.commit(); if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) { context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign)); } } else { + // There's only 'plus()', so we try 'a = a + b' binaryOperationTrace.commit(); context.trace.record(VARIABLE_REASSIGNMENT, expression); if (left instanceof JetArrayAccessExpression) { @@ -262,8 +265,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); + basic.checkLValue(context.trace, expression.getLeft()); } - basic.checkLValue(context.trace, expression.getLeft()); temporaryBindingTrace.commit(); return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); } diff --git a/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt b/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt new file mode 100644 index 00000000000..02f320878f7 --- /dev/null +++ b/compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt @@ -0,0 +1,36 @@ +class A() { + var x = 0 +} + +fun A.plusAssign(y: Int) { x += y } +fun A.minusAssign(y: Int) { x -= y } +fun A.timesAssign(y: Int) { x *= y } +fun A.divAssign(y: Int) { x /= y } +fun A.modAssign(y: Int) { x %= y } + +fun box(): String { + val original = A() + val a = original + + a += 1 + if (!(a identityEquals original)) return "Fail 1: $a !== $original" + if (a.x != 1) return "Fail 2: ${a.x} != 1" + + a -= 2 + if (!(a identityEquals original)) return "Fail 3: $a !== $original" + if (a.x != -1) return "Fail 4: ${a.x} != -1" + + a *= -10 + if (!(a identityEquals original)) return "Fail 5: $a !== $original" + if (a.x != 10) return "Fail 6: ${a.x} != 10" + + a /= 3 + if (!(a identityEquals original)) return "Fail 7: $a !== $original" + if (a.x != 3) return "Fail 8: ${a.x} != 3" + + a %= 2 + if (!(a identityEquals original)) return "Fail 9: $a !== $original" + if (a.x != 1) return "Fail 10: ${a.x} != 1" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/AssignmentOperations.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/AssignmentOperations.kt new file mode 100644 index 00000000000..7027dc751f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/AssignmentOperations.kt @@ -0,0 +1,40 @@ +class A { + fun plusAssign(x: Int) {} + fun minusAssign(x: Int) {} + fun timesAssign(x: Int) {} + fun divAssign(x: Int) {} + fun modAssign(x: Int) {} +} + +fun testVal() { + val a = A() + a += 1 + a -= 1 + a *= 1 + a /= 1 + a %= 1 +} + +fun testExpr() { + A() += 1 + A() -= 1 + A() *= 1 + A() /= 1 + A() %= 1 +} + +class B { + fun plus(x: Int): B = B() + fun minus(x: Int): B = B() + fun times(x: Int): B = B() + fun div(x: Int): B = B() + fun mod(x: Int): B = B() +} + +fun testWrong() { + B() += 1 + B() -= 1 + B() *= 1 + B() /= 1 + B() %= 1 +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 7cedb124fa7..19b18b0c4c1 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3076,6 +3076,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/operatorsOverloading/AssignOperatorAmbiguity.kt"); } + @TestMetadata("AssignmentOperations.kt") + public void testAssignmentOperations() throws Exception { + doTest("compiler/testData/diagnostics/tests/operatorsOverloading/AssignmentOperations.kt"); + } + @TestMetadata("IteratorAmbiguity.kt") public void testIteratorAmbiguity() throws Exception { doTest("compiler/testData/diagnostics/tests/operatorsOverloading/IteratorAmbiguity.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 4b695dcce92..4a8b08c8787 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -2728,6 +2728,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/operatorConventions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("assignmentOperations.kt") + public void testAssignmentOperations() throws Exception { + doTest("compiler/testData/codegen/box/operatorConventions/assignmentOperations.kt"); + } + @TestMetadata("compiler/testData/codegen/box/operatorConventions/compareTo") public static class CompareTo extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInCompareTo() throws Exception {