1
/* valamemberaccess.vala
3
* Copyright (C) 2006-2012 JĆ¼rg Billeter
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
* JĆ¼rg Billeter <j@bitron.ch>
26
* Represents an access to a type member in the source code.
28
public class Vala.MemberAccess : Expression {
30
* The parent of the member.
32
public Expression? inner {
39
_inner.parent_node = this;
45
* The name of the member.
47
public string member_name { get; set; }
50
* Pointer member access.
52
public bool pointer_member_access { get; set; }
55
* Represents access to an instance member without an actual instance,
56
* e.g. `MyClass.an_instance_method`.
58
public bool prototype_access { get; set; }
61
* Specifies whether the member is used for object creation.
63
public bool creation_member { get; set; }
66
* Qualified access to global symbol.
68
public bool qualified { get; set; }
70
private Expression? _inner;
71
private List<DataType> type_argument_list = new ArrayList<DataType> ();
74
* Creates a new member access expression.
76
* @param inner parent of the member
77
* @param member_name member name
78
* @param source_reference reference to source code
79
* @return newly created member access expression
81
public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) {
83
this.member_name = member_name;
84
this.source_reference = source_reference;
87
public MemberAccess.simple (string member_name, SourceReference? source_reference = null) {
88
this.member_name = member_name;
89
this.source_reference = source_reference;
92
public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
94
this.member_name = member_name;
95
this.source_reference = source_reference;
96
pointer_member_access = true;
100
* Appends the specified type as generic type argument.
102
* @param arg a type reference
104
public void add_type_argument (DataType arg) {
105
type_argument_list.add (arg);
106
arg.parent_node = this;
110
* Returns a copy of the list of generic type arguments.
112
* @return type argument list
114
public List<DataType> get_type_arguments () {
115
return type_argument_list;
118
public override void accept (CodeVisitor visitor) {
119
visitor.visit_member_access (this);
121
visitor.visit_expression (this);
124
public override void accept_children (CodeVisitor visitor) {
126
inner.accept (visitor);
129
foreach (DataType type_arg in type_argument_list) {
130
type_arg.accept (visitor);
134
public override string to_string () {
135
if (symbol_reference == null || symbol_reference.is_instance_member ()) {
139
return "%s.%s".printf (inner.to_string (), member_name);
142
// ensure to always use fully-qualified name
143
// to refer to static members
144
return symbol_reference.get_full_name ();
148
public override void replace_expression (Expression old_node, Expression new_node) {
149
if (inner == old_node) {
154
public override bool is_pure () {
155
// accessing property could have side-effects
156
return (inner == null || inner.is_pure ()) && !(symbol_reference is Property);
159
public override void replace_type (DataType old_type, DataType new_type) {
160
for (int i = 0; i < type_argument_list.size; i++) {
161
if (type_argument_list[i] == old_type) {
162
type_argument_list[i] = new_type;
168
public override bool is_constant () {
169
var method = symbol_reference as Method;
170
if (symbol_reference is Constant) {
172
} else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) {
173
// length of constant array
175
} else if (method != null &&
176
(method.binding == MemberBinding.STATIC || prototype_access)) {
183
public override bool is_non_null () {
184
var c = symbol_reference as Constant;
186
return !c.type_reference.nullable;
192
public override bool check (CodeContext context) {
200
inner.check (context);
203
foreach (DataType type_arg in type_argument_list) {
204
type_arg.check (context);
207
Symbol base_symbol = null;
208
Parameter this_parameter = null;
209
bool may_access_instance_members = false;
210
bool may_access_klass_members = false;
212
symbol_reference = null;
215
base_symbol = context.analyzer.root_symbol;
216
symbol_reference = context.analyzer.root_symbol.scope.lookup (member_name);
217
} else if (inner == null) {
218
if (member_name == "this") {
219
if (!context.analyzer.is_in_instance_method ()) {
221
Report.error (source_reference, "This access invalid outside of instance methods");
226
base_symbol = context.analyzer.current_symbol;
228
// track whether method has been found to make sure that access
229
// to instance member is denied from within static lambda expressions
230
bool method_found = false;
232
var sym = context.analyzer.current_symbol;
233
while (sym != null && symbol_reference == null) {
235
if (sym is CreationMethod) {
236
var cm = (CreationMethod) sym;
237
this_parameter = cm.this_parameter;
238
may_access_instance_members = true;
239
may_access_klass_members = true;
241
} else if (sym is Property) {
242
var prop = (Property) sym;
243
this_parameter = prop.this_parameter;
244
may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
245
may_access_klass_members = (prop.binding != MemberBinding.STATIC);
247
} else if (sym is Constructor) {
248
var c = (Constructor) sym;
249
this_parameter = c.this_parameter;
250
may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
251
may_access_klass_members = true;
253
} else if (sym is Destructor) {
254
var d = (Destructor) sym;
255
this_parameter = d.this_parameter;
256
may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
257
may_access_klass_members = true;
259
} else if (sym is Method) {
260
var m = (Method) sym;
261
this_parameter = m.this_parameter;
262
may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
263
may_access_klass_members = (m.binding != MemberBinding.STATIC);
268
symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name);
270
if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) {
271
// used for generated to_string methods in enums
272
symbol_reference = this_parameter.variable_type.get_member (member_name);
274
if (symbol_reference != null && is_instance_symbol (symbol_reference)) {
276
inner = new MemberAccess (null, "this", source_reference);
277
inner.value_type = this_parameter.variable_type.copy ();
278
inner.value_type.value_owned = false;
279
inner.symbol_reference = this_parameter;
281
symbol_reference = inner.value_type.get_member (member_name);
285
if (symbol_reference == null) {
286
if (sym is TypeSymbol) {
287
// do not allow instance access to outer classes
288
this_parameter = null;
289
may_access_instance_members = false;
290
may_access_klass_members = false;
294
sym = sym.parent_symbol;
297
if (symbol_reference == null && source_reference != null) {
298
foreach (UsingDirective ns in source_reference.using_directives) {
299
var local_sym = ns.namespace_symbol.scope.lookup (member_name);
300
if (local_sym != null) {
301
if (symbol_reference != null && symbol_reference != local_sym) {
303
Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (member_name, symbol_reference.get_full_name (), local_sym.get_full_name ()));
306
symbol_reference = local_sym;
312
/* if there was an error in the inner expression, skip this check */
317
if (inner.value_type is PointerType) {
318
var pointer_type = inner.value_type as PointerType;
319
if (pointer_type != null && pointer_type.base_type is ValueType) {
320
// transform foo->bar to (*foo).bar
321
inner = new PointerIndirection (inner, source_reference);
322
inner.check (context);
323
pointer_member_access = false;
327
if (inner is MemberAccess) {
328
var ma = (MemberAccess) inner;
329
if (ma.prototype_access) {
331
Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
336
if (inner is MemberAccess || inner is BaseAccess) {
337
base_symbol = inner.symbol_reference;
339
if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
340
symbol_reference = base_symbol.scope.lookup (member_name);
341
if (inner is BaseAccess) {
342
// inner expression is base access
343
// access to instance members of the base type possible
344
may_access_instance_members = true;
345
may_access_klass_members = true;
350
if (symbol_reference == null && inner.value_type != null) {
351
if (pointer_member_access) {
352
symbol_reference = inner.value_type.get_pointer_member (member_name);
354
if (inner.value_type.data_type != null) {
355
base_symbol = inner.value_type.data_type;
357
symbol_reference = inner.value_type.get_member (member_name);
359
if (symbol_reference != null) {
360
// inner expression is variable, field, or parameter
361
// access to instance members of the corresponding type possible
362
may_access_instance_members = true;
363
may_access_klass_members = true;
367
if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
368
// allow late bound members for dynamic types
369
var dynamic_object_type = (ObjectType) inner.value_type;
370
if (parent_node is MethodCall) {
371
var invoc = (MethodCall) parent_node;
372
if (invoc.call == this) {
375
if (invoc.target_type != null) {
376
ret_type = invoc.target_type.copy ();
377
ret_type.value_owned = true;
378
} else if (invoc.parent_node is ExpressionStatement) {
379
ret_type = new VoidType ();
381
// expect dynamic object of the same type
382
ret_type = inner.value_type.copy ();
384
var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
385
m.invocation = invoc;
386
var err = new ErrorType (null, null);
387
err.dynamic_error = true;
388
m.add_error_type (err);
389
m.access = SymbolAccessibility.PUBLIC;
390
m.add_parameter (new Parameter.with_ellipsis ());
391
dynamic_object_type.type_symbol.scope.add (null, m);
392
symbol_reference = m;
394
} else if (parent_node is Assignment) {
395
var a = (Assignment) parent_node;
397
&& (a.operator == AssignmentOperator.ADD
398
|| a.operator == AssignmentOperator.SUB)) {
400
var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
402
s.access = SymbolAccessibility.PUBLIC;
403
dynamic_object_type.type_symbol.scope.add (null, s);
404
symbol_reference = s;
405
} else if (a.left == this) {
406
// dynamic property assignment
407
var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
408
prop.access = SymbolAccessibility.PUBLIC;
409
prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
410
prop.owner = inner.value_type.data_type.scope;
411
dynamic_object_type.type_symbol.scope.add (null, prop);
412
symbol_reference = prop;
414
} else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
415
var ma = (MemberAccess) parent_node;
416
if (ma.member_name == "connect" || ma.member_name == "connect_after") {
418
var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
419
var mcall = (MethodCall) parent_node.parent_node;
420
// the first argument is the handler
421
if (mcall.get_argument_list().size > 0) {
422
s.handler = mcall.get_argument_list()[0];
424
s.access = SymbolAccessibility.PUBLIC;
425
dynamic_object_type.type_symbol.scope.add (null, s);
426
symbol_reference = s;
429
if (symbol_reference == null) {
430
// dynamic property read access
431
var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
432
if (target_type != null) {
433
prop.property_type = target_type;
435
// expect dynamic object of the same type
436
prop.property_type = inner.value_type.copy ();
438
prop.access = SymbolAccessibility.PUBLIC;
439
prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
440
prop.owner = inner.value_type.data_type.scope;
441
dynamic_object_type.type_symbol.scope.add (null, prop);
442
symbol_reference = prop;
444
if (symbol_reference != null) {
445
may_access_instance_members = true;
446
may_access_klass_members = true;
451
if (symbol_reference == null) {
454
string base_type_name = "(null)";
455
if (inner != null && inner.value_type != null) {
456
base_type_name = inner.value_type.to_string ();
457
} else if (base_symbol != null) {
458
base_type_name = base_symbol.get_full_name ();
461
Report.error (source_reference, "The name `%s' does not exist in the context of `%s'".printf (member_name, base_type_name));
465
var member = symbol_reference;
466
var access = SymbolAccessibility.PUBLIC;
467
bool instance = false;
469
bool generics = false;
471
if (!member.check (context)) {
475
if (member is LocalVariable) {
476
var local = (LocalVariable) member;
477
var block = local.parent_symbol as Block;
478
if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
479
// mark all methods between current method and the captured
480
// block as closures (to support nested closures)
481
Symbol sym = context.analyzer.current_method_or_property_accessor;
482
while (sym != block) {
483
var method = sym as Method;
484
if (method != null) {
485
method.closure = true;
486
// consider captured variables as used
487
// as we require captured variables to be initialized
488
method.add_captured_variable (local);
490
sym = sym.parent_symbol;
493
local.captured = true;
494
block.captured = true;
496
} else if (member is Parameter) {
497
var param = (Parameter) member;
498
var m = param.parent_symbol as Method;
499
if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
500
// mark all methods between current method and the captured
501
// parameter as closures (to support nested closures)
502
Symbol sym = context.analyzer.current_method_or_property_accessor;
504
var method = sym as Method;
505
if (method != null) {
506
method.closure = true;
508
sym = sym.parent_symbol;
511
param.captured = true;
512
m.body.captured = true;
514
if (param.direction != ParameterDirection.IN) {
516
Report.error (source_reference, "Cannot capture reference or output parameter `%s'".printf (param.get_full_name ()));
519
var acc = param.parent_symbol.parent_symbol as PropertyAccessor;
520
if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
521
// mark all methods between current method and the captured
522
// parameter as closures (to support nested closures)
523
Symbol sym = context.analyzer.current_method_or_property_accessor;
525
var method = sym as Method;
526
if (method != null) {
527
method.closure = true;
529
sym = sym.parent_symbol;
532
param.captured = true;
533
acc.body.captured = true;
536
} else if (member is Field) {
537
var f = (Field) member;
539
instance = (f.binding == MemberBinding.INSTANCE);
540
klass = (f.binding == MemberBinding.CLASS);
542
// do not allow access to fields of generic types
543
// if instance type does not specify type arguments
544
if (f.variable_type is GenericType) {
547
} else if (member is Constant) {
548
var c = (Constant) member;
551
var block = c.parent_symbol as Block;
552
if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
554
Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet");
557
} else if (member is Method) {
558
var m = (Method) member;
559
if (m.is_async_callback) {
560
// ensure to use right callback method for virtual/abstract async methods
561
// and also for lambda expressions within async methods
562
var async_method = context.analyzer.current_async_method;
564
bool is_valid_access = false;
565
if (async_method != null) {
566
if (m == async_method.get_callback_method ()) {
567
is_valid_access = true;
568
} else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) {
569
is_valid_access = true;
570
} else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) {
571
is_valid_access = true;
574
if (!is_valid_access) {
576
Report.error (source_reference, "Access to async callback `%s' not allowed in this context".printf (m.get_full_name ()));
580
if (async_method != context.analyzer.current_method) {
581
Symbol sym = context.analyzer.current_method;
582
while (sym != async_method) {
583
var method = sym as Method;
584
if (method != null) {
585
method.closure = true;
587
sym = sym.parent_symbol;
589
async_method.body.captured = true;
592
m = async_method.get_callback_method ();
593
symbol_reference = m;
594
member = symbol_reference;
595
} else if (m.base_method != null) {
596
// refer to base method to inherit default arguments
599
if (m.signal_reference != null) {
600
// method is class/default handler for a signal
601
// let signal deal with member access
602
symbol_reference = m.signal_reference;
604
symbol_reference = m;
607
member = symbol_reference;
608
} else if (m.base_interface_method != null) {
609
// refer to base method to inherit default arguments
610
m = m.base_interface_method;
612
if (m.signal_reference != null) {
613
// method is class/default handler for a signal
614
// let signal deal with member access
615
symbol_reference = m.signal_reference;
617
symbol_reference = m;
620
member = symbol_reference;
623
if (!(m is CreationMethod)) {
624
instance = (m.binding == MemberBinding.INSTANCE);
626
klass = (m.binding == MemberBinding.CLASS);
628
// do not allow access to methods using generic type parameters
629
// if instance type does not specify type arguments
630
foreach (var param in m.get_parameters ()) {
631
var generic_type = param.variable_type as GenericType;
632
if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
637
var generic_type = m.return_type as GenericType;
638
if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
641
} else if (member is Property) {
642
var prop = (Property) member;
643
if (!prop.check (context)) {
647
if (prop.base_property != null) {
648
// refer to base property
649
prop = prop.base_property;
650
symbol_reference = prop;
651
member = symbol_reference;
652
} else if (prop.base_interface_property != null) {
653
// refer to base property
654
prop = prop.base_interface_property;
655
symbol_reference = prop;
656
member = symbol_reference;
658
access = prop.access;
660
if (prop.set_accessor == null) {
662
Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
665
if (prop.access == SymbolAccessibility.PUBLIC) {
666
access = prop.set_accessor.access;
667
} else if (prop.access == SymbolAccessibility.PROTECTED
668
&& prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
669
access = prop.set_accessor.access;
672
if (prop.get_accessor == null) {
674
Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
677
if (prop.access == SymbolAccessibility.PUBLIC) {
678
access = prop.get_accessor.access;
679
} else if (prop.access == SymbolAccessibility.PROTECTED
680
&& prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
681
access = prop.get_accessor.access;
684
instance = (prop.binding == MemberBinding.INSTANCE);
686
// do not allow access to properties of generic types
687
// if instance type does not specify type arguments
688
if (prop.property_type is GenericType) {
691
} else if (member is Signal) {
693
access = member.access;
697
member.check_deprecated (source_reference);
698
member.check_experimental (source_reference);
700
if (access == SymbolAccessibility.PROTECTED) {
701
var target_type = (TypeSymbol) member.parent_symbol;
703
bool in_subtype = false;
704
for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
705
if (this_symbol == target_type) {
706
// required for interfaces with non-abstract methods
707
// accessing protected interface members
712
var cl = this_symbol as Class;
713
if (cl != null && cl.is_subtype_of (target_type)) {
721
Report.error (source_reference, "Access to protected member `%s' denied".printf (member.get_full_name ()));
724
} else if (access == SymbolAccessibility.PRIVATE) {
725
var target_type = member.parent_symbol;
727
bool in_target_type = false;
728
for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
729
if (target_type == this_symbol) {
730
in_target_type = true;
735
if (!in_target_type) {
737
Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
742
if (generics && inner != null) {
743
var instance_type = inner.value_type;
744
var pointer_type = inner.value_type as PointerType;
745
if (pointer_type != null) {
746
instance_type = pointer_type.base_type;
749
// instance type might be a subtype of the parent symbol of the member
750
// that subtype might not be generic, so do not report an error in that case
751
var object_type = instance_type as ObjectType;
752
if (object_type != null && object_type.type_symbol.get_type_parameters ().size > 0 &&
753
instance_type.get_type_arguments ().size == 0) {
755
Report.error (inner.source_reference, "missing generic type arguments");
760
if ((instance && !may_access_instance_members) ||
761
(klass && !may_access_klass_members)) {
762
prototype_access = true;
764
if (symbol_reference is Method) {
765
// also set static type for prototype access
766
// required when using instance methods as delegates in constants
767
// TODO replace by MethodPrototype
768
value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
769
} else if (symbol_reference is Field) {
770
value_type = new FieldPrototype ((Field) symbol_reference);
772
value_type = new InvalidType ();
775
if (target_type != null) {
776
value_type.value_owned = target_type.value_owned;
779
// implicit this access
780
if (instance && inner == null) {
781
inner = new MemberAccess (null, "this", source_reference);
782
inner.value_type = this_parameter.variable_type.copy ();
783
inner.value_type.value_owned = false;
784
inner.symbol_reference = this_parameter;
786
check_lvalue_access ();
789
if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) {
790
if (inner.symbol_reference is Method) {
791
// do not warn when calling .begin or .end on static async method
793
Report.warning (source_reference, "Access to static member `%s' with an instance reference".printf (symbol_reference.get_full_name ()));
797
if (context.experimental_non_null && instance && inner.value_type.nullable &&
798
!(inner.value_type is PointerType) && !(inner.value_type is GenericType)) {
799
Report.error (source_reference, "Access to instance member `%s' from nullable reference denied".printf (symbol_reference.get_full_name ()));
802
var m = symbol_reference as Method;
803
var inner_ma = inner as MemberAccess;
804
if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol &&
805
inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) {
806
// support static methods in generic classes
807
inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol);
809
foreach (var type_argument in inner_ma.type_argument_list) {
810
inner.value_type.add_type_argument (type_argument);
814
formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
815
if (inner != null && formal_value_type != null) {
816
value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
818
value_type = formal_value_type;
821
if (symbol_reference is Method) {
822
if (target_type != null) {
823
value_type.value_owned = target_type.value_owned;
827
if (m.base_method != null) {
828
base_method = m.base_method;
829
} else if (m.base_interface_method != null) {
830
base_method = m.base_interface_method;
835
if (instance && base_method.parent_symbol is TypeSymbol) {
836
inner.target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
837
inner.target_type.value_owned = base_method.this_parameter.variable_type.value_owned;
839
} else if (symbol_reference is Property) {
840
var prop = (Property) symbol_reference;
842
Property base_property;
843
if (prop.base_property != null) {
844
base_property = prop.base_property;
845
} else if (prop.base_interface_property != null) {
846
base_property = prop.base_interface_property;
848
base_property = prop;
851
if (instance && base_property.parent_symbol != null) {
852
inner.target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) base_property.parent_symbol);
854
} else if ((symbol_reference is Field
855
|| symbol_reference is Signal)
856
&& instance && symbol_reference.parent_symbol != null) {
857
var parent_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) symbol_reference.parent_symbol);
858
inner.target_type = parent_type.get_actual_type (inner.value_type, null, this);
865
static bool is_instance_symbol (Symbol symbol) {
866
if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) {
868
} else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) {
870
} else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) {
872
} else if (symbol is Signal) {
879
public void check_lvalue_access () {
883
var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE;
885
instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE;
888
instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE;
891
var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this";
892
var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || inner.value_type is ArrayType;
894
if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((inner is MemberAccess && inner.symbol_reference is Variable) || inner is ElementAccess) && !this_access) {
896
if (inner is MemberAccess) {
897
((MemberAccess) inner).check_lvalue_access ();
902
public override void emit (CodeGenerator codegen) {
904
inner.emit (codegen);
907
codegen.visit_member_access (this);
909
codegen.visit_expression (this);
912
public override void get_defined_variables (Collection<Variable> collection) {
914
inner.get_defined_variables (collection);
918
public override void get_used_variables (Collection<Variable> collection) {
920
inner.get_used_variables (collection);
922
var local = symbol_reference as LocalVariable;
923
var param = symbol_reference as Parameter;
925
collection.add (local);
926
} else if (param != null && param.direction == ParameterDirection.OUT) {
927
collection.add (param);