]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Fix assignment operators for element access
authorSimon Werbeck <simon.werbeck@gmail.com>
Tue, 17 Jul 2012 16:30:51 +0000 (18:30 +0200)
committerRico Tzschichholz <ricotz@ubuntu.com>
Mon, 14 Nov 2022 14:37:21 +0000 (15:37 +0100)
This transforms an assignment to element access other than `=' to a
binary expression i.e. `a[b] += 1' will become `a.set(a.get(b) + 1)'

Fixes https://gitlab.gnome.org/GNOME/vala/issues/135

tests/Makefile.am
tests/semantic/assignment-element-getter-setter.c-expected [new file with mode: 0644]
tests/semantic/assignment-element-getter-setter.vala [new file with mode: 0644]
vala/valaassignment.vala

index b93d4963caee98bb2b150b280c25bbd2702fc95d..4536dcb3b1cf6cd4298ad5c6cdc5dc01ad5ac37e 100644 (file)
@@ -1045,6 +1045,7 @@ TESTS = \
        semantic/array-length-nullable.test \
        semantic/array-too-few-type-arguments.test \
        semantic/array-too-many-type-arguments.test \
+       semantic/assignment-element-getter-setter.vala \
        semantic/assignment-element-incompatible-ownership.test \
        semantic/assignment-element-incompatible-type.test \
        semantic/assignment-fixed-array-length.test \
