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




commit 7e47aa080b0cafb81991d31f9bb3c9cd20efab71
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.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.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 ++++++++++++++++++--
 15 files changed, 137 insertions(+), 29 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 503c60119..224d219ae 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -122,6 +122,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 \
@@ -813,6 +814,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 \
@@ -930,6 +932,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.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.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 85b7b1f45..2d91490fb 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -200,7 +200,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 2b9e19030..f550bb7f4 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1557,6 +1557,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 2345c355e..2203c8e3e 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -1192,13 +1192,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");
                                                }
@@ -1985,17 +1979,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 9ecc96e9b..7d24babdb 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -456,10 +456,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);
                }
@@ -546,18 +549,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;
@@ -565,6 +572,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;
                }
@@ -588,10 +598,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));
@@ -600,6 +614,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;
@@ -1007,6 +1024,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]
@@ -1016,6 +1034,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;
                        }
@@ -1023,12 +1044,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));
 
@@ -1039,6 +1063,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]