manual: Update from wiki.gnome.org
[vala-gnome.git] / vala / valafield.vala
blob88f80905d750ae30ef3b2d586a7f9d07923475c8
1 /* valafield.vala
3 * Copyright (C) 2006-2010 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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents a type or namespace field.
28 public class Vala.Field : Variable, Lockable {
29 /**
30 * Specifies whether this field may only be accessed with an instance of
31 * the contained type.
33 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
35 /**
36 * Specifies whether the field is volatile. Volatile fields are
37 * necessary to allow multi-threaded access.
39 public bool is_volatile { get; set; }
41 private bool lock_used = false;
43 /**
44 * Creates a new field.
46 * @param name field name
47 * @param variable_type field type
48 * @param initializer initializer expression
49 * @param source_reference reference to source code
50 * @return newly created field
52 public Field (string name, DataType variable_type, Expression? initializer, SourceReference? source_reference = null, Comment? comment = null) {
53 base (variable_type, name, initializer, source_reference, comment);
56 public override void accept (CodeVisitor visitor) {
57 visitor.visit_field (this);
60 public override void accept_children (CodeVisitor visitor) {
61 variable_type.accept (visitor);
63 if (initializer != null) {
64 initializer.accept (visitor);
68 public bool get_lock_used () {
69 return lock_used;
72 public void set_lock_used (bool used) {
73 lock_used = used;
76 public override void replace_expression (Expression old_node, Expression new_node) {
77 if (initializer == old_node) {
78 initializer = new_node;
82 public override void replace_type (DataType old_type, DataType new_type) {
83 if (variable_type == old_type) {
84 variable_type = new_type;
88 public override bool check (CodeContext context) {
89 if (checked) {
90 return !error;
93 checked = true;
95 var old_source_file = context.analyzer.current_source_file;
96 var old_symbol = context.analyzer.current_symbol;
98 if (source_reference != null) {
99 context.analyzer.current_source_file = source_reference.file;
101 context.analyzer.current_symbol = this;
103 if (variable_type is VoidType) {
104 error = true;
105 Report.error (source_reference, "'void' not supported as field type");
106 return false;
109 variable_type.check (context);
111 // check whether field type is at least as accessible as the field
112 if (!context.analyzer.is_type_accessible (this, variable_type)) {
113 error = true;
114 Report.error (source_reference, "field type `%s` is less accessible than field `%s`".printf (variable_type.to_string (), get_full_name ()));
115 return false;
118 if (initializer != null) {
119 initializer.target_type = variable_type;
121 if (!initializer.check (context)) {
122 error = true;
123 return false;
126 if (initializer.value_type == null) {
127 error = true;
128 Report.error (source_reference, "expression type not allowed as initializer");
129 return false;
132 if (!initializer.value_type.compatible (variable_type)) {
133 error = true;
134 Report.error (source_reference, "Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
135 return false;
138 if (initializer.value_type.is_disposable ()) {
139 /* rhs transfers ownership of the expression */
140 if (!(variable_type is PointerType) && !variable_type.value_owned) {
141 /* lhs doesn't own the value */
142 error = true;
143 Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
144 return false;
148 if (parent_symbol is Namespace && !initializer.is_constant ()) {
149 error = true;
150 Report.error (source_reference, "Non-constant field initializers not supported in this context");
151 return false;
154 if (parent_symbol is Namespace && initializer.is_constant () && initializer.is_non_null ()) {
155 if (variable_type.is_disposable () && variable_type.value_owned) {
156 error = true;
157 Report.error (source_reference, "Owned namespace fields can only be initialized in a function or method");
158 return false;
162 if (binding == MemberBinding.STATIC && parent_symbol is Class && ((Class)parent_symbol).is_compact && !initializer.is_constant ()) {
163 error = true;
164 Report.error (source_reference, "Static fields in compact classes cannot have non-constant initializers");
165 return false;
168 if (external) {
169 error = true;
170 Report.error (source_reference, "External fields cannot use initializers");
174 if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
175 error = true;
176 Report.error (source_reference, "Interfaces may not have instance fields");
177 return false;
180 bool field_in_header = !is_internal_symbol ();
181 if (parent_symbol is Class) {
182 var cl = (Class) parent_symbol;
183 if (cl.is_compact && !cl.is_internal_symbol ()) {
184 // compact classes don't have priv structs
185 field_in_header = true;
189 if (!external_package && !hides && get_hidden_member () != null) {
190 Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
193 context.analyzer.current_source_file = old_source_file;
194 context.analyzer.current_symbol = old_symbol;
196 return !error;