codegen: Fix floating reference regression with Variants
[vala-gnome.git] / vala / valainterface.vala
blob1fda7951264f8b231a8cb43373ccbe8bea74cb29
1 /* valainterface.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 class declaration in the source code.
28 public class Vala.Interface : ObjectTypeSymbol {
29 private List<DataType> prerequisites = new ArrayList<DataType> ();
31 private List<Symbol> virtuals = new ArrayList<Symbol> ();
33 /**
34 * Creates a new interface.
36 * @param name type name
37 * @param source_reference reference to source code
38 * @return newly created interface
40 public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
41 base (name, source_reference, comment);
44 /**
45 * Adds the specified interface or class to the list of prerequisites of
46 * this interface.
48 * @param type an interface or class reference
50 public void add_prerequisite (DataType type) {
51 prerequisites.add (type);
52 type.parent_node = this;
55 /**
56 * Returns a copy of the base type list.
58 * @return list of base types
60 public List<DataType> get_prerequisites () {
61 return prerequisites;
64 /**
65 * Adds the specified method as a member to this interface.
67 * @param m a method
69 public override void add_method (Method m) {
70 if (m is CreationMethod) {
71 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
73 m.error = true;
74 return;
76 if (m.binding == MemberBinding.INSTANCE) {
77 m.this_parameter = new Parameter ("this", get_this_type ());
78 m.scope.add (m.this_parameter.name, m.this_parameter);
80 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
81 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
82 m.result_var.is_result = true;
85 base.add_method (m);
88 /**
89 * Adds the specified property as a member to this interface.
91 * @param prop a property
93 public override void add_property (Property prop) {
94 if (prop.field != null) {
95 Report.error (prop.source_reference, "automatic properties are not allowed in interfaces");
97 prop.error = true;
98 return;
101 base.add_property (prop);
103 prop.this_parameter = new Parameter ("this", new ObjectType (this));
104 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
107 public virtual List<Symbol> get_virtuals () {
108 return virtuals;
111 public override void accept (CodeVisitor visitor) {
112 visitor.visit_interface (this);
115 public override void accept_children (CodeVisitor visitor) {
116 foreach (DataType type in prerequisites) {
117 type.accept (visitor);
120 foreach (TypeParameter p in get_type_parameters ()) {
121 p.accept (visitor);
124 /* process enums first to avoid order problems in C code */
125 foreach (Enum en in get_enums ()) {
126 en.accept (visitor);
129 foreach (Method m in get_methods ()) {
130 m.accept (visitor);
133 foreach (Field f in get_fields ()) {
134 f.accept (visitor);
137 foreach (Constant c in get_constants ()) {
138 c.accept (visitor);
141 foreach (Property prop in get_properties ()) {
142 prop.accept (visitor);
145 foreach (Signal sig in get_signals ()) {
146 sig.accept (visitor);
149 foreach (Class cl in get_classes ()) {
150 cl.accept (visitor);
153 foreach (Struct st in get_structs ()) {
154 st.accept (visitor);
157 foreach (Delegate d in get_delegates ()) {
158 d.accept (visitor);
162 public override bool is_reference_type () {
163 return true;
166 public override bool is_subtype_of (TypeSymbol t) {
167 if (this == t) {
168 return true;
171 foreach (DataType prerequisite in prerequisites) {
172 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
173 return true;
177 return false;
180 public override void replace_type (DataType old_type, DataType new_type) {
181 for (int i = 0; i < prerequisites.size; i++) {
182 if (prerequisites[i] == old_type) {
183 prerequisites[i] = new_type;
184 new_type.parent_node = this;
185 return;
190 public override bool check (CodeContext context) {
191 if (checked) {
192 return !error;
195 checked = true;
197 var old_source_file = context.analyzer.current_source_file;
198 var old_symbol = context.analyzer.current_symbol;
200 if (source_reference != null) {
201 context.analyzer.current_source_file = source_reference.file;
203 context.analyzer.current_symbol = this;
205 foreach (DataType prerequisite_reference in get_prerequisites ()) {
206 // check whether prerequisite is at least as accessible as the interface
207 if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) {
208 error = true;
209 Report.error (source_reference, "prerequisite `%s' is less accessible than interface `%s'".printf (prerequisite_reference.to_string (), get_full_name ()));
210 return false;
214 /* check prerequisites */
215 Class prereq_class = null;
216 foreach (DataType prereq in get_prerequisites ()) {
217 TypeSymbol class_or_interface = prereq.data_type;
218 /* skip on previous errors */
219 if (class_or_interface == null) {
220 error = true;
221 continue;
224 if (!(class_or_interface is ObjectTypeSymbol)) {
225 error = true;
226 Report.error (source_reference, "Prerequisite `%s' of interface `%s' is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
227 return false;
230 /* interfaces are not allowed to have multiple instantiable prerequisites */
231 if (class_or_interface is Class) {
232 if (prereq_class != null) {
233 error = true;
234 Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
235 return false;
238 prereq_class = (Class) class_or_interface;
242 foreach (DataType type in prerequisites) {
243 type.check (context);
246 foreach (TypeParameter p in get_type_parameters ()) {
247 p.check (context);
250 foreach (Enum en in get_enums ()) {
251 en.check (context);
254 foreach (Field f in get_fields ()) {
255 f.check (context);
258 foreach (Constant c in get_constants ()) {
259 c.check (context);
262 if (context.abi_stability) {
263 foreach (Symbol s in get_members ()) {
264 if (s is Method) {
265 var m = (Method) s;
266 m.check (context);
267 if (m.is_virtual || m.is_abstract) {
268 virtuals.add (m);
270 } else if (s is Signal) {
271 var sig = (Signal) s;
272 sig.check (context);
273 if (sig.is_virtual) {
274 virtuals.add (sig);
276 } else if (s is Property) {
277 var prop = (Property) s;
278 prop.check (context);
279 if (prop.is_virtual || prop.is_abstract) {
280 virtuals.add (prop);
284 } else {
285 foreach (Method m in get_methods ()) {
286 m.check (context);
287 if (m.is_virtual || m.is_abstract) {
288 virtuals.add (m);
292 foreach (Signal sig in get_signals ()) {
293 sig.check (context);
294 if (sig.is_virtual) {
295 virtuals.add (sig);
299 foreach (Property prop in get_properties ()) {
300 prop.check (context);
301 if (prop.is_virtual || prop.is_abstract) {
302 virtuals.add (prop);
307 foreach (Class cl in get_classes ()) {
308 cl.check (context);
311 foreach (Struct st in get_structs ()) {
312 st.check (context);
315 foreach (Delegate d in get_delegates ()) {
316 d.check (context);
319 Map<int, Symbol>? positions = new HashMap<int, Symbol> ();
320 bool ordered_seen = false;
321 bool unordered_seen = false;
322 foreach (Symbol sym in virtuals) {
323 int ordering = sym.get_attribute_integer ("CCode", "ordering", -1);
324 if (ordering < -1) {
325 Report.error (sym.source_reference, "%s: Invalid ordering".printf (sym.get_full_name ()));
326 // Mark state as invalid
327 error = true;
328 ordered_seen = true;
329 unordered_seen = true;
330 continue;
332 bool ordered = ordering != -1;
333 if (ordered && unordered_seen && !ordered_seen) {
334 Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
335 error = true;
337 ordered_seen = ordered_seen || ordered;
338 if (!ordered && !unordered_seen && ordered_seen) {
339 Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
340 error = true;
342 unordered_seen = unordered_seen || !ordered;
343 if (!ordered_seen || !unordered_seen) {
344 if (ordered) {
345 Symbol? prev = positions[ordering];
346 if (prev != null) {
347 Report.error (sym.source_reference, "%s: Duplicate ordering (previous virtual with the same position is %s)".printf (sym.get_full_name (), prev.name));
348 error = true;
350 positions[ordering] = sym;
354 if (ordered_seen) {
355 for (int i = 0; i < virtuals.size; i++) {
356 Symbol? sym = positions[i];
357 if (sym == null) {
358 Report.error (source_reference, "%s: Gap in ordering in position %d".printf (get_full_name (), i));
359 error = true;
361 if (!error) {
362 virtuals[i] = sym;
367 context.analyzer.current_source_file = old_source_file;
368 context.analyzer.current_symbol = old_symbol;
370 return !error;