From 3af1cfb3bf6b1d3d4a8116382e6eda702f7335bf Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Mon, 6 May 2019 14:48:25 +0200 Subject: [PATCH] codegen: Support GObject properties with nullable GType-based struct type Fixes https://gitlab.gnome.org/GNOME/vala/issues/792 --- codegen/valaccodebasemodule.vala | 18 +++++--- codegen/valagobjectmodule.vala | 19 +++++--- tests/Makefile.am | 1 + tests/objects/property-gboxed-nullable.vala | 48 +++++++++++++++++++++ vala/valasemanticanalyzer.vala | 8 +++- 5 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 tests/objects/property-gboxed-nullable.vala diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 9d6320ccf..17091394f 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -1883,16 +1883,20 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0"))); } else if (property_type is StructValueType) { ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value")); - get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value"))); - - var get_expr = new CCodeCommaExpression (); - get_expr.append_expression (get_call); - get_expr.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value"))); - + if (property_type.nullable) { + ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call); + } else { + get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value"))); + ccode.add_expression (get_call); + } var equalfunc = generate_struct_equal_function ((Struct) property_type.data_type); var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc)); ccall.add_argument (new CCodeIdentifier ("value")); - ccall.add_argument (get_expr); + if (property_type.nullable) { + ccall.add_argument (new CCodeIdentifier ("old_value")); + } else { + ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value"))); + } ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE"))); } else { ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value"))); diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala index 8ad676ab9..8c31c924f 100644 --- a/codegen/valagobjectmodule.vala +++ b/codegen/valagobjectmodule.vala @@ -233,21 +233,26 @@ public class Vala.GObjectModule : GTypeModule { ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop)))); if (prop.property_type.is_real_struct_type ()) { - var st = prop.property_type.data_type as Struct; - ccode.open_block (); - ccode.add_declaration (get_ccode_name (st), new CCodeVariableDeclarator ("boxed")); + ccode.add_declaration (get_ccode_name (prop.property_type), new CCodeVariableDeclarator ("boxed")); ccall = new CCodeFunctionCall (cfunc); ccall.add_argument (cself); - var boxed_addr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")); - ccall.add_argument (boxed_addr); - ccode.add_expression (ccall); + if (prop.property_type.nullable) { + ccode.add_assignment (new CCodeIdentifier ("boxed"), ccall); + } else { + ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed"))); + ccode.add_expression (ccall); + } var csetcall = new CCodeFunctionCall (); csetcall.call = get_value_setter_function (prop.property_type); csetcall.add_argument (new CCodeIdentifier ("value")); - csetcall.add_argument (boxed_addr); + if (prop.property_type.nullable) { + csetcall.add_argument (new CCodeIdentifier ("boxed")); + } else { + csetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed"))); + } add_guarded_expression (prop, csetcall); if (requires_destroy (prop.get_accessor.value_type)) { diff --git a/tests/Makefile.am b/tests/Makefile.am index cfdfafa1e..4527506aa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -316,6 +316,7 @@ TESTS = \ objects/property-read-only-write.test \ objects/property-construct-only-write.test \ objects/property-construct-only-write-foreign.test \ + objects/property-gboxed-nullable.vala \ objects/property-static.vala \ objects/regex.vala \ objects/signals.vala \ diff --git a/tests/objects/property-gboxed-nullable.vala b/tests/objects/property-gboxed-nullable.vala new file mode 100644 index 000000000..bbf023f76 --- /dev/null +++ b/tests/objects/property-gboxed-nullable.vala @@ -0,0 +1,48 @@ +public struct Bar { + public string s; +} + +public class Foo : Object { + public Bar? bar { get; construct set; } + + public Foo (Bar? bar) { + Object (bar: bar); + } +} + +public class Faz : Object { + [NoAccessorMethod] + public Bar? baz { owned get; set; } +} + +void main () { + { + var foo = new Foo (null); + assert (foo.bar == null); + } + { + Bar bar = { "foo" }; + var foo = (Foo) Object.@new (typeof (Foo), "bar", bar); + assert (foo.bar == bar); + assert (foo.bar.s == "foo"); + foo.bar = null; + assert (foo.bar == null); + } + { + Bar bar = { "foo" }; + var foo = (Foo) Object.@new (typeof (Foo), "bar", null); + assert (foo.bar == null); + foo.bar = bar; + assert (foo.bar == bar); + } + { + Bar bar = { "foo" }; + var faz = new Faz (); + assert (faz.baz == null); + faz.baz = bar; + assert (faz.baz == bar); + assert (faz.baz.s == "foo"); + faz.baz = null; + assert (faz.baz == null); + } +} diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index af7e63eb6..fa90deb7a 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -450,8 +450,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor { public bool is_gobject_property_type (DataType property_type) { var st = property_type.data_type as Struct; - if (st != null && (!st.get_attribute_bool ("CCode", "has_type_id", true) || property_type.nullable)) { - return false; + if (st != null) { + if (st.get_attribute_bool ("CCode", "has_type_id", true)) { + // Allow GType-based struct types + } else if (property_type.nullable) { + return false; + } } if (property_type is ArrayType && ((ArrayType) property_type).element_type.data_type != string_type.data_type) { -- 2.47.2