vala: Allow read-only properties
[vala-gnome.git] / vala / valalocalvariable.vala
blob22d7c6991835302b7cd0b6b7f57aec4f38c46c30
1 /* valalocalvariable.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 local variable declaration in the source code.
28 public class Vala.LocalVariable : Variable {
29 public bool is_result { get; set; }
31 public bool captured { get; set; }
33 public bool init { get; set; }
35 /**
36 * Creates a new local variable.
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
43 public LocalVariable (DataType? variable_type, string name, Expression? initializer = null, SourceReference? source_reference = null) {
44 base (variable_type, name, initializer, source_reference);
47 public override void accept (CodeVisitor visitor) {
48 visitor.visit_local_variable (this);
51 public override void accept_children (CodeVisitor visitor) {
52 if (initializer != null) {
53 initializer.accept (visitor);
55 visitor.visit_end_full_expression (initializer);
58 if (variable_type != null) {
59 variable_type.accept (visitor);
63 public override void replace_expression (Expression old_node, Expression new_node) {
64 if (initializer == old_node) {
65 initializer = new_node;
69 public override void replace_type (DataType old_type, DataType new_type) {
70 if (variable_type == old_type) {
71 variable_type = new_type;
75 public override bool check (CodeContext context) {
76 if (checked) {
77 return !error;
80 checked = true;
82 if (variable_type != null) {
83 if (variable_type is VoidType) {
84 error = true;
85 Report.error (source_reference, "'void' not supported as variable type");
86 return false;
88 variable_type.check (context);
91 // Catch initializer list transformation:
92 bool is_initializer_list = false;
93 int initializer_size = -1;
95 if (initializer != null) {
96 initializer.target_type = variable_type;
98 if (initializer is InitializerList) {
99 initializer_size = ((InitializerList) initializer).size;
100 is_initializer_list = true;
103 initializer.check (context);
106 if (variable_type == null) {
107 /* var type */
109 if (initializer == null) {
110 error = true;
111 Report.error (source_reference, "var declaration not allowed without initializer");
112 return false;
114 if (initializer.value_type == null) {
115 error = true;
116 Report.error (source_reference, "var declaration not allowed with non-typed initializer");
117 return false;
119 if (initializer.value_type is FieldPrototype) {
120 error = true;
121 Report.error (initializer.source_reference, "Access to instance member `%s' denied".printf (initializer.symbol_reference.get_full_name ()));
122 return false;
125 variable_type = initializer.value_type.copy ();
126 variable_type.value_owned = true;
127 variable_type.floating_reference = false;
129 initializer.target_type = variable_type;
132 if (initializer != null && !initializer.error) {
133 if (initializer.value_type == null) {
134 if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
135 error = true;
136 Report.error (source_reference, "expression type not allowed as initializer");
137 return false;
140 if (initializer.symbol_reference is Method &&
141 variable_type is DelegateType) {
142 var m = (Method) initializer.symbol_reference;
143 var dt = (DelegateType) variable_type;
144 var cb = dt.delegate_symbol;
146 /* check whether method matches callback type */
147 if (!cb.matches_method (m, dt)) {
148 error = true;
149 Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
150 return false;
153 initializer.value_type = variable_type;
154 } else {
155 error = true;
156 Report.error (source_reference, "expression type not allowed as initializer");
157 return false;
161 if (!initializer.value_type.compatible (variable_type)) {
162 error = true;
163 Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
164 return false;
168 ArrayType variable_array_type = variable_type as ArrayType;
169 if (variable_array_type != null && variable_array_type.inline_allocated && !variable_array_type.fixed_length && is_initializer_list) {
170 variable_array_type.length = new IntegerLiteral (initializer_size.to_string ());
171 variable_array_type.fixed_length = true;
172 variable_array_type.nullable = false;
175 if (variable_array_type != null && variable_array_type.inline_allocated && initializer.value_type is ArrayType == false) {
176 error = true;
177 Report.error (source_reference, "only arrays are allowed as initializer for arrays with fixed length");
178 return false;
181 if (initializer.value_type.is_disposable ()) {
182 /* rhs transfers ownership of the expression */
183 if (!(variable_type is PointerType) && !variable_type.value_owned) {
184 /* lhs doesn't own the value */
185 error = true;
186 Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
187 return false;
192 context.analyzer.current_symbol.scope.add (name, this);
194 // current_symbol is a Method if this is the `result'
195 // variable used for postconditions
196 var block = context.analyzer.current_symbol as Block;
197 if (block != null) {
198 block.add_local_variable (this);
201 active = true;
203 return !error;