diff options
author | Nick Schrader <nick.schrader@mailbox.org> | 2020-07-19 22:13:37 +0200 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2023-03-19 12:55:01 +0100 |
commit | b16397964c37e0337410d3cab90c2136ff8264fa (patch) | |
tree | b5638c7aa9e60a99eeae1e907adf4dc60fe091c3 | |
parent | ed68b9f412bd6932e384cc8c6ac89257ae40142f (diff) | |
download | vala-wip/issue/658.tar.gz |
vala: Add support for anonymous delegateswip/issue/658
void foo (delegate(string, int) => int d) {
...
}
Fixes https://gitlab.gnome.org/GNOME/vala/issues/658
32 files changed, 2049 insertions, 8 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index 7b4317a18..4824493c7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -203,6 +203,8 @@ TESTS = \ methods/extern.vala \ methods/iterator.vala \ methods/local-functions.vala \ + methods/parameter-anonymous-delegate.vala \ + methods/parameter-anonymous-delegate-optional.vala \ methods/parameter-fixed-array-initializer.vala \ methods/parameter-out-free-on-error.vala \ methods/parameter-ref-array-resize.vala \ @@ -446,6 +448,24 @@ TESTS = \ structs/bug775761.vala \ structs/bug777194.vala \ structs/bug777194-2.vala \ + delegates/anonymous.vala \ + delegates/anonymous-array.vala \ + delegates/anonymous-dynamic.test \ + delegates/anonymous-generics.test \ + delegates/anonymous-inner-dynamic-param.test \ + delegates/anonymous-inner-dynamic-return.test \ + delegates/anonymous-inner-params.test \ + delegates/anonymous-inner-ref-out.vala \ + delegates/anonymous-inner-owned-unowned.vala \ + delegates/anonymous-optional-param.test \ + delegates/anonymous-out.test \ + delegates/anonymous-params.test \ + delegates/anonymous-param-attrs.vala \ + delegates/anonymous-ref.test \ + delegates/anonymous-return-anonymous.test \ + delegates/anonymous-throws.test \ + delegates/anonymous-type-param.vala \ + delegates/anonymous-variadic.test \ delegates/casting.vala \ delegates/class-field-initializer.vala \ delegates/compatible.vala \ diff --git a/tests/delegates/anonymous-array.c-expected b/tests/delegates/anonymous-array.c-expected new file mode 100644 index 000000000..d38f7a44c --- /dev/null +++ b/tests/delegates/anonymous-array.c-expected @@ -0,0 +1,117 @@ +/* delegates_anonymous_array.c generated by valac, the Vala compiler + * generated from delegates_anonymous_array.vala, do not modify */ + +#include <glib.h> +#include <string.h> + +#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 + +typedef gint (*__delegate0_) (gint* p0, gint p0_length1, gint* p1, gint p1_length1, gpointer user_data); +#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); + +static void _vala_main (void); +VALA_EXTERN void f (__delegate0_ abc, + gpointer abc_target); +static gint __lambda4_ (gint* a, + gint a_length1, + gint* b, + gint b_length1); +static gint ___lambda4____delegate0_ (gint* p0, + gint p0_length1, + gint* p1, + gint p1_length1, + gpointer self); + +static gint +__lambda4_ (gint* a, + gint a_length1, + gint* b, + gint b_length1) +{ + gint r = 0; + gint result; + r = 0; + { + gint i = 0; + i = 0; + { + gboolean _tmp0_ = FALSE; + _tmp0_ = TRUE; + while (TRUE) { + gint _tmp2_; + gint _tmp3_; + if (!_tmp0_) { + gint _tmp1_; + _tmp1_ = i; + i = _tmp1_ + 1; + } + _tmp0_ = FALSE; + if (!(i < a_length1)) { + break; + } + _tmp2_ = a[i]; + _tmp3_ = b[i]; + r += _tmp2_ * _tmp3_; + } + } + } + result = r; + return result; +} + +static gint +___lambda4____delegate0_ (gint* p0, + gint p0_length1, + gint* p1, + gint p1_length1, + gpointer self) +{ + gint result; + result = __lambda4_ (p0, p0_length1, p1, p1_length1); + return result; +} + +static void +_vala_main (void) +{ + f (___lambda4____delegate0_, NULL); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + +void +f (__delegate0_ abc, + gpointer abc_target) +{ + gint i[3] = {0}; + gint _tmp0_[3] = {0}; + gint j[3] = {0}; + gint _tmp1_[3] = {0}; + _tmp0_[0] = 1; + _tmp0_[1] = 2; + _tmp0_[2] = 3; + memcpy (i, _tmp0_, 3 * sizeof (gint)); + _tmp1_[0] = 7; + _tmp1_[1] = 8; + _tmp1_[2] = 9; + memcpy (j, _tmp1_, 3 * sizeof (gint)); + _vala_assert (abc (i, (gint) 3, j, (gint) 3, abc_target) == 50, "abc (i, j) == 50"); +} + diff --git a/tests/delegates/anonymous-array.vala b/tests/delegates/anonymous-array.vala new file mode 100644 index 000000000..b032b2915 --- /dev/null +++ b/tests/delegates/anonymous-array.vala @@ -0,0 +1,15 @@ +void main () { + f ((a, b) => { + int r = 0; + for (int i = 0; i < a.length; i++) { + r += a[i] * b[i]; + } + return r; + }); +} + +void f (delegate(int[], int[]) => int abc) { + int i[] = {1, 2, 3}; + int j[] = {7, 8, 9}; + assert (abc (i, j) == 50); +} diff --git a/tests/delegates/anonymous-dynamic.test b/tests/delegates/anonymous-dynamic.test new file mode 100644 index 000000000..fdbf22824 --- /dev/null +++ b/tests/delegates/anonymous-dynamic.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 9.9-9.33: error: Anonymous delegates cannot be dynamic types + * void p (dynamic delegate() => int d) { + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +void p (dynamic delegate() => int d) { + d (); +} + +void main () { + p (() => 7); +} diff --git a/tests/delegates/anonymous-generics.test b/tests/delegates/anonymous-generics.test new file mode 100644 index 000000000..112e06463 --- /dev/null +++ b/tests/delegates/anonymous-generics.test @@ -0,0 +1,19 @@ +Invalid Code + +/* + * 13.17-13.17: error: syntax error, expected `(' + * void f (delegate<T>(int) => void y) { + * ^ + */ + +void main () { + f (t); +} + +void f (delegate<T>(int) => void y) { + y (1); +} + +void t (int a) { + assert (a == 1); +} diff --git a/tests/delegates/anonymous-inner-dynamic-param.test b/tests/delegates/anonymous-inner-dynamic-param.test new file mode 100644 index 000000000..3d8199625 --- /dev/null +++ b/tests/delegates/anonymous-inner-dynamic-param.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 7.18-7.28: error: Dynamic types not allowed in anonymous delegates + * void p (delegate(dynamic int) => void d) { + * ^^^^^^^^^^^ + */ + +void p (delegate(dynamic int) => void d) { + d (7); +} + +void main () { + return; +} diff --git a/tests/delegates/anonymous-inner-dynamic-return.test b/tests/delegates/anonymous-inner-dynamic-return.test new file mode 100644 index 000000000..0a2b6adf7 --- /dev/null +++ b/tests/delegates/anonymous-inner-dynamic-return.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 9.23-9.33: error: Dynamic types not allowed in anonymous delegates + * void p (delegate() => dynamic int d) { + * ^^^^^^^^^^^ + */ + +void p (delegate() => dynamic int d) { + var x = d (); +} + +void main () { + return; +} diff --git a/tests/delegates/anonymous-inner-owned-unowned.c-expected b/tests/delegates/anonymous-inner-owned-unowned.c-expected new file mode 100644 index 000000000..53ac2b25e --- /dev/null +++ b/tests/delegates/anonymous-inner-owned-unowned.c-expected @@ -0,0 +1,500 @@ +/* delegates_anonymous_inner_owned_unowned.c generated by valac, the Vala compiler + * generated from delegates_anonymous_inner_owned_unowned.vala, do not modify */ + +#include <glib.h> +#include <glib-object.h> +#include <gobject/gvaluecollector.h> + +#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 + +typedef struct _Aaa Aaa; + +#define TYPE_BBB (bbb_get_type ()) +#define BBB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BBB, Bbb)) +#define BBB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BBB, BbbClass)) +#define IS_BBB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BBB)) +#define IS_BBB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BBB)) +#define BBB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BBB, BbbClass)) + +typedef struct _Bbb Bbb; +typedef struct _BbbClass BbbClass; +typedef struct _BbbPrivate BbbPrivate; +#define _aaa_free0(var) ((var == NULL) ? NULL : (var = (aaa_free (var), NULL))) +typedef struct _ParamSpecBbb ParamSpecBbb; +typedef void (*__delegate0_) (Aaa* p0, gpointer user_data); +typedef void (*__delegate1_) (Aaa* p0, gpointer user_data); +typedef Aaa* (*__delegate2_) (gpointer user_data); +typedef Aaa* (*__delegate3_) (gpointer user_data); +#define _bbb_unref0(var) ((var == NULL) ? NULL : (var = (bbb_unref (var), NULL))) +#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); + +struct _Aaa { + gint i; +}; + +struct _Bbb { + GTypeInstance parent_instance; + volatile int ref_count; + BbbPrivate * priv; +}; + +struct _BbbClass { + GTypeClass parent_class; + void (*finalize) (Bbb *self); +}; + +struct _BbbPrivate { + Aaa* a; +}; + +struct _ParamSpecBbb { + GParamSpec parent_instance; +}; + +static gint Bbb_private_offset; +static gpointer bbb_parent_class = NULL; + +VALA_EXTERN void aaa_free (Aaa * self); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Aaa, aaa_free) +static void aaa_instance_init (Aaa * self); +VALA_EXTERN Aaa* aaa_new (void); +VALA_EXTERN gpointer bbb_ref (gpointer instance); +VALA_EXTERN void bbb_unref (gpointer instance); +VALA_EXTERN GParamSpec* param_spec_bbb (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags); +VALA_EXTERN void value_set_bbb (GValue* value, + gpointer v_object); +VALA_EXTERN void value_take_bbb (GValue* value, + gpointer v_object); +VALA_EXTERN gpointer value_get_bbb (const GValue* value); +VALA_EXTERN GType bbb_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Bbb, bbb_unref) +VALA_EXTERN Aaa* bbb_get_a (Bbb* self); +VALA_EXTERN Bbb* bbb_new (void); +VALA_EXTERN Bbb* bbb_construct (GType object_type); +static void bbb_finalize (Bbb * obj); +static GType bbb_get_type_once (void); +VALA_EXTERN void p (__delegate0_ d, + gpointer d_target); +VALA_EXTERN void q (__delegate1_ d, + gpointer d_target); +VALA_EXTERN void r (__delegate2_ d, + gpointer d_target); +VALA_EXTERN void s (__delegate3_ d, + gpointer d_target); +static void _vala_main (void); +static void __lambda4_ (Aaa* a); +static void ___lambda4____delegate0_ (Aaa* p0, + gpointer self); +static void __lambda5_ (Aaa* a); +static void ___lambda5____delegate1_ (Aaa* p0, + gpointer self); +static Aaa* __lambda6_ (void); +static Aaa* ___lambda6____delegate2_ (gpointer self); +static Aaa* _bbb_get_a___delegate3_ (gpointer self); + +Aaa* +aaa_new (void) +{ + Aaa* self; + self = g_slice_new0 (Aaa); + aaa_instance_init (self); + return self; +} + +static void +aaa_instance_init (Aaa * self) +{ + self->i = 42; +} + +void +aaa_free (Aaa * self) +{ + g_slice_free (Aaa, self); +} + +static inline gpointer +bbb_get_instance_private (Bbb* self) +{ + return G_STRUCT_MEMBER_P (self, Bbb_private_offset); +} + +Aaa* +bbb_get_a (Bbb* self) +{ + Aaa* x = NULL; + Aaa* _tmp0_; + Aaa* result; + g_return_val_if_fail (IS_BBB (self), NULL); + _tmp0_ = self->priv->a; + x = _tmp0_; + _aaa_free0 (self->priv->a); + self->priv->a = NULL; + result = x; + return result; +} + +Bbb* +bbb_construct (GType object_type) +{ + Bbb* self = NULL; + self = (Bbb*) g_type_create_instance (object_type); + return self; +} + +Bbb* +bbb_new (void) +{ + return bbb_construct (TYPE_BBB); +} + +static void +value_bbb_init (GValue* value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_bbb_free_value (GValue* value) +{ + if (value->data[0].v_pointer) { + bbb_unref (value->data[0].v_pointer); + } +} + +static void +value_bbb_copy_value (const GValue* src_value, + GValue* dest_value) +{ + if (src_value->data[0].v_pointer) { + dest_value->data[0].v_pointer = bbb_ref (src_value->data[0].v_pointer); + } else { + dest_value->data[0].v_pointer = NULL; + } +} + +static gpointer +value_bbb_peek_pointer (const GValue* value) +{ + return value->data[0].v_pointer; +} + +static gchar* +value_bbb_collect_value (GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + if (collect_values[0].v_pointer) { + Bbb * object; + object = collect_values[0].v_pointer; + if (object->parent_instance.g_class == NULL) { + return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { + return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } + value->data[0].v_pointer = bbb_ref (object); + } else { + value->data[0].v_pointer = NULL; + } + return NULL; +} + +static gchar* +value_bbb_lcopy_value (const GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + Bbb ** object_p; + object_p = collect_values[0].v_pointer; + if (!object_p) { + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + } + if (!value->data[0].v_pointer) { + *object_p = NULL; + } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { + *object_p = value->data[0].v_pointer; + } else { + *object_p = bbb_ref (value->data[0].v_pointer); + } + return NULL; +} + +GParamSpec* +param_spec_bbb (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags) +{ + ParamSpecBbb* spec; + g_return_val_if_fail (g_type_is_a (object_type, TYPE_BBB), NULL); + spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); + G_PARAM_SPEC (spec)->value_type = object_type; + return G_PARAM_SPEC (spec); +} + +gpointer +value_get_bbb (const GValue* value) +{ + g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BBB), NULL); + return value->data[0].v_pointer; +} + +void +value_set_bbb (GValue* value, + gpointer v_object) +{ + Bbb * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BBB)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_BBB)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + bbb_ref (value->data[0].v_pointer); + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + bbb_unref (old); + } +} + +void +value_take_bbb (GValue* value, + gpointer v_object) +{ + Bbb * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BBB)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_BBB)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + bbb_unref (old); + } +} + +static void +bbb_class_init (BbbClass * klass, + gpointer klass_data) +{ + bbb_parent_class = g_type_class_peek_parent (klass); + ((BbbClass *) klass)->finalize = bbb_finalize; + g_type_class_adjust_private_offset (klass, &Bbb_private_offset); +} + +static void +bbb_instance_init (Bbb * self, + gpointer klass) +{ + Aaa* _tmp0_; + self->priv = bbb_get_instance_private (self); + _tmp0_ = aaa_new (); + self->priv->a = _tmp0_; + self->ref_count = 1; +} + +static void +bbb_finalize (Bbb * obj) +{ + Bbb * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_BBB, Bbb); + g_signal_handlers_destroy (self); + _aaa_free0 (self->priv->a); +} + +static GType +bbb_get_type_once (void) +{ + static const GTypeValueTable g_define_type_value_table = { value_bbb_init, value_bbb_free_value, value_bbb_copy_value, value_bbb_peek_pointer, "p", value_bbb_collect_value, "p", value_bbb_lcopy_value }; + static const GTypeInfo g_define_type_info = { sizeof (BbbClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) bbb_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Bbb), 0, (GInstanceInitFunc) bbb_instance_init, &g_define_type_value_table }; + static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; + GType bbb_type_id; + bbb_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Bbb", &g_define_type_info, &g_define_type_fundamental_info, 0); + Bbb_private_offset = g_type_add_instance_private (bbb_type_id, sizeof (BbbPrivate)); + return bbb_type_id; +} + +GType +bbb_get_type (void) +{ + static volatile gsize bbb_type_id__once = 0; + if (g_once_init_enter (&bbb_type_id__once)) { + GType bbb_type_id; + bbb_type_id = bbb_get_type_once (); + g_once_init_leave (&bbb_type_id__once, bbb_type_id); + } + return bbb_type_id__once; +} + +gpointer +bbb_ref (gpointer instance) +{ + Bbb * self; + self = instance; + g_atomic_int_inc (&self->ref_count); + return instance; +} + +void +bbb_unref (gpointer instance) +{ + Bbb * self; + self = instance; + if (g_atomic_int_dec_and_test (&self->ref_count)) { + BBB_GET_CLASS (self)->finalize (self); + g_type_free_instance ((GTypeInstance *) self); + } +} + +void +p (__delegate0_ d, + gpointer d_target) +{ + Aaa* a = NULL; + Aaa* _tmp0_; + Aaa* _tmp1_; + Aaa* _tmp2_; + _tmp0_ = aaa_new (); + a = _tmp0_; + _tmp1_ = a; + a = NULL; + d (_tmp1_, d_target); + _tmp2_ = a; + _vala_assert (_tmp2_ == NULL, "a == null"); + _aaa_free0 (a); +} + +void +q (__delegate1_ d, + gpointer d_target) +{ + Aaa* a = NULL; + Aaa* _tmp0_; + _tmp0_ = aaa_new (); + a = _tmp0_; + d (a, d_target); + _vala_assert (a->i == 42, "a.i == 42"); + _aaa_free0 (a); +} + +void +r (__delegate2_ d, + gpointer d_target) +{ + Aaa* _tmp0_; + Aaa* _tmp1_; + _tmp0_ = d (d_target); + _tmp1_ = _tmp0_; + _vala_assert (_tmp1_->i == 42, "d ().i == 42"); + _aaa_free0 (_tmp1_); +} + +void +s (__delegate3_ d, + gpointer d_target) +{ + Aaa* _tmp0_; + _tmp0_ = d (d_target); + _vala_assert (_tmp0_->i != 42, "d ().i != 42"); +} + +static void +__lambda4_ (Aaa* a) +{ + g_return_if_fail (a != NULL); + _vala_assert (a->i == 42, "a.i == 42"); + _aaa_free0 (a); +} + +static void +___lambda4____delegate0_ (Aaa* p0, + gpointer self) +{ + __lambda4_ (p0); +} + +static void +__lambda5_ (Aaa* a) +{ + g_return_if_fail (a != NULL); + _vala_assert (a->i == 42, "a.i == 42"); +} + +static void +___lambda5____delegate1_ (Aaa* p0, + gpointer self) +{ + __lambda5_ (p0); +} + +static Aaa* +__lambda6_ (void) +{ + Aaa* _tmp0_; + Aaa* result; + _tmp0_ = aaa_new (); + result = _tmp0_; + return result; +} + +static Aaa* +___lambda6____delegate2_ (gpointer self) +{ + Aaa* result; + result = __lambda6_ (); + return result; +} + +static Aaa* +_bbb_get_a___delegate3_ (gpointer self) +{ + Aaa* result; + result = bbb_get_a ((Bbb*) self); + return result; +} + +static void +_vala_main (void) +{ + Bbb* _tmp0_; + Bbb* _tmp1_; + p (___lambda4____delegate0_, NULL); + q (___lambda5____delegate1_, NULL); + r (___lambda6____delegate2_, NULL); + _tmp0_ = bbb_new (); + _tmp1_ = _tmp0_; + s (_bbb_get_a___delegate3_, _tmp1_); + _bbb_unref0 (_tmp1_); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/delegates/anonymous-inner-owned-unowned.vala b/tests/delegates/anonymous-inner-owned-unowned.vala new file mode 100644 index 000000000..7c3381e45 --- /dev/null +++ b/tests/delegates/anonymous-inner-owned-unowned.vala @@ -0,0 +1,41 @@ +[Compact] +class Aaa { + public int i = 42; +} + +class Bbb { + Aaa a = new Aaa (); + + public unowned Aaa get_a () { + unowned Aaa x = a; + a = null; + return x; + } +} + +void p (delegate(owned Aaa) => void d) { + var a = new Aaa (); + d ((owned) a); + assert (a == null); +} + +void q (delegate(Aaa) => void d) { + var a = new Aaa (); + d (a); + assert (a.i == 42); +} + +void r (delegate() => Aaa d) { + assert (d ().i == 42); +} + +void s (delegate() => unowned Aaa d) { + assert (d ().i != 42); +} + +void main () { + p ((a) => assert (a.i == 42)); + q ((a) => assert (a.i == 42)); + r (() => new Aaa()); + s (new Bbb().get_a); +} diff --git a/tests/delegates/anonymous-inner-params.test b/tests/delegates/anonymous-inner-params.test new file mode 100644 index 000000000..4dcb3e698 --- /dev/null +++ b/tests/delegates/anonymous-inner-params.test @@ -0,0 +1,19 @@ +Invalid Code + +/* + * 13.18-13.23: error: Params-arrays not allowed in anonymous delegates + * void f (delegate(params string[]) => void y) { + * ^^^^^^ + */ + +void main () { + f (t); +} + +void f (delegate(params string[]) => void y) { + y ("1", "2", "3"); +} + +void t (params string[] p) { + assert (p.length == 3); +} diff --git a/tests/delegates/anonymous-inner-ref-out.c-expected b/tests/delegates/anonymous-inner-ref-out.c-expected new file mode 100644 index 000000000..4ab8a1206 --- /dev/null +++ b/tests/delegates/anonymous-inner-ref-out.c-expected @@ -0,0 +1,100 @@ +/* delegates_anonymous_inner_ref_out.c generated by valac, the Vala compiler + * generated from delegates_anonymous_inner_ref_out.vala, do not modify */ + +#include <glib.h> + +#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 + +typedef void (*__delegate0_) (gint* p0, gpointer user_data); +typedef void (*__delegate1_) (gint* p0, gpointer user_data); +#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); + +static void _vala_main (void); +VALA_EXTERN void f (__delegate0_ x, + gpointer x_target); +VALA_EXTERN void t (gint* a); +static void _t___delegate0_ (gint* p0, + gpointer self); +VALA_EXTERN void g (__delegate1_ y, + gpointer y_target); +VALA_EXTERN void d (gint* a); +static void _d___delegate1_ (gint* p0, + gpointer self); + +static void +_t___delegate0_ (gint* p0, + gpointer self) +{ + t (p0); +} + +static void +_d___delegate1_ (gint* p0, + gpointer self) +{ + d (p0); +} + +static void +_vala_main (void) +{ + f (_t___delegate0_, NULL); + g (_d___delegate1_, NULL); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + +void +f (__delegate0_ x, + gpointer x_target) +{ + gint i = 0; + i = 42; + x (&i, x_target); + _vala_assert (i == 7, "i == 7"); +} + +void +g (__delegate1_ y, + gpointer y_target) +{ + gint i = 0; + gint _tmp0_ = 0; + y (&_tmp0_, y_target); + i = _tmp0_; + _vala_assert (i == 42, "i == 42"); +} + +void +t (gint* a) +{ + *a = 7; +} + +void +d (gint* a) +{ + gint _vala_a = 0; + _vala_a = 42; + if (a) { + *a = _vala_a; + } +} + diff --git a/tests/delegates/anonymous-inner-ref-out.vala b/tests/delegates/anonymous-inner-ref-out.vala new file mode 100644 index 000000000..b094d1ca0 --- /dev/null +++ b/tests/delegates/anonymous-inner-ref-out.vala @@ -0,0 +1,24 @@ +void main () { + f (t); + g (d); +} + +void f (delegate(ref int) => void x) { + int i = 42; + x (ref i); + assert (i == 7); +} + +void g (delegate(out int) => void y) { + int i; + y (out i); + assert (i == 42); +} + +void t (ref int a) { + a = 7; +} + +void d (out int a) { + a = 42; +} diff --git a/tests/delegates/anonymous-optional-param.test b/tests/delegates/anonymous-optional-param.test new file mode 100644 index 000000000..4ac24c470 --- /dev/null +++ b/tests/delegates/anonymous-optional-param.test @@ -0,0 +1,19 @@ +Invalid Code + +/* + * 11.21-11.21: error: Optional parameters not allowed in anonymous delegates + * void f (delegate(int=123) => int y) { + * ^ + */ + +void main () { + f (t); +} + +void f (delegate(int=123) => int y) { + y (1); +} + +int t (int a) { + return a; +} diff --git a/tests/delegates/anonymous-out.test b/tests/delegates/anonymous-out.test new file mode 100644 index 000000000..731320623 --- /dev/null +++ b/tests/delegates/anonymous-out.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 13.9-13.33: error: Anonymous delegates cannot be `out` parameters + * void f (out delegate(int) => void x) { + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +void main () { + assert (true); +} + +void f (out delegate(int) => void x) { + x(42); +} diff --git a/tests/delegates/anonymous-param-attrs.c-expected b/tests/delegates/anonymous-param-attrs.c-expected new file mode 100644 index 000000000..19961e26f --- /dev/null +++ b/tests/delegates/anonymous-param-attrs.c-expected @@ -0,0 +1,62 @@ +/* delegates_anonymous_param_attrs.c generated by valac, the Vala compiler + * generated from delegates_anonymous_param_attrs.vala, do not modify */ + +#include <glib.h> + +#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 + +typedef void (*__delegate0_) (gint8 p0, gpointer user_data); +#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 void f (__delegate0_ d, + gpointer d_target); +VALA_EXTERN void t (gint a); +static void _vala_main (void); +static void _t___delegate0_ (gint8 p0, + gpointer self); + +void +f (__delegate0_ d, + gpointer d_target) +{ + d ((gint8) 300, d_target); +} + +void +t (gint a) +{ + _vala_assert (a == 44, "a == 44"); +} + +static void +_t___delegate0_ (gint8 p0, + gpointer self) +{ + t (p0); +} + +static void +_vala_main (void) +{ + f (_t___delegate0_, NULL); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/delegates/anonymous-param-attrs.vala b/tests/delegates/anonymous-param-attrs.vala new file mode 100644 index 000000000..4b0726b1f --- /dev/null +++ b/tests/delegates/anonymous-param-attrs.vala @@ -0,0 +1,11 @@ +void f (delegate([CCode (type = "gint8")] int) => void d) { + d (300); +} + +void t (int a) { + assert (a == 44); +} + +void main () { + f (t); +} diff --git a/tests/delegates/anonymous-params.test b/tests/delegates/anonymous-params.test new file mode 100644 index 000000000..4772114bd --- /dev/null +++ b/tests/delegates/anonymous-params.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 9.9-9.32: error: Anonymous delegates cannot be param-arrays + * void p (params delegate() => int d) { + * ^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +void p (params delegate() => int d) { + d (); +} + +void main () { + return; +} diff --git a/tests/delegates/anonymous-ref.test b/tests/delegates/anonymous-ref.test new file mode 100644 index 000000000..e79835a38 --- /dev/null +++ b/tests/delegates/anonymous-ref.test @@ -0,0 +1,15 @@ +Invalid Code + +/* + * 13.9-13.33: error: Anonymous delegates cannot be `ref` parameters + * void f (ref delegate(int) => void x) { + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +void main() { + assert (true); +} + +void f (ref delegate(int) => void x) { + x (42); +} diff --git a/tests/delegates/anonymous-return-anonymous.test b/tests/delegates/anonymous-return-anonymous.test new file mode 100644 index 000000000..47be7785f --- /dev/null +++ b/tests/delegates/anonymous-return-anonymous.test @@ -0,0 +1,18 @@ +Invalid Code + + /* + * 9.26-9.33: error: syntax error, anonymous delegate not allowed here + * void f (delegate(int) => delegate() => int d) { + * ^^^^^^^^ + */ + +void f (delegate(int) => delegate() => int d) { + var r = d (14); + stdout.printf("%d\n", r ()); +} + +void main () { + f ((a) => { + return () => a; + }); +} diff --git a/tests/delegates/anonymous-throws.test b/tests/delegates/anonymous-throws.test new file mode 100644 index 000000000..ff11a805d --- /dev/null +++ b/tests/delegates/anonymous-throws.test @@ -0,0 +1,21 @@ +Invalid Code + +/* + * 11.30-11.30: error: syntax error, following expression/statement delimiter `)' missing + * void f (delegate(int) => int y throws Error) { + * ^ + */ + +void main () { + f (t); +} + +void f (delegate(int) => int y throws Error) { + try { + y (1); + } catch {} +} + +int t (int a) throws Error { + return a; +} diff --git a/tests/delegates/anonymous-type-param.c-expected b/tests/delegates/anonymous-type-param.c-expected new file mode 100644 index 000000000..d4240d4c5 --- /dev/null +++ b/tests/delegates/anonymous-type-param.c-expected @@ -0,0 +1,423 @@ +/* delegates_anonymous_type_param.c generated by valac, the Vala compiler + * generated from delegates_anonymous_type_param.vala, do not modify */ + +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#include <glib-object.h> +#include <gobject/gvaluecollector.h> + +#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_COMP (comp_get_type ()) +#define COMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_COMP, Comp)) +#define COMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_COMP, CompClass)) +#define IS_COMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_COMP)) +#define IS_COMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_COMP)) +#define COMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_COMP, CompClass)) + +typedef struct _Comp Comp; +typedef struct _CompClass CompClass; +typedef gchar* (*__delegate0_) (Comp* p0, Comp* p1, gpointer user_data); +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _comp_unref0(var) ((var == NULL) ? NULL : (var = (comp_unref (var), NULL))) +typedef struct _CompPrivate CompPrivate; +typedef struct _ParamSpecComp ParamSpecComp; +#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); + +struct _Comp { + GTypeInstance parent_instance; + volatile int ref_count; + CompPrivate * priv; +}; + +struct _CompClass { + GTypeClass parent_class; + void (*finalize) (Comp *self); +}; + +struct _CompPrivate { + GType a_type; + GBoxedCopyFunc a_dup_func; + GDestroyNotify a_destroy_func; + gpointer _a; +}; + +struct _ParamSpecComp { + GParamSpec parent_instance; +}; + +static gint Comp_private_offset; +static gpointer comp_parent_class = NULL; + +static void _vala_main (void); +VALA_EXTERN gpointer comp_ref (gpointer instance); +VALA_EXTERN void comp_unref (gpointer instance); +VALA_EXTERN GParamSpec* param_spec_comp (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags); +VALA_EXTERN void value_set_comp (GValue* value, + gpointer v_object); +VALA_EXTERN void value_take_comp (GValue* value, + gpointer v_object); +VALA_EXTERN gpointer value_get_comp (const GValue* value); +VALA_EXTERN GType comp_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Comp, comp_unref) +VALA_EXTERN void f (__delegate0_ abc, + gpointer abc_target); +VALA_EXTERN gchar* t (Comp* a, + Comp* b); +static gchar* _t___delegate0_ (Comp* p0, + Comp* p1, + gpointer self); +VALA_EXTERN gconstpointer comp_get_a (Comp* self); +VALA_EXTERN Comp* comp_new (GType a_type, + GBoxedCopyFunc a_dup_func, + GDestroyNotify a_destroy_func, + gconstpointer a); +VALA_EXTERN Comp* comp_construct (GType object_type, + GType a_type, + GBoxedCopyFunc a_dup_func, + GDestroyNotify a_destroy_func, + gconstpointer a); +static void comp_set_a (Comp* self, + gconstpointer value); +static void comp_finalize (Comp * obj); +static GType comp_get_type_once (void); + +static gchar* +_t___delegate0_ (Comp* p0, + Comp* p1, + gpointer self) +{ + gchar* result; + result = t (p0, p1); + return result; +} + +static void +_vala_main (void) +{ + f (_t___delegate0_, NULL); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + +gchar* +t (Comp* a, + Comp* b) +{ + gconstpointer _tmp0_; + gconstpointer _tmp1_; + gconstpointer _tmp2_; + gconstpointer _tmp3_; + gchar* _tmp4_; + gchar* result; + g_return_val_if_fail (IS_COMP (a), NULL); + g_return_val_if_fail (IS_COMP (b), NULL); + _tmp0_ = comp_get_a (a); + _tmp1_ = _tmp0_; + _tmp2_ = comp_get_a (b); + _tmp3_ = _tmp2_; + _tmp4_ = g_strconcat ((const gchar*) _tmp1_, (const gchar*) _tmp3_, NULL); + result = _tmp4_; + return result; +} + +void +f (__delegate0_ abc, + gpointer abc_target) +{ + Comp* _tmp0_; + Comp* _tmp1_; + Comp* _tmp2_; + Comp* _tmp3_; + gchar* _tmp4_; + gchar* _tmp5_; + _tmp0_ = comp_new (G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free, "x"); + _tmp1_ = _tmp0_; + _tmp2_ = comp_new (G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free, "y"); + _tmp3_ = _tmp2_; + _tmp4_ = abc (_tmp1_, _tmp3_, abc_target); + _tmp5_ = _tmp4_; + _vala_assert (g_strcmp0 (_tmp5_, "xy") == 0, "abc(new Comp<string> (\"x\"), new Comp<string> (\"y\")) == \"xy\""); + _g_free0 (_tmp5_); + _comp_unref0 (_tmp3_); + _comp_unref0 (_tmp1_); +} + +static inline gpointer +comp_get_instance_private (Comp* self) +{ + return G_STRUCT_MEMBER_P (self, Comp_private_offset); +} + +Comp* +comp_construct (GType object_type, + GType a_type, + GBoxedCopyFunc a_dup_func, + GDestroyNotify a_destroy_func, + gconstpointer a) +{ + Comp* self = NULL; + self = (Comp*) g_type_create_instance (object_type); + self->priv->a_type = a_type; + self->priv->a_dup_func = a_dup_func; + self->priv->a_destroy_func = a_destroy_func; + comp_set_a (self, a); + return self; +} + +Comp* +comp_new (GType a_type, + GBoxedCopyFunc a_dup_func, + GDestroyNotify a_destroy_func, + gconstpointer a) +{ + return comp_construct (TYPE_COMP, a_type, a_dup_func, a_destroy_func, a); +} + +gconstpointer +comp_get_a (Comp* self) +{ + gconstpointer result; + gconstpointer _tmp0_; + g_return_val_if_fail (IS_COMP (self), NULL); + _tmp0_ = self->priv->_a; + result = _tmp0_; + return result; +} + +static void +comp_set_a (Comp* self, + gconstpointer value) +{ + gpointer _tmp0_; + g_return_if_fail (IS_COMP (self)); + _tmp0_ = ((value != NULL) && (self->priv->a_dup_func != NULL)) ? self->priv->a_dup_func ((gpointer) value) : ((gpointer) value); + ((self->priv->_a == NULL) || (self->priv->a_destroy_func == NULL)) ? NULL : (self->priv->_a = (self->priv->a_destroy_func (self->priv->_a), NULL)); + self->priv->_a = _tmp0_; +} + +static void +value_comp_init (GValue* value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_comp_free_value (GValue* value) +{ + if (value->data[0].v_pointer) { + comp_unref (value->data[0].v_pointer); + } +} + +static void +value_comp_copy_value (const GValue* src_value, + GValue* dest_value) +{ + if (src_value->data[0].v_pointer) { + dest_value->data[0].v_pointer = comp_ref (src_value->data[0].v_pointer); + } else { + dest_value->data[0].v_pointer = NULL; + } +} + +static gpointer +value_comp_peek_pointer (const GValue* value) +{ + return value->data[0].v_pointer; +} + +static gchar* +value_comp_collect_value (GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + if (collect_values[0].v_pointer) { + Comp * object; + object = collect_values[0].v_pointer; + if (object->parent_instance.g_class == NULL) { + return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { + return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } + value->data[0].v_pointer = comp_ref (object); + } else { + value->data[0].v_pointer = NULL; + } + return NULL; +} + +static gchar* +value_comp_lcopy_value (const GValue* value, + guint n_collect_values, + GTypeCValue* collect_values, + guint collect_flags) +{ + Comp ** object_p; + object_p = collect_values[0].v_pointer; + if (!object_p) { + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + } + if (!value->data[0].v_pointer) { + *object_p = NULL; + } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { + *object_p = value->data[0].v_pointer; + } else { + *object_p = comp_ref (value->data[0].v_pointer); + } + return NULL; +} + +GParamSpec* +param_spec_comp (const gchar* name, + const gchar* nick, + const gchar* blurb, + GType object_type, + GParamFlags flags) +{ + ParamSpecComp* spec; + g_return_val_if_fail (g_type_is_a (object_type, TYPE_COMP), NULL); + spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); + G_PARAM_SPEC (spec)->value_type = object_type; + return G_PARAM_SPEC (spec); +} + +gpointer +value_get_comp (const GValue* value) +{ + g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_COMP), NULL); + return value->data[0].v_pointer; +} + +void +value_set_comp (GValue* value, + gpointer v_object) +{ + Comp * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_COMP)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_COMP)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + comp_ref (value->data[0].v_pointer); + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + comp_unref (old); + } +} + +void +value_take_comp (GValue* value, + gpointer v_object) +{ + Comp * old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_COMP)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_COMP)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + comp_unref (old); + } +} + +static void +comp_class_init (CompClass * klass, + gpointer klass_data) +{ + comp_parent_class = g_type_class_peek_parent (klass); + ((CompClass *) klass)->finalize = comp_finalize; + g_type_class_adjust_private_offset (klass, &Comp_private_offset); +} + +static void +comp_instance_init (Comp * self, + gpointer klass) +{ + self->priv = comp_get_instance_private (self); + self->ref_count = 1; +} + +static void +comp_finalize (Comp * obj) +{ + Comp * self; + self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_COMP, Comp); + g_signal_handlers_destroy (self); + ((self->priv->_a == NULL) || (self->priv->a_destroy_func == NULL)) ? NULL : (self->priv->_a = (self->priv->a_destroy_func (self->priv->_a), NULL)); +} + +static GType +comp_get_type_once (void) +{ + static const GTypeValueTable g_define_type_value_table = { value_comp_init, value_comp_free_value, value_comp_copy_value, value_comp_peek_pointer, "p", value_comp_collect_value, "p", value_comp_lcopy_value }; + static const GTypeInfo g_define_type_info = { sizeof (CompClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) comp_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Comp), 0, (GInstanceInitFunc) comp_instance_init, &g_define_type_value_table }; + static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; + GType comp_type_id; + comp_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Comp", &g_define_type_info, &g_define_type_fundamental_info, 0); + Comp_private_offset = g_type_add_instance_private (comp_type_id, sizeof (CompPrivate)); + return comp_type_id; +} + +GType +comp_get_type (void) +{ + static volatile gsize comp_type_id__once = 0; + if (g_once_init_enter (&comp_type_id__once)) { + GType comp_type_id; + comp_type_id = comp_get_type_once (); + g_once_init_leave (&comp_type_id__once, comp_type_id); + } + return comp_type_id__once; +} + +gpointer +comp_ref (gpointer instance) +{ + Comp * self; + self = instance; + g_atomic_int_inc (&self->ref_count); + return instance; +} + +void +comp_unref (gpointer instance) +{ + Comp * self; + self = instance; + if (g_atomic_int_dec_and_test (&self->ref_count)) { + COMP_GET_CLASS (self)->finalize (self); + g_type_free_instance ((GTypeInstance *) self); + } +} + diff --git a/tests/delegates/anonymous-type-param.vala b/tests/delegates/anonymous-type-param.vala new file mode 100644 index 000000000..b5485aa5c --- /dev/null +++ b/tests/delegates/anonymous-type-param.vala @@ -0,0 +1,20 @@ +void main () { + f (t); +} + +string t (Comp<string> a, Comp<string> b) { + return a.a + b.a; +} + + +void f (delegate(Comp<string>, Comp<string>) => string abc) { + assert (abc(new Comp<string> ("x"), new Comp<string> ("y")) == "xy"); +} + +class Comp<A> { + public A a { get; private set; } + + public Comp (A a) { + this.a = a; + } +} diff --git a/tests/delegates/anonymous-variadic.test b/tests/delegates/anonymous-variadic.test new file mode 100644 index 000000000..fabd3a422 --- /dev/null +++ b/tests/delegates/anonymous-variadic.test @@ -0,0 +1,19 @@ +Invalid Code + +/* + * 11.23-11.25: error: syntax error, expected identifier + * void f (delegate(int, ...) => int y) { + * ^^^ + */ + +void main () { + f (t); +} + +void f (delegate(int, ...) => int y) { + y (1); +} + +int t (int a, ...) { + return a; +} diff --git a/tests/delegates/anonymous.c-expected b/tests/delegates/anonymous.c-expected new file mode 100644 index 000000000..68c369b39 --- /dev/null +++ b/tests/delegates/anonymous.c-expected @@ -0,0 +1,70 @@ +/* delegates_anonymous.c generated by valac, the Vala compiler + * generated from delegates_anonymous.vala, do not modify */ + +#include <glib.h> + +#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 + +typedef gint (*__delegate0_) (gint p0, gint p1, gpointer user_data); +#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); + +static void _vala_main (void); +VALA_EXTERN void f (__delegate0_ abc, + gpointer abc_target); +static gint __lambda4_ (gint a, + gint b); +static gint ___lambda4____delegate0_ (gint p0, + gint p1, + gpointer self); + +static gint +__lambda4_ (gint a, + gint b) +{ + gint result; + result = a + b; + return result; +} + +static gint +___lambda4____delegate0_ (gint p0, + gint p1, + gpointer self) +{ + gint result; + result = __lambda4_ (p0, p1); + return result; +} + +static void +_vala_main (void) +{ + f (___lambda4____delegate0_, NULL); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + +void +f (__delegate0_ abc, + gpointer abc_target) +{ + _vala_assert (abc (1, 2, abc_target) == 3, "abc (1, 2) == 3"); +} + diff --git a/tests/delegates/anonymous.vala b/tests/delegates/anonymous.vala new file mode 100644 index 000000000..eff97e298 --- /dev/null +++ b/tests/delegates/anonymous.vala @@ -0,0 +1,9 @@ +void main () { + f ((a, b) => { + return a + b; + }); +} + +void f (delegate(int, int) => int abc) { + assert (abc (1, 2) == 3); +} diff --git a/tests/methods/parameter-anonymous-delegate-optional.c-expected b/tests/methods/parameter-anonymous-delegate-optional.c-expected new file mode 100644 index 000000000..5075818f3 --- /dev/null +++ b/tests/methods/parameter-anonymous-delegate-optional.c-expected @@ -0,0 +1,89 @@ +/* methods_parameter_anonymous_delegate_optional.c generated by valac, the Vala compiler + * generated from methods_parameter_anonymous_delegate_optional.vala, do not modify */ + +#include <glib.h> + +#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 + +typedef gint (*__delegate0_) (gint p0, gpointer user_data); +#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 gint f (__delegate0_ d, + gpointer d_target); +static void _vala_main (void); +static gint __lambda5_ (gint a); +static gint ___lambda5____delegate0_ (gint p0, + gpointer self); +static gint _lambda4_ (gint a); +static gint __lambda4____delegate0_ (gint p0, + gpointer self); + +gint +f (__delegate0_ d, + gpointer d_target) +{ + gint result; + result = d (7, d_target); + return result; +} + +static gint +__lambda5_ (gint a) +{ + gint result; + result = a; + return result; +} + +static gint +___lambda5____delegate0_ (gint p0, + gpointer self) +{ + gint result; + result = __lambda5_ (p0); + return result; +} + +static gint +_lambda4_ (gint a) +{ + gint result; + result = 2 * a; + return result; +} + +static gint +__lambda4____delegate0_ (gint p0, + gpointer self) +{ + gint result; + result = _lambda4_ (p0); + return result; +} + +static void +_vala_main (void) +{ + _vala_assert (f (___lambda5____delegate0_, NULL) == 7, "f (a => a) == 7"); + _vala_assert (f (__lambda4____delegate0_, NULL) == 14, "f () == 14"); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/methods/parameter-anonymous-delegate-optional.vala b/tests/methods/parameter-anonymous-delegate-optional.vala new file mode 100644 index 000000000..dc6085b34 --- /dev/null +++ b/tests/methods/parameter-anonymous-delegate-optional.vala @@ -0,0 +1,8 @@ +int f (delegate(int) => int d = (a) => 2*a) { + return d (7); +} + +void main () { + assert (f (a => a) == 7); + assert (f () == 14); +} diff --git a/tests/methods/parameter-anonymous-delegate.c-expected b/tests/methods/parameter-anonymous-delegate.c-expected new file mode 100644 index 000000000..a4f4aa324 --- /dev/null +++ b/tests/methods/parameter-anonymous-delegate.c-expected @@ -0,0 +1,130 @@ +/* methods_parameter_anonymous_delegate.c generated by valac, the Vala compiler + * generated from methods_parameter_anonymous_delegate.vala, do not modify */ + +#include <glib.h> + +#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 + +typedef gint (*__delegate0_) (gint p0, gint p1, gpointer user_data); +typedef gint (*__delegate1_) (gint p0, gint p1, gpointer user_data); +typedef gint (*__delegate2_) (gint p0, gint p1, gpointer user_data); +#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 gint func (gint a, + gint b); +VALA_EXTERN void foo (__delegate0_ p, + gpointer p_target, + gint r); +VALA_EXTERN void bar (gint r, + __delegate1_ p, + gpointer p_target, + GDestroyNotify p_target_destroy_notify); +VALA_EXTERN void manam (__delegate2_ p, + gpointer p_target, + gint r); +static void _vala_main (void); +static gint _func___delegate0_ (gint p0, + gint p1, + gpointer self); +static gint _func___delegate1_ (gint p0, + gint p1, + gpointer self); +static gint _func___delegate2_ (gint p0, + gint p1, + gpointer self); + +gint +func (gint a, + gint b) +{ + gint result; + result = a + b; + return result; +} + +void +foo (__delegate0_ p, + gpointer p_target, + gint r) +{ + _vala_assert (p (23, 42, p_target) == r, "p (23, 42) == r"); +} + +void +bar (gint r, + __delegate1_ p, + gpointer p_target, + GDestroyNotify p_target_destroy_notify) +{ + _vala_assert (p (23, 42, p_target) == r, "p (23, 42) == r"); + (p_target_destroy_notify == NULL) ? NULL : (p_target_destroy_notify (p_target), NULL); + p = NULL; + p_target = NULL; + p_target_destroy_notify = NULL; +} + +void +manam (__delegate2_ p, + gpointer p_target, + gint r) +{ + _vala_assert (p (23, 42, p_target) == r, "p (23, 42) == r"); +} + +static gint +_func___delegate0_ (gint p0, + gint p1, + gpointer self) +{ + gint result; + result = func (p0, p1); + return result; +} + +static gint +_func___delegate1_ (gint p0, + gint p1, + gpointer self) +{ + gint result; + result = func (p0, p1); + return result; +} + +static gint +_func___delegate2_ (gint p0, + gint p1, + gpointer self) +{ + gint result; + result = func (p0, p1); + return result; +} + +static void +_vala_main (void) +{ + foo (_func___delegate0_, NULL, 65); + bar (65, _func___delegate1_, NULL, NULL); + manam (_func___delegate2_, NULL, 65); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/methods/parameter-anonymous-delegate.vala b/tests/methods/parameter-anonymous-delegate.vala new file mode 100644 index 000000000..da3e624be --- /dev/null +++ b/tests/methods/parameter-anonymous-delegate.vala @@ -0,0 +1,21 @@ +int func (int a, int b) { + return a + b; +} + +void foo (delegate(int, int) => int p, int r) { + assert (p (23, 42) == r); +} + +void bar (int r, owned delegate(int, int) => int p) { + assert (p (23, 42) == r); +} + +void manam ([CCode (has_target = false)] delegate(int, int) => int p, int r) { + assert (p (23, 42) == r); +} + +void main () { + foo (func, 65); + bar (65, func); + manam (func, 65); +} diff --git a/vala/valacallabletype.vala b/vala/valacallabletype.vala index 6ea2349d0..c2957a342 100644 --- a/vala/valacallabletype.vala +++ b/vala/valacallabletype.vala @@ -71,7 +71,11 @@ public abstract class Vala.CallableType : DataType { // Append name builder.append_c (' '); - builder.append (override_name ?? this.to_string ()); + if (symbol.anonymous) { + builder.append ("<anonymous>"); + } else { + builder.append (override_name ?? this.to_string ()); + } builder.append_c (' '); // Append parameter-list diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala index f9f1fccd1..5887392fd 100644 --- a/vala/valacodewriter.vala +++ b/vala/valacodewriter.vala @@ -683,7 +683,11 @@ public class Vala.CodeWriter : CodeVisitor { } } - write_type (param.variable_type); + if (param.variable_type is DelegateType && param.variable_type.type_symbol.anonymous) { + write_anonymous_delegate (param.variable_type as DelegateType); + } else { + write_type (param.variable_type); + } write_string (" "); write_identifier (param.name); @@ -709,6 +713,10 @@ public class Vala.CodeWriter : CodeVisitor { return; } + if (cb.anonymous) { + return; + } + if (context.vapi_comments && cb.comment != null) { write_comment (cb.comment); } @@ -1614,6 +1622,43 @@ public class Vala.CodeWriter : CodeVisitor { stream.putc ('}'); } + private void write_anonymous_params (List<Parameter> params) { + write_string ("("); + + int i = 1; + foreach (Parameter param in params) { + if (i > 1) { + write_string (", "); + } + + write_attributes (param); + + if (param.direction == ParameterDirection.REF) { + write_string ("ref "); + } else if (param.direction == ParameterDirection.OUT) { + write_string ("out "); + } + + write_type (param.variable_type); + write_type_suffix (param.variable_type); + + i++; + } + + write_string (")"); + + } + + private void write_anonymous_delegate (DelegateType cb) { + write_attributes (cb); + + write_string ("delegate"); + write_anonymous_params (cb.get_parameters ()); + + write_string (" => "); + write_return_type (cb.get_return_type ()); + } + private bool check_accessibility (Symbol sym) { switch (type) { case CodeWriterType.EXTERNAL: diff --git a/vala/valaparser.vala b/vala/valaparser.vala index 9ac94e4a5..1b1e51ac4 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -517,7 +517,7 @@ public class Vala.Parser : CodeVisitor { return result; } - DataType parse_type (bool owned_by_default, bool can_weak_ref, bool require_unowned = false) throws ParseError { + DataType parse_type (bool owned_by_default, bool can_weak_ref, bool require_unowned = false, Symbol? parent=null, Method? method=null) throws ParseError { var begin = get_location (); bool is_dynamic = accept (TokenType.DYNAMIC); @@ -552,6 +552,19 @@ public class Vala.Parser : CodeVisitor { DataType type; + var begin_delegate_token = get_location (); + var is_delegate_token = accept (TokenType.DELEGATE); + rollback (begin_delegate_token); + + if (is_delegate_token && method == null) { + throw new ParseError.SYNTAX ("anonymous delegate not allowed here"); + } else if (is_delegate_token) { + type = parse_anonymous_delegate (parent, method); + type.value_owned = value_owned; + type.is_dynamic = is_dynamic; + return type; + } + bool inner_type_owned = true; if (accept (TokenType.OPEN_PARENS)) { type = parse_type (false, false, true); @@ -3280,7 +3293,7 @@ public class Vala.Parser : CodeVisitor { expect (TokenType.OPEN_PARENS); if (current () != TokenType.CLOSE_PARENS) { do { - var param = parse_parameter (); + var param = parse_parameter (parent, method); method.add_parameter (param); } while (accept (TokenType.COMMA)); } @@ -3815,7 +3828,8 @@ public class Vala.Parser : CodeVisitor { } } - Parameter parse_parameter () throws ParseError { + Parameter parse_parameter (Symbol? parent=null, Method? method=null) throws ParseError { + var begin_attrs = get_location (); var attrs = parse_attributes (); var begin = get_location (); if (accept (TokenType.ELLIPSIS)) { @@ -3831,18 +3845,45 @@ public class Vala.Parser : CodeVisitor { } DataType type; + string pretty_direction = null; if (direction == ParameterDirection.IN) { // in parameters are unowned by default - type = parse_type (false, false); + type = parse_type (false, false, false, parent, method); } else if (direction == ParameterDirection.REF) { // ref parameters own the value by default - type = parse_type (true, true); + type = parse_type (true, true, false, parent, method); + pretty_direction = "ref"; } else { // out parameters own the value by default - type = parse_type (true, false); + type = parse_type (true, false, false, parent, method); + pretty_direction = "out"; } + string id = parse_identifier (); + var possibly_delegate = type as DelegateType; + if (possibly_delegate != null && possibly_delegate.delegate_symbol.anonymous) { + if (attrs != null) { + var here = get_location (); + rollback (begin); + Report.warning (get_src (begin_attrs), "Ambiguous attribute: does it belong to `%s` or parameter `%s`?" + .printf (possibly_delegate.to_prototype_string (), id)); + rollback (here); + } + + if (pretty_direction != null) { + Report.error (get_src (begin), "Anonymous delegates cannot be `" + pretty_direction + "` parameters"); + } + + if (possibly_delegate.is_dynamic) { + Report.error (get_src (begin), "Anonymous delegates cannot be dynamic types"); + } + + if (params_array) { + Report.error (get_src (begin), "Anonymous delegates cannot be param-arrays"); + } + } + type = parse_inline_array_type (type); var param = new Parameter (id, type, get_src (begin)); @@ -3975,6 +4016,92 @@ public class Vala.Parser : CodeVisitor { } } + static int next_anonymous_id = 0; + + Parameter parse_anonymous_parameter (int id) throws ParseError { + var attrs = parse_attributes (); + var begin = get_location (); + + if (accept (TokenType.PARAMS)) { + Report.error (get_last_src (), "Params-arrays not allowed in anonymous delegates"); + } + + var direction = ParameterDirection.IN; + if (accept (TokenType.OUT)) { + direction = ParameterDirection.OUT; + } else if (accept (TokenType.REF)) { + direction = ParameterDirection.REF; + } + + DataType type; + var type_loc = get_location (); + if (direction == ParameterDirection.IN) { + // in parameters are unowned by default + type = parse_type (false, false); + } else if (direction == ParameterDirection.REF) { + // ref parameters own the value by default + type = parse_type (true, true); + } else { + // out parameters own the value by default + type = parse_type (true, false); + } + + if (type.is_dynamic) { + Report.error (get_src (type_loc), "Dynamic types not allowed in anonymous delegates"); + } + + type = parse_inline_array_type (type); + + if (accept (TokenType.ASSIGN)) { + Report.error (get_last_src (), "Optional paramters not allowed in anonymous delegates"); + } + + var param = new Parameter ("p%i".printf (id), type, get_src (begin)); + set_attributes (param, attrs); + param.direction = direction; + return param; + } + + DelegateType parse_anonymous_delegate (Symbol parent, Method method) throws ParseError { + var begin = get_location (); + expect (TokenType.DELEGATE); + + expect (TokenType.OPEN_PARENS); + var param_list = new ArrayList<Parameter> (); + if (current () != TokenType.CLOSE_PARENS) { + int next_parameter_id = 0; + do { + var param = parse_anonymous_parameter (next_parameter_id++); + param_list.add (param); + } while (accept (TokenType.COMMA)); + } + expect (TokenType.CLOSE_PARENS); + + expect (TokenType.LAMBDA); + var type_loc = get_location (); + var type = parse_type (true, false); + + if (type.is_dynamic) { + Report.error (get_src (type_loc), "Dynamic types not allowed in anonymous delegates"); + } + + var src = get_src (begin); + if (!context.experimental) { + Report.warning (src, "Anonymous delegates are experimental"); + } + + var d = new Delegate ("__delegate%i_".printf (next_anonymous_id++), type, get_src (begin), comment); + d.anonymous = true; + d.access = method.access; + + foreach (var param in param_list) { + d.add_parameter (param); + } + + parent.add_delegate (d); + return new DelegateType (d); + } + List<TypeParameter> parse_type_parameter_list () throws ParseError { if (accept (TokenType.OP_LT)) { var list = new ArrayList<TypeParameter> (); |