Line data Source code
1 : /* valafield.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a type or namespace field.
27 : */
28 600434 : public class Vala.Field : Variable, Lockable {
29 : /**
30 : * Specifies whether this field may only be accessed with an instance of
31 : * the contained type.
32 : */
33 1825935 : public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
34 :
35 : /**
36 : * Specifies whether the field is volatile. Volatile fields are
37 : * necessary to allow multi-threaded access.
38 : */
39 3146 : public bool is_volatile { get; set; }
40 :
41 4206 : public bool lock_used { get; set; }
42 :
43 : /**
44 : * Creates a new field.
45 : *
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
51 : */
52 1774703 : public Field (string name, DataType variable_type, Expression? initializer, SourceReference? source_reference = null, Comment? comment = null) {
53 597358 : base (variable_type, name, initializer, source_reference, comment);
54 : }
55 :
56 1302624 : public override void accept (CodeVisitor visitor) {
57 1302624 : visitor.visit_field (this);
58 : }
59 :
60 542235 : public override void accept_children (CodeVisitor visitor) {
61 542235 : variable_type.accept (visitor);
62 :
63 542235 : if (initializer != null) {
64 409 : initializer.accept (visitor);
65 : }
66 : }
67 :
68 15 : public override void replace_expression (Expression old_node, Expression new_node) {
69 15 : if (initializer == old_node) {
70 15 : initializer = new_node;
71 : }
72 : }
73 :
74 482496 : public override void replace_type (DataType old_type, DataType new_type) {
75 482496 : if (variable_type == old_type) {
76 482496 : variable_type = new_type;
77 : }
78 : }
79 :
80 660136 : public override bool check (CodeContext context) {
81 660136 : if (checked) {
82 102625 : return !error;
83 : }
84 :
85 557511 : checked = true;
86 :
87 557511 : var old_source_file = context.analyzer.current_source_file;
88 823454 : var old_symbol = context.analyzer.current_symbol;
89 :
90 557511 : if (source_reference != null) {
91 557511 : context.analyzer.current_source_file = source_reference.file;
92 : }
93 557511 : context.analyzer.current_symbol = this;
94 :
95 557511 : if (variable_type is VoidType) {
96 2 : error = true;
97 2 : Report.error (source_reference, "'void' not supported as field type");
98 2 : return false;
99 : }
100 :
101 557509 : if (variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
102 1 : error = true;
103 1 : Report.error (source_reference, "`%s' not supported as field type", variable_type.type_symbol.get_full_name ());
104 1 : return false;
105 : }
106 :
107 557508 : if (has_attribute ("GtkChild") && variable_type.value_owned) {
108 1 : Report.warning (source_reference, "[GtkChild] fields must be declared as `unowned'");
109 1 : variable_type.value_owned = false;
110 : }
111 :
112 557508 : variable_type.check (context);
113 557508 : if (!external_package) {
114 2534 : context.analyzer.check_type (variable_type);
115 2534 : variable_type.check_type_arguments (context, true);
116 :
117 : // check symbol availability
118 2534 : if (variable_type.type_symbol != null) {
119 2304 : variable_type.type_symbol.version.check (context, source_reference);
120 : }
121 : }
122 :
123 : // check whether field type is at least as accessible as the field
124 557508 : if (!variable_type.is_accessible (this)) {
125 1 : error = true;
126 1 : Report.error (source_reference, "field type `%s' is less accessible than field `%s'", variable_type.to_string (), get_full_name ());
127 1 : return false;
128 : }
129 :
130 557507 : unowned ArrayType? variable_array_type = variable_type as ArrayType;
131 38609 : if (variable_array_type != null && variable_array_type.inline_allocated
132 2240 : && initializer is ArrayCreationExpression && ((ArrayCreationExpression) initializer).initializer_list == null) {
133 0 : Report.warning (source_reference, "Inline allocated arrays don't require an explicit instantiation");
134 0 : initializer = null;
135 : }
136 :
137 557507 : if (variable_array_type != null && variable_array_type.inline_allocated
138 2240 : && !variable_array_type.fixed_length) {
139 2 : Report.error (source_reference, "Inline allocated array as field requires to have fixed length");
140 : }
141 :
142 557507 : if (initializer != null) {
143 409 : initializer.target_type = variable_type;
144 :
145 : // Catch initializer list transformation:
146 409 : bool is_initializer_list = false;
147 409 : int initializer_size = -1;
148 :
149 409 : if (initializer is InitializerList) {
150 19 : initializer_size = ((InitializerList) initializer).size;
151 19 : is_initializer_list = true;
152 : }
153 :
154 409 : if (!initializer.check (context)) {
155 2 : error = true;
156 2 : return false;
157 : }
158 :
159 407 : if (initializer.value_type == null) {
160 0 : error = true;
161 0 : Report.error (initializer.source_reference, "expression type not allowed as initializer");
162 0 : return false;
163 : }
164 :
165 407 : if (!initializer.value_type.compatible (variable_type)) {
166 2 : error = true;
167 2 : Report.error (source_reference, "Cannot convert from `%s' to `%s'", initializer.value_type.to_string (), variable_type.to_string ());
168 2 : return false;
169 : }
170 :
171 405 : if (variable_array_type != null && variable_array_type.inline_allocated && !variable_array_type.fixed_length && is_initializer_list) {
172 0 : variable_array_type.length = new IntegerLiteral (initializer_size.to_string ());
173 0 : variable_array_type.fixed_length = true;
174 0 : variable_array_type.nullable = false;
175 : }
176 :
177 405 : if (variable_array_type != null && variable_array_type.inline_allocated && !(initializer.value_type is ArrayType)) {
178 0 : error = true;
179 0 : Report.error (source_reference, "only arrays are allowed as initializer for arrays with fixed length");
180 0 : return false;
181 : }
182 :
183 405 : if (initializer.value_type.is_disposable ()) {
184 : /* rhs transfers ownership of the expression */
185 137 : if (!(variable_type is PointerType) && !variable_type.value_owned) {
186 : /* lhs doesn't own the value */
187 1 : error = true;
188 1 : Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
189 1 : return false;
190 : }
191 : }
192 :
193 404 : if (parent_symbol is Namespace && !initializer.is_constant ()) {
194 2 : error = true;
195 2 : Report.error (source_reference, "Non-constant field initializers not supported in this context");
196 2 : return false;
197 : }
198 :
199 402 : if (parent_symbol is Namespace && initializer.is_constant () && initializer.is_non_null ()) {
200 7 : if (variable_type.is_disposable () && variable_type.value_owned) {
201 2 : error = true;
202 2 : Report.error (source_reference, "Owned namespace fields can only be initialized in a function or method");
203 2 : return false;
204 : }
205 : }
206 :
207 400 : if (binding == MemberBinding.STATIC && parent_symbol is Class && ((Class)parent_symbol).is_compact && !initializer.is_constant ()) {
208 1 : error = true;
209 1 : Report.error (source_reference, "Static fields in compact classes cannot have non-constant initializers");
210 1 : return false;
211 : }
212 :
213 399 : if (external) {
214 1 : error = true;
215 1 : Report.error (source_reference, "External fields cannot use initializers");
216 : }
217 : }
218 :
219 557497 : if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
220 1 : error = true;
221 1 : Report.error (source_reference, "Interfaces may not have instance fields");
222 1 : return false;
223 : }
224 :
225 557496 : bool field_in_header = !is_internal_symbol ();
226 823439 : if (parent_symbol is Class) {
227 265943 : var cl = (Class) parent_symbol;
228 265943 : if (cl.is_compact && !cl.is_internal_symbol ()) {
229 : // compact classes don't have priv structs
230 265943 : field_in_header = true;
231 : }
232 : }
233 :
234 557496 : if (!external_package && !hides && get_hidden_member () != null) {
235 0 : Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' keyword if hiding was intentional", get_full_name (), get_hidden_member ().get_full_name ());
236 : }
237 :
238 557496 : context.analyzer.current_source_file = old_source_file;
239 557496 : context.analyzer.current_symbol = old_symbol;
240 :
241 557496 : return !error;
242 : }
243 : }
|