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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * A reference to a data type. This is used to specify static types of
31 public abstract class Vala
.DataType
: CodeNode
{
33 * Specifies that the expression or variable owns the value.
35 public bool value_owned
{ get; set; }
38 * Specifies that the expression may be null.
40 public bool nullable
{ get; set; }
43 * The referred data type.
45 public weak TypeSymbol data_type
{ get; set; }
48 * The referred generic type parameter.
50 public TypeParameter type_parameter
{ get; set; }
53 * Specifies that the expression transfers a floating reference.
55 public bool floating_reference
{ get; set; }
58 * Specifies that the type supports dynamic lookup.
60 public bool is_dynamic
{ get; set; }
62 private List
<DataType
> type_argument_list
;
63 private static List
<DataType
> _empty_type_list
;
66 * Appends the specified type as generic type argument.
68 * @param arg a type reference
70 public void add_type_argument (DataType arg
) {
71 if (type_argument_list
== null) {
72 type_argument_list
= new ArrayList
<DataType
> ();
74 type_argument_list
.add (arg
);
75 arg
.parent_node
= this
;
79 * Returns a copy of the list of generic type arguments.
81 * @return type argument list
83 public List
<DataType
> get_type_arguments () {
84 if (type_argument_list
!= null) {
85 return type_argument_list
;
87 if (_empty_type_list
== null) {
88 _empty_type_list
= new ArrayList
<DataType
> ();
90 return _empty_type_list
;
93 public bool has_type_arguments () {
94 if (type_argument_list
== null) {
98 return type_argument_list
.size
> 0;
102 * Removes all generic type arguments.
104 public void remove_all_type_arguments () {
105 type_argument_list
= null;
108 public override void accept (CodeVisitor visitor
) {
109 visitor
.visit_data_type (this
);
112 public override void accept_children (CodeVisitor visitor
) {
113 if (type_argument_list
!= null && type_argument_list
.size
> 0) {
114 foreach (DataType type_arg
in type_argument_list
) {
115 type_arg
.accept (visitor
);
120 public override string to_string () {
121 return to_qualified_string (null);
124 public virtual string to_qualified_string (Scope? scope
= null) {
125 // logic temporarily duplicated in DelegateType class
129 if (data_type
!= null) {
130 Symbol global_symbol
= data_type
;
131 while (global_symbol
.parent_symbol
.name
!= null) {
132 global_symbol
= global_symbol
.parent_symbol
;
136 Scope parent_scope
= scope
;
137 while (sym
== null && parent_scope
!= null) {
138 sym
= parent_scope
.lookup (global_symbol
.name
);
139 parent_scope
= parent_scope
.parent_scope
;
142 if (sym
!= null && global_symbol
!= sym
) {
143 s
= "global::" + data_type
.get_full_name ();;
145 s
= data_type
.get_full_name ();
151 var type_args
= get_type_arguments ();
152 if (type_args
.size
> 0) {
155 foreach (DataType type_arg
in type_args
) {
161 if (!type_arg
.value_owned
) {
164 s
+= type_arg
.to_qualified_string (scope
);
176 * Creates a shallow copy of this type reference.
178 * @return copy of this type reference
180 public abstract DataType
copy ();
183 * Checks two type references for equality. May only be used with
184 * resolved type references.
186 * @param type2 a type reference
187 * @return true if this type reference is equal to type2, false
190 public virtual bool equals (DataType type2
) {
191 if (type2
.is_disposable () != is_disposable ()) {
194 if (type2
.nullable
!= nullable
) {
197 if (type2
.data_type
!= data_type
) {
200 if (type2
.type_parameter
!= null || type_parameter
!= null) {
201 if (type2
.type_parameter
== null || type_parameter
== null) {
204 if (!type2
.type_parameter
.equals (type_parameter
)) {
208 if (type2
.floating_reference
!= floating_reference
) {
212 var type_args
= get_type_arguments ();
213 var type2_args
= type2
.get_type_arguments ();
214 if (type2_args
.size
!= type_args
.size
) {
218 for (int i
= 0; i
< type_args
.size
; i
++) {
219 if (!type2_args
[i
].equals (type_args
[i
]))
227 * Checks whether this type reference is at least as strict as the
228 * specified type reference type2.
230 * @param type2 a type reference
231 * @return true if this type reference is stricter or equal
233 public virtual bool stricter (DataType type2
) {
234 if (type2
.is_disposable () != is_disposable ()) {
238 if (!type2
.nullable
&& nullable
) {
242 /* temporarily ignore type parameters */
243 if (type_parameter
!= null || type2
.type_parameter
!= null) {
247 if (type2
.data_type
!= data_type
) {
248 // FIXME: allow this type reference to refer to a
249 // subtype of the type type2 is referring to
253 if (type2
.floating_reference
!= floating_reference
) {
260 public override void replace_type (DataType old_type
, DataType new_type
) {
261 if (type_argument_list
!= null) {
262 for (int i
= 0; i
< type_argument_list
.size
; i
++) {
263 if (type_argument_list
[i
] == old_type
) {
264 type_argument_list
[i
] = new_type
;
271 public virtual bool compatible (DataType target_type
) {
272 if (CodeContext
.get ().experimental_non_null
&& nullable
&& !target_type
.nullable
) {
276 if (target_type
.data_type
!= null) {
277 if (target_type
.data_type
.is_subtype_of (CodeContext
.get ().analyzer
.gvalue_type
.data_type
)) {
278 // allow implicit conversion to GValue
282 if (target_type
.data_type
.is_subtype_of (CodeContext
.get ().analyzer
.gvariant_type
.data_type
)) {
283 // allow implicit conversion to GVariant
288 if (target_type is PointerType
) {
289 /* any reference or array type or pointer type can be cast to a generic pointer */
290 if (type_parameter
!= null ||
291 (data_type
!= null && (
292 data_type
.is_reference_type () ||
293 this is DelegateType
))) {
300 /* temporarily ignore type parameters */
301 if (target_type
.type_parameter
!= null) {
305 if (this is ArrayType
!= target_type is ArrayType
) {
309 if (data_type is Enum
&& target_type
.data_type is Struct
&& ((Struct
) target_type
.data_type
).is_integer_type ()) {
313 if (data_type
!= null && target_type
.data_type
!= null && data_type
.is_subtype_of (target_type
.data_type
)) {
314 var base_type
= SemanticAnalyzer
.get_instance_base_type_for_member(this
, target_type
.data_type
, this
);
315 // check compatibility of generic type arguments
316 var base_type_args
= base_type
.get_type_arguments();
317 var target_type_args
= target_type
.get_type_arguments();
318 if (base_type_args
.size
== target_type_args
.size
) {
319 for (int i
= 0; i
< base_type_args
.size
; i
++) {
320 // mutable generic types require type argument equality,
321 // not just one way compatibility
322 // as we do not currently have immutable generic container types,
323 // the additional check would be very inconvenient, so we
324 // skip the additional check for now
325 if (!base_type_args
[i
].compatible (target_type_args
[i
])) {
333 if (data_type is Struct
&& target_type
.data_type is Struct
) {
334 var expr_struct
= (Struct
) data_type
;
335 var expect_struct
= (Struct
) target_type
.data_type
;
337 /* integer types may be implicitly cast to floating point types */
338 if (expr_struct
.is_integer_type () && expect_struct
.is_floating_type ()) {
342 if ((expr_struct
.is_integer_type () && expect_struct
.is_integer_type ()) ||
343 (expr_struct
.is_floating_type () && expect_struct
.is_floating_type ())) {
344 if (expr_struct
.get_rank () <= expect_struct
.get_rank ()) {
354 * Returns whether instances of this type are invokable.
356 * @return true if invokable, false otherwise
358 public virtual bool is_invokable () {
363 * Returns the return type of this invokable.
365 * @return return type
367 public virtual DataType?
get_return_type () {
372 * Returns copy of the list of invocation parameters.
374 * @return parameter list
376 public virtual List
<Parameter
>?
get_parameters () {
380 public virtual bool is_reference_type_or_type_parameter () {
381 return (data_type
!= null &&
382 data_type
.is_reference_type ()) ||
383 type_parameter
!= null;
386 public virtual bool is_array () {
390 // check whether this type is at least as accessible as the specified symbol
391 public virtual bool is_accessible (Symbol sym
) {
392 foreach (var type_arg
in get_type_arguments ()) {
393 if (!type_arg
.is_accessible (sym
)) {
397 if (data_type
!= null) {
398 return data_type
.is_accessible (sym
);
403 public virtual Symbol?
get_member (string member_name
) {
404 if (data_type
!= null) {
405 return SemanticAnalyzer
.symbol_lookup_inherited (data_type
, member_name
);
410 public virtual Symbol?
get_pointer_member (string member_name
) {
415 * Checks whether this data type references a real struct. A real struct
416 * is a struct which is not a simple (fundamental) type.
418 public virtual bool is_real_struct_type () {
419 var s
= data_type as Struct
;
420 if (s
!= null && !s
.is_simple_type ()) {
426 public bool is_real_non_null_struct_type () {
427 return is_real_struct_type () && !nullable
;
431 * Returns whether the value needs to be disposed, i.e. whether
432 * allocated memory or other resources need to be released when
433 * the value is no longer needed.
435 public virtual bool is_disposable () {
440 if (is_reference_type_or_type_parameter ()) {
446 public virtual DataType
get_actual_type (DataType? derived_instance_type
, List
<DataType
>? method_type_arguments
, CodeNode node_reference
) {
447 DataType result
= this
.copy ();
449 if (derived_instance_type
== null && method_type_arguments
== null) {
453 if (result is GenericType
) {
454 result
= SemanticAnalyzer
.get_actual_type (derived_instance_type
, method_type_arguments
, (GenericType
) result
, node_reference
);
455 // don't try to resolve type arguments of returned actual type
456 // they can never be resolved and are not related to the instance type
457 } else if (result
.type_argument_list
!= null) {
458 // recursely get actual types for type arguments
459 for (int i
= 0; i
< result
.type_argument_list
.size
; i
++) {
460 result
.type_argument_list
[i
] = result
.type_argument_list
[i
].get_actual_type (derived_instance_type
, method_type_arguments
, node_reference
);
468 * Search for the type parameter in this formal type and match it in
471 public virtual DataType?
infer_type_argument (TypeParameter type_param
, DataType value_type
) {
472 var value_type_arg_it
= value_type
.get_type_arguments ().iterator ();
473 foreach (var formal_type_arg
in this
.get_type_arguments ()) {
474 if (value_type_arg_it
.next ()) {
475 var inferred_type
= formal_type_arg
.infer_type_argument (type_param
, value_type_arg_it
.get ());
476 if (inferred_type
!= null) {
477 return inferred_type
;
486 * Returns a stringified representation used for detailed error output
488 * @param override_name used as name if given
489 * @return stringified representation
491 public virtual string to_prototype_string (string? override_name
= null) {
492 return "%s%s".printf (is_weak () ?
"unowned " : "", to_qualified_string ());
495 public bool is_weak () {
496 if (this
.value_owned
) {
498 } else if (this is VoidType
|| this is PointerType
) {
500 } else if (this is ValueType
) {
502 // nullable structs are heap allocated
506 // TODO return true for structs with destroy