From: Lorenz Wildberg Date: Sat, 24 Jun 2023 15:07:26 +0000 (+0200) Subject: Add no_generics_args attribute X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01a1788978e4a42e3389600bec18270ab3df093c;p=thirdparty%2Fvala.git Add no_generics_args attribute The no_generics_args attribute can be added to anything that can have generics, for example classes, interfaces and methods. It makes the C code generation not emit parameters, properties fields, etc. for the storage or passing over of type parameters. This means 3 things: the type id, copy function and free function. The attribute works in .vapi files as well as full implementations in .vala files. But these values still need to be taken from somewhere to for example copy an object with the type of the type parameter. For this reason it is required that there is a constrain for the generic parameter. The constrain needs to be an "object" type. So a type derived from GTypeInstance. This can be standard vala classes with or without GLib.Object as a base or Interfaces. It is because these types provide ref- and unref-functions. These together with the type id are used as constants instead of the variable type passed through parameters. The attribute applied on a type makes all its type parameters not emit no generic arguments. --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 8cc088aaf..ffdfbd143 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -3879,9 +3879,11 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { return new CCodeConstant ("NULL"); } - // unref functions are optional for type parameters - var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL")); - cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull); + if (!((GenericType) type).type_parameter.no_generic_args) { + // unref functions are optional for type parameters + var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL")); + cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull); + } } // glib collections already have the free_func argument, so make sure the instance parameter gets first @@ -4821,7 +4823,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { ccallarg = cexpr; } var cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cexpr, new CCodeConstant ("NULL")); - if (type is GenericType) { + if (type is GenericType && !((GenericType) type).type_parameter.no_generic_args) { // dup functions are optional for type parameters var cdupnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_dup_func_expression (type, node.source_reference), new CCodeConstant ("NULL")); cnotnull = new CCodeBinaryExpression (CCodeBinaryOperator.AND, cnotnull, cdupnotnull); @@ -5077,7 +5079,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_")); } - if (cl != null && (!cl.is_compact || get_ccode_simple_generics (m))) { + if (cl != null && !cl.get_attribute_bool ("CCode", "no_generic_args", false) && (!cl.is_compact || get_ccode_simple_generics (m))) { add_generic_type_arguments (m, in_arg_map, expr.type_reference.get_type_arguments (), expr); } diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index 95087b535..1277799b1 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -165,6 +165,9 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { // chain up to base class foreach (DataType base_type in current_class.get_base_types ()) { if (base_type.type_symbol is Class) { + if (((Class) base_type.type_symbol).get_attribute_bool ("CCode", "no_generic_args", false)) { + break; + } List type_parameters = null; if (get_ccode_real_name (m) == "g_object_new") { // gobject-style chainup @@ -179,6 +182,9 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { // chain up to other constructor in same class var cl = (Class) m.parent_symbol; foreach (TypeParameter type_param in cl.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (get_ccode_type_id (type_param))); in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_copy_function (type_param))); in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (get_ccode_destroy_function (type_param))); @@ -188,6 +194,9 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { if (current_class.has_type_parameters () && get_ccode_real_name (m) == "g_object_new") { // gobject-style construction foreach (var type_param in current_class.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } var type_param_name = type_param.name.ascii_down ().replace ("_", "-"); in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name))); in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_type_id (type_param))); @@ -380,6 +389,9 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule { /* type, dup func, and destroy func fields for generic types */ var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"); foreach (TypeParameter type_param in current_class.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } var type = get_ccode_type_id (type_param); var dup_func = get_ccode_copy_function (type_param); var destroy_func = get_ccode_destroy_function (type_param); diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala index 05b9a2916..d5e68609e 100644 --- a/codegen/valaccodemethodmodule.vala +++ b/codegen/valaccodemethodmodule.vala @@ -535,6 +535,9 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { // allow capturing generic type parameters var data_var = get_variable_cexpression ("_data%d_".printf (block_id)); foreach (var type_param in m.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } var type = get_ccode_type_id (type_param); var dup_func = get_ccode_copy_function (type_param); var destroy_func = get_ccode_destroy_function (type_param); @@ -635,6 +638,9 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { /* type, dup func, and destroy func fields for generic types */ var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"); foreach (TypeParameter type_param in current_class.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } var type = get_ccode_type_id (type_param); var dup_func = get_ccode_copy_function (type_param); var destroy_func = get_ccode_destroy_function (type_param); @@ -1080,6 +1086,9 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { if (type_parameters != null) { int type_param_index = 0; foreach (var type_param in type_parameters) { + if (type_param.no_generic_args) { + continue; + } cfile.add_include ("glib-object.h"); var type = get_ccode_type_id (type_param); var dup_func = get_ccode_copy_function (type_param); diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala index c380763b8..ed8834299 100644 --- a/codegen/valagobjectmodule.vala +++ b/codegen/valagobjectmodule.vala @@ -74,6 +74,9 @@ public class Vala.GObjectModule : GTypeModule { /* create type, dup_func, and destroy_func properties for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } string func_name, enum_value; CCodeConstant func_name_constant; CCodeFunctionCall cinst, cspec; @@ -304,6 +307,9 @@ public class Vala.GObjectModule : GTypeModule { /* type, dup func, and destroy func properties for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } string func_name, enum_value; CCodeMemberAccess cfield; CCodeFunctionCall csetcall; @@ -439,6 +445,9 @@ public class Vala.GObjectModule : GTypeModule { /* type, dup func, and destroy func properties for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } string func_name, enum_value; CCodeMemberAccess cfield; CCodeFunctionCall cgetcall; diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala index ec103d2f4..f238ebded 100644 --- a/codegen/valagtypemodule.vala +++ b/codegen/valagtypemodule.vala @@ -549,6 +549,9 @@ public class Vala.GTypeModule : GErrorModule { if (is_gtypeinstance) { /* create type, dup_func, and destroy_func fields for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters ()) { + if (type_param.no_generic_args) { + continue; + } instance_priv_struct.add_field ("GType", get_ccode_type_id (type_param)); instance_priv_struct.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param)); instance_priv_struct.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param)); diff --git a/tests/Makefile.am b/tests/Makefile.am index 2e6c1f7f0..6dbed7baa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -842,6 +842,10 @@ TESTS = \ generics/method-to-delegate-incompatible-2.test \ generics/method-to-delegate-incompatible-3.test \ generics/multiple-classes-constraints.test \ + generics/no-generic-args.vala \ + generics/no-generic-args-use-with-proper-generic-type.test \ + generics/no-generic-args-use-with-proper-generic-type-2.test \ + generics/no-generic-args-with-no-constraint.test \ generics/null-type.vala \ generics/property-gobject-set.vala \ generics/property-int-cast.vala \ @@ -851,6 +855,7 @@ TESTS = \ generics/type-parameter-properties.vala \ generics/type-parameter-property-clash.vala \ generics/type-parameter-static-in-runtime.test \ + generics/typeof-with-no-generic-args.test \ generics/value-pointer-type-access.vala \ generics/bug640330.vala \ generics/bug640330-2.test \ @@ -1493,6 +1498,7 @@ TESTS = \ genie/while.gs \ glib/conditional-glib-api.vala \ bindings/gio/memoryoutputstream.vala \ + bindings/gio/listmodel-compatibility.vala \ $(LINUX_TESTS) \ $(NULL) diff --git a/tests/bindings/gio/listmodel-compatibility.c-expected b/tests/bindings/gio/listmodel-compatibility.c-expected new file mode 100644 index 000000000..054b893d4 --- /dev/null +++ b/tests/bindings/gio/listmodel-compatibility.c-expected @@ -0,0 +1,637 @@ +/* bindings_gio_listmodel_compatibility.c generated by valac, the Vala compiler + * generated from bindings_gio_listmodel_compatibility.vala, do not modify */ + +#include +#include +#include + +#if !defined(VALA_EXTERN) +#if defined(_WIN32) || defined(__CYGWIN__) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +#define TYPE_NOT_ALIST_VIEW (not_alist_view_get_type ()) +#define NOT_ALIST_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOT_ALIST_VIEW, NotAListView)) +#define NOT_ALIST_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOT_ALIST_VIEW, NotAListViewClass)) +#define IS_NOT_ALIST_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOT_ALIST_VIEW)) +#define IS_NOT_ALIST_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOT_ALIST_VIEW)) +#define NOT_ALIST_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOT_ALIST_VIEW, NotAListViewClass)) + +typedef struct _NotAListView NotAListView; +typedef struct _NotAListViewClass NotAListViewClass; +typedef struct _NotAListViewPrivate NotAListViewPrivate; +enum { + NOT_ALIST_VIEW_0_PROPERTY, + NOT_ALIST_VIEW_G_TYPE_PROPERTY, + NOT_ALIST_VIEW_MODEL_PROPERTY, + NOT_ALIST_VIEW_NUM_PROPERTIES +}; +static GParamSpec* not_alist_view_properties[NOT_ALIST_VIEW_NUM_PROPERTIES]; +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) + +#define TYPE_FOO (foo_get_type ()) +#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FOO, Foo)) +#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FOO, FooClass)) +#define IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FOO)) +#define IS_FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FOO)) +#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FOO, FooClass)) + +typedef struct _Foo Foo; +typedef struct _FooClass FooClass; +typedef struct _FooPrivate FooPrivate; +enum { + FOO_0_PROPERTY, + FOO_MODEL_PROPERTY, + FOO_OTHER_THING_PROPERTY, + FOO_NUM_PROPERTIES +}; +static GParamSpec* foo_properties[FOO_NUM_PROPERTIES]; + +struct _NotAListView { + GObject parent_instance; + NotAListViewPrivate * priv; +}; + +struct _NotAListViewClass { + GObjectClass parent_class; +}; + +struct _NotAListViewPrivate { + GType _g_type; + GListModel* _model; +}; + +struct _Foo { + GObject parent_instance; + FooPrivate * priv; +}; + +struct _FooClass { + GObjectClass parent_class; +}; + +struct _FooPrivate { + GListModel* _model; + NotAListView* _other_thing; +}; + +static gint NotAListView_private_offset; +static gpointer not_alist_view_parent_class = NULL; +static gint Foo_private_offset; +static gpointer foo_parent_class = NULL; +static GListModelInterface * foo_g_list_model_parent_iface = NULL; + +VALA_EXTERN GType not_alist_view_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (NotAListView, g_object_unref) +VALA_EXTERN NotAListView* not_alist_view_new_with_type (GType g_type); +VALA_EXTERN NotAListView* not_alist_view_construct_with_type (GType object_type, + GType g_type); +VALA_EXTERN NotAListView* not_alist_view_new (void); +VALA_EXTERN NotAListView* not_alist_view_construct (GType object_type); +VALA_EXTERN GType not_alist_view_get_g_type (NotAListView* self); +static void not_alist_view_set_g_type (NotAListView* self, + GType value); +VALA_EXTERN GListModel* not_alist_view_get_model (NotAListView* self); +VALA_EXTERN void not_alist_view_set_model (NotAListView* self, + GListModel* value); +static GObject * not_alist_view_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam * construct_properties); +static void not_alist_view_finalize (GObject * obj); +static GType not_alist_view_get_type_once (void); +static void _vala_not_alist_view_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec); +static void _vala_not_alist_view_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec); +VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, g_object_unref) +static GType foo_real_get_item_type (GListModel* base); +static GObject* foo_real_get_item (GListModel* base, + guint pos); +static guint foo_real_get_n_items (GListModel* base); +VALA_EXTERN Foo* foo_new (void); +VALA_EXTERN Foo* foo_construct (GType object_type); +VALA_EXTERN GListModel* foo_get_model (Foo* self); +VALA_EXTERN void foo_set_model (Foo* self, + GListModel* value); +VALA_EXTERN NotAListView* foo_get_other_thing (Foo* self); +VALA_EXTERN void foo_set_other_thing (Foo* self, + NotAListView* value); +static void foo_finalize (GObject * obj); +static GType foo_get_type_once (void); +static void _vala_foo_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec); +static void _vala_foo_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec); +static void _vala_main (void); + +static inline gpointer +not_alist_view_get_instance_private (NotAListView* self) +{ + return G_STRUCT_MEMBER_P (self, NotAListView_private_offset); +} + +NotAListView* +not_alist_view_construct_with_type (GType object_type, + GType g_type) +{ + NotAListView * self = NULL; + self = (NotAListView*) g_object_new (object_type, "g-type", g_type, NULL); + return self; +} + +NotAListView* +not_alist_view_new_with_type (GType g_type) +{ + return not_alist_view_construct_with_type (TYPE_NOT_ALIST_VIEW, g_type); +} + +NotAListView* +not_alist_view_construct (GType object_type) +{ + NotAListView * self = NULL; + self = (NotAListView*) g_object_new (object_type, NULL); + return self; +} + +NotAListView* +not_alist_view_new (void) +{ + return not_alist_view_construct (TYPE_NOT_ALIST_VIEW); +} + +GType +not_alist_view_get_g_type (NotAListView* self) +{ + GType result; + g_return_val_if_fail (IS_NOT_ALIST_VIEW (self), 0UL); + result = self->priv->_g_type; + return result; +} + +static void +not_alist_view_set_g_type (NotAListView* self, + GType value) +{ + GType old_value; + g_return_if_fail (IS_NOT_ALIST_VIEW (self)); + old_value = not_alist_view_get_g_type (self); + if (old_value != value) { + self->priv->_g_type = value; + g_object_notify_by_pspec ((GObject *) self, not_alist_view_properties[NOT_ALIST_VIEW_G_TYPE_PROPERTY]); + } +} + +GListModel* +not_alist_view_get_model (NotAListView* self) +{ + GListModel* result; + GListModel* _tmp0_; + g_return_val_if_fail (IS_NOT_ALIST_VIEW (self), NULL); + _tmp0_ = self->priv->_model; + result = _tmp0_; + return result; +} + +static gpointer +_g_object_ref0 (gpointer self) +{ + return self ? g_object_ref (self) : NULL; +} + +void +not_alist_view_set_model (NotAListView* self, + GListModel* value) +{ + GListModel* old_value; + g_return_if_fail (IS_NOT_ALIST_VIEW (self)); + old_value = not_alist_view_get_model (self); + if (old_value != value) { + GListModel* _tmp0_; + _tmp0_ = _g_object_ref0 (value); + _g_object_unref0 (self->priv->_model); + self->priv->_model = _tmp0_; + g_object_notify_by_pspec ((GObject *) self, not_alist_view_properties[NOT_ALIST_VIEW_MODEL_PROPERTY]); + } +} + +static GObject * +not_alist_view_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam * construct_properties) +{ + GObject * obj; + GObjectClass * parent_class; + NotAListView * self; + GType _tmp0_; + GListStore* _tmp1_; + GListStore* _tmp2_; + parent_class = G_OBJECT_CLASS (not_alist_view_parent_class); + obj = parent_class->constructor (type, n_construct_properties, construct_properties); + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_NOT_ALIST_VIEW, NotAListView); + _tmp0_ = self->priv->_g_type; + _tmp1_ = g_list_store_new (_tmp0_); + _tmp2_ = _tmp1_; + not_alist_view_set_model (self, G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, g_list_model_get_type (), GListModel)); + _g_object_unref0 (_tmp2_); + return obj; +} + +static void +not_alist_view_class_init (NotAListViewClass * klass, + gpointer klass_data) +{ + not_alist_view_parent_class = g_type_class_peek_parent (klass); + g_type_class_adjust_private_offset (klass, &NotAListView_private_offset); + G_OBJECT_CLASS (klass)->get_property = _vala_not_alist_view_get_property; + G_OBJECT_CLASS (klass)->set_property = _vala_not_alist_view_set_property; + G_OBJECT_CLASS (klass)->constructor = not_alist_view_constructor; + G_OBJECT_CLASS (klass)->finalize = not_alist_view_finalize; + g_object_class_install_property (G_OBJECT_CLASS (klass), NOT_ALIST_VIEW_G_TYPE_PROPERTY, not_alist_view_properties[NOT_ALIST_VIEW_G_TYPE_PROPERTY] = g_param_spec_gtype ("g-type", "g-type", "g-type", G_TYPE_OBJECT, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), NOT_ALIST_VIEW_MODEL_PROPERTY, not_alist_view_properties[NOT_ALIST_VIEW_MODEL_PROPERTY] = g_param_spec_object ("model", "model", "model", g_list_model_get_type (), G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE)); +} + +static void +not_alist_view_instance_init (NotAListView * self, + gpointer klass) +{ + self->priv = not_alist_view_get_instance_private (self); + self->priv->_g_type = G_TYPE_OBJECT; +} + +static void +not_alist_view_finalize (GObject * obj) +{ + NotAListView * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_NOT_ALIST_VIEW, NotAListView); + _g_object_unref0 (self->priv->_model); + G_OBJECT_CLASS (not_alist_view_parent_class)->finalize (obj); +} + +static GType +not_alist_view_get_type_once (void) +{ + static const GTypeInfo g_define_type_info = { sizeof (NotAListViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) not_alist_view_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotAListView), 0, (GInstanceInitFunc) not_alist_view_instance_init, NULL }; + GType not_alist_view_type_id; + not_alist_view_type_id = g_type_register_static (G_TYPE_OBJECT, "NotAListView", &g_define_type_info, 0); + NotAListView_private_offset = g_type_add_instance_private (not_alist_view_type_id, sizeof (NotAListViewPrivate)); + return not_alist_view_type_id; +} + +GType +not_alist_view_get_type (void) +{ + static volatile gsize not_alist_view_type_id__once = 0; + if (g_once_init_enter (¬_alist_view_type_id__once)) { + GType not_alist_view_type_id; + not_alist_view_type_id = not_alist_view_get_type_once (); + g_once_init_leave (¬_alist_view_type_id__once, not_alist_view_type_id); + } + return not_alist_view_type_id__once; +} + +static void +_vala_not_alist_view_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + NotAListView * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_NOT_ALIST_VIEW, NotAListView); + switch (property_id) { + case NOT_ALIST_VIEW_G_TYPE_PROPERTY: + g_value_set_gtype (value, not_alist_view_get_g_type (self)); + break; + case NOT_ALIST_VIEW_MODEL_PROPERTY: + g_value_set_object (value, not_alist_view_get_model (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +_vala_not_alist_view_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + NotAListView * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_NOT_ALIST_VIEW, NotAListView); + switch (property_id) { + case NOT_ALIST_VIEW_G_TYPE_PROPERTY: + not_alist_view_set_g_type (self, g_value_get_gtype (value)); + break; + case NOT_ALIST_VIEW_MODEL_PROPERTY: + not_alist_view_set_model (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static inline gpointer +foo_get_instance_private (Foo* self) +{ + return G_STRUCT_MEMBER_P (self, Foo_private_offset); +} + +static GType +foo_real_get_item_type (GListModel* base) +{ + Foo * self; + GType result; + self = G_TYPE_CHECK_INSTANCE_CAST (base, TYPE_FOO, Foo); + result = G_TYPE_OBJECT; + return result; +} + +static GObject* +foo_real_get_item (GListModel* base, + guint pos) +{ + Foo * self; + GObject* result; + self = G_TYPE_CHECK_INSTANCE_CAST (base, TYPE_FOO, Foo); + result = NULL; + return result; +} + +static guint +foo_real_get_n_items (GListModel* base) +{ + Foo * self; + guint result; + self = G_TYPE_CHECK_INSTANCE_CAST (base, TYPE_FOO, Foo); + result = (guint) 0; + return result; +} + +Foo* +foo_construct (GType object_type) +{ + Foo * self = NULL; + self = (Foo*) g_object_new (object_type, NULL); + return self; +} + +Foo* +foo_new (void) +{ + return foo_construct (TYPE_FOO); +} + +GListModel* +foo_get_model (Foo* self) +{ + GListModel* result; + GListModel* _tmp0_; + g_return_val_if_fail (IS_FOO (self), NULL); + _tmp0_ = self->priv->_model; + result = _tmp0_; + return result; +} + +void +foo_set_model (Foo* self, + GListModel* value) +{ + GListModel* old_value; + g_return_if_fail (IS_FOO (self)); + old_value = foo_get_model (self); + if (old_value != value) { + GListModel* _tmp0_; + _tmp0_ = _g_object_ref0 (value); + _g_object_unref0 (self->priv->_model); + self->priv->_model = _tmp0_; + g_object_notify_by_pspec ((GObject *) self, foo_properties[FOO_MODEL_PROPERTY]); + } +} + +NotAListView* +foo_get_other_thing (Foo* self) +{ + NotAListView* result; + NotAListView* _tmp0_; + g_return_val_if_fail (IS_FOO (self), NULL); + _tmp0_ = self->priv->_other_thing; + result = _tmp0_; + return result; +} + +void +foo_set_other_thing (Foo* self, + NotAListView* value) +{ + NotAListView* old_value; + g_return_if_fail (IS_FOO (self)); + old_value = foo_get_other_thing (self); + if (old_value != value) { + NotAListView* _tmp0_; + _tmp0_ = _g_object_ref0 (value); + _g_object_unref0 (self->priv->_other_thing); + self->priv->_other_thing = _tmp0_; + g_object_notify_by_pspec ((GObject *) self, foo_properties[FOO_OTHER_THING_PROPERTY]); + } +} + +static void +foo_class_init (FooClass * klass, + gpointer klass_data) +{ + foo_parent_class = g_type_class_peek_parent (klass); + g_type_class_adjust_private_offset (klass, &Foo_private_offset); + G_OBJECT_CLASS (klass)->get_property = _vala_foo_get_property; + G_OBJECT_CLASS (klass)->set_property = _vala_foo_set_property; + G_OBJECT_CLASS (klass)->finalize = foo_finalize; + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_MODEL_PROPERTY, foo_properties[FOO_MODEL_PROPERTY] = g_param_spec_object ("model", "model", "model", g_list_model_get_type (), G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_OTHER_THING_PROPERTY, foo_properties[FOO_OTHER_THING_PROPERTY] = g_param_spec_object ("other-thing", "other-thing", "other-thing", TYPE_NOT_ALIST_VIEW, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE)); +} + +static void +foo_g_list_model_interface_init (GListModelInterface * iface, + gpointer iface_data) +{ + foo_g_list_model_parent_iface = g_type_interface_peek_parent (iface); + iface->get_item_type = (GType (*) (GListModel*)) foo_real_get_item_type; + iface->get_item = (GObject* (*) (GListModel*, guint)) foo_real_get_item; + iface->get_n_items = (guint (*) (GListModel*)) foo_real_get_n_items; +} + +static void +foo_instance_init (Foo * self, + gpointer klass) +{ + self->priv = foo_get_instance_private (self); +} + +static void +foo_finalize (GObject * obj) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_FOO, Foo); + _g_object_unref0 (self->priv->_model); + _g_object_unref0 (self->priv->_other_thing); + G_OBJECT_CLASS (foo_parent_class)->finalize (obj); +} + +static GType +foo_get_type_once (void) +{ + static const GTypeInfo g_define_type_info = { sizeof (FooClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) foo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Foo), 0, (GInstanceInitFunc) foo_instance_init, NULL }; + static const GInterfaceInfo g_list_model_info = { (GInterfaceInitFunc) foo_g_list_model_interface_init, (GInterfaceFinalizeFunc) NULL, NULL}; + GType foo_type_id; + foo_type_id = g_type_register_static (G_TYPE_OBJECT, "Foo", &g_define_type_info, 0); + g_type_add_interface_static (foo_type_id, g_list_model_get_type (), &g_list_model_info); + Foo_private_offset = g_type_add_instance_private (foo_type_id, sizeof (FooPrivate)); + return foo_type_id; +} + +GType +foo_get_type (void) +{ + static volatile gsize foo_type_id__once = 0; + if (g_once_init_enter (&foo_type_id__once)) { + GType foo_type_id; + foo_type_id = foo_get_type_once (); + g_once_init_leave (&foo_type_id__once, foo_type_id); + } + return foo_type_id__once; +} + +static void +_vala_foo_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_FOO, Foo); + switch (property_id) { + case FOO_MODEL_PROPERTY: + g_value_set_object (value, foo_get_model (self)); + break; + case FOO_OTHER_THING_PROPERTY: + g_value_set_object (value, foo_get_other_thing (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +_vala_foo_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_FOO, Foo); + switch (property_id) { + case FOO_MODEL_PROPERTY: + foo_set_model (self, g_value_get_object (value)); + break; + case FOO_OTHER_THING_PROPERTY: + foo_set_other_thing (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +_vala_main (void) +{ + GListModel* l = NULL; + GListStore* _tmp0_; + GObject* o = NULL; + GListModel* _tmp1_; + GObject* _tmp2_; + Foo* foo = NULL; + Foo* _tmp3_; + GListModel* _tmp4_; + GListModel* _tmp5_; + GListModel* _tmp6_; + GObject* _tmp7_; + NotAListView* n = NULL; + NotAListView* _tmp8_; + NotAListView* _tmp9_; + GListModel* _tmp10_; + GListModel* _tmp11_; + GObject* _tmp12_; + GListModel* _tmp13_; + NotAListView* _tmp14_; + NotAListView* _tmp15_; + GListModel* _tmp16_; + NotAListView* _tmp17_; + GListModel* _tmp18_; + GListModel* _tmp19_; + GListModel* _tmp20_; + _tmp0_ = g_list_store_new (g_list_model_get_type ()); + l = G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, g_list_model_get_type (), GListModel); + _tmp1_ = l; + _tmp2_ = g_list_model_get_item (_tmp1_, (guint) 10); + o = _tmp2_; + _tmp3_ = foo_new (); + foo = _tmp3_; + _tmp4_ = l; + foo_set_model (foo, _tmp4_); + _tmp5_ = foo_get_model (foo); + _tmp6_ = _tmp5_; + _tmp7_ = g_list_model_get_item (_tmp6_, (guint) 0); + _g_object_unref0 (o); + o = _tmp7_; + _tmp8_ = not_alist_view_new (); + n = _tmp8_; + _tmp9_ = n; + _tmp10_ = not_alist_view_get_model (_tmp9_); + _tmp11_ = _tmp10_; + _tmp12_ = g_list_model_get_item (_tmp11_, (guint) 0); + _g_object_unref0 (o); + o = _tmp12_; + _tmp13_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (foo, g_list_model_get_type (), GListModel)); + _g_object_unref0 (l); + l = _tmp13_; + _tmp14_ = not_alist_view_new (); + _g_object_unref0 (n); + n = _tmp14_; + _tmp15_ = n; + _tmp16_ = l; + not_alist_view_set_model (_tmp15_, _tmp16_); + _tmp17_ = n; + _tmp18_ = not_alist_view_get_model (_tmp17_); + _tmp19_ = _tmp18_; + _tmp20_ = _g_object_ref0 (_tmp19_); + _g_object_unref0 (l); + l = _tmp20_; + _g_object_unref0 (n); + _g_object_unref0 (foo); + _g_object_unref0 (o); + _g_object_unref0 (l); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/bindings/gio/listmodel-compatibility.vala b/tests/bindings/gio/listmodel-compatibility.vala new file mode 100644 index 000000000..9f2967b3c --- /dev/null +++ b/tests/bindings/gio/listmodel-compatibility.vala @@ -0,0 +1,49 @@ +[CCode (no_generic_args = true)] +class NotAListView : Object where G : Object { + public Type g_type { get; construct; default = typeof (Object); } + + public ListModel model { get; set; } + + public NotAListView.with_type (Type g_type) { + Object (g_type: g_type); + } + + construct { + model = new ListStore (g_type); + } +} + +class Foo : Object, ListModel { + public ListModel model { get; set; } + + public NotAListView other_thing { get; set; } + + public Type get_item_type () { + return typeof (Object); + } + + public Object? get_item (uint pos) { + return null; + } + + public uint get_n_items () { + return 0; + } +} + +void main () { + ListModel l = (ListModel) new ListStore (typeof (ListModel)); + Object? o = l.get_item (10); + + Foo foo = new Foo (); + foo.model = l; + o = foo.model.get_item (0); + + NotAListView n = new NotAListView (); + o = n.model.get_item (0); + l = foo; + + n = new NotAListView (); + n.model = l; + l = n.model; +} diff --git a/tests/generics/no-generic-args-use-with-proper-generic-type-2.test b/tests/generics/no-generic-args-use-with-proper-generic-type-2.test new file mode 100644 index 000000000..c806b5166 --- /dev/null +++ b/tests/generics/no-generic-args-use-with-proper-generic-type-2.test @@ -0,0 +1,14 @@ +Invalid Code + +void foo () { +} + +[CCode (no_generic_args = true)] +class Bar : Object { + public Bar () { + foo (); + } +} + +void main () { +} diff --git a/tests/generics/no-generic-args-use-with-proper-generic-type.test b/tests/generics/no-generic-args-use-with-proper-generic-type.test new file mode 100644 index 000000000..467cbba93 --- /dev/null +++ b/tests/generics/no-generic-args-use-with-proper-generic-type.test @@ -0,0 +1,14 @@ +Invalid Code + +class Foo : Object { +} + +[CCode (no_generic_args = true)] +class Bar : Object { + public Bar () { + var foo = new Foo (); + } +} + +void main () { +} diff --git a/tests/generics/no-generic-args-with-no-constraint.test b/tests/generics/no-generic-args-with-no-constraint.test new file mode 100644 index 000000000..c33f1102f --- /dev/null +++ b/tests/generics/no-generic-args-with-no-constraint.test @@ -0,0 +1,8 @@ +Invalid Code + +[CCode (no_generic_args = true)] +class Foo : Object { +} + +void main () { +} diff --git a/tests/generics/no-generic-args.vala b/tests/generics/no-generic-args.vala new file mode 100644 index 000000000..47d1088ce --- /dev/null +++ b/tests/generics/no-generic-args.vala @@ -0,0 +1,22 @@ + +[CCode (no_generic_args = true)] +class Foo : Object where G : Object { + public G bar { get; set; } + + public G get_b () { + return this.bar; + } + + public void set_b (G b) { + this.bar = b; + } +} + +class Baz : Object { +} + +void main () { + var f = new Foo (); + f.set_b (new Baz()); + Baz b = f.get_b (); +} diff --git a/tests/generics/typeof-with-no-generic-args.test b/tests/generics/typeof-with-no-generic-args.test new file mode 100644 index 000000000..e2918af30 --- /dev/null +++ b/tests/generics/typeof-with-no-generic-args.test @@ -0,0 +1,11 @@ +Invalid Code + +[CCode (no_generic_args = true)] +class Foo : Object where G : Object { + public void bar () { + var g = typeof (G); + } +} + +void main () { +} diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala index 97a7202a1..8afedc915 100644 --- a/vala/valadatatype.vala +++ b/vala/valadatatype.vala @@ -733,6 +733,13 @@ public abstract class Vala.DataType : CodeNode { } it.next (); + + if (!it.get ().no_generic_args && type is GenericType && !(type_symbol is Delegate) && ((TypeParameter) type.type_symbol).no_generic_args) { + error = true; + Report.error (source_reference, "Cannot retrieve runtime information from type-parameter with `[CCode (no_generic_args = true)]' attribute"); + return false; + } + unowned List type_constraints = it.get ().get_type_constraints (); foreach (DataType type_constraint in type_constraints) { if (!type.compatible (type_constraint)) { diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala index 66bfe8b57..7b4470545 100644 --- a/vala/valagirparser.vala +++ b/vala/valagirparser.vala @@ -1848,6 +1848,8 @@ public class Vala.GirParser : CodeVisitor { var type_parameters_length = type_parameters.length; GLib.StringBuilder current = new GLib.StringBuilder.sized (type_parameters_length); + type_symbol.set_attribute_bool ("CCode", "no_generic_args", true); + string? constraint = null; for (var c = 0 ; c < type_parameters_length ; c++) { if (type_parameters[c] == ',') { diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index 08b5b384e..98cf10d9c 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -977,7 +977,7 @@ public class Vala.MemberAccess : Expression { // that subtype might not be generic, so do not report an error in that case unowned ObjectType? object_type = instance_type as ObjectType; if (object_type != null && object_type.object_type_symbol.has_type_parameters () - && !instance_type.has_type_arguments ()) { + && !instance_type.check_type_arguments (context) && !instance_type.has_type_arguments ()) { error = true; Report.error (inner.source_reference, "missing generic type arguments"); return false; diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index afa120a9c..0d1e887b0 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -381,8 +381,9 @@ public class Vala.MethodCall : Expression, CallableExpression { } } + unowned List type_args = ma.get_type_arguments (); int n_type_params = m.get_type_parameters ().size; - int n_type_args = ma.get_type_arguments ().size; + int n_type_args = type_args.size; if (n_type_args > 0 && n_type_args < n_type_params) { error = true; Report.error (ma.source_reference, "too few type arguments for `%s'", m.to_string ()); @@ -392,6 +393,12 @@ public class Vala.MethodCall : Expression, CallableExpression { Report.error (ma.source_reference, "too many type arguments for `%s'", m.to_string ()); return false; } + + if (n_type_args >= 1 && type_args[0] is GenericType && ((TypeParameter) type_args[0].type_symbol).no_generic_args) { + error = true; + Report.error (ma.source_reference, "Cannot retrieve runtime information from type-parameter with `[CCode (no_generic_args = true)]' attribute"); + return false; + } } // FIXME partial code duplication in ObjectCreationExpression.check diff --git a/vala/valatypeofexpression.vala b/vala/valatypeofexpression.vala index 2449b6086..e1a0b0de7 100644 --- a/vala/valatypeofexpression.vala +++ b/vala/valatypeofexpression.vala @@ -90,6 +90,11 @@ public class Vala.TypeofExpression : Expression { Report.warning (_data_type.source_reference, "Arrays do not have a `GLib.Type', with the exception of `string[]'"); } + if (type_reference.type_symbol is TypeParameter && ((TypeParameter) type_reference.type_symbol).no_generic_args) { + Report.error (_data_type.source_reference, "You cannot retrieve type parameters of types with the `[CCode (no_generic_args=true)]' attribute"); + error = true; + } + return !error; } diff --git a/vala/valatypeparameter.vala b/vala/valatypeparameter.vala index 29db5df39..95a8c1745 100644 --- a/vala/valatypeparameter.vala +++ b/vala/valatypeparameter.vala @@ -29,6 +29,12 @@ public class Vala.TypeParameter : TypeSymbol { List type_constraint_list; static List _empty_type_list; + public bool no_generic_args { + get { + return parent_symbol.get_attribute_bool ("CCode", "no_generic_args", false); + } + } + /** * Creates a new generic type parameter. * @@ -164,6 +170,12 @@ public class Vala.TypeParameter : TypeSymbol { Report.error (source_reference, "currently it is only supported to constrain a type parameter with one type"); error = true; } + + if (no_generic_args && !has_type_constraints ()) { + Report.error (source_reference, "type parameters need to be constrained for using `no_generic_args'"); + error = true; + } + return !error; } } diff --git a/vala/valausedattr.vala b/vala/valausedattr.vala index 8823b9122..a68544c3f 100644 --- a/vala/valausedattr.vala +++ b/vala/valausedattr.vala @@ -36,7 +36,7 @@ public class Vala.UsedAttr : CodeVisitor { "param_spec_function", "has_target", "has_typedef", "type_cname", "ref_function", "ref_function_void", "unref_function", "type", "has_construct_function", "returns_floating_reference", "gir_namespace", "gir_version", "construct_function", "lower_case_cprefix", "simple_generics", "sentinel", "scope", "has_destroy_function", "ordering", "type_check_function", "type_get_function", - "has_copy_function", "lower_case_csuffix", "ref_sink_function", "dup_function", "finish_function", "generic_type_pos", + "has_copy_function", "lower_case_csuffix", "ref_sink_function", "dup_function", "finish_function", "generic_type_pos", "no_generic_args", "array_length_type", "array_length", "array_length_cname", "array_length_cexpr", "array_null_terminated", "vfunc_name", "finish_vfunc_name", "finish_name", "free_function_address_of", "pos", "delegate_target", "delegate_target_cname", "array_length_pos", "delegate_target_pos", "destroy_notify_pos", "ctype", "has_new_function", "notify", "finish_instance",