2008-08-10 Jürg Billeter <j@bitron.ch>
+ * vala/valasemanticanalyzer.vala:
+ * gobject/valaccodeclassbinding.vala:
+ * gobject/valaccodegenerator.vala:
+
+ Use accessor vfuncs to implement virtual and abstract properties,
+ fixes bug 508472 and bug 505966
+
+2008-08-10 Jürg Billeter <j@bitron.ch>
+
* vapi/packages/vte/:
Fix vte_terminal_set_colors binding, fixes bug 547136
init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.base_method.vfunc_name), new CCodeIdentifier (m.get_real_cname ()))));
}
+ /* 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 CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+
+ if (prop.get_accessor != null) {
+ string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ if (prop.set_accessor != null) {
+ string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ }
+
if (cl.is_subtype_of (codegen.gobject_type)) {
/* create type, dup_func, and destroy_func properties for generic types */
foreach (TypeParameter type_param in cl.get_type_parameters ()) {
}
var ciface = new CCodeIdentifier ("iface");
- var cname = m.get_real_cname ();
+ string cname = m.get_real_cname ();
if (m.is_abstract || m.is_virtual) {
// FIXME results in C compiler warning
cname = m.get_cname ();
}
}
+ foreach (Property prop in cl.get_properties ()) {
+ if (prop.base_interface_property == null) {
+ continue;
+ }
+
+ var base_type = prop.base_interface_property.parent_symbol;
+ if (base_type != iface) {
+ continue;
+ }
+
+ var ciface = new CCodeIdentifier ("iface");
+
+ if (prop.get_accessor != null) {
+ string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ if (prop.is_abstract || prop.is_virtual) {
+ cname = "%s_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ }
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ if (prop.set_accessor != null) {
+ string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ if (prop.is_abstract || prop.is_virtual) {
+ cname = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ }
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ }
+
+ foreach (Property prop in iface.get_properties ()) {
+ if (!prop.is_abstract) {
+ continue;
+ }
+
+ Property cl_prop = null;
+ var base_class = cl;
+ while (base_class != null && cl_prop == null) {
+ cl_prop = base_class.scope.lookup (prop.name) as Property;
+ base_class = base_class.base_class;
+ }
+ if (base_class != null && cl_prop.parent_symbol != cl) {
+ // property inherited from base class
+
+ var ciface = new CCodeIdentifier ("iface");
+
+ if (prop.get_accessor != null) {
+ string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ if (prop.set_accessor != null) {
+ string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+ }
+ }
+ }
+
codegen.source_type_member_definition.append (iface_init);
}
continue;
}
- bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
-
string prefix = cl.get_lower_case_cname (null);
- if (is_virtual) {
- prefix += "_real";
+ CCodeExpression cself = new CCodeIdentifier ("self");
+ if (prop.base_property != null) {
+ var base_type = (Class) prop.base_property.parent_symbol;
+ prefix = base_type.get_lower_case_cname (null);
+ cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
+ } else if (prop.base_interface_property != null) {
+ var base_type = (Interface) prop.base_interface_property.parent_symbol;
+ prefix = base_type.get_lower_case_cname (null);
+ cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
}
var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
- ccall.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (cself);
var csetcall = new CCodeFunctionCall ();
csetcall.call = get_value_setter_function (prop.property_type);
csetcall.add_argument (new CCodeIdentifier ("value"));
continue;
}
- bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
-
string prefix = cl.get_lower_case_cname (null);
- if (is_virtual) {
- prefix += "_real";
+ CCodeExpression cself = new CCodeIdentifier ("self");
+ if (prop.base_property != null) {
+ var base_type = (Class) prop.base_property.parent_symbol;
+ prefix = base_type.get_lower_case_cname (null);
+ cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
+ } else if (prop.base_interface_property != null) {
+ var base_type = (Interface) prop.base_interface_property.parent_symbol;
+ prefix = base_type.get_lower_case_cname (null);
+ cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
}
var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
- ccall.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (cself);
var cgetcall = new CCodeFunctionCall ();
if (prop.property_type.data_type != null) {
cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());
var cvalueparam = new CCodeFormalParameter ("value", value_type.get_cname ());
if (prop.is_abstract || prop.is_virtual) {
+ CCodeFunctionDeclarator vdeclarator;
+
if (acc.readable) {
function = new CCodeFunction (acc.get_cname (), prop.property_type.get_cname ());
+
+ var vdecl = new CCodeDeclaration (prop.property_type.get_cname ());
+ vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (prop.name));
+ vdecl.add_declarator (vdeclarator);
+ type_struct.add_declaration (vdecl);
} else {
function = new CCodeFunction (acc.get_cname (), "void");
+
+ var vdecl = new CCodeDeclaration ("void");
+ vdeclarator = new CCodeFunctionDeclarator ("set_%s".printf (prop.name));
+ vdecl.add_declarator (vdeclarator);
+ type_struct.add_declaration (vdecl);
}
function.add_parameter (cselfparam);
+ vdeclarator.add_parameter (cselfparam);
if (acc.writable || acc.construction) {
function.add_parameter (cvalueparam);
+ vdeclarator.add_parameter (cvalueparam);
}
if (!prop.is_internal_symbol () && (acc.readable || acc.writable) && acc.access != SymbolAccessibility.PRIVATE) {
var block = new CCodeBlock ();
function.block = block;
- if (acc.readable) {
- // declare temporary variable to save the property value
- var decl = new CCodeDeclaration (prop.property_type.get_cname ());
- decl.add_declarator (new CCodeVariableDeclarator ("value"));
- block.add_statement (decl);
-
- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
-
- var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
- ccast.add_argument (new CCodeIdentifier ("self"));
- ccall.add_argument (ccast);
-
- // property name is second argument of g_object_get
- ccall.add_argument (prop.get_canonical_cconstant ());
-
- ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+ CCodeFunctionCall vcast = null;
+ if (prop.parent_symbol is Interface) {
+ var iface = (Interface) prop.parent_symbol;
- ccall.add_argument (new CCodeConstant ("NULL"));
-
- block.add_statement (new CCodeExpressionStatement (ccall));
-
- // HACK: decrement the refcount before returning the value to simulate a weak reference getter function
- if (prop.property_type.data_type != null && prop.property_type.data_type.is_reference_counting ()) {
- var unref_cond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("value"), new CCodeConstant ("NULL"));
- var unref_function = new CCodeFunctionCall (get_destroy_func_expression (prop.property_type));
- unref_function.add_argument (new CCodeIdentifier ("value"));
- var unref_block = new CCodeBlock ();
- unref_block.add_statement (new CCodeExpressionStatement (unref_function));
- block.add_statement (new CCodeIfStatement (unref_cond, unref_block));
- }
-
- block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
} else {
- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
-
- var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
- ccast.add_argument (new CCodeIdentifier ("self"));
- ccall.add_argument (ccast);
-
- // property name is second argument of g_object_set
- ccall.add_argument (prop.get_canonical_cconstant ());
+ var cl = (Class) prop.parent_symbol;
- ccall.add_argument (new CCodeIdentifier ("value"));
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
+ }
+ vcast.add_argument (new CCodeIdentifier ("self"));
- ccall.add_argument (new CCodeConstant ("NULL"));
-
- block.add_statement (new CCodeExpressionStatement (ccall));
+ if (acc.readable) {
+ var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+ block.add_statement (new CCodeReturnStatement (vcall));
+ } else {
+ var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+ vcall.add_argument (new CCodeIdentifier ("value"));
}
source_type_member_definition.append (function);
function = new CCodeFunction (cname, "void");
}
+ ObjectType base_type = null;
if (is_virtual) {
+ if (prop.base_property != null) {
+ base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
+ } else if (prop.base_interface_property != null) {
+ base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
+ }
function.modifiers |= CCodeModifiers.STATIC;
+ function.add_parameter (new CCodeFormalParameter ("base", base_type.get_cname ()));
+ } else {
+ function.add_parameter (cselfparam);
}
- function.add_parameter (cselfparam);
if (returns_real_struct) {
// return non simple structs as out parameter
var coutparamname = "%s*".printf (prop.property_type.get_cname ());
function.block = (CCodeBlock) acc.body.ccodenode;
+ if (is_virtual) {
+ var cdecl = new CCodeDeclaration (this_type.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", transform_expression (new CCodeIdentifier ("base"), base_type, this_type)));
+ function.block.prepend_statement (cdecl);
+ }
+
if (current_method_inner_error) {
var cdecl = new CCodeDeclaration ("GError *");
cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
function.block.prepend_statement (cdecl);
}
- if (returns_real_struct) {
- function.block.prepend_statement (create_property_type_check_statement (prop, false, t, true, "self"));
- } else {
- function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+ if (!is_virtual) {
+ if (returns_real_struct) {
+ function.block.prepend_statement (create_property_type_check_statement (prop, false, t, true, "self"));
+ } else {
+ function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+ }
}
// notify on property changes
return;
}
- /* abstract/virtual properties using reference types without
- * reference counting need to transfer ownership of their
- * return values because of limitations in the GObject property
- * system (g_object_get always returns strong references).
- * Reference counting types can simulate to return a weak
- * reference */
- if ((prop.is_abstract || prop.is_virtual) &&
- prop.property_type.data_type != null &&
- prop.property_type.data_type.is_reference_type () &&
- !prop.property_type.data_type.is_reference_counting () &&
- !prop.property_type.value_owned)
- {
- Report.error (prop.source_reference, "%s: abstract or virtual properties using reference types not supporting reference counting, like `%s', have to mark their return value to transfer ownership.".printf (prop.get_full_name (), prop.property_type.data_type.get_full_name ()));
- prop.error = true;
- }
-
current_symbol = current_symbol.parent_symbol;
if (!prop.is_internal_symbol ()) {