valadatatype.vala 13 KB
Newer Older
1
/* valadatatype.vala
2
 *
3
 * Copyright (C) 2006-2010  Jürg Billeter
4
 * Copyright (C) 2006-2008  Raffaele Sandrini
5 6 7 8
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10 11 12 13 14 15 16 17 18 19 20 21

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
22
 *	Raffaele Sandrini <raffaele@sandrini.ch>
23 24 25 26
 */

using GLib;

27 28 29 30
/**
 * A reference to a data type. This is used to specify static types of
 * expressions.
 */
31
public abstract class Vala.DataType : CodeNode {
32
	/**
33
	 * Specifies that the expression or variable owns the value.
34
	 */
35
	public bool value_owned { get; set; }
36

37
	/**
38
	 * Specifies that the expression may be null.
39
	 */
40 41
	public bool nullable { get; set; }

42 43 44
	/**
	 * The referred data type.
	 */
45
	public weak TypeSymbol data_type { get; set; }
46

47 48 49 50
	/**
	 * Specifies that the expression transfers a floating reference.
	 */
	public bool floating_reference { get; set; }
51 52 53 54 55

	/**
	 * Specifies that the type supports dynamic lookup.
	 */
	public bool is_dynamic { get; set; }
56

57 58
	private List<DataType> type_argument_list;
	private static List<DataType> _empty_type_list;
59 60 61 62 63 64

	/**
	 * Appends the specified type as generic type argument.
	 *
	 * @param arg a type reference
	 */
65
	public void add_type_argument (DataType arg) {
66 67 68
		if (type_argument_list == null) {
			type_argument_list = new ArrayList<DataType> ();
		}
69 70
		type_argument_list.add (arg);
		arg.parent_node = this;
71
	}
72

73 74 75 76 77
	/**
	 * Returns a copy of the list of generic type arguments.
	 *
	 * @return type argument list
	 */
78
	public List<DataType> get_type_arguments () {
79 80 81 82
		if (type_argument_list != null) {
			return type_argument_list;
		}
		if (_empty_type_list == null) {
83
			_empty_type_list = new ArrayList<DataType> ();
84 85
		}
		return _empty_type_list;
86
	}
87

88 89 90 91 92 93 94 95
	public bool has_type_arguments () {
		if (type_argument_list == null) {
			return false;
		}

		return type_argument_list.size > 0;
	}

96 97 98 99
	/**
	 * Removes all generic type arguments.
	 */
	public void remove_all_type_arguments () {
100
		type_argument_list = null;
101 102
	}

103
	public override void accept (CodeVisitor visitor) {
104 105 106 107
		visitor.visit_data_type (this);
	}

	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 111
				type_arg.accept (visitor);
			}
112
		}
113
	}
114

115
	public override string to_string () {
116 117 118 119
		return to_qualified_string (null);
	}

	public virtual string to_qualified_string (Scope? scope = null) {
120 121
		// logic temporarily duplicated in DelegateType class

122 123
		string s;

124
		if (data_type != null) {
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
			Symbol global_symbol = data_type;
			while (global_symbol.parent_symbol.name != null) {
				global_symbol = global_symbol.parent_symbol;
			}

			Symbol sym = null;
			Scope parent_scope = scope;
			while (sym == null && parent_scope != null) {
				sym = parent_scope.lookup (global_symbol.name);
				parent_scope = parent_scope.parent_scope;
			}

			if (sym != null && global_symbol != sym) {
				s = "global::" + data_type.get_full_name ();;
			} else {
				s = data_type.get_full_name ();
			}
142
		} else {
143
			s = "null";
144
		}
145 146

		var type_args = get_type_arguments ();
147
		if (type_args.size > 0) {
148 149 150 151 152 153 154 155
			s += "<";
			bool first = true;
			foreach (DataType type_arg in type_args) {
				if (!first) {
					s += ",";
				} else {
					first = false;
				}
156
				if (!type_arg.value_owned) {
157 158
					s += "weak ";
				}
159
				s += type_arg.to_qualified_string (scope);
160 161 162
			}
			s += ">";
		}
163 164
		if (nullable) {
			s += "?";
165 166 167
		}

		return s;
168
	}
169

170
	/**
171
	 * Creates a shallow copy of this type reference.
172 173 174
	 *
	 * @return copy of this type reference
	 */
175 176
	public abstract DataType copy ();

177 178 179 180 181 182 183 184
	/**
	 * Checks two type references for equality. May only be used with
	 * resolved type references.
	 *
	 * @param type2 a type reference
	 * @return      true if this type reference is equal to type2, false
	 *              otherwise
	 */
