Do not free values returned via g_object_get prematurely, require
[vala-lang.git] / vala / valalocalvariable.vala
blob59ddf8eb4d62b94abc4aab473cc0923169557a5c
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 (initializer != null) {
146 if (initializer.value_type == null) {
147 if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
148 error = true;
149 Report.error (source_reference, "expression type not allowed as initializer");
150 return false;
153 if (initializer.symbol_reference is Method &&
154 variable_type is DelegateType) {
155 var m = (Method) initializer.symbol_reference;
156 var dt = (DelegateType) variable_type;
157 var cb = dt.delegate_symbol;
159 /* check whether method matches callback type */
160 if (!cb.matches_method (m)) {
161 error = true;
162 Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
163 return false;
166 initializer.value_type = variable_type;
167 } else {
168 error = true;
169 Report.error (source_reference, "expression type not allowed as initializer");
170 return false;
174 if (!initializer.value_type.compatible (variable_type)) {
175 error = true;
176 Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
177 return false;
180 if (initializer.value_type.is_disposable ()) {
181 /* rhs transfers ownership of the expression */
182 if (!(variable_type is PointerType) && !variable_type.value_owned) {
183 /* lhs doesn't own the value */
184 error = true;
185 Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
186 return false;
191 analyzer.current_source_file.add_type_dependency (variable_type, SourceFileDependencyType.SOURCE);
193 analyzer.current_symbol.scope.add (name, this);
195 var block = (Block) analyzer.current_symbol;
196 block.add_local_variable (this);
198 active = true;
200 return !error;