[vala/staging] vala: Transform assignment of an array element as needed



commit f853104ebf94ce1f72ab408dc5d5b50c81b69d51
Author: wxx <769218589 qq com>
Date:   Wed Dec 1 02:54:04 2021 +0800

    vala: Transform assignment of an array element as needed
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/889
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/1258

 tests/Makefile.am                                  |   2 +
 .../arrays/element-nullable-assignment.c-expected  | 154 +++++++++++++++++++++
 tests/arrays/element-nullable-assignment.vala      |  11 ++
 tests/basic-types/string-array-append.c-expected   | 118 ++++++++++++++++
 tests/basic-types/string-array-append.vala         |  12 ++
 vala/valaassignment.vala                           |  35 ++++-
 6 files changed, 325 insertions(+), 7 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0b9f71524..cf9bd1e93 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -51,6 +51,7 @@ TESTS = \
        basic-types/custom-types.vala \
        basic-types/default-gtype.vala \
        basic-types/strings.vala \
+       basic-types/string-array-append.vala \
        basic-types/string-concat-null.test \
        basic-types/arrays.vala \
        basic-types/arrays-generics.vala \
@@ -112,6 +113,7 @@ TESTS = \
        arrays/class-field-initializer.vala \
        arrays/class-field-length-cname.vala \
        arrays/constant-element-access.vala \
+       arrays/element-nullable-assignment.vala \
        arrays/empty-length-0.vala \
        arrays/expression-bracket.test \
        arrays/fixed-length-init0-not-allowed.vala \
