Line data Source code
1 : /* valalocalvariable.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 local variable declaration in the source code.
27 : */
28 673449 : public class Vala.LocalVariable : Variable {
29 138357 : public bool is_result { get; set; }
30 :
31 170869 : public bool captured { get; set; }
32 :
33 187025 : public bool init { get; set; }
34 :
35 : /**
36 : * Creates a new local variable.
37 : *
38 : * @param name name of the variable
39 : * @param initializer optional initializer expression
40 : * @param source_reference reference to source code
41 : * @return newly created variable declarator
42 : */
43 2015736 : public LocalVariable (DataType? variable_type, string name, Expression? initializer = null, SourceReference? source_reference = null) {
44 671912 : base (variable_type, name, initializer, source_reference);
45 : }
46 :
47 212180 : public override void accept (CodeVisitor visitor) {
48 212180 : visitor.visit_local_variable (this);
49 : }
50 :
51 94788 : public override void accept_children (CodeVisitor visitor) {
52 94788 : if (initializer != null) {
53 72915 : initializer.accept (visitor);
54 :
55 72915 : visitor.visit_end_full_expression (initializer);
56 : }
57 :
58 94788 : if (variable_type != null) {
59 94747 : variable_type.accept (visitor);
60 : }
61 : }
62 :
63 376 : public override void replace_expression (Expression old_node, Expression new_node) {
64 376 : if (initializer == old_node) {
65 376 : initializer = new_node;
66 : }
67 : }
68 :
69 47828 : public override void replace_type (DataType old_type, DataType new_type) {
70 47828 : if (variable_type == old_type) {
71 47828 : variable_type = new_type;
72 : }
73 : }
74 :
75 601906 : public override bool check (CodeContext context) {
76 601906 : if (checked) {
77 441835 : return !error;
78 : }
79 :
80 160071 : checked = true;
81 :
82 160071 : if (variable_type == null) {
83 12626 : variable_type = new VarType ();
84 : }
85 :
86 160071 : if (!context.experimental_non_null) {
87 : // local reference variables are considered nullable
88 : // except when using experimental non-null enhancements
89 158690 : if (variable_type is ReferenceType) {
90 36059 : unowned ArrayType? array_type = variable_type as ArrayType;
91 36059 : if (array_type != null && array_type.fixed_length) {
92 : // local fixed length arrays are not nullable
93 : } else {
94 36020 : variable_type.nullable = true;
95 : }
96 : }
97 : }
98 :
99 160071 : if (!(variable_type is VarType)) {
100 139633 : if (variable_type is VoidType) {
101 1 : error = true;
102 1 : Report.error (source_reference, "'void' not supported as variable type");
103 139632 : } else if (!variable_type.check (context)) {
104 10 : error = true;
105 : }
106 139633 : if (!external_package) {
107 7950 : context.analyzer.check_type (variable_type);
108 7950 : variable_type.check_type_arguments (context, true);
109 : }
110 : }
111 :
112 : // Catch initializer list transformation:
113 160071 : bool is_initializer_list = false;
114 160071 : int initializer_size = -1;
115 :
116 160071 : if (initializer != null && !error) {
117 93249 : initializer.target_type = variable_type;
118 :
119 93249 : if (initializer is InitializerList) {
120 185 : initializer_size = ((InitializerList) initializer).size;
121 185 : is_initializer_list = true;
122 : }
123 :
124 93249 : if (!initializer.check (context)) {
125 66 : error = true;
126 93183 : } else if (initializer.value_type is VoidType) {
127 0 : error = true;
128 0 : Report.error (initializer.source_reference, "'void' not supported as initializer type");
129 : }
130 : }
131 :
132 : // local variables are defined even on errors
133 160071 : context.analyzer.current_symbol.scope.add (name, this);
134 :
135 160071 : if (error) {
136 102 : return false;
137 : }
138 :
139 159994 : if (variable_type is VarType) {
140 : /* var type */
141 :
142 20400 : if (initializer == null) {
143 1 : error = true;
144 1 : Report.error (source_reference, "var declaration not allowed without initializer");
145 1 : return false;
146 : }
147 20399 : if (initializer.value_type == null) {
148 0 : error = true;
149 0 : Report.error (source_reference, "var declaration not allowed with non-typed initializer");
150 0 : return false;
151 : }
152 20399 : if (initializer.value_type is FieldPrototype || initializer.value_type is PropertyPrototype) {
153 2 : error = true;
154 2 : Report.error (initializer.source_reference, "Access to instance member `%s' denied", initializer.symbol_reference.get_full_name ());
155 2 : return false;
156 : }
157 :
158 20397 : bool nullable = variable_type.nullable;
159 20397 : bool value_owned = variable_type.value_owned;
160 20397 : bool is_dynamic = variable_type.is_dynamic;
161 20397 : variable_type = initializer.value_type.copy ();
162 20397 : variable_type.value_owned = value_owned;
163 20397 : variable_type.floating_reference = false;
164 20397 : if (nullable) {
165 10 : variable_type.nullable = true;
166 : }
167 20397 : if (is_dynamic) {
168 8 : variable_type.is_dynamic = true;
169 : }
170 :
171 20397 : initializer.target_type = variable_type;
172 20397 : variable_type.check (context);
173 : }
174 :
175 159991 : if (!external_package) {
176 : // check symbol availability
177 12719 : if (variable_type.type_symbol != null) {
178 12150 : variable_type.type_symbol.version.check (context, source_reference);
179 : }
180 : }
181 :
182 159991 : unowned ArrayType? variable_array_type = variable_type as ArrayType;
183 9004 : if (variable_array_type != null && variable_array_type.inline_allocated
184 44 : && initializer is ArrayCreationExpression && ((ArrayCreationExpression) initializer).initializer_list == null) {
185 2 : Report.warning (source_reference, "Inline allocated arrays don't require an explicit instantiation");
186 2 : initializer = null;
187 : }
188 :
189 159991 : if (variable_array_type != null && variable_array_type.inline_allocated
190 44 : && variable_array_type.length == null && !(initializer is ArrayCreationExpression)) {
191 2 : error = true;
192 2 : Report.error (source_reference, "Inline allocated array requires either a given length or an initializer");
193 : }
194 :
195 159991 : if (initializer != null && !initializer.error) {
196 93179 : if (initializer.value_type is MethodType) {
197 92 : if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
198 0 : error = true;
199 0 : Report.error (initializer.source_reference, "expression type not allowed as initializer");
200 0 : return false;
201 : }
202 :
203 92 : if (variable_type is DelegateType) {
204 : /* check whether method matches callback type */
205 91 : if (!initializer.value_type.compatible (variable_type)) {
206 5 : unowned Method m = (Method) initializer.symbol_reference;
207 5 : unowned Delegate cb = ((DelegateType) variable_type).delegate_symbol;
208 5 : error = true;
209 5 : Report.error (source_reference, "Declaration of method `%s' is not compatible with delegate `%s'", m.get_full_name (), cb.get_full_name ());
210 5 : return false;
211 : }
212 : } else {
213 1 : error = true;
214 1 : Report.error (initializer.source_reference, "expression type not allowed as initializer");
215 1 : return false;
216 : }
217 93087 : } else if (initializer.value_type == null) {
218 1 : error = true;
219 1 : Report.error (initializer.source_reference, "expression type not allowed as initializer");
220 1 : return false;
221 : }
222 :
223 93172 : if (!initializer.value_type.compatible (variable_type)) {
224 14 : error = true;
225 14 : Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'", initializer.value_type.to_string (), variable_type.to_string ());
226 14 : return false;
227 93158 : } else if (variable_type is EnumValueType && initializer.value_type is IntegerType
228 3 : && (!(initializer is IntegerLiteral) || ((IntegerLiteral) initializer).value != "0")) {
229 : //FIXME This will have to be an error in the future?
230 1 : Report.notice (source_reference, "Assignment: Unsafe conversion from `%s' to `%s'", initializer.value_type.to_string (), variable_type.to_string ());
231 : }
232 :
233 93158 : if (variable_array_type != null && variable_array_type.inline_allocated && !variable_array_type.fixed_length && is_initializer_list) {
234 4 : variable_array_type.length = new IntegerLiteral (initializer_size.to_string ());
235 4 : variable_array_type.fixed_length = true;
236 4 : variable_array_type.nullable = false;
237 : }
238 :
239 93158 : if (variable_array_type != null && variable_array_type.inline_allocated && initializer.value_type is ArrayType == false) {
240 0 : error = true;
241 0 : Report.error (source_reference, "only arrays are allowed as initializer for arrays with fixed length");
242 0 : return false;
243 : }
244 :
245 93158 : if (initializer.value_type.is_disposable ()) {
246 : /* rhs transfers ownership of the expression */
247 23165 : if (!(variable_type is PointerType) && !variable_type.value_owned) {
248 : /* lhs doesn't own the value */
249 1 : error = true;
250 1 : Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
251 1 : return false;
252 : }
253 : }
254 : }
255 :
256 : // current_symbol is a Method if this is the `result'
257 : // variable used for postconditions
258 159969 : unowned Block? block = context.analyzer.current_symbol as Block;
259 159955 : if (block != null) {
260 159955 : block.add_local_variable (this);
261 : }
262 :
263 159969 : active = true;
264 :
265 159969 : return !error;
266 : }
267 : }
|