185
	public virtual bool equals (DataType type2) {
186
		if (type2.is_disposable () != is_disposable ()) {
187 188
			return false;
		}
189
		if (type2.nullable != nullable) {
190 191 192 193 194
			return false;
		}
		if (type2.data_type != data_type) {
			return false;
		}
195 196
		if (type2 is GenericType || this is GenericType) {
			if (!(type2 is GenericType) || !(this is GenericType)) {
197 198
				return false;
			}
199
			if (!((GenericType) type2).type_parameter.equals (((GenericType) this).type_parameter)) {
200 201
				return false;
			}
202 203 204 205
		}
		if (type2.floating_reference != floating_reference) {
			return false;
		}
206 207 208 209 210 211 212 213 214 215 216

		var type_args = get_type_arguments ();
		var type2_args = type2.get_type_arguments ();
		if (type2_args.size != type_args.size) {
			return false;
		}

		for (int i = 0; i < type_args.size; i++) {
			if (!type2_args[i].equals (type_args[i]))
				return false;
		}
217

218 219
		return true;
	}
220

221 222 223 224 225 226 227
	/**
	 * Checks whether this type reference is at least as strict as the
	 * specified type reference type2.
	 *
	 * @param type2 a type reference
	 * @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 231
			return false;
		}
232

233
		if (!type2.nullable && nullable) {
234 235 236
			return false;
		}

237
		/* temporarily ignore type parameters */
238
		if (this is GenericType || type2 is GenericType) {
239 240 241
			return true;
		}

242 243 244 245
		if (type2.data_type != data_type) {
			// FIXME: allow this type reference to refer to a
			//        subtype of the type type2 is referring to
			return false;
246
		}
247

248 249 250
		if (type2.floating_reference != floating_reference) {
			return false;
		}
251

252
		return true;
253
	}
254

255
	public override void replace_type (DataType old_type, DataType new_type) {
256 257 258 259 260 261
		if (type_argument_list != null) {
			for (int i = 0; i < type_argument_list.size; i++) {
				if (type_argument_list[i] == old_type) {
					type_argument_list[i] = new_type;
					return;
				}
262 263 264
			}
		}
	}
265

266
	public virtual bool compatible (DataType target_type) {
267 268 269 270
		if (CodeContext.get ().experimental_non_null && nullable && !target_type.nullable) {
			return false;
		}

271
		if (CodeContext.get ().profile == Profile.GOBJECT && target_type.data_type != null) {
272 273 274 275
			if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvalue_type.data_type)) {
				// allow implicit conversion to GValue
				return true;
			}
276

277 278 279 280
			if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvariant_type.data_type)) {
				// allow implicit conversion to GVariant
				return true;
			}
281 282
		}

Jürg Billeter's avatar
Jürg Billeter committed
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 287
				(data_type != null && (
					data_type.is_reference_type () ||
Jürg Billeter's avatar
Jürg Billeter committed
288
					this is DelegateType))) {
289 290 291 292 293 294 295
				return true;
			}

			return false;
		}

		/* temporarily ignore type parameters */
296
		if (target_type is GenericType) {
297 298 299
			return true;
		}

Jürg Billeter's avatar
Jürg Billeter committed
300
		if (this is ArrayType != target_type is ArrayType) {
301 302 303 304 305 306 307
			return false;
		}

		if (data_type is Enum && target_type.data_type is Struct && ((Struct) target_type.data_type).is_integer_type ()) {
			return true;
		}

308 309
		if (data_type != null && target_type.data_type != null && data_type.is_subtype_of (target_type.data_type)) {
			var base_type = SemanticAnalyzer.get_instance_base_type_for_member(this, target_type.data_type, this);
310
			// check compatibility of generic type arguments
311 312 313 314
			var base_type_args = base_type.get_type_arguments();
			var target_type_args = target_type.get_type_arguments();
			if (base_type_args.size == target_type_args.size) {
				for (int i = 0; i < base_type_args.size; i++) {
315 316 317 318 319
					// mutable generic types require type argument equality,
					// not just one way compatibility
					// as we do not currently have immutable generic container types,
					// the additional check would be very inconvenient, so we
					// skip the additional check for now
320
					if (!base_type_args[i].compatible (target_type_args[i])) {
321 322 323 324
						return false;
					}
				}
			}
325 326 327 328 329 330 331 332 333 334 335 336 337 338
			return true;
		}

		if (data_type is Struct && target_type.data_type is Struct) {
			var expr_struct = (Struct) data_type;
			var expect_struct = (Struct) target_type.data_type;

			/* integer types may be implicitly cast to floating point types */
			if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
				return true;
			}

			if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
			    (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
339
				if (expr_struct.rank <= expect_struct.rank) {
340 341 342 343 344
					return true;
				}
			}
		}

