From: wxx <769218589@qq.com> Date: Tue, 30 Nov 2021 18:54:04 +0000 (+0800) Subject: vala: Transform assignment of an array element as needed X-Git-Tag: 0.55.2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f853104ebf94ce1f72ab408dc5d5b50c81b69d51;p=thirdparty%2Fvala.git 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 --- 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 +#include + +#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 +#include +#include + +#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 ());