[vala/staging] vala: Add GenericType.dup/destroy fields



commit d14248fdfa5ba2a39dfb8ce8a6a6a4a083c4f081
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Fri Nov 1 21:31:47 2019 +0100

    vala: Add GenericType.dup/destroy fields
    
    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 |  4 ++
 tests/Makefile.am                        |  1 +
 tests/generics/member-dup-destroy.vala   | 88 ++++++++++++++++++++++++++++++++
 vala/Makefile.am                         |  2 +
 vala/valagenericdestroyfield.vala        | 36 +++++++++++++
 vala/valagenericdupfield.vala            | 36 +++++++++++++
 vala/valagenerictype.vala                | 24 +++++++++
 vala/valamemberaccess.vala               |  5 ++
 vala/valasemanticanalyzer.vala           |  3 ++
 9 files changed, 199 insertions(+)
---
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index 7674402ca..e520ede93 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -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) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0265bc99c..daf29e9dc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 000000000..defe162dc
--- /dev/null
+++ b/tests/generics/member-dup-destroy.vala
@@ -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);
+}
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 57c758fdc..c6aed1c54 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -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
index 000000000..6627bcca2
--- /dev/null
+++ b/vala/valagenericdestroyfield.vala
@@ -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
index 000000000..12ab9ecea
--- /dev/null
+++ b/vala/valagenericdupfield.vala
@@ -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;
+       }
+}
diff --git a/vala/valagenerictype.vala b/vala/valagenerictype.vala
index e5e1a50a8..1f7a2d1ee 100644
--- a/vala/valagenerictype.vala
+++ b/vala/valagenerictype.vala
@@ -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;
+       }
 }
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 9316e5644..421ee8a9f 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -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);
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 25c812dc4..c83d58b53 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -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 ());


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