[vala/wip/issue/607: 47/48] Add native support to specify non default length-type for arrays




commit bc41b66ca94c6374eb18f5a23cfb01fe72e30289
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Thu Apr 15 16:49:14 2021 +0200

    Add native support to specify non default length-type for arrays
    
        string[:long] foo = new string[:long] { "foo" };
    
    This applies to generated bindings where this new syntax will be
    picked up. It will apply a stricker variable type checking for
    such array types.
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/607

 tests/Makefile.am                          |   4 +
 tests/arrays/length-type.c-expected        | 210 +++++++++++++++++++++++++++++
 tests/arrays/length-type.vala              |  49 +++++++
 tests/gir/bug651773.test                   |   4 +-
 tests/gir/bug788775.test                   |   4 +-
 tests/gir/delegate-array-length-type.test  |   4 +-
 tests/gir/method-array-length-type.test    |   4 +-
 tests/gir/parameter-array-length-type.test |   2 +-
 tests/parser/array-length.c-expected       |  90 +++++++++++++
 tests/parser/array-length.vala             |  13 ++
 tests/semantic/array-length-invalid.test   |   5 +
 tests/semantic/array-length-nullable.test  |   5 +
 vala/valaarraycreationexpression.vala      |   4 +
 vala/valaarraytype.vala                    |   8 +-
 vala/valacodewriter.vala                   |   5 +
 vala/valagirparser.vala                    |  22 +--
 vala/valaparser.vala                       |  33 ++++-
 17 files changed, 437 insertions(+), 29 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2628320bb..f6bd6cab8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -126,6 +126,7 @@ TESTS = \
        arrays/inline-struct-field.test \
        arrays/in-operator-with-boxed-needle.vala \
        arrays/length-inline-assignment.vala \
+       arrays/length-type.vala \
        arrays/length-type-include.vala \
        arrays/length-no-int-type.test \
        arrays/struct-field-length-cname.vala \
@@ -845,6 +846,7 @@ TESTS = \
        scanner/string-escape-x.vala \
        parser/argument-list-incomplete.test \
        parser/array-creation-invalid.test \
+       parser/array-length.vala \
        parser/assignment.vala \
        parser/attribute-duplicate.test \
        parser/attribute-missing-literal.test \
@@ -963,6 +965,8 @@ TESTS = \
        semantic/array-incompatible-initializer.test \
        semantic/array-incompatible-initializer2.test \
        semantic/array-invalid-type-argument.test \
+       semantic/array-length-invalid.test \
+       semantic/array-length-nullable.test \
        semantic/array-too-few-type-arguments.test \
        semantic/array-too-many-type-arguments.test \
        semantic/assignment-element-incompatible-ownership.test \
diff --git a/tests/arrays/length-type.c-expected b/tests/arrays/length-type.c-expected
new file mode 100644
index 000000000..7da10b31d
--- /dev/null
+++ b/tests/arrays/length-type.c-expected
@@ -0,0 +1,210 @@
+/* arrays_length_type.c generated by valac, the Vala compiler
+ * generated from arrays_length_type.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 guint8* (*ManamFunc) (guint8* param, gsize param_length1, guint64* result_length1);
+#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);
+
+VALA_EXTERN guint8* field;
+VALA_EXTERN gsize field_length1;
+guint8* field = NULL;
+gsize field_length1 = 0;
+static gsize _field_size_ = 0;
+
+VALA_EXTERN guint8* manam (guint8* param,
+               gsize param_length1,
+               guint64* result_length1);
+VALA_EXTERN void test_pass (void);
+static guint8* _manam_manam_func (guint8* param,
+                           gsize param_length1,
+                           guint64* result_length1);
+VALA_EXTERN void foo (guint8** param,
+          gssize* param_length1);
+VALA_EXTERN void test_ref (void);
+VALA_EXTERN void bar (guint8** param,
+          gssize* param_length1);
+VALA_EXTERN void test_out (void);
+static void _vala_main (void);
+
+guint8*
+manam (guint8* param,
+       gsize param_length1,
+       guint64* result_length1)
+{
+       guint8* _tmp0_;
+       guint64 _tmp0__length1;
+       guint8* result = NULL;
+       _vala_assert (((gint64) param_length1) == 2147483648LL, "param.length == 2147483648LL");
+       _tmp0_ = param;
+       _tmp0__length1 = param_length1;
+       if (result_length1) {
+               *result_length1 = _tmp0__length1;
+       }
+       result = _tmp0_;
+       return result;
+}
+
+static guint8*
+_manam_manam_func (guint8* param,
+                   gsize param_length1,
+                   guint64* result_length1)
+{
+       guint8* result;
+       result = manam (param, param_length1, result_length1);
+       return result;
+}
+
+void
+test_pass (void)
+{
+       guint8* foo = NULL;
+       guint8* _tmp0_;
+       gssize foo_length1;
+       gssize _foo_size_;
+       guint8* _tmp1_;
+       gssize _tmp1__length1;
+       ManamFunc func = NULL;
+       guint8* bar = NULL;
+       guint8* _tmp2_;
+       gssize _tmp2__length1;
+       guint64 _tmp3_ = 0;
+       guint8* _tmp4_;
+       guint64 bar_length1;
+       guint64 _bar_size_;
+       guint8* _tmp5_;
+       gssize _tmp5__length1;
+       guint8* _tmp6_;
+       gsize _tmp6__length1;
+       _tmp0_ = g_new0 (guint8, 2147483648LL);
+       foo = _tmp0_;
+       foo_length1 = 2147483648LL;
+       _foo_size_ = foo_length1;
+       _tmp1_ = foo;
+       _tmp1__length1 = foo_length1;
+       _vala_assert (((gint64) _tmp1__length1) == 2147483648LL, "foo.length == 2147483648LL");
+       func = _manam_manam_func;
+       _tmp2_ = foo;
+       _tmp2__length1 = foo_length1;
+       _tmp4_ = func (_tmp2_, (gsize) _tmp2__length1, &_tmp3_);
+       bar = _tmp4_;
+       bar_length1 = _tmp3_;
+       _bar_size_ = bar_length1;
+       _vala_assert (bar_length1 == ((guint64) 2147483648LL), "bar.length == 2147483648LL");
+       _tmp5_ = foo;
+       _tmp5__length1 = foo_length1;
+       foo = NULL;
+       foo_length1 = 0;
+       field = (g_free (field), NULL);
+       field = _tmp5_;
+       field_length1 = _tmp5__length1;
+       _field_size_ = field_length1;
+       _tmp6_ = field;
+       _tmp6__length1 = field_length1;
+       _vala_assert (((gint64) _tmp6__length1) == 2147483648LL, "field.length == 2147483648LL");
+       field = (g_free (field), NULL);
+       field = NULL;
+       field_length1 = 0;
+       _field_size_ = field_length1;
+       foo = (g_free (foo), NULL);
+}
+
+void
+foo (guint8** param,
+     gssize* param_length1)
+{
+       guint8* _tmp0_;
+       _tmp0_ = g_new0 (guint8, 2147483648LL);
+       *param = (g_free (*param), NULL);
+       *param = _tmp0_;
+       *param_length1 = 2147483648LL;
+}
+
+void
+test_ref (void)
+{
+       guint8* a = NULL;
+       guint8* _tmp0_;
+       gssize a_length1;
+       gssize _a_size_;
+       guint8* _tmp1_;
+       gssize _tmp1__length1;
+       _tmp0_ = g_new0 (guint8, 0);
+       a = _tmp0_;
+       a_length1 = 0;
+       _a_size_ = a_length1;
+       foo (&a, (gssize*) (&a_length1));
+       _a_size_ = a_length1;
+       _tmp1_ = a;
+       _tmp1__length1 = a_length1;
+       _vala_assert (((gint64) _tmp1__length1) == 2147483648LL, "a.length == 2147483648LL");
+       a = (g_free (a), NULL);
+}
+
+void
+bar (guint8** param,
+     gssize* param_length1)
+{
+       guint8* _vala_param = NULL;
+       gssize _vala_param_length1 = 0;
+       guint8* _tmp0_;
+       _tmp0_ = g_new0 (guint8, 2147483648LL);
+       _vala_param = (g_free (_vala_param), NULL);
+       _vala_param = _tmp0_;
+       _vala_param_length1 = 2147483648LL;
+       if (param) {
+               *param = _vala_param;
+       } else {
+               _vala_param = (g_free (_vala_param), NULL);
+       }
+       if (param_length1) {
+               *param_length1 = _vala_param_length1;
+       }
+}
+
+void
+test_out (void)
+{
+       guint8* a = NULL;
+       gssize a_length1 = 0L;
+       gssize _a_size_ = 0L;
+       guint8* _tmp0_ = NULL;
+       gssize _tmp1_ = 0;
+       bar (&_tmp0_, &_tmp1_);
+       a = (g_free (a), NULL);
+       a = _tmp0_;
+       a_length1 = _tmp1_;
+       _a_size_ = a_length1;
+       _vala_assert (((gint64) a_length1) == 2147483648LL, "a.length == 2147483648LL");
+       a = (g_free (a), NULL);
+}
+
+static void
+_vala_main (void)
+{
+       test_pass ();
+       test_ref ();
+       test_out ();
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/arrays/length-type.vala b/tests/arrays/length-type.vala
new file mode 100644
index 000000000..63f6124d6
--- /dev/null
+++ b/tests/arrays/length-type.vala
@@ -0,0 +1,49 @@
+[CCode (has_target = false)]
+delegate unowned uint8[:uint64] ManamFunc (uint8[:size_t] param);
+
+unowned uint8[:uint64] manam (uint8[:size_t] param) {
+       assert (param.length == 2147483648LL);
+       return param;
+}
+
+uint8[:size_t] field;
+
+void test_pass () {
+       var foo = new uint8[2147483648LL:ssize_t];
+       assert (foo.length == 2147483648LL);
+
+       ManamFunc func = manam;
+       unowned var bar = func (foo);
+       assert (bar.length == 2147483648LL);
+
+       field = (owned) foo;
+       assert (field.length == 2147483648LL);
+
+       field = null;
+}
+
+void foo (ref uint8[:ssize_t] param) {
+       param = new uint8[2147483648LL:ssize_t];
+}
+
+void test_ref () {
+       var a = new uint8[:ssize_t] {};
+       foo (ref a);
+       assert (a.length == 2147483648LL);
+}
+
+void bar (out uint8[:ssize_t] param) {
+       param = new uint8[2147483648LL:ssize_t];
+}
+
+void test_out () {
+       uint8[:ssize_t] a;
+       bar (out a);
+       assert (a.length == 2147483648LL);
+}
+
+void main () {
+       test_pass ();
+       test_ref ();
+       test_out ();
+}
diff --git a/tests/gir/bug651773.test b/tests/gir/bug651773.test
index 7f499de5b..ff97bc290 100644
--- a/tests/gir/bug651773.test
+++ b/tests/gir/bug651773.test
@@ -20,5 +20,5 @@ Input:
 
 Output:
 
-[CCode (array_length_pos = 0.1, array_length_type = "gsize", cheader_filename = "test.h")]
-public static unowned uint8[] get_array ();
+[CCode (array_length_pos = 0.1, cheader_filename = "test.h")]
+public static unowned uint8[:size_t] get_array ();
diff --git a/tests/gir/bug788775.test b/tests/gir/bug788775.test
index 80ae7cd21..08a6a90e5 100644
--- a/tests/gir/bug788775.test
+++ b/tests/gir/bug788775.test
@@ -25,5 +25,5 @@ Input:
 
 Output:
 
-[CCode (array_length = true, array_length_pos = 1.1, array_length_type = "gsize", array_null_terminated = 
true, cheader_filename = "test.h")]
-public static string[] get_string_list (string key);
+[CCode (array_length = true, array_length_pos = 1.1, array_null_terminated = true, cheader_filename = 
"test.h")]
+public static string[:size_t] get_string_list (string key);
diff --git a/tests/gir/delegate-array-length-type.test b/tests/gir/delegate-array-length-type.test
index 127ac8a76..798955dd3 100644
--- a/tests/gir/delegate-array-length-type.test
+++ b/tests/gir/delegate-array-length-type.test
@@ -24,5 +24,5 @@ Input:
 
 Output:
 
-[CCode (array_length_pos = 0.1, array_length_type = "gsize", cheader_filename = "test.h", instance_pos = 
0.9)]
-public delegate string[] Foo ();
+[CCode (array_length_pos = 0.1, cheader_filename = "test.h", instance_pos = 0.9)]
+public delegate string[:size_t] Foo ();
diff --git a/tests/gir/method-array-length-type.test b/tests/gir/method-array-length-type.test
index b7ebccfc5..b13df3967 100644
--- a/tests/gir/method-array-length-type.test
+++ b/tests/gir/method-array-length-type.test
@@ -17,5 +17,5 @@ Input:
 
 Output:
 
-[CCode (array_length_pos = 0.1, array_length_type = "gsize", cheader_filename = "test.h")]
-public static string[] function ();
+[CCode (array_length_pos = 0.1, cheader_filename = "test.h")]
+public static string[:size_t] function ();
diff --git a/tests/gir/parameter-array-length-type.test b/tests/gir/parameter-array-length-type.test
index 3bbbe9ec6..9c2b22921 100644
--- a/tests/gir/parameter-array-length-type.test
+++ b/tests/gir/parameter-array-length-type.test
@@ -21,4 +21,4 @@ Input:
 Output:
 
 [CCode (cheader_filename = "test.h")]
-public static void function ([CCode (array_length_cname = "foo_length", array_length_pos = 1.1, 
array_length_type = "gsize")] string[] foo);
+public static void function ([CCode (array_length_cname = "foo_length", array_length_pos = 1.1)] 
string[:size_t] foo);
diff --git a/tests/parser/array-length.c-expected b/tests/parser/array-length.c-expected
new file mode 100644
index 000000000..53433362a
--- /dev/null
+++ b/tests/parser/array-length.c-expected
@@ -0,0 +1,90 @@
+/* parser_array_length.c generated by valac, the Vala compiler
+ * generated from parser_array_length.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 guint8* (*FooFunc) (guint8* param0, gsize param0_length1, guint8** param1, gint64* param1_length1, 
guint8** param2, guint* param2_length1, guint8* param3, guint64* result_length1, gpointer user_data);
+
+VALA_EXTERN guint8* field0;
+VALA_EXTERN gssize field0_length1;
+guint8* field0 = NULL;
+gssize field0_length1 = 0;
+static gssize _field0_size_ = 0;
+VALA_EXTERN guint8 field1[4711];
+guint8 field1[4711] = {0};
+
+VALA_EXTERN guint8* func (guint8* param0,
+              gsize param0_length1,
+              guint8** param1,
+              gint64* param1_length1,
+              guint8** param2,
+              guint* param2_length1,
+              guint8* param3,
+              guint64* result_length1);
+static void _vala_main (void);
+
+guint8*
+func (guint8* param0,
+      gsize param0_length1,
+      guint8** param1,
+      gint64* param1_length1,
+      guint8** param2,
+      guint* param2_length1,
+      guint8* param3,
+      guint64* result_length1)
+{
+       guint8* _vala_param2 = NULL;
+       guint _vala_param2_length1 = 0;
+       guint8* _tmp0_;
+       guint64 _tmp0__length1;
+       guint8* result = NULL;
+       _tmp0_ = param0;
+       _tmp0__length1 = param0_length1;
+       if (result_length1) {
+               *result_length1 = _tmp0__length1;
+       }
+       result = _tmp0_;
+       if (param2) {
+               *param2 = _vala_param2;
+       } else {
+               _vala_param2 = (g_free (_vala_param2), NULL);
+       }
+       if (param2_length1) {
+               *param2_length1 = _vala_param2_length1;
+       }
+       return result;
+}
+
+static void
+_vala_main (void)
+{
+       guint8* local_heap = NULL;
+       guint8* _tmp0_;
+       gssize local_heap_length1;
+       gssize _local_heap_size_;
+       guint8 local_stack[42] = {0};
+       _tmp0_ = g_new0 (guint8, 23);
+       local_heap = _tmp0_;
+       local_heap_length1 = 23;
+       _local_heap_size_ = local_heap_length1;
+       local_heap = (g_free (local_heap), NULL);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
diff --git a/tests/parser/array-length.vala b/tests/parser/array-length.vala
new file mode 100644
index 000000000..4de401cf4
--- /dev/null
+++ b/tests/parser/array-length.vala
@@ -0,0 +1,13 @@
+delegate unowned uint8[:uint64] FooFunc (uint8[:size_t] param0, ref uint8[:int64] param1, out uint8[:uint] 
param2, uint8 param3[42:ssize_t]);
+
+unowned uint8[:uint64] func (uint8[:size_t] param0, ref uint8[:int64] param1, out uint8[:uint] param2, uint8 
param3[42:ssize_t]) {
+       return param0;
+}
+
+uint8[:ssize_t] field0;
+uint8 field1[4711:ssize_t];
+
+void main () {
+       var local_heap = new uint8[23:ssize_t];
+       uint8 local_stack[42:ssize_t];
+}
diff --git a/tests/semantic/array-length-invalid.test b/tests/semantic/array-length-invalid.test
new file mode 100644
index 000000000..aee2cfdb8
--- /dev/null
+++ b/tests/semantic/array-length-invalid.test
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = new uint8[23:float];
+}
diff --git a/tests/semantic/array-length-nullable.test b/tests/semantic/array-length-nullable.test
new file mode 100644
index 000000000..fa56e48ee
--- /dev/null
+++ b/tests/semantic/array-length-nullable.test
@@ -0,0 +1,5 @@
+Invalid Code
+
+void main () {
+       var foo = new uint8[23:size_t?];
+}
diff --git a/vala/valaarraycreationexpression.vala b/vala/valaarraycreationexpression.vala
index 70fc4425a..3b423b224 100644
--- a/vala/valaarraycreationexpression.vala
+++ b/vala/valaarraycreationexpression.vala
@@ -167,6 +167,10 @@ public class Vala.ArrayCreationExpression : Expression {
                                builder.append_printf (", %s", size.to_string ());
                        }
                }
+               var length_str = length_type.to_string ();
+               if (length_str != "int") {
+                       builder.append_printf (":%s", length_str);
+               }
                builder.append_c (']');
                if (initializer_list != null) {
                        builder.append (initializer_list.to_string ());
diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala
index 55847d5db..b032de4f7 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -199,7 +199,13 @@ public class Vala.ArrayType : ReferenceType {
                }
 
                if (!fixed_length) {
-                       return "%s[%s]%s".printf (elem_str, string.nfill (rank - 1, ','), nullable ? "?" : 
"");
+                       var length_str = length_type == null ? "int" : length_type.to_qualified_string 
(scope);
+                       if (length_str != "int") {
+                               length_str = ":%s".printf (length_str);
+                       } else {
+                               length_str = "";
+                       }
+                       return "%s[%s%s]%s".printf (elem_str, string.nfill (rank - 1, ','), length_str, 
nullable ? "?" : "");
                } else {
                        return elem_str;
                }
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index cb3bd998d..f9f1fccd1 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1569,6 +1569,11 @@ public class Vala.CodeWriter : CodeVisitor {
                if (array_type != null && array_type.fixed_length) {
                        write_string ("[");
                        array_type.length.accept (this);
+                       var length_type = array_type.length_type.to_qualified_string (current_scope);
+                       if (length_type != "int") {
+                               write_string (":");
+                               write_string (length_type);
+                       }
                        write_string ("]");
                }
        }
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 6a4b572af..a9ca6001c 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -1195,13 +1195,7 @@ public class Vala.GirParser : CodeVisitor {
                                                        var length_field = (Field) array_length.symbol;
                                                        // array has length
                                                        field.set_attribute_string ("CCode", 
"array_length_cname", length_field.name);
-                                                       var length_type = 
length_field.variable_type.to_qualified_string ();
-                                                       if (length_type != "int") {
-                                                               var st = parser.root.lookup (length_type);
-                                                               if (st != null) {
-                                                                       field.set_attribute_string ("CCode", 
"array_length_type", st.get_cname ());
-                                                               }
-                                                       }
+                                                       ((ArrayType) field.variable_type).length_type = 
length_field.variable_type.copy ();
                                                        field.remove_attribute_argument ("CCode", 
"array_length");
                                                        field.remove_attribute_argument ("CCode", 
"array_null_terminated");
                                                }
@@ -1990,17 +1984,13 @@ public class Vala.GirParser : CodeVisitor {
 
        void set_array_ccode (Symbol sym, ParameterInfo info) {
                sym.set_attribute_double ("CCode", "array_length_pos", info.vala_idx);
+               var length_type = info.param.variable_type.copy ();
+               length_type.nullable = false;
                if (sym is Parameter) {
                        sym.set_attribute_string ("CCode", "array_length_cname", info.param.name);
-               }
-               var type_name = info.param.variable_type.to_qualified_string ();
-               if (type_name != "int") {
-                       var st = root.lookup (type_name);
-                       if (st != null) {
-                               if (sym is Callable || sym is Parameter) {
-                                       sym.set_attribute_string ("CCode", "array_length_type", st.get_cname 
());
-                               }
-                       }
+                       ((ArrayType) ((Parameter) sym).variable_type).length_type = length_type;
+               } else if (sym is Callable) {
+                       ((ArrayType) ((Callable) sym).return_type).length_type = length_type;
                }
        }
 
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 93031cee1..0fb839bf1 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -459,10 +459,13 @@ public class Vala.Parser : CodeVisitor {
                while (accept (TokenType.OPEN_BRACKET)) {
                        do {
                                // required for decision between expression and declaration statement
-                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET && 
current () != TokenType.COLON) {
                                        parse_expression ();
                                }
                        } while (accept (TokenType.COMMA));
+                       if (accept (TokenType.COLON)) {
+                               skip_symbol_name ();
+                       }
                        expect (TokenType.CLOSE_BRACKET);
                        accept (TokenType.INTERR);
                }
@@ -549,18 +552,22 @@ public class Vala.Parser : CodeVisitor {
                // array brackets in types are read from right to left,
                // this is more logical, especially when nullable arrays
                // or pointers are involved
+               DataType? array_length_type = null;
                while (accept (TokenType.OPEN_BRACKET)) {
                        bool invalid_array = false;
                        int array_rank = 0;
                        do {
                                array_rank++;
                                // required for decision between expression and declaration statement
-                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET && 
current () != TokenType.COLON) {
                                        parse_expression ();
                                        // only used for parsing, reject use as real type
                                        invalid_array = true;
                                }
                        } while (accept (TokenType.COMMA));
+                       if (accept (TokenType.COLON)) {
+                               array_length_type = parse_type (true, false);
+                       }
                        expect (TokenType.CLOSE_BRACKET);
 
                        type.value_owned = inner_type_owned;
@@ -568,6 +575,9 @@ public class Vala.Parser : CodeVisitor {
                        var array_type = new ArrayType (type, array_rank, get_src (begin));
                        array_type.nullable = accept (TokenType.INTERR);
                        array_type.invalid_syntax = invalid_array;
+                       if (array_length_type != null) {
+                               array_type.length_type = array_length_type.copy ();
+                       }
 
                        type = array_type;
                }
@@ -591,10 +601,14 @@ public class Vala.Parser : CodeVisitor {
                // inline-allocated array
                if (type != null && accept (TokenType.OPEN_BRACKET)) {
                        Expression array_length = null;
+                       DataType? array_length_type = null;
 
                        if (current () != TokenType.CLOSE_BRACKET) {
                                array_length = parse_expression ();
                        }
+                       if (accept (TokenType.COLON)) {
+                               array_length_type = parse_type (true, false);
+                       }
                        expect (TokenType.CLOSE_BRACKET);
 
                        var array_type = new ArrayType (type, 1, get_src (begin));
@@ -603,6 +617,9 @@ public class Vala.Parser : CodeVisitor {
                                array_type.fixed_length = true;
                                array_type.length = array_length;
                        }
+                       if (array_length_type != null) {
+                               array_type.length_type = array_length_type;
+                       }
                        array_type.value_owned = type.value_owned;
 
                        return array_type;
@@ -1033,6 +1050,7 @@ public class Vala.Parser : CodeVisitor {
                bool size_specified = false;
                List<Expression> size_specifier_list = null;
                bool first = true;
+               DataType? array_length_type = null;
                do {
                        if (!first) {
                                // array of arrays: new T[][42]
@@ -1042,6 +1060,9 @@ public class Vala.Parser : CodeVisitor {
                                }
 
                                element_type = new ArrayType (element_type, size_specifier_list.size, 
element_type.source_reference);
+                               if (array_length_type != null) {
+                                       ((ArrayType) element_type).length_type = array_length_type.copy ();
+                               }
                        } else {
                                first = false;
                        }
@@ -1049,12 +1070,15 @@ public class Vala.Parser : CodeVisitor {
                        size_specifier_list = new ArrayList<Expression> ();
                        do {
                                Expression size = null;
-                               if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
+                               if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA && 
current () != TokenType.COLON) {
                                        size = parse_expression ();
                                        size_specified = true;
                                }
                                size_specifier_list.add (size);
                        } while (accept (TokenType.COMMA));
+                       if (accept (TokenType.COLON)) {
+                               array_length_type = parse_type (true, false);
+                       }
                        expect (TokenType.CLOSE_BRACKET);
                } while (accept (TokenType.OPEN_BRACKET));
 
@@ -1065,6 +1089,9 @@ public class Vala.Parser : CodeVisitor {
                        initializer = parse_initializer ();
                }
                var expr = new ArrayCreationExpression (element_type, size_specifier_list.size, initializer, 
src);
+               if (array_length_type != null) {
+                       expr.length_type = array_length_type.copy ();
+               }
                if (size_specified) {
                        foreach (Expression size in size_specifier_list) {
                                expr.append_size (size);


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