345
		return false;
346 347
	}

348 349 350 351 352 353 354 355 356 357 358 359 360 361
	/**
	 * Returns whether instances of this type are invokable.
	 *
	 * @return true if invokable, false otherwise
	 */
	public virtual bool is_invokable () {
		return false;
	}

	/**
	 * Returns the return type of this invokable.
	 *
	 * @return return type
	 */
362
	public virtual DataType? get_return_type () {
363 364 365 366 367 368 369 370
		return null;
	}

	/**
	 * Returns copy of the list of invocation parameters.
	 *
	 * @return parameter list
	 */
371
	public virtual List<Parameter>? get_parameters () {
372 373
		return null;
	}
374 375 376 377

	public virtual bool is_reference_type_or_type_parameter () {
		return (data_type != null &&
		        data_type.is_reference_type ()) ||
378
		       this is GenericType;
379
	}
380

381
	public virtual bool is_array () {
Jürg Billeter's avatar
Jürg Billeter committed
382
		return false;
383 384
	}

385 386
	// check whether this type is at least as accessible as the specified symbol
	public virtual bool is_accessible (Symbol sym) {
387 388 389 390 391
		foreach (var type_arg in get_type_arguments ()) {
			if (!type_arg.is_accessible (sym)) {
				return false;
			}
		}
392
		if (data_type != null) {
393
			return data_type.is_accessible (sym);
394
		}
395
		return true;
396
	}
397

398 399 400 401 402 403 404
	public virtual Symbol? get_member (string member_name) {
		if (data_type != null) {
			return SemanticAnalyzer.symbol_lookup_inherited (data_type, member_name);
		}
		return null;
	}

405
	public virtual Symbol? get_pointer_member (string member_name) {
406 407
		return null;
	}
408 409 410 411 412 413 414 415 416 417 418 419

	/**
	 * Checks whether this data type references a real struct. A real struct
	 * is a struct which is not a simple (fundamental) type.
	 */
	public virtual bool is_real_struct_type () {
		var s = data_type as Struct;
		if (s != null && !s.is_simple_type ()) {
			return true;
		}
		return false;
	}
420

421 422 423 424
	public bool is_real_non_null_struct_type () {
		return is_real_struct_type () && !nullable;
	}

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	/**
	 * Returns whether the value needs to be disposed, i.e. whether
	 * allocated memory or other resources need to be released when
	 * the value is no longer needed.
	 */
	public virtual bool is_disposable () {
		if (!value_owned) {
			return false;
		}

		if (is_reference_type_or_type_parameter ()) {
			return true;
		}
		return false;
	}
440

441
	public virtual DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, CodeNode node_reference) {
442 443
		DataType result = this.copy ();

444
		if (derived_instance_type == null && method_type_arguments == null) {
445
			return result;
446 447 448
		}

		if (result is GenericType) {
449
			result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_type_arguments, (GenericType) result, node_reference);
450 451 452
			// don't try to resolve type arguments of returned actual type
			// they can never be resolved and are not related to the instance type
		} else if (result.type_argument_list != null) {
453 454
			// recursely get actual types for type arguments
			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);
456 457 458 459 460
			}
		}

		return result;
	}
461

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	/**
	 * Search for the type parameter in this formal type and match it in
	 * value_type.
	 */
	public virtual DataType? infer_type_argument (TypeParameter type_param, DataType value_type) {
		var value_type_arg_it = value_type.get_type_arguments ().iterator ();
		foreach (var formal_type_arg in this.get_type_arguments ()) {
			if (value_type_arg_it.next ()) {
				var inferred_type = formal_type_arg.infer_type_argument (type_param, value_type_arg_it.get ());
				if (inferred_type != null) {
					return inferred_type;
				}
			}
		}

		return null;
	}

480 481 482 483 484 485 486 487 488 489
	/**
	 * Returns a stringified representation used for detailed error output
	 *
	 * @param override_name used as name if given
	 * @return stringified representation
	 */
	public virtual string to_prototype_string (string? override_name = null) {
		return "%s%s".printf (is_weak () ? "unowned " : "", to_qualified_string ());
	}

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
	public bool is_weak () {
		if (this.value_owned) {
			return false;
		} else if (this is VoidType || this is PointerType) {
			return false;
		} else if (this is ValueType) {
			if (this.nullable) {
				// nullable structs are heap allocated
				return true;
			}

			// TODO return true for structs with destroy
			return false;
		}

		return true;
	}
507
}