diff --git a/tests/arrays/element-nullable-assignment.c-expected 
b/tests/arrays/element-nullable-assignment.c-expected
new file mode 100644
index 000000000..ffba74e24
--- /dev/null
+++ b/tests/arrays/element-nullable-assignment.c-expected
@@ -0,0 +1,154 @@
+/* arrays_element_nullable_assignment.c generated by valac, the Vala compiler
+ * generated from arrays_element_nullable_assignment.vala, do not modify */
+
+#include <glib.h>
+#include <string.h>
+
+#define _g_free0(var) ((var == NULL) ? NULL : (var = (g_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);
+
+static void _vala_main (void);
+static gint* _int_dup (gint* self);
+static gboolean _int_equal (const gint * s1,
+                     const gint * s2);
+static void _vala_array_destroy (gpointer array,
+                          gssize array_length,
+                          GDestroyNotify destroy_func);
+static void _vala_array_free (gpointer array,
+                       gssize array_length,
+                       GDestroyNotify destroy_func);
+
+static gint*
+_int_dup (gint* self)
+{
+       gint* dup;
+       dup = g_new0 (gint, 1);
+       memcpy (dup, self, sizeof (gint));
+       return dup;
+}
+
+static gpointer
+__int_dup0 (gpointer self)
+{
+       return self ? _int_dup (self) : NULL;
+}
+
+static gboolean
+_int_equal (const gint * s1,
+            const gint * s2)
+{
+       if (s1 == s2) {
+               return TRUE;
+       }
+       if (s1 == NULL) {
+               return FALSE;
+       }
+       if (s2 == NULL) {
+               return FALSE;
+       }
+       return (*s1) == (*s2);
+}
+
+static void
+_vala_main (void)
+{
+       gint** foo = NULL;
+       gint _tmp0_;
+       gint* _tmp1_;
+       gint _tmp2_;
+       gint* _tmp3_;
+       gint _tmp4_;
+       gint* _tmp5_;
+       gint** _tmp6_;
+       gint foo_length1;
+       gint _foo_size_;
+       gint* _tmp7_;
+       gint _tmp8_;
+       gint* _tmp9_;
+       gint* _tmp10_;
+       gint _tmp11_;
+       gint* _tmp12_;
+       gint* _tmp13_;
+       gint _tmp14_;
+       gint* _tmp15_;
+       gint* _tmp16_;
+       gint _tmp17_;
+       gint* _tmp18_;
+       gint _tmp19_;
+       gint* _tmp20_;
+       gint _tmp21_;
+       _tmp0_ = 23;
+       _tmp1_ = __int_dup0 (&_tmp0_);
+       _tmp2_ = 42;
+       _tmp3_ = __int_dup0 (&_tmp2_);
+       _tmp4_ = 4711;
+       _tmp5_ = __int_dup0 (&_tmp4_);
+       _tmp6_ = g_new0 (gint*, 3);
+       _tmp6_[0] = _tmp1_;
+       _tmp6_[1] = _tmp3_;
+       _tmp6_[2] = _tmp5_;
+       foo = _tmp6_;
+       foo_length1 = 3;
+       _foo_size_ = foo_length1;
+       _tmp7_ = foo[0];
+       _tmp8_ = (*_tmp7_) + 1;
+       _tmp9_ = __int_dup0 (&_tmp8_);
+       _g_free0 (foo[0]);
+       foo[0] = _tmp9_;
+       _tmp10_ = foo[1];
+       _tmp11_ = (*_tmp10_) * 3;
+       _tmp12_ = __int_dup0 (&_tmp11_);
+       _g_free0 (foo[1]);
+       foo[1] = _tmp12_;
+       _tmp13_ = foo[2];
+       _tmp14_ = (*_tmp13_) - 2;
+       _tmp15_ = __int_dup0 (&_tmp14_);
+       _g_free0 (foo[2]);
+       foo[2] = _tmp15_;
+       _tmp16_ = foo[0];
+       _tmp17_ = 24;
+       _vala_assert (_int_equal (_tmp16_, &_tmp17_) == TRUE, "foo[0] == 24");
+       _tmp18_ = foo[1];
+       _tmp19_ = 126;
+       _vala_assert (_int_equal (_tmp18_, &_tmp19_) == TRUE, "foo[1] == 126");
+       _tmp20_ = foo[2];
+       _tmp21_ = 4709;
+       _vala_assert (_int_equal (_tmp20_, &_tmp21_) == TRUE, "foo[2] == 4709");
+       foo = (_vala_array_free (foo, foo_length1, (GDestroyNotify) g_free), NULL);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
+static void
+_vala_array_destroy (gpointer array,
+                     gssize array_length,
+                     GDestroyNotify destroy_func)
+{
+       if ((array != NULL) && (destroy_func != NULL)) {
+               gssize i;
+               for (i = 0; i < array_length; i = i + 1) {
+                       if (((gpointer*) array)[i] != NULL) {
+                               destroy_func (((gpointer*) array)[i]);
+                       }
+               }
+       }
+}
+
+static void
+_vala_array_free (gpointer array,
+                  gssize array_length,
+                  GDestroyNotify destroy_func)
+{
+       _vala_array_destroy (array, array_length, destroy_func);
+       g_free (array);
+}
+
diff --git a/tests/arrays/element-nullable-assignment.vala b/tests/arrays/element-nullable-assignment.vala
new file mode 100644
index 000000000..29dc2950e
--- /dev/null
+++ b/tests/arrays/element-nullable-assignment.vala
@@ -0,0 +1,11 @@
+void main () {
+       int?[] foo = { 23, 42, 4711 };
+
+       foo[0] += 1;
+       foo[1] *= 3;
+       foo[2] -= 2;
+
+       assert (foo[0] == 24);
+       assert (foo[1] == 126);
+       assert (foo[2] == 4709);
+}
diff --git a/tests/basic-types/string-array-append.c-expected 
b/tests/basic-types/string-array-append.c-expected
new file mode 100644
index 000000000..222f34faa
--- /dev/null
+++ b/tests/basic-types/string-array-append.c-expected
@@ -0,0 +1,118 @@
+/* basic_types_string_array_append.c generated by valac, the Vala compiler
+ * generated from basic_types_string_array_append.vala, do not modify */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define _g_free0(var) (var = (g_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);
+
+static void _vala_main (void);
+static void _vala_array_destroy (gpointer array,
+                          gssize array_length,
+                          GDestroyNotify destroy_func);
+static void _vala_array_free (gpointer array,
+                       gssize array_length,
+                       GDestroyNotify destroy_func);
+
+static void
+_vala_main (void)
+{
+       gchar** foo = NULL;
+       gchar* _tmp0_;
+       gchar* _tmp1_;
+       gchar* _tmp2_;
+       gchar** _tmp3_;
+       gint foo_length1;
+       gint _foo_size_;
+       const gchar* _tmp4_;
+       gchar* _tmp5_;
+       const gchar* _tmp6_;
+       gchar* _tmp7_;
+       gchar* _tmp8_;
+       gchar* _tmp9_;
+       const gchar* _tmp10_;
+       gchar* _tmp11_;
+       gchar* _tmp12_;
+       gchar* _tmp13_;
+       gchar* _tmp14_;
+       gchar* _tmp15_;
+       const gchar* _tmp16_;
+       const gchar* _tmp17_;
+       const gchar* _tmp18_;
+       _tmp0_ = g_strdup ("foo");
+       _tmp1_ = g_strdup ("bar");
+       _tmp2_ = g_strdup ("foo bar");
+       _tmp3_ = g_new0 (gchar*, 3 + 1);
+       _tmp3_[0] = _tmp0_;
+       _tmp3_[1] = _tmp1_;
+       _tmp3_[2] = _tmp2_;
+       foo = _tmp3_;
+       foo_length1 = 3;
+       _foo_size_ = foo_length1;
+       _tmp4_ = foo[0];
+       _tmp5_ = g_strconcat (_tmp4_, "abc", NULL);
+       _g_free0 (foo[0]);
+       foo[0] = _tmp5_;
+       _tmp6_ = foo[1];
+       _tmp7_ = g_strdup_printf ("%i", 123);
+       _tmp8_ = _tmp7_;
+       _tmp9_ = g_strconcat (_tmp6_, _tmp8_, NULL);
+       _g_free0 (foo[1]);
+       foo[1] = _tmp9_;
+       _g_free0 (_tmp8_);
+       _tmp10_ = foo[2];
+       _tmp11_ = g_strdup_printf ("%i", 123);
+       _tmp12_ = _tmp11_;
+       _tmp13_ = g_strconcat (" abc", _tmp12_, NULL);
+       _tmp14_ = _tmp13_;
+       _tmp15_ = g_strconcat (_tmp10_, _tmp14_, NULL);
+       _g_free0 (foo[2]);
+       foo[2] = _tmp15_;
+       _g_free0 (_tmp14_);
+       _g_free0 (_tmp12_);
+       _tmp16_ = foo[0];
+       _vala_assert (g_strcmp0 (_tmp16_, "fooabc") == 0, "foo[0] == \"fooabc\"");
+       _tmp17_ = foo[1];
+       _vala_assert (g_strcmp0 (_tmp17_, "bar123") == 0, "foo[1] == \"bar123\"");
+       _tmp18_ = foo[2];
+       _vala_assert (g_strcmp0 (_tmp18_, "foo bar abc123") == 0, "foo[2] == \"foo bar abc123\"");
+       foo = (_vala_array_free (foo, foo_length1, (GDestroyNotify) g_free), NULL);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
+static void
+_vala_array_destroy (gpointer array,
+                     gssize array_length,
+                     GDestroyNotify destroy_func)
+{
+       if ((array != NULL) && (destroy_func != NULL)) {
+               gssize i;
+               for (i = 0; i < array_length; i = i + 1) {
+                       if (((gpointer*) array)[i] != NULL) {
+                               destroy_func (((gpointer*) array)[i]);
+                       }
+               }
+       }
+}
+
+static void
+_vala_array_free (gpointer array,
+                  gssize array_length,
+                  GDestroyNotify destroy_func)
+{
+       _vala_array_destroy (array, array_length, destroy_func);
+       g_free (array);
+}
+
diff --git a/tests/basic-types/string-array-append.vala b/tests/basic-types/string-array-append.vala
new file mode 100644
index 000000000..4b1ae328e
--- /dev/null
+++ b/tests/basic-types/string-array-append.vala
@@ -0,0 +1,12 @@
+void main () {
+       string[] foo = { "foo", "bar", "foo bar" };
+
+       foo[0] += "abc";
+       foo[1] += 123.to_string ();
+       foo[2] += " abc" + 123.to_string ();
+
+       assert (foo[0] == "fooabc");
+       assert (foo[1] == "bar123");
+       assert (foo[2] == "foo bar abc123");
+}
+
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index 8c0948ef3..150c34723 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -229,13 +229,36 @@ public class Vala.Assignment : Expression {
                }
 
                unowned MemberAccess? ma = left as MemberAccess;
-               if (operator != AssignmentOperator.SIMPLE && ma != null
-                   && !(left.value_type.is_non_null_simple_type () && ma.symbol_reference is LocalVariable)) 
{
+               unowned ElementAccess? ea = left as ElementAccess;
+               bool transform_assignment = false;
+
+               if (ma != null && !(ma.symbol_reference is LocalVariable)) {
+                       transform_assignment = true;
+               } else if (left.value_type != null && !left.value_type.is_non_null_simple_type ()) {
+                       transform_assignment = true;
+               } else if (ea != null && ea.container.value_type is ArrayType) {
+                       // check if the left is an array and its element is non-null simple type
+                       unowned ArrayType array_type = (ArrayType) ea.container.value_type;
+                       transform_assignment = !array_type.element_type.is_non_null_simple_type ();
+               }
+
+               if ((operator != AssignmentOperator.SIMPLE) && transform_assignment) {
                        // transform into simple assignment
                        // FIXME: only do this if the backend doesn't support
                        // the assignment natively
-
-                       var old_value = new MemberAccess (ma.inner, ma.member_name, source_reference);
+                       Expression old_value = null;
+
+                       if (ma != null) {
+                               old_value = new MemberAccess (ma.inner, ma.member_name, 
left.source_reference);
+                       } else if (ea !=null) {
+                               old_value = new ElementAccess (ea.container, left.source_reference);
+                               var indices = ea.get_indices ();
+                               foreach (var index in indices) {
+                                       ((ElementAccess) old_value).append_index (index);
+                               }
+                       } else {
+                               assert_not_reached ();
+                       }
 
                        BinaryOperator bop;
 
@@ -361,9 +384,7 @@ public class Vala.Assignment : Expression {
                                        }
                                }
                        }
-               } else if (left is ElementAccess) {
-                       unowned ElementAccess ea = (ElementAccess) left;
-
+               } else if (ea != null) {
                        if (!right.value_type.compatible (left.value_type)) {
                                error = true;
                                Report.error (source_reference, "Assignment: Cannot convert from `%s' to 
`%s'", right.value_type.to_string (), left.value_type.to_string ());


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]