6f01e8a0b164b80f8e8fcdbb3e18a353bbf91cc9
[roobuilder] / src / codegen / valaccodememberaccessmodule.vala
1 /* valaccodememberaccessmodule.vala
2  *
3  * Copyright (C) 2006-2010  Jürg Billeter
4  * Copyright (C) 2006-2008  Raffaele Sandrini
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19  *
20  * Author:
21  *      Jürg Billeter <j@bitron.ch>
22  *      Raffaele Sandrini <raffaele@sandrini.ch>
23  */
24
25 public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
26         public override void visit_member_access (MemberAccess expr) {
27                 CCodeExpression pub_inst = null;
28
29                 if (expr.inner != null) {
30                         pub_inst = get_cvalue (expr.inner);
31                 }
32
33                 var array_type = expr.value_type as ArrayType;
34                 var delegate_type = expr.value_type as DelegateType;
35
36                 if (expr.symbol_reference is Method) {
37                         var m = (Method) expr.symbol_reference;
38
39                         if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArrayCopyMethod)) {
40                                 generate_method_declaration (m, cfile);
41
42                                 if (!m.external && m.external_package) {
43                                         // internal VAPI methods
44                                         // only add them once per source file
45                                         if (add_generated_external_symbol (m)) {
46                                                 visit_method (m);
47                                         }
48                                 }
49                         }
50
51                         if (expr.inner is BaseAccess) {
52                                 CCodeExpression? vcast = null;
53                                 if (m.base_method != null) {
54                                         unowned Class base_class = (Class) m.base_method.parent_symbol;
55                                         vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
56                                         ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
57                                 } else if (m.base_interface_method != null) {
58                                         unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
59                                         vcast = get_this_interface_cexpression (base_iface);
60                                 }
61                                 if (vcast != null) {
62                                         set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
63                                         return;
64                                 }
65                         }
66
67                         if (m.base_method != null) {
68                                 if (get_ccode_no_wrapper (m.base_method)) {
69                                         unowned Class base_class = (Class) m.base_method.parent_symbol;
70                                         if (!base_class.is_compact) {
71                                                 var vclass = get_this_class_cexpression (base_class, expr.inner.target_value);
72                                                 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
73                                         } else {
74                                                 set_cvalue (expr, new CCodeMemberAccess.pointer (pub_inst, get_ccode_vfunc_name (m)));
75                                         }
76                                 } else {
77                                         set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_method)));
78                                 }
79                         } else if (m.base_interface_method != null) {
80                                 if (get_ccode_no_wrapper (m.base_interface_method)) {
81                                         unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
82                                         var vclass = get_this_interface_cexpression (base_iface, expr.inner.target_value);
83                                         set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
84                                 } else {
85                                         set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_interface_method)));
86                                 }
87                         } else if (m is CreationMethod) {
88                                 set_cvalue (expr, new CCodeIdentifier (get_ccode_real_name (m)));
89                         } else {
90                                 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m)));
91                         }
92
93                         set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
94                         if (m.binding == MemberBinding.STATIC) {
95                                 set_delegate_target (expr, new CCodeConstant ("NULL"));
96                         } else if (m.is_async_callback) {
97                                 if (current_method.closure) {
98                                         var block = ((Method) m.parent_symbol).body;
99                                         set_delegate_target (expr, new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"));
100                                 } else {
101                                         set_delegate_target (expr, new CCodeIdentifier ("_data_"));
102                                 }
103                         } else if (expr.inner != null && !expr.prototype_access) {
104                                 // expr.inner is null in the special case of referencing the method in a constant initializer
105                                 var delegate_target = (CCodeExpression) get_ccodenode (expr.inner);
106                                 delegate_type = expr.target_type as DelegateType;
107                                 if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.type_symbol != null && is_reference_counting (expr.inner.value_type.type_symbol)) {
108                                         var ref_call = new CCodeFunctionCall (get_dup_func_expression (expr.inner.value_type, expr.source_reference));
109                                         ref_call.add_argument (delegate_target);
110                                         delegate_target = ref_call;
111                                         set_delegate_target_destroy_notify (expr, get_destroy_func_expression (expr.inner.value_type));
112                                 }
113                                 set_delegate_target (expr, delegate_target);
114                         }
115                 } else if (expr.symbol_reference is ArrayLengthField) {
116                         set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
117                 } else if (expr.symbol_reference is DelegateTargetField) {
118                         CCodeExpression delegate_target_destroy_notify;
119                         set_cvalue (expr, get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify) ?? new CCodeConstant ("NULL"));
120                 } else if (expr.symbol_reference is DelegateDestroyField) {
121                         CCodeExpression delegate_target_destroy_notify;
122                         get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify);
123                         set_cvalue (expr, delegate_target_destroy_notify ?? new CCodeConstant ("NULL"));
124                 } else if (expr.symbol_reference is GenericDupField) {
125                         set_cvalue (expr, get_dup_func_expression (expr.inner.value_type, expr.source_reference));
126                 } else if (expr.symbol_reference is GenericDestroyField) {
127                         set_cvalue (expr, get_destroy_func_expression (expr.inner.value_type));
128                 } else if (expr.symbol_reference is Field) {
129                         var field = (Field) expr.symbol_reference;
130                         if (expr.lvalue) {
131                                 expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
132                         } else {
133                                 expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null, expr);
134                         }
135                 } else if (expr.symbol_reference is EnumValue) {
136                         var ev = (EnumValue) expr.symbol_reference;
137
138                         generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
139
140                         set_cvalue (expr, new CCodeConstant (get_ccode_name (ev)));
141                 } else if (expr.symbol_reference is Constant) {
142                         var c = (Constant) expr.symbol_reference;
143
144                         generate_constant_declaration (c, cfile,
145                                 c.source_reference != null && expr.source_reference != null &&
146                                 c.source_reference.file == expr.source_reference.file);
147
148                         string fn = c.get_full_name ();
149                         if (fn == "GLib.Log.FILE") {
150                                 string s = Path.get_basename (expr.source_reference.file.filename);
151                                 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
152                         } else if (fn == "GLib.Log.LINE") {
153                                 int i = expr.source_reference.begin.line;
154                                 set_cvalue (expr, new CCodeConstant ("%d".printf (i)));
155                         } else if (fn == "GLib.Log.METHOD") {
156                                 string s = "";
157                                 if (current_method != null) {
158                                         s = current_method.get_full_name ();
159                                 }
160                                 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
161                         } else if (c.type_reference.is_non_null_simple_type ()) {
162                                 set_cvalue (expr, new CCodeConstant (get_ccode_name (c)));
163                         } else {
164                                 set_cvalue (expr, new CCodeConstantIdentifier (get_ccode_name (c)));
165                         }
166
167                         if (array_type != null) {
168                                 string sub = "";
169                                 for (int i = 0; i < array_type.rank; i++) {
170                                         CCodeFunctionCall ccall;
171                                         if (context.profile == Profile.POSIX) {
172                                                 requires_array_n_elements = true;
173                                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("VALA_N_ELEMENTS"));
174                                         } else {
175                                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
176                                         }
177                                         ccall.add_argument (new CCodeIdentifier (get_ccode_name (c) + sub));
178                                         append_array_length (expr, ccall);
179                                         sub += "[0]";
180                                 }
181                                 ((GLibValue) expr.target_value).non_null = true;
182                         }
183                 } else if (expr.symbol_reference is Property) {
184                         var prop = (Property) expr.symbol_reference;
185
186                         if (!(prop is DynamicProperty)) {
187                                 generate_property_accessor_declaration (prop.get_accessor, cfile);
188
189                                 if (!prop.external && prop.external_package) {
190                                         // internal VAPI properties
191                                         // only add them once per source file
192                                         if (add_generated_external_symbol (prop)) {
193                                                 visit_property (prop);
194                                         }
195                                 }
196                         }
197
198                         if (pub_inst == null && prop.binding == MemberBinding.INSTANCE) {
199                                 // FIXME Report this with proper source-reference on the vala side!
200                                 Report.error (prop.source_reference, "Invalid access to instance member `%s'", prop.get_full_name ());
201                                 set_cvalue (expr, new CCodeInvalidExpression ());
202                                 return;
203                         }
204
205                         unowned Property base_prop = prop;
206                         if (prop.base_property != null) {
207                                 base_prop = prop.base_property;
208                         } else if (prop.base_interface_property != null) {
209                                 base_prop = prop.base_interface_property;
210                         }
211                         if (expr.inner is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
212                                 CCodeExpression? vcast = null;
213                                 if (base_prop.parent_symbol is Class) {
214                                         unowned Class base_class = (Class) base_prop.parent_symbol;
215                                         vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
216                                         ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
217                                 } else if (base_prop.parent_symbol is Interface) {
218                                         unowned Interface base_iface = (Interface) base_prop.parent_symbol;
219                                         vcast = get_this_interface_cexpression (base_iface);
220                                 }
221                                 if (vcast != null) {
222                                         var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
223                                         ccall.add_argument (get_cvalue (expr.inner));
224                                         if (prop.property_type.is_real_non_null_struct_type ()) {
225                                                 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
226                                                 expr.target_value = load_temp_value (temp_value);
227                                                 var ctemp = get_cvalue_ (temp_value);
228                                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
229                                                 ccode.add_expression (ccall);
230                                         } else {
231                                                 set_cvalue (expr, ccall);
232                                         }
233                                 } else {
234                                         Report.error (expr.source_reference, "internal: Invalid access to `%s'", base_prop.get_full_name ());
235                                 }
236                         } else if (prop.binding == MemberBinding.INSTANCE &&
237                             prop.get_accessor.automatic_body &&
238                             !prop.get_accessor.value_type.value_owned &&
239                             current_type_symbol == prop.parent_symbol &&
240                             current_type_symbol is Class &&
241                             prop.base_property == null &&
242                             prop.base_interface_property == null &&
243                             !(prop.property_type is ArrayType || prop.property_type is DelegateType)) {
244                                 CCodeExpression inst = pub_inst;
245                                 if (!((Class) current_type_symbol).is_compact) {
246                                         inst = new CCodeMemberAccess.pointer (inst, "priv");
247                                 }
248                                 set_cvalue (expr, new CCodeMemberAccess.pointer (inst, get_ccode_name (prop.field)));
249                         } else if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
250                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.get_accessor)));
251
252                                 if (prop.binding == MemberBinding.INSTANCE) {
253                                         if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
254                                                 // we need to pass struct instance by reference
255                                                 var instance = expr.inner.target_value;
256                                                 if (!get_lvalue (instance)) {
257                                                         instance = store_temp_value (instance, expr);
258                                                 }
259                                                 pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
260                                         }
261
262                                         ccall.add_argument (pub_inst);
263                                 }
264
265                                 bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type ();
266                                 bool requires_init = prop.property_type is DelegateType || prop_is_real_non_null_struct_type;
267                                 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, requires_init, expr);
268                                 expr.target_value = load_temp_value (temp_value);
269                                 var ctemp = get_cvalue_ (temp_value);
270
271                                 // Property access to real struct types is handled differently
272                                 // The value is returned by out parameter
273                                 if (prop_is_real_non_null_struct_type) {
274                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
275                                         ccode.add_expression (ccall);
276                                 } else {
277                                         array_type = prop.property_type as ArrayType;
278                                         if (array_type != null) {
279                                                 if (get_ccode_array_null_terminated (prop)) {
280                                                         requires_array_length = true;
281                                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
282                                                         len_call.add_argument (ctemp);
283
284                                                         ccode.add_assignment (ctemp, ccall);
285                                                         ccode.add_assignment (temp_value.array_length_cvalues[0], len_call);
286                                                 } else if (get_ccode_array_length (prop)) {
287                                                         var temp_refs = new ArrayList<CCodeExpression> ();
288                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
289                                                                 var length_ctype = get_ccode_array_length_type (prop);
290                                                                 var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
291                                                                 var temp_ref = get_variable_cexpression (temp_var.name);
292                                                                 emit_temp_var (temp_var);
293                                                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
294                                                                 temp_refs.add (temp_ref);
295                                                         }
296
297                                                         ccode.add_assignment (ctemp, ccall);
298                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
299                                                                 ccode.add_assignment (temp_value.array_length_cvalues[dim - 1], temp_refs.get (dim - 1));
300                                                         }
301                                                 } else {
302                                                         ccode.add_assignment (ctemp, ccall);
303                                                 }
304                                         } else {
305                                                 ccode.add_assignment (ctemp, ccall);
306
307                                                 delegate_type = prop.property_type as DelegateType;
308                                                 if (delegate_type != null && get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
309                                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue (temp_value)));
310                                                 } else {
311                                                         if (temp_value.delegate_target_cvalue != null) {
312                                                                 ccode.add_assignment (temp_value.delegate_target_cvalue, new CCodeConstant ("NULL"));
313                                                         }
314                                                         if (temp_value.delegate_target_destroy_notify_cvalue != null) {
315                                                                 ccode.add_assignment (temp_value.delegate_target_destroy_notify_cvalue, new CCodeConstant ("NULL"));
316                                                         }
317                                                 }
318                                         }
319                                 }
320                         } else {
321                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
322                                 ccall.add_argument (pub_inst);
323
324                                 // property name is second argument of g_object_get
325                                 ccall.add_argument (get_property_canonical_cconstant (prop));
326
327                                 // g_object_get always returns owned values
328                                 // therefore, property getters of properties
329                                 // without accessor methods need to be marked as owned
330                                 if (!(prop is DynamicProperty) && !prop.get_accessor.value_type.value_owned) {
331                                         // only report error for types where there actually
332                                         // is a difference between `owned' and `unowned'
333                                         var owned_value_type = prop.get_accessor.value_type.copy ();
334                                         owned_value_type.value_owned = true;
335                                         if (requires_copy (owned_value_type)) {
336                                                 Report.error (prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor", prop.get_full_name ());
337                                         }
338                                 }
339
340                                 if (expr.value_type.is_real_struct_type ()) {
341                                         // gobject allocates structs on heap
342                                         expr.value_type.nullable = true;
343                                 }
344
345                                 var temp_var = get_temp_variable (expr.value_type);
346                                 var ctemp = get_variable_cexpression (temp_var.name);
347                                 emit_temp_var (temp_var);
348                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
349                                 ccall.add_argument (new CCodeConstant ("NULL"));
350                                 ccode.add_expression (ccall);
351                                 set_cvalue (expr, ctemp);
352                         }
353
354                         if (prop.get_accessor.value_type is GenericType) {
355                                 expr.target_value.value_type = prop.get_accessor.value_type.copy ();
356                         } else {
357                                 expr.target_value.value_type = expr.value_type.copy ();
358                         }
359                         expr.target_value = store_temp_value (expr.target_value, expr);
360                 } else if (expr.symbol_reference is LocalVariable) {
361                         var local = (LocalVariable) expr.symbol_reference;
362
363                         if (expr.parent_node is ReturnStatement &&
364                             current_return_type.value_owned &&
365                             local.variable_type.value_owned &&
366                             !local.captured &&
367                             !variable_accessible_in_finally (local) &&
368                             !(local.variable_type is ArrayType && ((ArrayType) local.variable_type).inline_allocated)) {
369                                 /* return expression is local variable taking ownership and
370                                  * current method is transferring ownership */
371
372                                 // don't ref expression
373                                 expr.value_type.value_owned = true;
374
375                                 // don't unref variable
376                                 local.active = false;
377
378                                 var glib_value = (GLibValue) get_local_cvalue (local);
379                                 expr.target_value = glib_value;
380                                 if (glib_value.delegate_target_cvalue == null) {
381                                         glib_value.delegate_target_cvalue = new CCodeConstant ("NULL");
382                                 }
383                                 if (glib_value.delegate_target_destroy_notify_cvalue == null) {
384                                         glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
385                                 }
386                         } else {
387                                 if (expr.lvalue) {
388                                         expr.target_value = get_local_cvalue (local);
389                                 } else {
390                                         expr.target_value = load_local (local, expr);
391                                 }
392                         }
393                 } else if (expr.symbol_reference is Parameter) {
394                         var param = (Parameter) expr.symbol_reference;
395                         if (expr.lvalue) {
396                                 expr.target_value = get_parameter_cvalue (param);
397                         } else {
398                                 expr.target_value = load_parameter (param, expr);
399                         }
400                 }
401
402                 // Add cast for narrowed type access of variables if needed
403                 if (expr.symbol_reference is Variable) {
404                         unowned GLibValue cvalue = (GLibValue) expr.target_value;
405                         if (!(cvalue.value_type is GenericType) && cvalue.value_type.type_symbol != null
406                             && cvalue.value_type.type_symbol != expr.value_type.type_symbol) {
407                                 cvalue.cvalue = new CCodeCastExpression (cvalue.cvalue, get_ccode_name (expr.value_type));
408                         }
409                 }
410         }
411
412         /* Returns lvalue access to the given local variable */
413         public override TargetValue get_local_cvalue (LocalVariable local) {
414                 var result = new GLibValue (local.variable_type.copy ());
415                 result.lvalue = true;
416
417                 var array_type = local.variable_type as ArrayType;
418                 var delegate_type = local.variable_type as DelegateType;
419                 if (local.is_result) {
420                         // used in postconditions
421                         // structs are returned as out parameter
422                         if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type ()) {
423                                 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
424                         } else {
425                                 result.cvalue = new CCodeIdentifier ("result");
426                         }
427                         if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null)) {
428                                 for (int dim = 1; dim <= array_type.rank; dim++) {
429                                         result.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_array_length_cname ("result", dim))));
430                                 }
431                         }
432                 } else if (local.captured) {
433                         // captured variables are stored on the heap
434                         var block = (Block) local.parent_symbol;
435                         result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_local_cname (local));
436                         if (array_type != null && !array_type.fixed_length) {
437                                 for (int dim = 1; dim <= array_type.rank; dim++) {
438                                         result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_local_cname (local), dim)));
439                                 }
440                                 if (array_type.rank == 1) {
441                                         result.array_size_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_size_cname (get_local_cname (local)));
442                                 }
443                         } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
444                                 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_local_cname (local)));
445                                 if (delegate_type.is_disposable ()) {
446                                         result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
447                                 }
448                         }
449                 } else {
450                         result.cvalue = get_local_cexpression (local);
451                         if (array_type != null && !array_type.fixed_length) {
452                                 for (int dim = 1; dim <= array_type.rank; dim++) {
453                                         result.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local), dim)));
454                                 }
455                                 if (array_type.rank == 1) {
456                                         result.array_size_cvalue = get_variable_cexpression (get_array_size_cname (get_local_cname (local)));
457                                 }
458                         } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
459                                 if (is_in_coroutine ()) {
460                                         result.delegate_target_cvalue = get_variable_cexpression (get_delegate_target_cname (get_local_cname (local)));
461                                         if (local.variable_type.is_disposable ()) {
462                                                 result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
463                                         }
464                                 } else {
465                                         result.delegate_target_cvalue = new CCodeIdentifier (get_delegate_target_cname (get_local_cname (local)));
466                                         if (local.variable_type.is_disposable ()) {
467                                                 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
468                                         }
469                                 }
470                         }
471                 }
472
473                 return result;
474         }
475
476         /* Returns access values to the given parameter */
477         public override TargetValue get_parameter_cvalue (Parameter param) {
478                 var result = new GLibValue (param.variable_type.copy ());
479                 result.lvalue = true;
480                 result.array_null_terminated = get_ccode_array_null_terminated (param);
481                 if (get_ccode_array_length_expr (param) != null) {
482                         result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (param));
483                 }
484                 result.ctype = get_ccode_type (param);
485
486                 var array_type = result.value_type as ArrayType;
487                 var delegate_type = result.value_type as DelegateType;
488
489                 bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;
490                 if ((param.captured || is_in_coroutine ()) && !is_unowned_delegate) {
491                         result.value_type.value_owned = true;
492                 }
493
494                 if (param.name == "this") {
495                         if (is_in_coroutine ()) {
496                                 // use closure
497                                 result.cvalue = get_this_cexpression ();
498                         } else {
499                                 unowned Struct? st = result.value_type.type_symbol as Struct;
500                                 if (st != null && !st.is_simple_type ()) {
501                                         result.cvalue = new CCodeIdentifier ("(*self)");
502                                 } else {
503                                         result.cvalue = new CCodeIdentifier ("self");
504                                 }
505                         }
506                 } else {
507                         string name = get_ccode_name (param);
508
509                         if (param.captured && !is_in_method_precondition) {
510                                 // captured variables are stored on the heap
511                                 var block = param.parent_symbol as Block;
512                                 if (block == null) {
513                                         block = ((Method) param.parent_symbol).body;
514                                 }
515                                 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_name (param));
516                                 if (array_type != null && get_ccode_array_length (param)) {
517                                         for (int dim = 1; dim <= array_type.rank; dim++) {
518                                                 result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_array_length_cname (param, dim)));
519                                         }
520                                 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
521                                         result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_name (param));
522                                         if (result.value_type.is_disposable ()) {
523                                                 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_destroy_notify_name (param));
524                                         }
525                                 }
526                         } else if (is_in_coroutine ()) {
527                                 // use closure
528                                 result.cvalue = get_parameter_cexpression (param);
529                                 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
530                                         result.delegate_target_cvalue = get_variable_cexpression (get_ccode_delegate_target_name (param));
531                                         if (delegate_type.is_disposable ()) {
532                                                 result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_ccode_delegate_target_destroy_notify_name (param));
533                                         }
534                                 }
535                         } else {
536                                 unowned Struct? type_as_struct = result.value_type.type_symbol as Struct;
537
538                                 if (param.direction == ParameterDirection.OUT) {
539                                         name = "_vala_%s".printf (name);
540                                 }
541
542                                 if (param.direction == ParameterDirection.REF ||
543                                         (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type () && !result.value_type.nullable)) {
544                                         result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (name));
545                                 } else {
546                                         result.cvalue = get_variable_cexpression (name);
547                                 }
548                                 if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
549                                         var target_cname = get_ccode_delegate_target_name (param);
550                                         var destroy_cname = get_ccode_delegate_target_destroy_notify_name (param);
551                                         if (param.direction == ParameterDirection.OUT) {
552                                                 target_cname = "_vala_%s".printf (target_cname);
553                                                 destroy_cname = "_vala_%s".printf (destroy_cname);
554                                         }
555                                         CCodeExpression target_expr = new CCodeIdentifier (target_cname);
556                                         CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier (destroy_cname);
557                                         if (param.direction == ParameterDirection.REF) {
558                                                 // accessing argument of ref param
559                                                 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
560                                                 delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
561                                         }
562                                         result.delegate_target_cvalue = target_expr;
563                                         if (result.value_type.is_disposable ()) {
564                                                 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
565                                         }
566                                 }
567                         }
568                         if (!param.captured && array_type != null) {
569                                 if (get_ccode_array_length (param) && !get_ccode_array_null_terminated (param)) {
570                                         for (int dim = 1; dim <= array_type.rank; dim++) {
571                                                 CCodeExpression length_expr = get_cexpression (get_variable_array_length_cname (param, dim));
572                                                 if (param.direction == ParameterDirection.OUT) {
573                                                         length_expr = get_cexpression (get_array_length_cname (name, dim));
574                                                 } else if (param.direction == ParameterDirection.REF) {
575                                                         // accessing argument of ref param
576                                                         length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
577                                                 }
578                                                 result.append_array_length_cvalue (length_expr);
579                                         }
580                                 }
581                         }
582                 }
583
584                 return result;
585         }
586
587         /* Returns lvalue access to the given field */
588         public override TargetValue get_field_cvalue (Field field, TargetValue? instance) {
589                 var value_type = field.variable_type.copy ();
590
591                 var result = new GLibValue (value_type);
592                 if (instance != null) {
593                         result.actual_value_type = field.variable_type.get_actual_type (instance.value_type, null, field);
594                 }
595                 result.lvalue = true;
596                 result.array_null_terminated = get_ccode_array_null_terminated (field);
597                 if (get_ccode_array_length_expr (field) != null) {
598                         result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (field));
599                 }
600                 result.ctype = get_ccode_type (field);
601
602                 var array_type = result.value_type as ArrayType;
603                 if (field.binding == MemberBinding.INSTANCE) {
604                         CCodeExpression pub_inst = null;
605
606                         if (instance != null) {
607                                 pub_inst = get_cvalue_ (instance);
608                         }
609
610                         var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol (field.parent_symbol);
611
612                         unowned Class? cl = instance_target_type.type_symbol as Class;
613                         bool is_gtypeinstance = ((instance_target_type.type_symbol == cl) && (cl == null || !cl.is_compact));
614
615                         CCodeExpression inst;
616                         if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
617                                 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
618                         } else {
619                                 if (cl != null) {
620                                         generate_class_struct_declaration (cl, cfile);
621                                 }
622                                 inst = pub_inst;
623                         }
624
625                         if (inst == null) {
626                                 // FIXME Report this with proper source-reference on the vala side!
627                                 Report.error (field.source_reference, "Invalid access to instance member `%s'", field.get_full_name ());
628                                 result.cvalue = new CCodeInvalidExpression ();
629                                 return result;
630                         }
631
632                         if (instance_target_type.type_symbol.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
633                                 result.cvalue = new CCodeMemberAccess.pointer (inst, get_ccode_name (field));
634                         } else {
635                                 result.cvalue = new CCodeMemberAccess (inst, get_ccode_name (field));
636                         }
637
638                         if (array_type != null && get_ccode_array_length (field)) {
639                                 for (int dim = 1; dim <= array_type.rank; dim++) {
640                                         CCodeExpression length_expr = null;
641                                         string length_cname = get_variable_array_length_cname (field, dim);
642
643                                         if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
644                                                 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
645                                         } else {
646                                                 length_expr = new CCodeMemberAccess (inst, length_cname);
647                                         }
648
649                                         result.append_array_length_cvalue (length_expr);
650                                 }
651                                 if (array_type.rank == 1 && field.is_internal_symbol ()) {
652                                         string size_cname = get_array_size_cname (get_ccode_name (field));
653
654                                         if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
655                                                 set_array_size_cvalue (result, new CCodeMemberAccess.pointer (inst, size_cname));
656                                         } else {
657                                                 set_array_size_cvalue (result, new CCodeMemberAccess (inst, size_cname));
658                                         }
659                                 }
660                         } else if (get_ccode_delegate_target (field)) {
661                                 string target_cname = get_ccode_delegate_target_name (field);
662                                 string target_destroy_notify_cname = get_ccode_delegate_target_destroy_notify_name (field);
663
664                                 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
665                                         result.delegate_target_cvalue = new CCodeMemberAccess.pointer (inst, target_cname);
666                                         if (result.value_type.is_disposable ()){
667                                                 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
668                                         }
669                                 } else {
670                                         result.delegate_target_cvalue = new CCodeMemberAccess (inst, target_cname);
671                                         if (result.value_type.is_disposable ()) {
672                                                 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess (inst, target_destroy_notify_cname);
673                                         }
674                                 }
675                         }
676                 } else if (field.binding == MemberBinding.CLASS) {
677                         unowned Class cl = (Class) field.parent_symbol;
678                         var cast = get_this_class_cexpression (cl, instance);
679                         if (field.access == SymbolAccessibility.PRIVATE) {
680                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
681                                 ccall.add_argument (cast);
682                                 result.cvalue = new CCodeMemberAccess.pointer (ccall, get_ccode_name (field));
683                         } else {
684                                 result.cvalue = new CCodeMemberAccess.pointer (cast, get_ccode_name (field));
685                         }
686
687                 } else {
688                         generate_field_declaration (field, cfile);
689
690                         result.cvalue = new CCodeIdentifier (get_ccode_name (field));
691
692                         if (array_type != null && get_ccode_array_length (field)) {
693                                 for (int dim = 1; dim <= array_type.rank; dim++) {
694                                         string length_cname = get_variable_array_length_cname (field, dim);
695                                         result.append_array_length_cvalue (new CCodeIdentifier (length_cname));
696                                 }
697                                 if (array_type.rank == 1 && field.is_internal_symbol ()) {
698                                         set_array_size_cvalue (result, new CCodeIdentifier (get_array_size_cname (get_ccode_name (field))));
699                                 }
700                         } else if (get_ccode_delegate_target (field)) {
701                                 result.delegate_target_cvalue = new CCodeIdentifier (get_ccode_delegate_target_name (field));
702                                 if (result.value_type.is_disposable ()) {
703                                         result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_ccode_delegate_target_destroy_notify_name (field));
704                                 }
705                         }
706                 }
707
708                 return result;
709         }
710
711         public override TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null) {
712                 var result = (GLibValue) value;
713                 var array_type = result.value_type as ArrayType;
714                 var delegate_type = result.value_type as DelegateType;
715                 if (array_type != null) {
716                         if (array_type.fixed_length) {
717                                 result.array_length_cvalues = null;
718                                 result.append_array_length_cvalue (get_ccodenode (array_type.length));
719                                 result.lvalue = false;
720                         } else if (get_ccode_array_null_terminated (variable)) {
721                                 requires_array_length = true;
722                                 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
723                                 len_call.add_argument (result.cvalue);
724
725                                 result.array_length_cvalues = null;
726                                 result.append_array_length_cvalue (len_call);
727                                 result.lvalue = false;
728                         } else if (get_ccode_array_length_expr (variable) != null) {
729                                 var length_expr = new CCodeConstant (get_ccode_array_length_expr (variable));
730
731                                 result.array_length_cvalues = null;
732                                 result.append_array_length_cvalue (length_expr);
733                                 result.lvalue = false;
734                         } else if (!get_ccode_array_length (variable)) {
735                                 result.array_length_cvalues = null;
736                                 for (int dim = 1; dim <= array_type.rank; dim++) {
737                                         result.append_array_length_cvalue (new CCodeConstant ("-1"));
738                                 }
739                                 result.lvalue = false;
740                         } else if (get_ccode_array_length_type (variable.variable_type) != get_ccode_array_length_type (array_type)) {
741                                 for (int dim = 1; dim <= array_type.rank; dim++) {
742                                         // cast if variable does not use int for array length
743                                         result.array_length_cvalues[dim - 1] = new CCodeCastExpression (result.array_length_cvalues[dim - 1], get_ccode_array_length_type (array_type));
744                                 }
745                                 result.lvalue = false;
746                         }
747                         result.array_size_cvalue = null;
748                         result.non_null = array_type.inline_allocated;
749                 } else if (delegate_type != null) {
750                         if (!get_ccode_delegate_target (variable)) {
751                                 result.delegate_target_cvalue = new CCodeConstant ("NULL");
752                                 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
753                         }
754
755                         result.lvalue = false;
756                 }
757                 result.value_type.value_owned = false;
758
759                 bool use_temp = true;
760                 if (!is_lvalue_access_allowed (result.value_type)) {
761                         // special handling for types such as va_list
762                         use_temp = false;
763                 }
764                 if (variable is Parameter) {
765                         var param = (Parameter) variable;
766                         if (variable.name == "this") {
767                                 use_temp = false;
768                         } else if ((param.direction != ParameterDirection.OUT)
769                             && !(param.variable_type.is_real_non_null_struct_type ())) {
770                                 use_temp = false;
771                         }
772                 }
773                 if (variable.single_assignment && !result.value_type.is_real_non_null_struct_type ()) {
774                         // no need to copy values from variables that are assigned exactly once
775                         // as there is no risk of modification
776                         // except for structs that are always passed by reference
777                         use_temp = false;
778                 }
779                 if (result.value_type.is_non_null_simple_type ()) {
780                         // no need to an extra copy of variables that are stack allocated simple types
781                         use_temp = false;
782                 }
783                 // our implementation of postfix-expressions require temporary variables
784                 if (expr is MemberAccess && ((MemberAccess) expr).tainted_access) {
785                         use_temp = true;
786                 }
787
788                 var local = variable as LocalVariable;
789                 if (local != null && local.name[0] == '.') {
790                         // already a temporary variable generated internally
791                         // and safe to access without temporary variable
792                         use_temp = false;
793                 }
794
795                 if (use_temp) {
796                         result = (GLibValue) store_temp_value (result, variable);
797                 }
798
799                 return result;
800         }
801
802         /* Returns unowned access to the given local variable */
803         public override TargetValue load_local (LocalVariable local, Expression? expr = null) {
804                 return load_variable (local, get_local_cvalue (local), expr);
805         }
806
807         /* Returns unowned access to the given parameter */
808         public override TargetValue load_parameter (Parameter param, Expression? expr = null) {
809                 return load_variable (param, get_parameter_cvalue (param), expr);
810         }
811
812         /* Convenience method returning access to "this" */
813         public override TargetValue load_this_parameter (TypeSymbol sym) {
814                 var param = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (sym));
815                 return load_parameter (param);
816         }
817
818         /* Returns unowned access to the given field */
819         public override TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null) {
820                 return load_variable (field, get_field_cvalue (field, instance), expr);
821         }
822 }