gstreamer-pbutils-0.10: Ownership transfer fixes
[vala-lang.git] / vala / valalocalvariable.vala
blobcdc9b3a69f12ef1117d7d4f703c38225fd41aab3
1 /* valalocalvariable.vala
3 * Copyright (C) 2006-2009 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 : Symbol {
29 /**
30 * The optional initializer expression.
32 public Expression? initializer {
33 get {
34 return _initializer;
36 set {
37 _initializer = value;
38 if (_initializer != null) {
39 _initializer.parent_node = this;
44 /**
45 * The variable type.
47 public DataType? variable_type {
48 get { return _variable_type; }
49 set {
50 _variable_type = value;
51 if (_variable_type != null) {
52 _variable_type.parent_node = this;
57 /**
58 * Floating variables may only be accessed exactly once.
60 public bool floating { get; set; }
62 private Expression? _initializer;
63 private DataType? _variable_type;
65 /**
66 * Creates a new local variable.
68 * @param name name of the variable
69 * @param init optional initializer expression
70 * @param source reference to source code
71 * @return newly created variable declarator
73 public LocalVariable (DataType? variable_type, string name, Expression? initializer = null, SourceReference? source_reference = null) {
74 base (name, source_reference);
75 this.variable_type = variable_type;
76 this.initializer = initializer;
79 public override void accept (CodeVisitor visitor) {
80 visitor.visit_local_variable (this);
83 public override void accept_children (CodeVisitor visitor) {
84 if (initializer != null) {
85 initializer.accept (visitor);
87 visitor.visit_end_full_expression (initializer);
90 if (variable_type != null) {
91 variable_type.accept (visitor);
95 public override void replace_expression (Expression old_node, Expression new_node) {
96 if (initializer == old_node) {
97 initializer = new_node;
101 public override void replace_type (DataType old_type, DataType new_type) {
102 if (variable_type == old_type) {
103 variable_type = new_type;
107 public override bool check (SemanticAnalyzer analyzer) {
108 if (checked) {
109 return !error;
112 checked = true;
114 if (variable_type != null) {
115 variable_type.check (analyzer);
118 if (initializer != null) {
119 initializer.target_type = variable_type;
121 initializer.check (analyzer);
124 if (variable_type == null) {
125 /* var type */
127 if (initializer == null) {
128 error = true;
129 Report.error (source_reference, "var declaration not allowed without initializer");
130 return false;
132 if (initializer.value_type == null) {
133 error = true;
134 Report.error (source_reference, "var declaration not allowed with non-typed initializer");
135 return false;
138 variable_type = initializer.value_type.copy ();
139 variable_type.value_owned = true;
140 variable_type.floating_reference = false;
142 initializer.target_type = variable_type;
145 if (name == "result") {
146 // warn if type of `result' variable is incompatible with return type
147 // as an implicit `result' variable might be introduced to be used
148 // by Vala postconditions and implicit checks generated by the code generated
149 if (analyzer.current_return_type == null
150 || !variable_type.compatible (analyzer.current_return_type)) {
151 Report.warning (source_reference, "result variable type incompatible with return type");
155 if (initializer != null) {
156 if (initializer.value_type == null) {
157 if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
158 error = true;
159 Report.error (source_reference, "expression type not allowed as initializer");
160 return false;
163 if (initializer.symbol_reference is Method &&
164 variable_type is DelegateType) {
165 var m = (Method) initializer.symbol_reference;
166 var dt = (DelegateType) variable_type;
167 var cb = dt.delegate_symbol;
169 /* check whether method matches callback type */
170 if (!cb.matches_method (m)) {
171 error = true;
172 Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
173 return false;
176 initializer.value_type = variable_type;
177 } else {
178 error = true;
179 Report.error (source_reference, "expression type not allowed as initializer");
180 return false;
184 if (!initializer.value_type.compatible (variable_type)) {
185 error = true;
186 Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
187 return false;
190 if (initializer.value_type.is_disposable ()) {
191 /* rhs transfers ownership of the expression */
192 if (!(variable_type is PointerType) && !variable_type.value_owned) {
193 /* lhs doesn't own the value */
194 error = true;
195 Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
196 return false;
201 analyzer.current_source_file.add_type_dependency (variable_type, SourceFileDependencyType.SOURCE);
203 analyzer.current_symbol.scope.add (name, this);
205 // current_symbol is a Method if this is the `result'
206 // variable used for postconditions
207 var block = analyzer.current_symbol as Block;
208 if (block != null) {
209 block.add_local_variable (this);
212 active = true;
214 return !error;