Release 0.41.92
[vala-gnome.git] / vala / valadatatype.vala
blob6d4876344a8f8e423b7c0b67f3e5d8084c5c31e6
1 /* valadatatype.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * A reference to a data type. This is used to specify static types of
29 * expressions.
31 public abstract class Vala.DataType : CodeNode {
32 /**
33 * Specifies that the expression or variable owns the value.
35 public bool value_owned { get; set; }
37 /**
38 * Specifies that the expression may be null.
40 public bool nullable { get; set; }
42 /**
43 * The referred data type.
45 public weak TypeSymbol data_type { get; set; }
47 /**
48 * Specifies that the expression transfers a floating reference.
50 public bool floating_reference { get; set; }
52 /**
53 * Specifies that the type supports dynamic lookup.
55 public bool is_dynamic { get; set; }
57 private List<DataType> type_argument_list;
58 private static List<DataType> _empty_type_list;
60 /**
61 * Appends the specified type as generic type argument.
63 * @param arg a type reference
65 public void add_type_argument (DataType arg) {
66 if (type_argument_list == null) {
67 type_argument_list = new ArrayList<DataType> ();
69 type_argument_list.add (arg);
70 arg.parent_node = this;
73 /**
74 * Returns a copy of the list of generic type arguments.
76 * @return type argument list
78 public List<DataType> get_type_arguments () {
79 if (type_argument_list != null) {
80 return type_argument_list;
82 if (_empty_type_list == null) {
83 _empty_type_list = new ArrayList<DataType> ();
85 return _empty_type_list;
88 public bool has_type_arguments () {
89 if (type_argument_list == null) {
90 return false;
93 return type_argument_list.size > 0;
96 /**
97 * Removes all generic type arguments.
99 public void remove_all_type_arguments () {
100 type_argument_list = null;
103 public override void accept (CodeVisitor visitor) {
104 visitor.visit_data_type (this);
107 public override void accept_children (CodeVisitor visitor) {
108 if (type_argument_list != null && type_argument_list.size > 0) {
109 foreach (DataType type_arg in type_argument_list) {
110 type_arg.accept (visitor);
115 public override string to_string () {
116 return to_qualified_string (null);
119 public virtual string to_qualified_string (Scope? scope = null) {
120 // logic temporarily duplicated in DelegateType class
122 string s;
124 if (data_type != null) {
125 Symbol global_symbol = data_type;
126 while (global_symbol.parent_symbol.name != null) {
127 global_symbol = global_symbol.parent_symbol;
130 Symbol sym = null;
131 Scope parent_scope = scope;
132 while (sym == null && parent_scope != null) {
133 sym = parent_scope.lookup (global_symbol.name);
134 parent_scope = parent_scope.parent_scope;
137 if (sym != null && global_symbol != sym) {
138 s = "global::" + data_type.get_full_name ();;
139 } else {
140 s = data_type.get_full_name ();
142 } else {
143 s = "null";
146 var type_args = get_type_arguments ();
147 if (type_args.size > 0) {
148 s += "<";
149 bool first = true;
150 foreach (DataType type_arg in type_args) {
151 if (!first) {
152 s += ",";
153 } else {
154 first = false;
156 if (!type_arg.value_owned) {
157 s += "weak ";
159 s += type_arg.to_qualified_string (scope);
161 s += ">";
163 if (nullable) {
164 s += "?";
167 return s;
171 * Creates a shallow copy of this type reference.
173 * @return copy of this type reference
175 public abstract DataType copy ();
178 * Checks two type references for equality. May only be used with
179 * resolved type references.
181 * @param type2 a type reference
182 * @return true if this type reference is equal to type2, false
183 * otherwise
185 public virtual bool equals (DataType type2) {
186 if (type2.is_disposable () != is_disposable ()) {
187 return false;
189 if (type2.nullable != nullable) {
190 return false;
192 if (type2.data_type != data_type) {
193 return false;
195 if (type2 is GenericType || this is GenericType) {
196 if (!(type2 is GenericType) || !(this is GenericType)) {
197 return false;
199 if (!((GenericType) type2).type_parameter.equals (((GenericType) this).type_parameter)) {
200 return false;
203 if (type2.floating_reference != floating_reference) {
204 return false;
207 var type_args = get_type_arguments ();
208 var type2_args = type2.get_type_arguments ();
209 if (type2_args.size != type_args.size) {
210 return false;
213 for (int i = 0; i < type_args.size; i++) {
214 if (!type2_args[i].equals (type_args[i]))
215 return false;
218 return true;
222 * Checks whether this type reference is at least as strict as the
223 * specified type reference type2.
225 * @param type2 a type reference
226 * @return true if this type reference is stricter or equal
228 public virtual bool stricter (DataType type2) {
229 if (type2.is_disposable () != is_disposable ()) {
230 return false;
233 if (!type2.nullable && nullable) {
234 return false;
237 /* temporarily ignore type parameters */
238 if (this is GenericType || type2 is GenericType) {
239 return true;
242 if (type2.data_type != data_type) {
243 // FIXME: allow this type reference to refer to a
244 // subtype of the type type2 is referring to
245 return false;
248 if (type2.floating_reference != floating_reference) {
249 return false;
252 return true;
255 public override void replace_type (DataType old_type, DataType new_type) {
256 if (type_argument_list != null) {
257 for (int i = 0; i < type_argument_list.size; i++) {
258 if (type_argument_list[i] == old_type) {
259 type_argument_list[i] = new_type;
260 return;
266 public virtual bool compatible (DataType target_type) {
267 if (CodeContext.get ().experimental_non_null && nullable && !target_type.nullable) {
268 return false;
271 if (CodeContext.get ().profile == Profile.GOBJECT && target_type.data_type != null) {
272 if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvalue_type.data_type)) {
273 // allow implicit conversion to GValue
274 return true;
277 if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvariant_type.data_type)) {
278 // allow implicit conversion to GVariant
279 return true;
283 if (target_type is PointerType) {
284 /* any reference or array type or pointer type can be cast to a generic pointer */
285 if (this is GenericType ||
286 (data_type != null && (
287 data_type.is_reference_type () ||
288 this is DelegateType))) {
289 return true;
292 return false;
295 /* temporarily ignore type parameters */
296 if (target_type is GenericType) {
297 return true;
300 if (this is ArrayType != target_type is ArrayType) {
301 return false;
304 if (data_type is Enum && target_type.data_type is Struct && ((Struct) target_type.data_type).is_integer_type ()) {
305 return true;
308 if (data_type != null && target_type.data_type != null && data_type.is_subtype_of (target_type.data_type)) {
309 var base_type = SemanticAnalyzer.get_instance_base_type_for_member(this, target_type.data_type, this);
310 // check compatibility of generic type arguments
311 var base_type_args = base_type.get_type_arguments();
312 var target_type_args = target_type.get_type_arguments();
313 if (base_type_args.size == target_type_args.size) {
314 for (int i = 0; i < base_type_args.size; i++) {
315 // mutable generic types require type argument equality,
316 // not just one way compatibility
317 // as we do not currently have immutable generic container types,
318 // the additional check would be very inconvenient, so we
319 // skip the additional check for now
320 if (!base_type_args[i].compatible (target_type_args[i])) {
321 return false;
325 return true;
328 if (data_type is Struct && target_type.data_type is Struct) {
329 var expr_struct = (Struct) data_type;
330 var expect_struct = (Struct) target_type.data_type;
332 /* integer types may be implicitly cast to floating point types */
333 if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
334 return true;
337 if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
338 (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
339 if (expr_struct.rank <= expect_struct.rank) {
340 return true;
345 return false;
349 * Returns whether instances of this type are invokable.
351 * @return true if invokable, false otherwise
353 public virtual bool is_invokable () {
354 return false;
358 * Returns the return type of this invokable.
360 * @return return type
362 public virtual DataType? get_return_type () {
363 return null;
367 * Returns copy of the list of invocation parameters.
369 * @return parameter list
371 public virtual List<Parameter>? get_parameters () {
372 return null;
375 public virtual bool is_reference_type_or_type_parameter () {
376 return (data_type != null &&
377 data_type.is_reference_type ()) ||
378 this is GenericType;
381 public virtual bool is_array () {
382 return false;
385 // check whether this type is at least as accessible as the specified symbol
386 public virtual bool is_accessible (Symbol sym) {
387 foreach (var type_arg in get_type_arguments ()) {
388 if (!type_arg.is_accessible (sym)) {
389 return false;
392 if (data_type != null) {
393 return data_type.is_accessible (sym);
395 return true;
398 public virtual Symbol? get_member (string member_name) {
399 if (data_type != null) {
400 return SemanticAnalyzer.symbol_lookup_inherited (data_type, member_name);
402 return null;
405 public virtual Symbol? get_pointer_member (string member_name) {
406 return null;
410 * Checks whether this data type references a real struct. A real struct
411 * is a struct which is not a simple (fundamental) type.
413 public virtual bool is_real_struct_type () {
414 var s = data_type as Struct;
415 if (s != null && !s.is_simple_type ()) {
416 return true;
418 return false;
421 public bool is_real_non_null_struct_type () {
422 return is_real_struct_type () && !nullable;
426 * Returns whether the value needs to be disposed, i.e. whether
427 * allocated memory or other resources need to be released when
428 * the value is no longer needed.
430 public virtual bool is_disposable () {
431 if (!value_owned) {
432 return false;
435 if (is_reference_type_or_type_parameter ()) {
436 return true;
438 return false;
441 public virtual DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, CodeNode node_reference) {
442 DataType result = this.copy ();
444 if (derived_instance_type == null && method_type_arguments == null) {
445 return result;
448 if (result is GenericType) {
449 result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_type_arguments, (GenericType) result, node_reference);
450 // don't try to resolve type arguments of returned actual type
451 // they can never be resolved and are not related to the instance type
452 } else if (result.type_argument_list != null) {
453 // recursely get actual types for type arguments
454 for (int i = 0; i < result.type_argument_list.size; i++) {
455 result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_type_arguments, node_reference);
459 return result;
463 * Search for the type parameter in this formal type and match it in
464 * value_type.
466 public virtual DataType? infer_type_argument (TypeParameter type_param, DataType value_type) {
467 var value_type_arg_it = value_type.get_type_arguments ().iterator ();
468 foreach (var formal_type_arg in this.get_type_arguments ()) {
469 if (value_type_arg_it.next ()) {
470 var inferred_type = formal_type_arg.infer_type_argument (type_param, value_type_arg_it.get ());
471 if (inferred_type != null) {
472 return inferred_type;
477 return null;
481 * Returns a stringified representation used for detailed error output
483 * @param override_name used as name if given
484 * @return stringified representation
486 public virtual string to_prototype_string (string? override_name = null) {
487 return "%s%s".printf (is_weak () ? "unowned " : "", to_qualified_string ());
490 public bool is_weak () {
491 if (this.value_owned) {
492 return false;
493 } else if (this is VoidType || this is PointerType) {
494 return false;
495 } else if (this is ValueType) {
496 if (this.nullable) {
497 // nullable structs are heap allocated
498 return true;
501 // TODO return true for structs with destroy
502 return false;
505 return true;