[vala/staging] codegen: Add support for abstract methods/properties in compact classes
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/staging] codegen: Add support for abstract methods/properties in compact classes
- Date: Thu, 11 Jan 2018 23:07:25 +0000 (UTC)
commit d3c358e7693b869b4db0ad0ff9b007b0fed78d70
Author: Daniel Espinosa <esodan gmail com>
Date: Tue Jan 9 18:07:50 2018 -0600
codegen: Add support for abstract methods/properties in compact classes
https://bugzilla.gnome.org/show_bug.cgi?id=741465
codegen/valaccodebasemodule.vala | 12 +++--
codegen/valaccodemethodmodule.vala | 39 ++++++++++-----
codegen/valagtypemodule.vala | 91 +++++++++++++++++++++++++++++++-----
tests/Makefile.am | 1 +
tests/objects/bug741465.vala | 63 +++++++++++++++++++++++++
5 files changed, 177 insertions(+), 29 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index a65a3f4..56e12c6 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1651,17 +1651,21 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
}
}
- CCodeFunctionCall vcast = null;
+ CCodeExpression vcast;
if (prop.parent_symbol is Interface) {
var iface = (Interface) prop.parent_symbol;
vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf
(get_ccode_upper_case_name (iface, null))));
+ ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
} else {
var cl = (Class) prop.parent_symbol;
-
- vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf
(get_ccode_upper_case_name (cl, null))));
+ if (!cl.is_compact) {
+ vcast = new CCodeFunctionCall (new CCodeIdentifier
("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl, null))));
+ ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier
("self"));
+ } else {
+ vcast = new CCodeIdentifier ("self");
+ }
}
- vcast.add_argument (new CCodeIdentifier ("self"));
if (acc.readable) {
var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast,
"get_%s".printf (prop.name)));
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 4efd04b..0c0150b 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -801,6 +801,13 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
cresult = new CCodeCastExpression (cresult,
get_ccode_type (m));
}
+ var cl = (Class) current_type_symbol;
+ if (cl.is_compact && cl.base_class != null) {
+ var cinitcall = new CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
+ cinitcall.add_argument (get_this_cexpression ());
+ ccode.add_expression (cinitcall);
+ }
+
ccode.add_return (cresult);
}
}
@@ -815,17 +822,19 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
// complain during compile time of such en error.
// add critical warning that this method should not have been called
- var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier
("G_TYPE_FROM_INSTANCE"));
- type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
-
- var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
- type_name_call.add_argument (type_from_instance_call);
+ var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
+ if (!((Class) current_type_symbol).is_compact) {
+ var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier
("G_TYPE_FROM_INSTANCE"));
+ type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
- var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf
(get_ccode_name (m));
+ var type_name_call = new CCodeFunctionCall (new CCodeIdentifier
("g_type_name"));
+ type_name_call.add_argument (type_from_instance_call);
- var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
- cerrorcall.add_argument (new CCodeConstant (error_string));
- cerrorcall.add_argument (type_name_call);
+ cerrorcall.add_argument (new CCodeConstant ("\"Type `%%s' does not implement
abstract method `%s'\"".printf (get_ccode_name (m))));
+ cerrorcall.add_argument (type_name_call);
+ } else {
+ cerrorcall.add_argument (new CCodeConstant ("\"Abstract method `%s' is not
implemented\"".printf (get_ccode_name (m))));
+ }
ccode.add_expression (cerrorcall);
@@ -1087,17 +1096,21 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
}
var vfunc = new CCodeFunction (cname + suffix);
- CCodeFunctionCall vcast = null;
+ CCodeExpression vcast;
if (m.parent_symbol is Interface) {
var iface = (Interface) m.parent_symbol;
vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf
(get_ccode_upper_case_name (iface))));
+ ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
} else {
var cl = (Class) m.parent_symbol;
-
- vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf
(get_ccode_upper_case_name (cl))));
+ if (!cl.is_compact) {
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf
(get_ccode_upper_case_name (cl))));
+ ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
+ } else {
+ vcast = new CCodeIdentifier ("self");
+ }
}
- vcast.add_argument (new CCodeIdentifier ("self"));
cname = get_ccode_vfunc_name (m);
if (suffix == "_finish" && cname.has_suffix ("_async")) {
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index d342198..30d99e0 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -225,11 +225,6 @@ public class Vala.GTypeModule : GErrorModule {
instance_struct.add_field ("volatile int", "ref_count");
}
- if (cl.is_compact && cl.base_class == null && cl.get_fields ().size == 0) {
- // add dummy member, C doesn't allow empty structs
- instance_struct.add_field ("int", "dummy");
- }
-
if (is_gtypeinstance) {
decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %sPrivate".printf
(instance_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (get_ccode_name (cl)))));
@@ -245,8 +240,22 @@ public class Vala.GTypeModule : GErrorModule {
}
}
+ bool have_abstract = false;
foreach (Method m in cl.get_methods ()) {
- generate_virtual_method_declaration (m, decl_space, type_struct);
+ if (!cl.is_compact) {
+ generate_virtual_method_declaration (m, decl_space, type_struct);
+ } else if (cl.is_compact && cl.base_class == null) {
+ generate_virtual_method_declaration (m, decl_space, instance_struct);
+ }
+
+ if (!have_abstract && m.is_abstract) {
+ have_abstract = true;
+ }
+ }
+
+ if (cl.is_compact && cl.base_class == null && cl.get_fields ().size == 0 && !have_abstract) {
+ // add dummy member, C doesn't allow empty structs
+ instance_struct.add_field ("int", "dummy");
}
foreach (Signal sig in cl.get_signals ()) {
@@ -290,6 +299,10 @@ public class Vala.GTypeModule : GErrorModule {
var vdecl = new CCodeDeclaration (creturn_type);
vdecl.add_declarator (vdeclarator);
type_struct.add_declaration (vdecl);
+
+ if (cl.is_compact && cl.base_class == null) {
+ instance_struct.add_declaration (vdecl);
+ }
}
if (prop.set_accessor != null) {
CCodeParameter cvalueparam;
@@ -315,6 +328,10 @@ public class Vala.GTypeModule : GErrorModule {
var vdecl = new CCodeDeclaration ("void");
vdecl.add_declarator (vdeclarator);
type_struct.add_declaration (vdecl);
+
+ if (cl.is_compact && cl.base_class == null) {
+ instance_struct.add_declaration (vdecl);
+ }
}
}
@@ -370,6 +387,13 @@ public class Vala.GTypeModule : GErrorModule {
if (is_gtypeinstance) {
decl_space.add_type_definition (type_struct);
}
+
+ if (cl.is_compact) {
+ var instance_init_fun = new CCodeFunction ("%sinstance_init".printf
(get_ccode_lower_case_prefix (cl)), "void");
+ instance_init_fun.add_parameter (new CCodeParameter ("self", "%s *".printf
(get_ccode_name (cl))));
+ instance_init_fun.modifiers = CCodeModifiers.STATIC;
+ decl_space.add_function_declaration (instance_init_fun);
+ }
}
public virtual void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct
type_struct) {
@@ -592,7 +616,7 @@ public class Vala.GTypeModule : GErrorModule {
begin_class_finalize_function (cl);
begin_finalize_function (cl);
} else {
- if (cl.base_class == null || cl.base_class == gsource_type) {
+ if (cl.is_compact || cl.base_class == null || cl.base_class == gsource_type) {
begin_instance_init_function (cl);
begin_finalize_function (cl);
}
@@ -735,8 +759,7 @@ public class Vala.GTypeModule : GErrorModule {
cfile.add_function (unref_fun);
}
} else {
- if (cl.base_class == null || cl.base_class == gsource_type) {
- // derived compact classes do not have fields
+ if (cl.is_compact || cl.base_class == null || cl.base_class == gsource_type) {
add_instance_init_function (cl);
add_finalize_function (cl);
}
@@ -1565,9 +1588,48 @@ public class Vala.GTypeModule : GErrorModule {
push_function (func);
if (cl.is_compact) {
- // Add declaration, since the instance_init function is explicitly called
- // by the creation methods
- cfile.add_function_declaration (func);
+ // connect overridden methods
+ foreach (Method m in cl.get_methods ()) {
+ if (m.base_method == null) {
+ continue;
+ }
+ var base_type = (ObjectTypeSymbol) m.base_method.parent_symbol;
+
+ // there is currently no default handler for abstract async methods
+ if (!m.is_abstract || !m.coroutine) {
+ CCodeExpression cfunc = new CCodeIdentifier (get_ccode_real_name (m));
+ cfunc = cast_method_pointer (m.base_method, cfunc, base_type,
(m.coroutine ? 1 : 3));
+ var ccast = new CCodeCastExpression (new CCodeIdentifier ("self"),
"%s *".printf (get_ccode_name (base_type)));
+ func.add_assignment (new CCodeMemberAccess.pointer (ccast,
get_ccode_vfunc_name (m.base_method)), cfunc);
+
+ if (m.coroutine) {
+ cfunc = new CCodeIdentifier (get_ccode_finish_real_name (m));
+ cfunc = cast_method_pointer (m.base_method, cfunc, base_type,
2);
+ ccode.add_assignment (new CCodeMemberAccess.pointer (ccast,
get_ccode_finish_vfunc_name (m.base_method)), cfunc);
+ }
+ }
+ }
+
+ // connect overridden properties
+ foreach (Property prop in cl.get_properties ()) {
+ if (prop.base_property == null) {
+ continue;
+ }
+ var base_type = prop.base_property.parent_symbol;
+
+ var ccast = new CCodeCastExpression (new CCodeIdentifier ("self"), "%s
*".printf (get_ccode_name (base_type)));
+
+ if (!get_ccode_no_accessor_method (prop.base_property) &&
!get_ccode_concrete_accessor (prop.base_property)) {
+ if (prop.get_accessor != null) {
+ string cname = get_ccode_real_name (prop.get_accessor);
+ ccode.add_assignment (new CCodeMemberAccess.pointer (ccast,
"get_%s".printf (prop.name)), new CCodeIdentifier (cname));
+ }
+ if (prop.set_accessor != null) {
+ string cname = get_ccode_real_name (prop.set_accessor);
+ ccode.add_assignment (new CCodeMemberAccess.pointer (ccast,
"set_%s".printf (prop.name)), new CCodeIdentifier (cname));
+ }
+ }
+ }
}
if (!cl.is_compact && (cl.has_private_fields || cl.get_type_parameters ().size > 0)) {
@@ -2283,6 +2345,11 @@ public class Vala.GTypeModule : GErrorModule {
base_prop = prop.base_interface_property;
}
+ if (cl != null && cl.is_compact && (prop.get_accessor == null ||
prop.get_accessor.automatic_body)) {
+ Report.error (prop.source_reference, "Properties without accessor bodies are not
supported in compact classes");
+ return;
+ }
+
if (base_prop.get_attribute ("NoAccessorMethod") == null &&
prop.name == "type" && ((cl != null && !cl.is_compact) || (st != null &&
get_ccode_has_type_id (st)))) {
Report.error (prop.source_reference, "Property 'type' not allowed");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5f41f1c..e705764 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -243,6 +243,7 @@ TESTS = \
objects/bug702736.vala \
objects/bug702846.vala \
objects/bug731547.vala \
+ objects/bug741465.vala \
objects/bug751338.vala \
objects/bug758816.vala \
objects/bug760031.test \
diff --git a/tests/objects/bug741465.vala b/tests/objects/bug741465.vala
new file mode 100644
index 0000000..81faffe
--- /dev/null
+++ b/tests/objects/bug741465.vala
@@ -0,0 +1,63 @@
+[Compact]
+abstract class AbstractFoo {
+ public int field = 23;
+ public abstract int prop { get; set; }
+ public abstract unowned string foo ();
+}
+
+[Compact]
+class Foo : AbstractFoo {
+ public override int prop {
+ get { return field + 1; }
+ set { field = value - 1; }
+ }
+
+ public Foo () {
+ field = 42;
+ }
+
+ public override unowned string foo () {
+ return "Foo";
+ }
+}
+
+[Compact]
+class Bar : Foo {
+ public override int prop {
+ get { return field * 2; }
+ set { field = value / 2; }
+ }
+
+ public Bar () {
+ field = 42;
+ }
+
+ public override unowned string foo () {
+ return "Bar";
+ }
+}
+
+[Compact]
+class Manam {
+ public int field = 12;
+ public Manam (int i) {
+ field = i;
+ }
+}
+
+void main () {
+ var foo = new Foo ();
+ assert (foo.foo () == "Foo");
+ assert (foo.prop == 43);
+ foo.prop = 4711;
+ assert (foo.field == 4710);
+
+ var bar = new Bar ();
+ assert (bar.foo () == "Bar");
+ assert (bar.prop == 84);
+ bar.prop = 32;
+ assert (bar.field == 16);
+
+ var manam = new Manam (4711);
+ assert (manam.field == 4711);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]