From: Rico Tzschichholz Date: Sun, 6 Feb 2022 07:57:35 +0000 (+0100) Subject: vala: Move dynamic property errors to semantic analyzer pass X-Git-Tag: 0.54.7~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9abf7a7ee8c884b1346d982728b0885261eb3ab2;p=thirdparty%2Fvala.git vala: Move dynamic property errors to semantic analyzer pass --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 70447ab67..2a4a37afb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -521,6 +521,8 @@ TESTS = \ objects/property-array.vala \ objects/property-array-length.vala \ objects/property-base-access.vala \ + objects/property-dynamic-not-supported.test \ + objects/property-dynamic-type-inference.vala \ objects/property-enum.vala \ objects/property-notify.vala \ objects/property-notify-owned-getter.vala \ diff --git a/tests/objects/property-dynamic-not-supported.test b/tests/objects/property-dynamic-not-supported.test new file mode 100644 index 000000000..15d659099 --- /dev/null +++ b/tests/objects/property-dynamic-not-supported.test @@ -0,0 +1,10 @@ +Invalid Code + +class Foo { +} + +void main () { + dynamic Foo foo = new Foo (); + foo.bar = "foo"; + int i = foo.bar; +} diff --git a/tests/objects/property-dynamic-type-inference.c-expected b/tests/objects/property-dynamic-type-inference.c-expected new file mode 100644 index 000000000..f970e5fca --- /dev/null +++ b/tests/objects/property-dynamic-type-inference.c-expected @@ -0,0 +1,310 @@ +/* objects_property_dynamic_type_inference.c generated by valac, the Vala compiler + * generated from objects_property_dynamic_type_inference.vala, do not modify */ + +#include +#include + +#if !defined(VALA_EXTERN) +#if defined(_MSC_VER) +#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_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_BAR_PROPERTY, + FOO_NUM_PROPERTIES +}; +static GParamSpec* foo_properties[FOO_NUM_PROPERTIES]; +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_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 _Foo { + GObject parent_instance; + FooPrivate * priv; +}; + +struct _FooClass { + GObjectClass parent_class; +}; + +struct _FooPrivate { + Foo* _bar; +}; + +static gint Foo_private_offset; +static gpointer foo_parent_class = NULL; + +VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, g_object_unref) +VALA_EXTERN Foo* foo_new (void); +VALA_EXTERN Foo* foo_construct (GType object_type); +VALA_EXTERN Foo* foo_get_bar (Foo* self); +VALA_EXTERN void foo_set_bar (Foo* self, + Foo* 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 Foo* _dynamic_get_manam0 (Foo* obj); +static inline void _dynamic_set_manam1 (Foo* obj, + Foo* value); +static inline Foo* _dynamic_get_manam2 (Foo* obj); + +static inline gpointer +foo_get_instance_private (Foo* self) +{ + return G_STRUCT_MEMBER_P (self, Foo_private_offset); +} + +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); +} + +static gpointer +_g_object_ref0 (gpointer self) +{ + return self ? g_object_ref (self) : NULL; +} + +Foo* +foo_get_bar (Foo* self) +{ + Foo* result; + Foo* _tmp0_; + Foo* _tmp1_; + g_return_val_if_fail (IS_FOO (self), NULL); + _tmp0_ = self->priv->_bar; + _tmp1_ = _g_object_ref0 (_tmp0_); + result = _tmp1_; + return result; +} + +void +foo_set_bar (Foo* self, + Foo* value) +{ + Foo* old_value; + g_return_if_fail (IS_FOO (self)); + old_value = foo_get_bar (self); + if (old_value != value) { + Foo* _tmp0_; + _tmp0_ = _g_object_ref0 (value); + _g_object_unref0 (self->priv->_bar); + self->priv->_bar = _tmp0_; + g_object_notify_by_pspec ((GObject *) self, foo_properties[FOO_BAR_PROPERTY]); + } + _g_object_unref0 (old_value); +} + +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_BAR_PROPERTY, foo_properties[FOO_BAR_PROPERTY] = g_param_spec_object ("manam", "bar", "bar", TYPE_FOO, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE)); +} + +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->_bar); + 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 }; + GType foo_type_id; + foo_type_id = g_type_register_static (G_TYPE_OBJECT, "Foo", &g_define_type_info, 0); + 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__volatile = 0; + if (g_once_init_enter (&foo_type_id__volatile)) { + GType foo_type_id; + foo_type_id = foo_get_type_once (); + g_once_init_leave (&foo_type_id__volatile, foo_type_id); + } + return foo_type_id__volatile; +} + +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_BAR_PROPERTY: + g_value_take_object (value, foo_get_bar (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_BAR_PROPERTY: + foo_set_bar (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static inline Foo* +_dynamic_get_manam0 (Foo* obj) +{ + Foo* result; + g_object_get (obj, "manam", &result, NULL); + return result; +} + +static inline void +_dynamic_set_manam1 (Foo* obj, + Foo* value) +{ + g_object_set (obj, "manam", value, NULL); +} + +static inline Foo* +_dynamic_get_manam2 (Foo* obj) +{ + Foo* result; + g_object_get (obj, "manam", &result, NULL); + return result; +} + +static void +_vala_main (void) +{ + Foo* foo = NULL; + Foo* _tmp0_; + Foo* _tmp1_; + Foo* dfoo = NULL; + Foo* _tmp2_; + Foo* _tmp3_; + Foo* _tmp4_; + Foo* _tmp5_; + Foo* _tmp6_; + Foo* _tmp7_; + Foo* _tmp8_; + Foo* _tmp9_; + Foo* _tmp10_; + Foo* _tmp11_; + Foo* _tmp12_; + Foo* _tmp13_; + Foo* _tmp14_; + Foo* _tmp15_; + Foo* _tmp16_; + Foo* _tmp17_; + _tmp0_ = foo_new (); + foo = _tmp0_; + _tmp1_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 1), "foo.ref_count == 1"); + _tmp2_ = foo; + _tmp3_ = _g_object_ref0 (_tmp2_); + dfoo = _tmp3_; + _tmp4_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp4_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 2), "foo.ref_count == 2"); + _tmp5_ = dfoo; + _tmp6_ = _dynamic_get_manam0 (_tmp5_); + _tmp7_ = _tmp6_; + _vala_assert (_tmp7_ == NULL, "dfoo.manam == null"); + _tmp8_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp8_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 2), "foo.ref_count == 2"); + _tmp9_ = dfoo; + _tmp10_ = foo; + _dynamic_set_manam1 (_tmp9_, _tmp10_); + _tmp11_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp11_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 3), "foo.ref_count == 3"); + _tmp12_ = dfoo; + _tmp13_ = _dynamic_get_manam2 (_tmp12_); + _tmp14_ = _tmp13_; + _g_object_unref0 (foo); + foo = _tmp14_; + _tmp15_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp15_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 3), "foo.ref_count == 3"); + _g_object_unref0 (dfoo); + dfoo = NULL; + _tmp16_ = foo; + foo_set_bar (_tmp16_, NULL); + _tmp17_ = foo; + _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (_tmp17_, G_TYPE_OBJECT, GObject)->ref_count == ((guint) 1), "foo.ref_count == 1"); + _g_object_unref0 (dfoo); + _g_object_unref0 (foo); +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/objects/property-dynamic-type-inference.vala b/tests/objects/property-dynamic-type-inference.vala new file mode 100644 index 000000000..3f555da3c --- /dev/null +++ b/tests/objects/property-dynamic-type-inference.vala @@ -0,0 +1,25 @@ +class Foo : Object { + [CCode (cname = "manam")] + public Foo? bar { owned get; set; } +} + +void main () { + var foo = new Foo (); + assert (foo.ref_count == 1); + + dynamic Foo dfoo = foo; + assert (foo.ref_count == 2); + + assert (dfoo.manam == null); + assert (foo.ref_count == 2); + + dfoo.manam = foo; + assert (foo.ref_count == 3); + + foo = dfoo.manam; + assert (foo.ref_count == 3); + + dfoo = null; + foo.bar = null; + assert (foo.ref_count == 1); +} diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index 798d79178..dfc5e2308 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -488,6 +488,10 @@ public class Vala.MemberAccess : Expression { prop.owner = inner.value_type.type_symbol.scope; dynamic_object_type.type_symbol.scope.add (null, prop); symbol_reference = prop; + if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) { + Report.error (source_reference, "dynamic properties are not supported for `%s'", dynamic_object_type.type_symbol.get_full_name ()); + error = true; + } } } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) { unowned MemberAccess ma = (MemberAccess) parent_node; @@ -530,6 +534,10 @@ public class Vala.MemberAccess : Expression { prop.owner = inner.value_type.type_symbol.scope; dynamic_object_type.type_symbol.scope.add (null, prop); symbol_reference = prop; + if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) { + Report.error (source_reference, "dynamic properties are not supported for %s", dynamic_object_type.type_symbol.get_full_name ()); + error = true; + } } if (symbol_reference != null) { may_access_instance_members = true;