]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add GenericType.dup/destroy fields
authorRico Tzschichholz <ricotz@ubuntu.com>
Fri, 1 Nov 2019 20:31:47 +0000 (21:31 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Mon, 4 Nov 2019 10:05:49 +0000 (11:05 +0100)
This provides direct access to the according values of generic-types
and type-parameters.

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

codegen/valaccodememberaccessmodule.vala
tests/Makefile.am
tests/generics/member-dup-destroy.vala [new file with mode: 0644]
vala/Makefile.am
vala/valagenericdestroyfield.vala [new file with mode: 0644]
vala/valagenericdupfield.vala [new file with mode: 0644]
vala/valagenerictype.vala
vala/valamemberaccess.vala
vala/valasemanticanalyzer.vala

index 7674402ca3d741157afd056d88fd395bd1b0cc41..e520ede93b6742b833c588591abb90e8bb22be1f 100644 (file)
@@ -125,6 +125,10 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                        CCodeExpression delegate_target_destroy_notify;
                        get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify);
                        set_cvalue (expr, delegate_target_destroy_notify);
+               } else if (expr.symbol_reference is GenericDupField) {
+                       set_cvalue (expr, get_dup_func_expression (expr.inner.value_type, expr.source_reference));
+               } else if (expr.symbol_reference is GenericDestroyField) {
+                       set_cvalue (expr, get_destroy_func_expression (expr.inner.value_type));
                } else if (expr.symbol_reference is Field) {
                        var field = (Field) expr.symbol_reference;
                        if (expr.lvalue) {
index 0265bc99c0886acd87e998773da5165aec6c0844..daf29e9dc59ee917a4c377431218b7a53a646185 100644 (file)
@@ -502,6 +502,7 @@ TESTS = \
        generics/constructor-chain-up.vala \
        generics/inference-static-function.vala \
        generics/parameter-sizeof-initializer.vala \
+       generics/member-dup-destroy.vala \
        generics/type-parameter-properties.vala \
        generics/bug640330.test \
        generics/bug640330.vala \
diff --git a/tests/generics/member-dup-destroy.vala b/tests/generics/member-dup-destroy.vala
new file mode 100644 (file)
index 0000000..defe162
--- /dev/null
@@ -0,0 +1,88 @@
+delegate void FooFunc ();
+
+class Foo<G> : Object {
+       public Foo () {
+               assert (typeof (G) == typeof (string));
+               assert (G.dup == (BoxedCopyFunc) string.dup);
+               assert (G.destroy == (DestroyNotify) free);
+
+               G g = null;
+               assert (g.dup == (BoxedCopyFunc) string.dup);
+               assert (g.destroy == (DestroyNotify) free);
+       }
+
+       public void foo () {
+               assert (typeof (G) == typeof (string));
+               assert (G.dup == (BoxedCopyFunc) string.dup);
+               assert (G.destroy == (DestroyNotify) free);
+
+               G g = null;
+               assert (g.dup == (BoxedCopyFunc) string.dup);
+               assert (g.destroy == (DestroyNotify) free);
+       }
+
+       public async void foo_async () {
+               assert (typeof (G) == typeof (string));
+               assert (G.dup == (BoxedCopyFunc) string.dup);
+               assert (G.destroy == (DestroyNotify) free);
+
+               G g = null;
+               assert (g.dup == (BoxedCopyFunc) string.dup);
+               assert (g.destroy == (DestroyNotify) free);
+       }
+
+       public void foo_captured () {
+               FooFunc f = () => {
+                       assert (typeof (G) == typeof (string));
+                       assert (G.dup == (BoxedCopyFunc) string.dup);
+                       assert (G.destroy == (DestroyNotify) free);
+
+                       G g = null;
+                       assert (g.dup == (BoxedCopyFunc) string.dup);
+                       assert (g.destroy == (DestroyNotify) free);
+               };
+               f ();
+       }
+}
+
+void bar<T> (T t) {
+       assert (typeof (T) == typeof (Foo));
+       assert (T.dup == (BoxedCopyFunc) Object.@ref);
+       assert (T.destroy == (DestroyNotify) Object.unref);
+
+       assert (t.dup == (BoxedCopyFunc) Object.@ref);
+       assert (t.destroy == (DestroyNotify) Object.unref);
+}
+
+async void bar_async<T> (T t) {
+       assert (typeof (T) == typeof (Foo));
+       assert (T.dup == (BoxedCopyFunc) Object.@ref);
+       assert (T.destroy == (DestroyNotify) Object.unref);
+
+       assert (t.dup == (BoxedCopyFunc) Object.@ref);
+       assert (t.destroy == (DestroyNotify) Object.unref);
+}
+
+void bar_captured<T> (T t) {
+       FooFunc f = () => {
+               assert (typeof (T) == typeof (Foo));
+               assert (T.dup == (BoxedCopyFunc) Object.@ref);
+               assert (T.destroy == (DestroyNotify) Object.unref);
+
+               assert (t.dup == (BoxedCopyFunc) Object.@ref);
+               assert (t.destroy == (DestroyNotify) Object.unref);
+       };
+       f ();
+}
+
+void main () {
+       var foo = new Foo<string> ();
+
+       foo.foo ();
+       foo.foo_async.begin ();
+       foo.foo_captured ();
+
+       bar<Foo> (foo);
+       bar_async<Foo>.begin (foo);
+       bar_captured<Foo> (foo);
+}
index 57c758fdce359560a7aad713449122b98459fbcc..c6aed1c5453d4b455d3b7ea3f915da85e988cd78 100644 (file)
@@ -90,6 +90,8 @@ libvala_la_VALASOURCES = \
        valaforeachstatement.vala \
        valaforstatement.vala \
        valagirparser.vala \
+       valagenericdestroyfield.vala \
+       valagenericdupfield.vala \
        valagenerictype.vala \
        valagenieparser.vala \
        valageniescanner.vala \
diff --git a/vala/valagenericdestroyfield.vala b/vala/valagenericdestroyfield.vala
new file mode 100644 (file)
index 0000000..6627bcc
--- /dev/null
@@ -0,0 +1,36 @@
+/* valagenericdestroyfield.vala
+ *
+ * Copyright (C) 2019  Rico Tzschichholz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Rico Tzschichholz <ricotz@ubuntu.com>
+ */
+
+/**
+ * Represents the Generic.destroy field.
+ */
+public class Vala.GenericDestroyField : Field {
+       /**
+        * Creates a new generic destroy field.
+        *
+        * @return newly created field
+        */
+       public GenericDestroyField (SourceReference source_reference) {
+               base ("destroy", CodeContext.get ().analyzer.delegate_target_destroy_type, null, source_reference);
+               external = true;
+       }
+}
diff --git a/vala/valagenericdupfield.vala b/vala/valagenericdupfield.vala
new file mode 100644 (file)
index 0000000..12ab9ec
--- /dev/null
@@ -0,0 +1,36 @@
+/* valagenericdupfield.vala
+ *
+ * Copyright (C) 2019  Rico Tzschichholz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Rico Tzschichholz <ricotz@ubuntu.com>
+ */
+
+/**
+ * Represents the Generic.dup field.
+ */
+public class Vala.GenericDupField : Field {
+       /**
+        * Creates a new generic dup field.
+        *
+        * @return newly created field
+        */
+       public GenericDupField (SourceReference source_reference) {
+               base ("dup", CodeContext.get ().analyzer.generics_dup_func_type, null, source_reference);
+               external = true;
+       }
+}
index e5e1a50a83991d1b93ee4d452195942d47329452..1f7a2d1eef8a9da6322d35741b178b3537a1d076 100644 (file)
@@ -31,6 +31,9 @@ public class Vala.GenericType : DataType {
         */
        public weak TypeParameter type_parameter { get; set; }
 
+       GenericDupField? dup_field;
+       GenericDestroyField? destroy_field;
+
        public GenericType (TypeParameter type_parameter) {
                this.type_parameter = type_parameter;
                // type parameters are always considered nullable
@@ -74,6 +77,27 @@ public class Vala.GenericType : DataType {
        }
 
        public override Symbol? get_member (string member_name) {
+               if (member_name == "dup") {
+                       return get_dup_field ();
+               } else if (member_name == "destroy") {
+                       return get_destroy_field ();
+               }
                return null;
        }
+
+       unowned GenericDupField get_dup_field () {
+               if (dup_field == null) {
+                       dup_field = new GenericDupField (source_reference);
+                       dup_field.access = SymbolAccessibility.PUBLIC;
+               }
+               return dup_field;
+       }
+
+       unowned GenericDestroyField get_destroy_field () {
+               if (destroy_field == null) {
+                       destroy_field = new GenericDestroyField (source_reference);
+                       destroy_field.access = SymbolAccessibility.PUBLIC;
+               }
+               return destroy_field;
+       }
 }
index 9316e5644e89a3ea79e569b8fa53a9ed579861c7..421ee8a9fb4be62b499d581593c67c091e973226 100644 (file)
@@ -362,6 +362,11 @@ public class Vala.MemberAccess : Expression {
                                }
                        }
 
+                       if (inner is MemberAccess && inner.symbol_reference is TypeParameter) {
+                               inner.value_type = new GenericType ((TypeParameter) inner.symbol_reference);
+                               inner.value_type.source_reference = source_reference;
+                       }
+
                        if (symbol_reference == null && inner.value_type != null) {
                                if (pointer_member_access) {
                                        symbol_reference = inner.value_type.get_pointer_member (member_name);
index 25c812dc43e8a5f13f705670f673ce1316560d46..c83d58b53c997606bc73187a6b9c44fb15e9e7a8 100644 (file)
@@ -169,6 +169,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public Class gsource_type;
        public DataType delegate_target_type;
        public DelegateType delegate_target_destroy_type;
+       public DelegateType generics_dup_func_type;
 
        Delegate destroy_notify;
 
@@ -236,6 +237,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        delegate_target_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer"));
                        destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify");
                        delegate_target_destroy_type = new DelegateType (destroy_notify);
+
+                       generics_dup_func_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("BoxedCopyFunc"));
                } else {
                        delegate_target_type = new PointerType (new VoidType ());
                        destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ());