1/* valasemanticanalyzer.vala 2 * 3 * Copyright (C) 2006-2010 Jürg Billeter 4 * Copyright (C) 2006-2008 Raffaele Sandrini 5 * 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. 10 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. 15 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 19 * 20 * Author: 21 * Jürg Billeter <j@bitron.ch> 22 * Raffaele Sandrini <raffaele@sandrini.ch> 23 */ 24 25using GLib; 26 27/** 28 * Code visitor analyzing and checking code. 29 */ 30public class Vala.SemanticAnalyzer : CodeVisitor { 31 CodeContext context; 32 33 public Symbol? current_symbol { get; set; } 34 public SourceFile current_source_file { get; set; } 35 36 public TypeSymbol? current_type_symbol { 37 get { 38 unowned Symbol? sym = current_symbol; 39 while (sym != null) { 40 if (sym is TypeSymbol) { 41 return (TypeSymbol) sym; 42 } 43 sym = sym.parent_symbol; 44 } 45 return null; 46 } 47 } 48 49 public Class? current_class { 50 get { return current_type_symbol as Class; } 51 } 52 53 54 public Struct? current_struct { 55 get { return current_type_symbol as Struct; } 56 } 57 58 public Method? current_method { 59 get { 60 unowned Symbol? sym = current_symbol; 61 while (sym is Block) { 62 sym = sym.parent_symbol; 63 } 64 return sym as Method; 65 } 66 } 67 68 public Method? current_async_method { 69 get { 70 unowned Symbol? sym = current_symbol; 71 while (sym is Block || sym is Method) { 72 unowned Method? m = sym as Method; 73 if (m != null && m.coroutine) { 74 break; 75 } 76 77 sym = sym.parent_symbol; 78 } 79 return sym as Method; 80 } 81 } 82 83 public PropertyAccessor? current_property_accessor { 84 get { 85 unowned Symbol? sym = current_symbol; 86 while (sym is Block) { 87 sym = sym.parent_symbol; 88 } 89 return sym as PropertyAccessor; 90 } 91 } 92 93 public Symbol? current_method_or_property_accessor { 94 get { 95 unowned Symbol? sym = current_symbol; 96 while (sym is Block) { 97 sym = sym.parent_symbol; 98 } 99 if (sym is Method) { 100 return sym; 101 } else if (sym is PropertyAccessor) { 102 return sym; 103 } else { 104 return null; 105 } 106 } 107 } 108 109 public DataType? current_return_type { 110 get { 111 unowned Method? m = current_method; 112 if (m != null) { 113 return m.return_type; 114 } 115 116 unowned PropertyAccessor? acc = current_property_accessor; 117 if (acc != null) { 118 if (acc.readable) { 119 return acc.value_type; 120 } else { 121 return void_type; 122 } 123 } 124 125 if (is_in_constructor () || is_in_destructor ()) { 126 return void_type; 127 } 128 129 return null; 130 } 131 } 132 133 public Block insert_block; 134 135 public DataType void_type = new VoidType (); 136 public DataType bool_type; 137 public DataType char_type; 138 public DataType uchar_type; 139 public DataType short_type; 140 public DataType ushort_type; 141 public DataType int_type; 142 public DataType uint_type; 143 public DataType long_type; 144 public DataType ulong_type; 145 public DataType int8_type; 146 public DataType uint8_type; 147 public DataType int16_type; 148 public DataType uint16_type; 149 public DataType int32_type; 150 public DataType uint32_type; 151 public DataType size_t_type; 152 public DataType ssize_t_type; 153 public DataType unichar_type; 154 public DataType double_type; 155 public DataType string_type; 156 public DataType regex_type; 157 public DataType type_type; 158 public DataType va_list_type; 159 public Class object_type; 160 public StructValueType gvalue_type; 161 public ObjectType gvariant_type; 162 public DataType glist_type; 163 public DataType gslist_type; 164 public DataType garray_type; 165 public DataType gvaluearray_type; 166 public Class gerror_type; 167 public DataType list_type; 168 public DataType tuple_type; 169 public Class gsource_type; 170 public DataType delegate_target_type; 171 public DelegateType delegate_target_destroy_type; 172 public DelegateType generics_dup_func_type; 173 174 Delegate destroy_notify; 175 176 // keep replaced alive to make sure they remain valid 177 // for the whole execution of CodeNode.accept 178 public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> (); 179 180 public SemanticAnalyzer () { 181 } 182 183 /** 184 * Analyze and check code in the specified context. 185 * 186 * @param context a code context 187 */ 188 public void analyze (CodeContext context) { 189 this.context = context; 190 191 var root_symbol = context.root; 192 193 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool")); 194 char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char")); 195 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar")); 196 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short")); 197 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort")); 198 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int")); 199 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint")); 200 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long")); 201 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong")); 202 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8")); 203 uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8")); 204 int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16")); 205 uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16")); 206 int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32")); 207 uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32")); 208 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t")); 209 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t")); 210 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double")); 211 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string")); 212 va_list_type = new StructValueType ((Struct) root_symbol.scope.lookup ("va_list")); 213 214 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar"); 215 if (unichar_struct != null) { 216 unichar_type = new IntegerType (unichar_struct); 217 } 218 219 if (context.profile == Profile.GOBJECT) { 220 var glib_ns = root_symbol.scope.lookup ("GLib"); 221 222 object_type = (Class) glib_ns.scope.lookup ("Object"); 223 type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type")); 224 gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value")); 225 gvariant_type = new ObjectType ((Class) glib_ns.scope.lookup ("Variant")); 226 227 glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List")); 228 gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList")); 229 garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array")); 230 gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray")); 231 232 gerror_type = (Class) glib_ns.scope.lookup ("Error"); 233 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex")); 234 235 gsource_type = (Class) glib_ns.scope.lookup ("Source"); 236 237 delegate_target_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer")); 238 destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify"); 239 delegate_target_destroy_type = new DelegateType (destroy_notify); 240 241 generics_dup_func_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("BoxedCopyFunc")); 242 } else { 243 delegate_target_type = new PointerType (new VoidType ()); 244 destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ()); 245 destroy_notify.add_parameter (new Parameter ("data", new PointerType (new VoidType ()))); 246 destroy_notify.has_target = false; 247 destroy_notify.owner = context.root.scope; 248 delegate_target_destroy_type = new DelegateType (destroy_notify); 249 } 250 251 current_symbol = root_symbol; 252 context.root.check (context); 253 context.accept (this); 254 255 this.context = null; 256 } 257 258 public override void visit_source_file (SourceFile file) { 259 current_source_file = file; 260 261 file.check (context); 262 } 263 264 // check whether type is at least as accessible as the specified symbol 265 public bool is_type_accessible (Symbol sym, DataType type) { 266 return type.is_accessible (sym); 267 } 268 269 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) { 270 if (sym is Field) { 271 unowned Field f = (Field) sym; 272 var type = f.variable_type.copy (); 273 if (!lvalue) { 274 type.value_owned = false; 275 } 276 return type; 277 } else if (sym is EnumValue) { 278 return new EnumValueType ((Enum) sym.parent_symbol); 279 } else if (sym is Constant) { 280 unowned Constant c = (Constant) sym; 281 return c.type_reference.copy (); 282 } else if (sym is Property) { 283 unowned Property prop = (Property) sym; 284 if (lvalue) { 285 if (prop.set_accessor != null && prop.set_accessor.value_type != null) { 286 return prop.set_accessor.value_type.copy (); 287 } 288 } else { 289 if (prop.get_accessor != null && prop.get_accessor.value_type != null) { 290 return prop.get_accessor.value_type.copy (); 291 } 292 } 293 } else if (sym is Parameter) { 294 unowned Parameter p = (Parameter) sym; 295 var type = p.variable_type.copy (); 296 if (!lvalue) { 297 type.value_owned = false; 298 } 299 return type; 300 } else if (sym is LocalVariable) { 301 unowned LocalVariable local = (LocalVariable) sym; 302 var type = local.variable_type.copy (); 303 if (!lvalue) { 304 type.value_owned = false; 305 } 306 return type; 307 } else if (sym is Method) { 308 return new MethodType ((Method) sym); 309 } else if (sym is Signal) { 310 return new SignalType ((Signal) sym); 311 } 312 return null; 313 } 314 315 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) { 316 var result = sym.scope.lookup (name); 317 if (result != null) { 318 return result; 319 } 320 321 if (sym is Class) { 322 unowned Class cl = (Class) sym; 323 // first check interfaces without prerequisites 324 // (prerequisites can be assumed to be met already) 325 foreach (DataType base_type in cl.get_base_types ()) { 326 if (base_type.type_symbol is Interface) { 327 result = base_type.type_symbol.scope.lookup (name); 328 if (result != null) { 329 return result; 330 } 331 } 332 } 333 // then check base class recursively 334 if (cl.base_class != null) { 335 return symbol_lookup_inherited (cl.base_class, name); 336 } 337 } else if (sym is Struct) { 338 unowned Struct st = (Struct) sym; 339 if (st.base_type != null) { 340 result = symbol_lookup_inherited (st.base_type.type_symbol, name); 341 if (result != null) { 342 return result; 343 } 344 } 345 } else if (sym is Interface) { 346 unowned Interface iface = (Interface) sym; 347 // first check interface prerequisites recursively 348 foreach (DataType prerequisite in iface.get_prerequisites ()) { 349 if (prerequisite.type_symbol is Interface) { 350 result = symbol_lookup_inherited (prerequisite.type_symbol, name); 351 if (result != null) { 352 return result; 353 } 354 } 355 } 356 // then check class prerequisite recursively 357 foreach (DataType prerequisite in iface.get_prerequisites ()) { 358 if (prerequisite.type_symbol is Class) { 359 result = symbol_lookup_inherited (prerequisite.type_symbol, name); 360 if (result != null) { 361 return result; 362 } 363 } 364 } 365 } 366 367 return null; 368 } 369 370 public static DataType get_data_type_for_symbol (Symbol sym) { 371 DataType type; 372 373 List<TypeParameter> type_parameters = null; 374 if (sym is ObjectTypeSymbol) { 375 unowned Class cl = sym as Class; 376 if (cl != null && cl.is_error_base) { 377 type = new ErrorType (null, null); 378 } else { 379 type = new ObjectType ((ObjectTypeSymbol) sym); 380 type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters (); 381 } 382 } else if (sym is Struct) { 383 unowned Struct st = (Struct) sym; 384 if (st.is_boolean_type ()) { 385 type = new BooleanType (st); 386 } else if (st.is_integer_type ()) { 387 type = new IntegerType (st); 388 } else if (st.is_floating_type ()) { 389 type = new FloatingType (st); 390 } else { 391 type = new StructValueType (st); 392 } 393 type_parameters = st.get_type_parameters (); 394 } else if (sym is Enum) { 395 type = new EnumValueType ((Enum) sym); 396 } else if (sym is ErrorDomain) { 397 type = new ErrorType ((ErrorDomain) sym, null); 398 } else if (sym is ErrorCode) { 399 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym); 400 } else { 401 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ())); 402 return new InvalidType (); 403 } 404 405 if (type_parameters != null) { 406 foreach (var type_param in type_parameters) { 407 var type_arg = new GenericType (type_param); 408 type_arg.value_owned = true; 409 type.add_type_argument (type_arg); 410 } 411 } 412 413 return type; 414 } 415 416 public static unowned Symbol? get_symbol_for_data_type (DataType type) { 417 unowned Symbol? sym = null; 418 419 if (type is ObjectType) { 420 sym = ((ObjectType) type).type_symbol; 421 } else if (type is ClassType) { 422 sym = ((ClassType) type).class_symbol; 423 } else if (type is InterfaceType) { 424 sym = ((InterfaceType) type).interface_symbol; 425 } else if (type is MethodType) { 426 sym = ((MethodType) type).method_symbol; 427 } else if (type is SignalType) { 428 sym = ((SignalType) type).signal_symbol; 429 } else if (type is DelegateType) { 430 sym = ((DelegateType) type).delegate_symbol; 431 } else if (type is ValueType) { 432 sym = ((ValueType) type).type_symbol; 433 } 434 435 return sym; 436 } 437 438 public bool is_gobject_property (Property prop) { 439 unowned ObjectTypeSymbol? type_sym = prop.parent_symbol as ObjectTypeSymbol; 440 if (type_sym == null || !type_sym.is_subtype_of (object_type)) { 441 return false; 442 } 443 444 if (prop.binding != MemberBinding.INSTANCE) { 445 return false; 446 } 447 448 if (prop.access == SymbolAccessibility.PRIVATE) { 449 return false; 450 } 451 452 if (!is_gobject_property_type (prop.property_type)) { 453 if (prop.property_type is ArrayType && (!prop.get_attribute_bool ("CCode", "array_length", true) 454 && prop.get_attribute_bool ("CCode", "array_null_terminated", false))) { 455 // null-terminated arrays without length are allowed 456 } else if (prop.property_type is DelegateType && !prop.get_attribute_bool ("CCode", "delegate_target", true)) { 457 // delegates omitting their target are allowed 458 } else { 459 return false; 460 } 461 } 462 463 if (type_sym is Class && prop.base_interface_property != null && 464 !is_gobject_property (prop.base_interface_property)) { 465 return false; 466 } 467 468 if (!prop.name[0].isalpha ()) { 469 // GObject requires properties to start with a letter 470 return false; 471 } 472 473 if (type_sym is Interface && !prop.is_abstract && !prop.external && !prop.external_package) { 474 // GObject does not support non-abstract interface properties, 475 // however we assume external properties always are GObject properties 476 return false; 477 } 478 479 if (type_sym is Interface && type_sym.get_attribute ("DBus") != null) { 480 // GObject properties not currently supported in D-Bus interfaces 481 return false; 482 } 483 484 return true; 485 } 486 487 public bool is_gobject_property_type (DataType property_type) { 488 unowned Struct? st = property_type.type_symbol as Struct; 489 if (st != null) { 490 if (!st.is_simple_type () && st.get_attribute_bool ("CCode", "has_type_id", true)) { 491 // Allow GType-based struct types 492 } else if (property_type.nullable) { 493 return false; 494 } else if (!st.get_attribute_bool ("CCode", "has_type_id", true)) { 495 return false; 496 } 497 } 498 499 if (property_type is ArrayType && ((ArrayType) property_type).element_type.type_symbol != string_type.type_symbol) { 500 return false; 501 } 502 503 unowned DelegateType? d = property_type as DelegateType; 504 if (d != null && d.delegate_symbol.has_target) { 505 return false; 506 } 507 508 return true; 509 } 510 511 public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) { 512 bool error = false; 513 514 Expression prev_arg = null; 515 Iterator<Expression> arg_it = args.iterator (); 516 517 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null); 518 519 bool ellipsis = false; 520 int i = 0; 521 foreach (Parameter param in params) { 522 if (param.ellipsis) { 523 ellipsis = true; 524 break; 525 } 526 527 if (param.params_array) { 528 while (arg_it.next ()) { 529 var arg = arg_it.get (); 530 if (!check_argument (arg, i, param.direction)) { 531 expr.error = true; 532 error = true; 533 } 534 535 i++; 536 } 537 538 break; 539 } 540 541 if (arg_it == null || !arg_it.next ()) { 542 if (param.initializer == null) { 543 expr.error = true; 544 unowned MethodType? m = mtype as MethodType; 545 if (m != null) { 546 Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ())); 547 } else { 548 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size)); 549 } 550 error = true; 551 } else { 552 unowned MethodCall? invocation_expr = expr as MethodCall; 553 unowned ObjectCreationExpression? object_creation_expr = expr as ObjectCreationExpression; 554 if (invocation_expr != null) { 555 invocation_expr.add_argument (param.initializer); 556 } else if (object_creation_expr != null) { 557 object_creation_expr.add_argument (param.initializer); 558 } else { 559 assert_not_reached (); 560 } 561 arg_it = null; 562 } 563 } else { 564 var arg = arg_it.get (); 565 if (!check_argument (arg, i, param.direction)) { 566 expr.error = true; 567 error = true; 568 } 569 570 prev_arg = arg; 571 572 i++; 573 } 574 } 575 576 if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) { 577 expr.error = true; 578 error = true; 579 } else if (!ellipsis && arg_it != null && arg_it.next ()) { 580 expr.error = true; 581 unowned MethodType? m = mtype as MethodType; 582 if (m != null) { 583 Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ())); 584 } else { 585 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size)); 586 } 587 error = true; 588 } 589 590 if (diag && prev_arg != null) { 591 unowned StringLiteral? format_arg = prev_arg as StringLiteral; 592 if (format_arg != null) { 593 format_arg.value = "\"%s:%d: %s".printf (Path.get_basename (expr.source_reference.file.filename), expr.source_reference.begin.line, format_arg.value.substring (1)); 594 } 595 } 596 597 return !error; 598 } 599 600 bool check_argument (Expression arg, int i, ParameterDirection direction) { 601 if (arg.error) { 602 // ignore inner error 603 return false; 604 } else if (arg is NamedArgument) { 605 Report.error (arg.source_reference, "Named arguments are not supported yet"); 606 return false; 607 } else if (arg.value_type == null) { 608 // disallow untyped arguments except for type inference of callbacks 609 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) { 610 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1)); 611 return false; 612 } 613 } else { 614 // 0 => null, 1 => in, 2 => ref, 3 => out 615 int arg_type = 1; 616 if (arg.value_type is NullType) { 617 arg_type = 0; 618 } else if (arg is UnaryExpression) { 619 var unary = (UnaryExpression) arg; 620 if (unary.operator == UnaryOperator.REF) { 621 arg_type = 2; 622 } else if (unary.operator == UnaryOperator.OUT) { 623 arg_type = 3; 624 } 625 } 626 627 if (arg_type == 0) { 628 if (direction == ParameterDirection.REF) { 629 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1)); 630 return false; 631 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) { 632 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1)); 633 } 634 } else if (arg_type == 1) { 635 if (direction != ParameterDirection.IN) { 636 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1)); 637 return false; 638 } 639 } else if (arg_type == 2) { 640 if (direction != ParameterDirection.REF) { 641 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1)); 642 return false; 643 } 644 645 // weak variables can only be used with weak ref parameters 646 if (arg.target_type.is_disposable ()) { 647 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) { 648 /* variable doesn't own the value */ 649 Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1)); 650 return false; 651 } 652 } 653 654 // owned variables can only be used with owned ref parameters 655 if (arg.value_type.is_disposable ()) { 656 if (!arg.target_type.value_owned) { 657 /* parameter doesn't own the value */ 658 Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1)); 659 return false; 660 } 661 } 662 } else if (arg_type == 3) { 663 if (direction != ParameterDirection.OUT) { 664 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1)); 665 return false; 666 } 667 668 // weak variables can only be used with weak out parameters 669 if (arg.target_type.is_disposable ()) { 670 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) { 671 /* variable doesn't own the value */ 672 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable"); 673 return false; 674 } 675 } 676 } 677 } 678 679 if (arg.target_type != null) { 680 if ((direction == ParameterDirection.IN || direction == ParameterDirection.REF) 681 && !arg.value_type.compatible (arg.target_type)) { 682 Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.value_type.to_prototype_string (), arg.target_type.to_prototype_string ())); 683 return false; 684 } else if ((direction == ParameterDirection.REF || direction == ParameterDirection.OUT) 685 && !arg.target_type.compatible (arg.value_type) 686 && !(arg is NullLiteral)) { 687 Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.target_type.to_prototype_string (), arg.value_type.to_prototype_string ())); 688 return false; 689 } 690 } 691 692 unowned MemberAccess? ma = arg as MemberAccess; 693 if (ma != null && ma.prototype_access) { 694 // allow prototype access if target type is delegate without target 695 unowned DelegateType? deleg_type = arg.target_type as DelegateType; 696 if (deleg_type == null || deleg_type.delegate_symbol.has_target) { 697 Report.error (arg.source_reference, "Access to instance member `%s' denied".printf (arg.symbol_reference.get_full_name ())); 698 return false; 699 } 700 } 701 return true; 702 } 703 704 public bool check_variadic_arguments (Iterator<Expression>? arg_it, int i, SourceReference? source_reference = null) { 705 while (arg_it != null && arg_it.next ()) { 706 var arg = arg_it.get (); 707 if (arg.error) { 708 // ignore inner error 709 return false; 710 } else if (arg.value_type is SignalType) { 711 arg.error = true; 712 Report.error (arg.source_reference, "Cannot pass signals as arguments"); 713 return false; 714 } else if (arg.value_type == null) { 715 // disallow untyped arguments except for type inference of callbacks 716 if (!(arg.symbol_reference is Method)) { 717 Report.error (source_reference, "Invalid type for argument %d".printf (i + 1)); 718 return false; 719 } 720 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) { 721 // target_type known for printf arguments 722 Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.value_type.to_string (), arg.target_type.to_string ())); 723 return false; 724 } 725 726 i++; 727 } 728 729 return true; 730 } 731 732 public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference? source_reference = null) { 733 bool unsupported_format = false; 734 735 weak string format_it = format; 736 unichar c = format_it.get_char (); 737 while (c != '\0') { 738 if (c != '%') { 739 format_it = format_it.next_char (); 740 c = format_it.get_char (); 741 continue; 742 } 743 744 format_it = format_it.next_char (); 745 c = format_it.get_char (); 746 // flags 747 while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') { 748 format_it = format_it.next_char (); 749 c = format_it.get_char (); 750 } 751 // field width 752 while (c >= '0' && c <= '9') { 753 format_it = format_it.next_char (); 754 c = format_it.get_char (); 755 } 756 // precision 757 if (c == '.') { 758 format_it = format_it.next_char (); 759 c = format_it.get_char (); 760 while (c >= '0' && c <= '9') { 761 format_it = format_it.next_char (); 762 c = format_it.get_char (); 763 } 764 } 765 // length modifier 766 int length = 0; 767 if (c == 'h') { 768 length = -1; 769 format_it = format_it.next_char (); 770 c = format_it.get_char (); 771 if (c == 'h') { 772 length = -2; 773 format_it = format_it.next_char (); 774 c = format_it.get_char (); 775 } 776 } else if (c == 'l') { 777 length = 1; 778 format_it = format_it.next_char (); 779 c = format_it.get_char (); 780 } else if (c == 'z') { 781 length = 2; 782 format_it = format_it.next_char (); 783 c = format_it.get_char (); 784 } 785 // conversion specifier 786 DataType param_type = null; 787 if (c == 'd' || c == 'i' || c == 'c') { 788 // integer 789 if (length == -2) { 790 param_type = int8_type; 791 } else if (length == -1) { 792 param_type = short_type; 793 } else if (length == 0) { 794 param_type = int_type; 795 } else if (length == 1) { 796 param_type = long_type; 797 } else if (length == 2) { 798 param_type = ssize_t_type; 799 } 800 } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') { 801 // unsigned integer 802 if (length == -2) { 803 param_type = uchar_type; 804 } else if (length == -1) { 805 param_type = ushort_type; 806 } else if (length == 0) { 807 param_type = uint_type; 808 } else if (length == 1) { 809 param_type = ulong_type; 810 } else if (length == 2) { 811 param_type = size_t_type; 812 } 813 } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F' 814 || c == 'g' || c == 'G' || c == 'a' || c == 'A') { 815 // double 816 param_type = double_type; 817 } else if (c == 's') { 818 // string 819 param_type = string_type; 820 } else if (c == 'p') { 821 // pointer 822 param_type = new PointerType (new VoidType ()); 823 } else if (c == '%') { 824 // literal % 825 } else { 826 unsupported_format = true; 827 break; 828 } 829 if (c != '\0') { 830 format_it = format_it.next_char (); 831 c = format_it.get_char (); 832 } 833 if (param_type != null) { 834 if (arg_it.next ()) { 835 Expression arg = arg_it.get (); 836 837 arg.target_type = param_type; 838 } else { 839 Report.error (source_reference, "Too few arguments for specified format"); 840 return false; 841 } 842 } 843 } 844 if (!unsupported_format && arg_it.next ()) { 845 Report.error (source_reference, "Too many arguments for specified format"); 846 return false; 847 } 848 849 return true; 850 } 851 852 private static DataType get_instance_base_type (DataType instance_type, DataType base_type, CodeNode? node_reference) { 853 // construct a new type reference for the base type with correctly linked type arguments 854 DataType instance_base_type; 855 if (base_type.type_symbol is ObjectTypeSymbol) { 856 instance_base_type = new ObjectType ((ObjectTypeSymbol) base_type.type_symbol); 857 } else if (base_type.type_symbol is Struct) { 858 instance_base_type = new StructValueType ((Struct) base_type.type_symbol); 859 } else { 860 assert_not_reached (); 861 } 862 foreach (DataType type_arg in base_type.get_type_arguments ()) { 863 // resolve type argument specified in base type (possibly recursively for nested generic types) 864 type_arg = type_arg.get_actual_type (instance_type, null, node_reference); 865 instance_base_type.add_type_argument (type_arg); 866 } 867 return instance_base_type; 868 } 869 870 internal static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode? node_reference) { 871 DataType instance_type = derived_instance_type; 872 873 while (instance_type is PointerType) { 874 unowned PointerType instance_pointer_type = (PointerType) instance_type; 875 instance_type = instance_pointer_type.base_type; 876 } 877 878 if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) { 879 return instance_type; 880 } else if (instance_type.type_symbol == type_symbol) { 881 return instance_type; 882 } 883 884 DataType? instance_base_type = null; 885 886 // use same algorithm as symbol_lookup_inherited 887 if (instance_type.type_symbol is Class) { 888 unowned Class cl = (Class) instance_type.type_symbol; 889 // first check interfaces without prerequisites 890 // (prerequisites can be assumed to be met already) 891 foreach (DataType base_type in cl.get_base_types ()) { 892 if (base_type.type_symbol is Interface) { 893 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference); 894 if (instance_base_type != null) { 895 return instance_base_type; 896 } 897 } 898 } 899 // then check base class recursively 900 if (instance_base_type == null) { 901 foreach (DataType base_type in cl.get_base_types ()) { 902 if (base_type.type_symbol is Class) { 903 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference); 904 if (instance_base_type != null) { 905 return instance_base_type; 906 } 907 } 908 } 909 } 910 } else if (instance_type.type_symbol is Struct) { 911 unowned Struct st = (Struct) instance_type.type_symbol; 912 if (st.base_type != null) { 913 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference); 914 if (instance_base_type != null) { 915 return instance_base_type; 916 } 917 } 918 } else if (instance_type.type_symbol is Interface) { 919 unowned Interface iface = (Interface) instance_type.type_symbol; 920 // first check interface prerequisites recursively 921 foreach (DataType prerequisite in iface.get_prerequisites ()) { 922 if (prerequisite.type_symbol is Interface) { 923 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference); 924 if (instance_base_type != null) { 925 return instance_base_type; 926 } 927 } 928 } 929 if (instance_base_type == null) { 930 // then check class prerequisite recursively 931 foreach (DataType prerequisite in iface.get_prerequisites ()) { 932 if (prerequisite.type_symbol is Class) { 933 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference); 934 if (instance_base_type != null) { 935 return instance_base_type; 936 } 937 } 938 } 939 } 940 } 941 942 return null; 943 } 944 945 public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, GenericType generic_type, CodeNode? node_reference) { 946 DataType actual_type = null; 947 if (generic_type.type_parameter.parent_symbol is TypeSymbol) { 948 if (derived_instance_type != null) { 949 // trace type arguments back to the datatype where the method has been declared 950 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference); 951 952 if (instance_type == null) { 953 if (node_reference != null) { 954 CodeNode? reference = get_symbol_for_data_type (derived_instance_type); 955 Report.error ((reference ?? node_reference).source_reference, "The type-parameter `%s' is missing".printf (generic_type.to_string ())); 956 node_reference.error = true; 957 } 958 return new InvalidType (); 959 } 960 961 int param_index; 962 if (instance_type is DelegateType) { 963 param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name); 964 } else { 965 param_index = instance_type.type_symbol.get_type_parameter_index (generic_type.type_parameter.name); 966 } 967 if (param_index == -1) { 968 if (node_reference != null) { 969 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name)); 970 node_reference.error = true; 971 } 972 return new InvalidType (); 973 } 974 975 if (param_index < instance_type.get_type_arguments ().size) { 976 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index); 977 } 978 } 979 } else { 980 // generic method 981 unowned Method m = (Method) generic_type.type_parameter.parent_symbol; 982 983 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name); 984 if (param_index == -1) { 985 if (node_reference != null) { 986 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name)); 987 node_reference.error = true; 988 } 989 return new InvalidType (); 990 } 991 992 if (method_type_arguments != null) { 993 if (param_index < method_type_arguments.size) { 994 actual_type = (DataType) method_type_arguments.get (param_index); 995 } 996 } 997 } 998 999 if (actual_type == null) { 1000 // no actual type available 1001 return generic_type; 1002 } 1003 actual_type = actual_type.copy (); 1004 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned; 1005 return actual_type; 1006 } 1007 1008 public bool is_in_instance_method () { 1009 unowned Symbol? sym = current_symbol; 1010 while (sym != null) { 1011 if (sym is CreationMethod) { 1012 return true; 1013 } else if (sym is Method) { 1014 unowned Method m = (Method) sym; 1015 return m.binding == MemberBinding.INSTANCE; 1016 } else if (sym is Constructor) { 1017 unowned Constructor c = (Constructor) sym; 1018 return c.binding == MemberBinding.INSTANCE; 1019 } else if (sym is Destructor) { 1020 unowned Destructor d = (Destructor) sym; 1021 return d.binding == MemberBinding.INSTANCE; 1022 } else if (sym is Property) { 1023 unowned Property p = (Property) sym; 1024 return p.binding == MemberBinding.INSTANCE; 1025 } 1026 sym = sym.parent_symbol; 1027 } 1028 1029 return false; 1030 } 1031 1032 // Create an access to a temporary variable, with proper reference transfer if needed 1033 public static Expression create_temp_access (LocalVariable local, DataType? target_type) { 1034 Expression temp_access = new MemberAccess.simple (local.name, local.source_reference); 1035 1036 var target_owned = target_type != null && target_type.value_owned; 1037 if (target_owned && local.variable_type.is_disposable ()) { 1038 temp_access = new ReferenceTransferExpression (temp_access, local.source_reference); 1039 temp_access.target_type = target_type != null ? target_type.copy () : local.variable_type.copy (); 1040 temp_access.target_type.value_owned = true; 1041 } else { 1042 temp_access.target_type = target_type != null ? target_type.copy () : null; 1043 } 1044 1045 return temp_access; 1046 } 1047 1048 public void visit_member_initializer (MemberInitializer init, DataType type) { 1049 init.symbol_reference = symbol_lookup_inherited (type.type_symbol, init.name); 1050 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) { 1051 init.error = true; 1052 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.type_symbol.get_full_name ())); 1053 return; 1054 } 1055 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) { 1056 init.error = true; 1057 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ())); 1058 return; 1059 } 1060 DataType member_type = null; 1061 if (init.symbol_reference is Field) { 1062 unowned Field f = (Field) init.symbol_reference; 1063 member_type = f.variable_type; 1064 } else if (init.symbol_reference is Property) { 1065 unowned Property prop = (Property) init.symbol_reference; 1066 member_type = prop.property_type; 1067 if (prop.set_accessor == null || !prop.set_accessor.writable) { 1068 init.error = true; 1069 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ())); 1070 return; 1071 } 1072 } 1073 1074 init.initializer.formal_target_type = member_type; 1075 init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init); 1076 1077 if (!init.check (context)) { 1078 return; 1079 } 1080 1081 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) { 1082 init.error = true; 1083 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name)); 1084 return; 1085 } 1086 } 1087 1088 unowned Struct? get_arithmetic_struct (DataType type) { 1089 unowned Struct? result = type.type_symbol as Struct; 1090 if (result == null && type is EnumValueType) { 1091 return (Struct) int_type.type_symbol; 1092 } 1093 return result; 1094 } 1095 1096 public unowned DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) { 1097 unowned Struct? left = get_arithmetic_struct (left_type); 1098 unowned Struct? right = get_arithmetic_struct (right_type); 1099 1100 if (left == null || right == null) { 1101 // at least one operand not struct 1102 return null; 1103 } 1104 1105 if ((!left.is_floating_type () && !left.is_integer_type ()) || 1106 (!right.is_floating_type () && !right.is_integer_type ())) { 1107 // at least one operand not numeric 1108 return null; 1109 } 1110 1111 if (left.is_floating_type () == right.is_floating_type ()) { 1112 // both operands integer or floating type 1113 if (left.rank >= right.rank) { 1114 return left_type; 1115 } else { 1116 return right_type; 1117 } 1118 } else { 1119 // one integer and one floating type operand 1120 if (left.is_floating_type ()) { 1121 return left_type; 1122 } else { 1123 return right_type; 1124 } 1125 } 1126 } 1127 1128 public unowned Method? find_current_method () { 1129 unowned Symbol? sym = current_symbol; 1130 while (sym != null) { 1131 if (sym is Method) { 1132 return (Method) sym; 1133 } 1134 sym = sym.parent_symbol; 1135 } 1136 return null; 1137 } 1138 1139 public static unowned Method? find_parent_method (Symbol sym) { 1140 while (sym is Block) { 1141 sym = sym.parent_symbol; 1142 } 1143 return sym as Method; 1144 } 1145 1146 public static unowned Symbol? find_parent_method_or_property_accessor (Symbol sym) { 1147 while (sym is Block) { 1148 sym = sym.parent_symbol; 1149 } 1150 if (sym is Method) { 1151 return sym; 1152 } else if (sym is PropertyAccessor) { 1153 return sym; 1154 } else { 1155 return null; 1156 } 1157 } 1158 1159 public static unowned TypeSymbol? find_parent_type_symbol (Symbol sym) { 1160 while (sym != null) { 1161 if (sym is TypeSymbol) { 1162 return (TypeSymbol) sym; 1163 } 1164 sym = sym.parent_symbol; 1165 } 1166 return null; 1167 } 1168 1169 public static DataType? get_this_type (Symbol s, TypeSymbol? parent = null) { 1170 unowned TypeSymbol? parent_type = parent ?? find_parent_type_symbol (s); 1171 if (parent_type == null) { 1172 Report.error (parent_type.source_reference, "internal: Unsupported symbol type"); 1173 return new InvalidType (); 1174 } 1175 1176 MemberBinding binding; 1177 if (s is Method) { 1178 binding = ((Method) s).binding; 1179 } else if (s is Constructor) { 1180 binding = ((Constructor) s).binding; 1181 } else if (s is Destructor) { 1182 binding = ((Destructor) s).binding; 1183 } else if (s is Property) { 1184 binding = ((Property) s).binding; 1185 } else { 1186 Report.error (s.source_reference, "internal: Unsupported symbol type"); 1187 return new InvalidType (); 1188 } 1189 1190 DataType? this_type = null; 1191 List<TypeParameter>? type_parameters = null; 1192 switch (binding) { 1193 case MemberBinding.INSTANCE: 1194 if (parent_type is Class) { 1195 this_type = new ObjectType ((Class) parent_type); 1196 type_parameters = ((Class) parent_type).get_type_parameters (); 1197 } else if (parent_type is Interface) { 1198 this_type = new ObjectType ((Interface) parent_type); 1199 type_parameters = ((Interface) parent_type).get_type_parameters (); 1200 } else if (parent_type is Struct) { 1201 this_type = new StructValueType ((Struct) parent_type); 1202 type_parameters = ((Struct) parent_type).get_type_parameters (); 1203 } else if (parent_type is Enum) { 1204 this_type = new EnumValueType ((Enum) parent_type); 1205 } else { 1206 Report.error (parent_type.source_reference, "internal: Unsupported symbol type"); 1207 this_type = new InvalidType (); 1208 } 1209 break; 1210 case MemberBinding.CLASS: 1211 if (parent_type is Class) { 1212 this_type = new ClassType ((Class) parent_type); 1213 } else if (parent_type is Interface) { 1214 this_type = new InterfaceType ((Interface) parent_type); 1215 } else { 1216 Report.error (parent_type.source_reference, "internal: Unsupported symbol type"); 1217 this_type = new InvalidType (); 1218 } 1219 break; 1220 case MemberBinding.STATIC: 1221 default: 1222 Report.error (s.source_reference, "internal: Does not support a parent instance"); 1223 this_type = new InvalidType (); 1224 break; 1225 } 1226 1227 if (type_parameters != null) { 1228 foreach (var type_param in type_parameters) { 1229 var type_arg = new GenericType (type_param); 1230 type_arg.value_owned = true; 1231 this_type.add_type_argument (type_arg); 1232 } 1233 } 1234 1235 return this_type; 1236 } 1237 1238 public bool is_in_constructor () { 1239 unowned Symbol? sym = current_symbol; 1240 while (sym != null) { 1241 if (sym is Constructor) { 1242 return true; 1243 } 1244 sym = sym.parent_symbol; 1245 } 1246 return false; 1247 } 1248 1249 public bool is_in_destructor () { 1250 unowned Symbol? sym = current_symbol; 1251 while (sym != null) { 1252 if (sym is Destructor) { 1253 return true; 1254 } 1255 sym = sym.parent_symbol; 1256 } 1257 return false; 1258 } 1259 1260 public bool is_reference_type_argument (DataType type_arg) { 1261 if (type_arg is ErrorType || (type_arg.type_symbol != null && type_arg.type_symbol.is_reference_type ())) { 1262 return true; 1263 } else { 1264 return false; 1265 } 1266 } 1267 1268 public bool is_nullable_value_type_argument (DataType type_arg) { 1269 if (type_arg is ValueType && type_arg.nullable) { 1270 return true; 1271 } else { 1272 return false; 1273 } 1274 } 1275 1276 public bool is_signed_integer_type_argument (DataType type_arg) { 1277 unowned Struct? st = type_arg.type_symbol as Struct; 1278 if (type_arg is EnumValueType) { 1279 return true; 1280 } else if (type_arg.nullable) { 1281 return false; 1282 } else if (st == null) { 1283 return false; 1284 } else if (st.is_subtype_of (bool_type.type_symbol)) { 1285 return true; 1286 } else if (st.is_subtype_of (char_type.type_symbol)) { 1287 return true; 1288 } else if (unichar_type != null && st.is_subtype_of (unichar_type.type_symbol)) { 1289 return true; 1290 } else if (st.is_subtype_of (short_type.type_symbol)) { 1291 return true; 1292 } else if (st.is_subtype_of (int_type.type_symbol)) { 1293 return true; 1294 } else if (st.is_subtype_of (long_type.type_symbol)) { 1295 return true; 1296 } else if (st.is_subtype_of (int8_type.type_symbol)) { 1297 return true; 1298 } else if (st.is_subtype_of (int16_type.type_symbol)) { 1299 return true; 1300 } else if (st.is_subtype_of (int32_type.type_symbol)) { 1301 return true; 1302 } else if (st.is_subtype_of (type_type.type_symbol)) { 1303 return true; 1304 } else { 1305 return false; 1306 } 1307 } 1308 1309 public bool is_unsigned_integer_type_argument (DataType type_arg) { 1310 unowned Struct? st = type_arg.type_symbol as Struct; 1311 if (st == null) { 1312 return false; 1313 } else if (type_arg.nullable) { 1314 return false; 1315 } else if (st.is_subtype_of (uchar_type.type_symbol)) { 1316 return true; 1317 } else if (st.is_subtype_of (ushort_type.type_symbol)) { 1318 return true; 1319 } else if (st.is_subtype_of (uint_type.type_symbol)) { 1320 return true; 1321 } else if (st.is_subtype_of (ulong_type.type_symbol)) { 1322 return true; 1323 } else if (st.is_subtype_of (uint8_type.type_symbol)) { 1324 return true; 1325 } else if (st.is_subtype_of (uint16_type.type_symbol)) { 1326 return true; 1327 } else if (st.is_subtype_of (uint32_type.type_symbol)) { 1328 return true; 1329 } else { 1330 return false; 1331 } 1332 } 1333 1334 public void check_type (DataType type) { 1335 foreach (var type_arg in type.get_type_arguments ()) { 1336 check_type (type_arg); 1337 check_type_argument (type_arg); 1338 } 1339 } 1340 1341 public void check_type_arguments (MemberAccess access) { 1342 foreach (var type_arg in access.get_type_arguments ()) { 1343 check_type (type_arg); 1344 check_type_argument (type_arg); 1345 } 1346 } 1347 1348 void check_type_argument (DataType type_arg) { 1349 if (type_arg is GenericType 1350 || type_arg is PointerType 1351 || type_arg is VoidType 1352 || is_reference_type_argument (type_arg) 1353 || is_nullable_value_type_argument (type_arg) 1354 || is_signed_integer_type_argument (type_arg) 1355 || is_unsigned_integer_type_argument (type_arg)) { 1356 // no error 1357 } else if (type_arg is DelegateType) { 1358 var delegate_type = (DelegateType) type_arg; 1359 if (delegate_type.delegate_symbol.has_target) { 1360 Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments"); 1361 } 1362 } else if (type_arg is ArrayType) { 1363 Report.error (type_arg.source_reference, "Arrays are not supported as generic type arguments"); 1364 } else { 1365 Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ())); 1366 } 1367 } 1368} 1369