diff --git a/tests/semantic/assignment-element-getter-setter.c-expected b/tests/semantic/assignment-element-getter-setter.c-expected
new file mode 100644 (file)
index 0000000..b0abb87
--- /dev/null
@@ -0,0 +1,140 @@
+/* semantic_assignment_element_getter_setter.c generated by valac, the Vala compiler
+ * generated from semantic_assignment_element_getter_setter.vala, do not modify */
+
+#include <glib.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+typedef struct _Foo Foo;
+#define _foo_free0(var) ((var == NULL) ? NULL : (var = (foo_free (var), NULL)))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+struct _Foo {
+       gpointer* elements;
+       gint elements_length1;
+};
+
+VALA_EXTERN void foo_free (Foo * self);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, foo_free)
+static void foo_instance_init (Foo * self);
+VALA_EXTERN Foo* foo_new (void);
+VALA_EXTERN gpointer foo_get (Foo* self,
+                  gint idx);
+VALA_EXTERN void foo_set (Foo* self,
+              gint idx,
+              gconstpointer val);
+static void _vala_main (void);
+
+Foo*
+foo_new (void)
+{
+       Foo* self;
+       gpointer* _tmp0_;
+       self = g_slice_new0 (Foo);
+       foo_instance_init (self);
+       _tmp0_ = g_new0 (gpointer, 1);
+       _tmp0_[0] = NULL;
+       self->elements = (g_free (self->elements), NULL);
+       self->elements = _tmp0_;
+       self->elements_length1 = 1;
+       return self;
+}
+
+gpointer
+foo_get (Foo* self,
+         gint idx)
+{
+       gpointer* _tmp0_;
+       gint _tmp0__length1;
+       gconstpointer _tmp1_;
+       gpointer result;
+       g_return_val_if_fail (self != NULL, NULL);
+       _tmp0_ = self->elements;
+       _tmp0__length1 = self->elements_length1;
+       _tmp1_ = _tmp0_[idx];
+       result = _tmp1_;
+       return result;
+}
+
+void
+foo_set (Foo* self,
+         gint idx,
+         gconstpointer val)
+{
+       gpointer* _tmp0_;
+       gint _tmp0__length1;
+       g_return_if_fail (self != NULL);
+       _tmp0_ = self->elements;
+       _tmp0__length1 = self->elements_length1;
+       _tmp0_[idx] = val;
+}
+
+static void
+foo_instance_init (Foo * self)
+{
+}
+
+void
+foo_free (Foo * self)
+{
+       self->elements = (g_free (self->elements), NULL);
+       g_slice_free (Foo, self);
+}
+
+static void
+_vala_main (void)
+{
+       Foo* foo = NULL;
+       Foo* _tmp0_;
+       gpointer _tmp1_;
+       gpointer _tmp2_;
+       gpointer _tmp3_;
+       gpointer _tmp4_;
+       gpointer _tmp5_;
+       gpointer _tmp6_;
+       gpointer _tmp7_;
+       gpointer _tmp8_;
+       gpointer _tmp9_;
+       _tmp0_ = foo_new ();
+       foo = _tmp0_;
+       foo_set (foo, 0, (gpointer) ((gintptr) 23));
+       _tmp1_ = foo_get (foo, 0);
+       _vala_assert (((gint) ((gintptr) _tmp1_)) == 23, "foo[0] == 23");
+       _tmp2_ = foo_get (foo, 0);
+       foo_set (foo, 0, (gpointer) ((gintptr) (((gint) ((gintptr) _tmp2_)) + 42)));
+       _tmp3_ = foo_get (foo, 0);
+       _vala_assert (((gint) ((gintptr) _tmp3_)) == 65, "foo[0] == 65");
+       _tmp4_ = foo_get (foo, 0);
+       foo_set (foo, 0, (gpointer) ((gintptr) (((gint) ((gintptr) _tmp4_)) * 2)));
+       _tmp5_ = foo_get (foo, 0);
+       _vala_assert (((gint) ((gintptr) _tmp5_)) == 130, "foo[0] == 130");
+       _tmp6_ = foo_get (foo, 0);
+       foo_set (foo, 0, (gpointer) ((gintptr) (((gint) ((gintptr) _tmp6_)) / 5)));
+       _tmp7_ = foo_get (foo, 0);
+       _vala_assert (((gint) ((gintptr) _tmp7_)) == 26, "foo[0] == 26");
+       _tmp8_ = foo_get (foo, 0);
+       foo_set (foo, 0, (gpointer) ((gintptr) (((gint) ((gintptr) _tmp8_)) - 4711)));
+       _tmp9_ = foo_get (foo, 0);
+       _vala_assert (((gint) ((gintptr) _tmp9_)) == -4685, "foo[0] == -4685");
+       _foo_free0 (foo);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/semantic/assignment-element-getter-setter.vala b/tests/semantic/assignment-element-getter-setter.vala
new file mode 100644 (file)
index 0000000..8399dc0
--- /dev/null
@@ -0,0 +1,35 @@
+[Compact]
+public class Foo<G> {
+       public G[] elements;
+
+       public Foo () {
+               elements = new G[] { null };
+       }
+
+       public G get (int idx) {
+               return elements[idx];
+       }
+
+       public void set (int idx, G val) {
+               elements[idx] = val;
+       }
+}
+
+void main () {
+       var foo = new Foo<int> ();
+
+       foo[0] = 23;
+       assert (foo[0] == 23);
+
+       foo[0] += 42;
+       assert (foo[0] == 65);
+
+       foo[0] *= 2;
+       assert (foo[0] == 130);
+
+       foo[0] /= 5;
+       assert (foo[0] == 26);
+
+       foo[0] -= 4711;
+       assert (foo[0] == -4685);
+}
index 150c34723c83496368a3def06200103aab26a219..929fa7b66cb94e7db4c16c769df9e2ccabba4345 100644 (file)
@@ -204,6 +204,36 @@ public class Vala.Assignment : Expression {
                                foreach (Expression e in ea.get_indices ()) {
                                        set_call.add_argument (e);
                                }
+
+                               if (operator != AssignmentOperator.SIMPLE && ea.container.value_type.get_member ("get") is Method) {
+                                       // transform into binary expression inside set call
+                                       var get_call = new MethodCall (new MemberAccess (ea.container, "get", source_reference), source_reference);
+                                       foreach (Expression e in ea.get_indices ()) {
+                                               get_call.add_argument (e);
+                                       }
+
+                                       BinaryOperator bop;
+
+                                       switch (operator) {
+                                       case AssignmentOperator.BITWISE_OR: bop = BinaryOperator.BITWISE_OR; break;
+                                       case AssignmentOperator.BITWISE_AND: bop = BinaryOperator.BITWISE_AND; break;
+                                       case AssignmentOperator.BITWISE_XOR: bop = BinaryOperator.BITWISE_XOR; break;
+                                       case AssignmentOperator.ADD: bop = BinaryOperator.PLUS; break;
+                                       case AssignmentOperator.SUB: bop = BinaryOperator.MINUS; break;
+                                       case AssignmentOperator.MUL: bop = BinaryOperator.MUL; break;
+                                       case AssignmentOperator.DIV: bop = BinaryOperator.DIV; break;
+                                       case AssignmentOperator.PERCENT: bop = BinaryOperator.MOD; break;
+                                       case AssignmentOperator.SHIFT_LEFT: bop = BinaryOperator.SHIFT_LEFT; break;
+                                       case AssignmentOperator.SHIFT_RIGHT: bop = BinaryOperator.SHIFT_RIGHT; break;
+                                       default:
+                                               error = true;
+                                               Report.error (source_reference, "internal error: unsupported assignment operator");
+                                               return false;
+                                       }
+
+                                       right = new BinaryExpression (bop, get_call, right, source_reference);
+                               }
+
                                set_call.add_argument (right);
                                parent_node.replace_expression (this, set_call);
                                return set_call.check (context);