OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/class_finalizer.h" | 5 #include "vm/class_finalizer.h" |
6 | 6 |
7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
8 #include "vm/heap.h" | 8 #include "vm/heap.h" |
9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 // i.e. cls_args = [String, double], offset = 2, length = 2. | 500 // i.e. cls_args = [String, double], offset = 2, length = 2. |
501 // Output: arguments = [int, double, String, double] | 501 // Output: arguments = [int, double, String, double] |
502 void ClassFinalizer::FinalizeTypeArguments( | 502 void ClassFinalizer::FinalizeTypeArguments( |
503 const Class& cls, | 503 const Class& cls, |
504 const AbstractTypeArguments& arguments, | 504 const AbstractTypeArguments& arguments, |
505 FinalizationKind finalization, | 505 FinalizationKind finalization, |
506 Error* bound_error) { | 506 Error* bound_error) { |
507 ASSERT(arguments.Length() >= cls.NumTypeArguments()); | 507 ASSERT(arguments.Length() >= cls.NumTypeArguments()); |
508 if (!cls.is_finalized()) { | 508 if (!cls.is_finalized()) { |
509 FinalizeTypeParameters(cls); | 509 FinalizeTypeParameters(cls); |
| 510 ResolveUpperBounds(cls); |
510 } | 511 } |
511 AbstractType& super_type = AbstractType::Handle(cls.super_type()); | 512 AbstractType& super_type = AbstractType::Handle(cls.super_type()); |
512 if (!super_type.IsNull()) { | 513 if (!super_type.IsNull()) { |
513 const Class& super_class = Class::Handle(super_type.type_class()); | 514 const Class& super_class = Class::Handle(super_type.type_class()); |
514 AbstractTypeArguments& super_type_args = AbstractTypeArguments::Handle(); | 515 AbstractTypeArguments& super_type_args = AbstractTypeArguments::Handle(); |
515 if (super_type.IsBeingFinalized()) { | 516 if (super_type.IsBeingFinalized()) { |
516 // This type references itself via its type arguments. This is legal, but | 517 // This type references itself via its type arguments. This is legal, but |
517 // we must avoid endless recursion. We therefore map the innermost | 518 // we must avoid endless recursion. We therefore map the innermost |
518 // super type to dynamic. | 519 // super type to dynamic. |
519 // Note that a direct self-reference via the super class chain is illegal | 520 // Note that a direct self-reference via the super class chain is illegal |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 // Check the type argument vector 'arguments' against the corresponding bounds | 568 // Check the type argument vector 'arguments' against the corresponding bounds |
568 // of the type parameters of class 'cls' and, recursively, of its superclasses. | 569 // of the type parameters of class 'cls' and, recursively, of its superclasses. |
569 // Replace a type argument that cannot be checked at compile time by a | 570 // Replace a type argument that cannot be checked at compile time by a |
570 // BoundedType, thereby postponing the bound check to run time. | 571 // BoundedType, thereby postponing the bound check to run time. |
571 // Return a bound error if a type argument is not within bound at compile time. | 572 // Return a bound error if a type argument is not within bound at compile time. |
572 void ClassFinalizer::CheckTypeArgumentBounds( | 573 void ClassFinalizer::CheckTypeArgumentBounds( |
573 const Class& cls, | 574 const Class& cls, |
574 const AbstractTypeArguments& arguments, | 575 const AbstractTypeArguments& arguments, |
575 Error* bound_error) { | 576 Error* bound_error) { |
576 if (!cls.is_finalized()) { | 577 if (!cls.is_finalized()) { |
577 ResolveAndFinalizeUpperBounds(cls); | 578 FinalizeUpperBounds(cls); |
578 } | 579 } |
579 // Note that when finalizing a type, we need to verify the bounds in both | 580 // Note that when finalizing a type, we need to verify the bounds in both |
580 // production mode and checked mode, because the finalized type may be written | 581 // production mode and checked mode, because the finalized type may be written |
581 // to a snapshot. It would be wrong to ignore bounds when generating the | 582 // to a snapshot. It would be wrong to ignore bounds when generating the |
582 // snapshot in production mode and then use the unchecked type in checked mode | 583 // snapshot in production mode and then use the unchecked type in checked mode |
583 // after reading it from the snapshot. | 584 // after reading it from the snapshot. |
584 // However, we do not immediately report a bound error, which would be wrong | 585 // However, we do not immediately report a bound error, which would be wrong |
585 // in production mode, but simply postpone the bound checking to runtime. | 586 // in production mode, but simply postpone the bound checking to runtime. |
586 const intptr_t num_type_params = cls.NumTypeParameters(); | 587 const intptr_t num_type_params = cls.NumTypeParameters(); |
587 const intptr_t offset = cls.NumTypeArguments() - num_type_params; | 588 const intptr_t offset = cls.NumTypeArguments() - num_type_params; |
(...skipping 12 matching lines...) Expand all Loading... |
600 } | 601 } |
601 cls_type_param = cls_type_params.TypeAt(i); | 602 cls_type_param = cls_type_params.TypeAt(i); |
602 const TypeParameter& type_param = TypeParameter::Cast(cls_type_param); | 603 const TypeParameter& type_param = TypeParameter::Cast(cls_type_param); |
603 ASSERT(type_param.IsFinalized()); | 604 ASSERT(type_param.IsFinalized()); |
604 declared_bound = type_param.bound(); | 605 declared_bound = type_param.bound(); |
605 if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) { | 606 if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) { |
606 Error& malformed_error = Error::Handle(); | 607 Error& malformed_error = Error::Handle(); |
607 // Note that the bound may be malformed, in which case the bound check | 608 // Note that the bound may be malformed, in which case the bound check |
608 // will return an error and the bound check will be postponed to run time. | 609 // will return an error and the bound check will be postponed to run time. |
609 // Note also that the bound may still be unfinalized. | 610 // Note also that the bound may still be unfinalized. |
610 if (!declared_bound.IsFinalized()) { | |
611 ASSERT(declared_bound.IsBeingFinalized()); | |
612 // The bound refers to type parameters, creating a cycle; postpone | |
613 // bound check to run time, when the bound will be finalized. | |
614 // TODO(regis): Do we need to instantiate an uninstantiated bound here? | |
615 type_arg = BoundedType::New(type_arg, declared_bound, type_param); | |
616 arguments.SetTypeAt(offset + i, type_arg); | |
617 continue; | |
618 } | |
619 if (declared_bound.IsInstantiated()) { | 611 if (declared_bound.IsInstantiated()) { |
620 instantiated_bound = declared_bound.raw(); | 612 instantiated_bound = declared_bound.raw(); |
621 } else { | 613 } else { |
622 instantiated_bound = | 614 instantiated_bound = |
623 declared_bound.InstantiateFrom(arguments, &malformed_error); | 615 declared_bound.InstantiateFrom(arguments, &malformed_error); |
624 } | 616 } |
| 617 if (!instantiated_bound.IsFinalized()) { |
| 618 // The bound refers to type parameters, creating a cycle; postpone |
| 619 // bound check to run time, when the bound will be finalized. |
| 620 // The bound may not necessarily be 'IsBeingFinalized' yet, as is the |
| 621 // case with a pair of type parameters of the same class referring to |
| 622 // each other via their bounds. |
| 623 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param); |
| 624 arguments.SetTypeAt(offset + i, type_arg); |
| 625 continue; |
| 626 } |
625 // TODO(regis): We could simplify this code if we could differentiate | 627 // TODO(regis): We could simplify this code if we could differentiate |
626 // between a failed bound check and a bound check that is undecidable at | 628 // between a failed bound check and a bound check that is undecidable at |
627 // compile time. | 629 // compile time. |
628 // Shortcut the special case where we check a type parameter against its | 630 // Shortcut the special case where we check a type parameter against its |
629 // declared upper bound. | 631 // declared upper bound. |
| 632 bool below_bound = true; |
630 if (malformed_error.IsNull() && | 633 if (malformed_error.IsNull() && |
631 (!type_arg.Equals(type_param) || | 634 (!type_arg.Equals(type_param) || |
632 !instantiated_bound.Equals(declared_bound))) { | 635 !instantiated_bound.Equals(declared_bound))) { |
633 type_param.CheckBound(type_arg, instantiated_bound, &malformed_error); | 636 // Pass NULL to prevent expensive and unnecessary error formatting in |
| 637 // the case the bound check is postponed to run time. |
| 638 below_bound = type_param.CheckBound(type_arg, instantiated_bound, NULL); |
634 } | 639 } |
635 if (!malformed_error.IsNull()) { | 640 if (!malformed_error.IsNull() || !below_bound) { |
636 if (!type_arg.IsInstantiated() || | 641 if (!type_arg.IsInstantiated() || |
637 !instantiated_bound.IsInstantiated()) { | 642 !instantiated_bound.IsInstantiated()) { |
638 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param); | 643 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param); |
639 arguments.SetTypeAt(offset + i, type_arg); | 644 arguments.SetTypeAt(offset + i, type_arg); |
640 } else if (bound_error->IsNull()) { | 645 } else if (bound_error->IsNull()) { |
| 646 if (malformed_error.IsNull()) { |
| 647 // Call CheckBound again to format error message. |
| 648 type_param.CheckBound(type_arg, |
| 649 instantiated_bound, |
| 650 &malformed_error); |
| 651 } |
| 652 ASSERT(!malformed_error.IsNull()); |
641 *bound_error = malformed_error.raw(); | 653 *bound_error = malformed_error.raw(); |
642 } | 654 } |
643 } | 655 } |
644 } | 656 } |
645 } | 657 } |
646 AbstractType& super_type = AbstractType::Handle(cls.super_type()); | 658 AbstractType& super_type = AbstractType::Handle(cls.super_type()); |
647 if (!super_type.IsNull()) { | 659 if (!super_type.IsNull()) { |
648 const Class& super_class = Class::Handle(super_type.type_class()); | 660 const Class& super_class = Class::Handle(super_type.type_class()); |
649 CheckTypeArgumentBounds(super_class, arguments, bound_error); | 661 CheckTypeArgumentBounds(super_class, arguments, bound_error); |
650 } | 662 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 parameterized_type.set_is_being_finalized(); | 722 parameterized_type.set_is_being_finalized(); |
711 | 723 |
712 // The type class does not need to be finalized in order to finalize the type, | 724 // The type class does not need to be finalized in order to finalize the type, |
713 // however, it must at least be resolved (this was done as part of resolving | 725 // however, it must at least be resolved (this was done as part of resolving |
714 // the type itself, a precondition to calling FinalizeType). | 726 // the type itself, a precondition to calling FinalizeType). |
715 // Also, the interfaces of the type class must be resolved and the type | 727 // Also, the interfaces of the type class must be resolved and the type |
716 // parameters of the type class must be finalized. | 728 // parameters of the type class must be finalized. |
717 Class& type_class = Class::Handle(parameterized_type.type_class()); | 729 Class& type_class = Class::Handle(parameterized_type.type_class()); |
718 if (!type_class.is_finalized()) { | 730 if (!type_class.is_finalized()) { |
719 FinalizeTypeParameters(type_class); | 731 FinalizeTypeParameters(type_class); |
| 732 ResolveUpperBounds(type_class); |
720 } | 733 } |
721 | 734 |
722 // Finalize the current type arguments of the type, which are still the | 735 // Finalize the current type arguments of the type, which are still the |
723 // parsed type arguments. | 736 // parsed type arguments. |
724 AbstractTypeArguments& arguments = | 737 AbstractTypeArguments& arguments = |
725 AbstractTypeArguments::Handle(parameterized_type.arguments()); | 738 AbstractTypeArguments::Handle(parameterized_type.arguments()); |
726 if (!arguments.IsNull()) { | 739 if (!arguments.IsNull()) { |
727 intptr_t num_arguments = arguments.Length(); | 740 intptr_t num_arguments = arguments.Length(); |
728 AbstractType& type_argument = AbstractType::Handle(); | 741 AbstractType& type_argument = AbstractType::Handle(); |
729 for (intptr_t i = 0; i < num_arguments; i++) { | 742 for (intptr_t i = 0; i < num_arguments; i++) { |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 !function.is_static() && | 984 !function.is_static() && |
972 !function.IsMethodExtractor()) { | 985 !function.IsMethodExtractor()) { |
973 return super_class.raw(); | 986 return super_class.raw(); |
974 } | 987 } |
975 super_class = super_class.SuperClass(); | 988 super_class = super_class.SuperClass(); |
976 } | 989 } |
977 return Class::null(); | 990 return Class::null(); |
978 } | 991 } |
979 | 992 |
980 | 993 |
981 // Resolve and finalize the upper bounds of the type parameters of class cls. | 994 // Resolve the upper bounds of the type parameters of class cls. |
982 void ClassFinalizer::ResolveAndFinalizeUpperBounds(const Class& cls) { | 995 void ClassFinalizer::ResolveUpperBounds(const Class& cls) { |
983 const intptr_t num_type_params = cls.NumTypeParameters(); | 996 const intptr_t num_type_params = cls.NumTypeParameters(); |
984 TypeParameter& type_param = TypeParameter::Handle(); | 997 TypeParameter& type_param = TypeParameter::Handle(); |
985 AbstractType& bound = AbstractType::Handle(); | 998 AbstractType& bound = AbstractType::Handle(); |
986 const AbstractTypeArguments& type_params = | 999 const AbstractTypeArguments& type_params = |
987 AbstractTypeArguments::Handle(cls.type_parameters()); | 1000 AbstractTypeArguments::Handle(cls.type_parameters()); |
988 ASSERT((type_params.IsNull() && (num_type_params == 0)) || | 1001 ASSERT((type_params.IsNull() && (num_type_params == 0)) || |
989 (type_params.Length() == num_type_params)); | 1002 (type_params.Length() == num_type_params)); |
| 1003 // In a first pass, resolve all bounds. This guarantees that finalization |
| 1004 // of mutually referencing bounds will not encounter an unresolved bound. |
| 1005 for (intptr_t i = 0; i < num_type_params; i++) { |
| 1006 type_param ^= type_params.TypeAt(i); |
| 1007 bound = type_param.bound(); |
| 1008 ResolveType(cls, bound, kCanonicalize); |
| 1009 } |
| 1010 } |
| 1011 |
| 1012 |
| 1013 // Finalize the upper bounds of the type parameters of class cls. |
| 1014 void ClassFinalizer::FinalizeUpperBounds(const Class& cls) { |
| 1015 const intptr_t num_type_params = cls.NumTypeParameters(); |
| 1016 TypeParameter& type_param = TypeParameter::Handle(); |
| 1017 AbstractType& bound = AbstractType::Handle(); |
| 1018 const AbstractTypeArguments& type_params = |
| 1019 AbstractTypeArguments::Handle(cls.type_parameters()); |
| 1020 ASSERT((type_params.IsNull() && (num_type_params == 0)) || |
| 1021 (type_params.Length() == num_type_params)); |
990 for (intptr_t i = 0; i < num_type_params; i++) { | 1022 for (intptr_t i = 0; i < num_type_params; i++) { |
991 type_param ^= type_params.TypeAt(i); | 1023 type_param ^= type_params.TypeAt(i); |
992 bound = type_param.bound(); | 1024 bound = type_param.bound(); |
993 if (bound.IsFinalized() || bound.IsBeingFinalized()) { | 1025 if (bound.IsFinalized() || bound.IsBeingFinalized()) { |
994 // A bound involved in F-bounded quantification may form a cycle. | 1026 // A bound involved in F-bounded quantification may form a cycle. |
995 continue; | 1027 continue; |
996 } | 1028 } |
997 ResolveType(cls, bound, kCanonicalize); | |
998 bound = FinalizeType(cls, bound, kCanonicalize); | 1029 bound = FinalizeType(cls, bound, kCanonicalize); |
999 type_param.set_bound(bound); | 1030 type_param.set_bound(bound); |
1000 } | 1031 } |
1001 } | 1032 } |
1002 | 1033 |
1003 | 1034 |
1004 void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) { | 1035 void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) { |
1005 // Note that getters and setters are explicitly listed as such in the list of | 1036 // Note that getters and setters are explicitly listed as such in the list of |
1006 // functions of a class, so we do not need to consider fields as implicitly | 1037 // functions of a class, so we do not need to consider fields as implicitly |
1007 // generating getters and setters. | 1038 // generating getters and setters. |
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1362 FinalizeClass(super_class); | 1393 FinalizeClass(super_class); |
1363 } | 1394 } |
1364 if (cls.mixin() != Type::null()) { | 1395 if (cls.mixin() != Type::null()) { |
1365 // Copy instance methods and fields from the mixin class. | 1396 // Copy instance methods and fields from the mixin class. |
1366 // This has to happen before the check whether the methods of | 1397 // This has to happen before the check whether the methods of |
1367 // the class conflict with inherited methods. | 1398 // the class conflict with inherited methods. |
1368 ApplyMixin(cls); | 1399 ApplyMixin(cls); |
1369 } | 1400 } |
1370 // Finalize type parameters before finalizing the super type. | 1401 // Finalize type parameters before finalizing the super type. |
1371 FinalizeTypeParameters(cls); | 1402 FinalizeTypeParameters(cls); |
| 1403 ResolveUpperBounds(cls); |
1372 // Finalize super type. | 1404 // Finalize super type. |
1373 AbstractType& super_type = AbstractType::Handle(cls.super_type()); | 1405 AbstractType& super_type = AbstractType::Handle(cls.super_type()); |
1374 if (!super_type.IsNull()) { | 1406 if (!super_type.IsNull()) { |
1375 // In case of a bound error in the super type in production mode, the | 1407 // In case of a bound error in the super type in production mode, the |
1376 // finalized super type will be a BoundedType with a malformed bound. | 1408 // finalized super type will be a BoundedType with a malformed bound. |
1377 // It should not be a problem if the class is written to a snapshot and | 1409 // It should not be a problem if the class is written to a snapshot and |
1378 // later executed in checked mode. Note that the finalized type argument | 1410 // later executed in checked mode. Note that the finalized type argument |
1379 // vector of any type of the base class will contain a BoundedType for the | 1411 // vector of any type of the base class will contain a BoundedType for the |
1380 // out of bound type argument. | 1412 // out of bound type argument. |
1381 super_type = FinalizeType(cls, super_type, kCanonicalizeWellFormed); | 1413 super_type = FinalizeType(cls, super_type, kCanonicalizeWellFormed); |
1382 cls.set_super_type(super_type); | 1414 cls.set_super_type(super_type); |
1383 } | 1415 } |
1384 if (cls.IsSignatureClass()) { | 1416 if (cls.IsSignatureClass()) { |
1385 // Check for illegal self references. | 1417 // Check for illegal self references. |
1386 GrowableArray<intptr_t> visited_aliases; | 1418 GrowableArray<intptr_t> visited_aliases; |
1387 if (!IsAliasCycleFree(cls, &visited_aliases)) { | 1419 if (!IsAliasCycleFree(cls, &visited_aliases)) { |
1388 const String& name = String::Handle(cls.Name()); | 1420 const String& name = String::Handle(cls.Name()); |
1389 const Script& script = Script::Handle(cls.script()); | 1421 const Script& script = Script::Handle(cls.script()); |
1390 ReportError(script, cls.token_pos(), | 1422 ReportError(script, cls.token_pos(), |
1391 "typedef '%s' illegally refers to itself", | 1423 "typedef '%s' illegally refers to itself", |
1392 name.ToCString()); | 1424 name.ToCString()); |
1393 } | 1425 } |
1394 cls.Finalize(); | 1426 cls.Finalize(); |
1395 // Signature classes extend Object. No need to add this class to the direct | 1427 // Signature classes extend Object. No need to add this class to the direct |
1396 // subclasses of Object. | 1428 // subclasses of Object. |
1397 ASSERT(super_type.IsNull() || super_type.IsObjectType()); | 1429 ASSERT(super_type.IsNull() || super_type.IsObjectType()); |
1398 | 1430 |
1399 // The type parameters of signature classes may have bounds. | 1431 // The type parameters of signature classes may have bounds. |
1400 ResolveAndFinalizeUpperBounds(cls); | 1432 FinalizeUpperBounds(cls); |
1401 | 1433 |
1402 // Resolve and finalize the result and parameter types of the signature | 1434 // Resolve and finalize the result and parameter types of the signature |
1403 // function of this signature class. | 1435 // function of this signature class. |
1404 const Function& sig_function = Function::Handle(cls.signature_function()); | 1436 const Function& sig_function = Function::Handle(cls.signature_function()); |
1405 ResolveAndFinalizeSignature(cls, sig_function); | 1437 ResolveAndFinalizeSignature(cls, sig_function); |
1406 | 1438 |
1407 // Resolve and finalize the signature type of this signature class. | 1439 // Resolve and finalize the signature type of this signature class. |
1408 const Type& sig_type = Type::Handle(cls.SignatureType()); | 1440 const Type& sig_type = Type::Handle(cls.SignatureType()); |
1409 FinalizeType(cls, sig_type, kCanonicalizeWellFormed); | 1441 FinalizeType(cls, sig_type, kCanonicalizeWellFormed); |
1410 return; | 1442 return; |
(...skipping 30 matching lines...) Expand all Loading... |
1441 String::Handle(interface_type.Name()).ToCString(), | 1473 String::Handle(interface_type.Name()).ToCString(), |
1442 String::Handle(cls.Name()).ToCString()); | 1474 String::Handle(cls.Name()).ToCString()); |
1443 } | 1475 } |
1444 } | 1476 } |
1445 } | 1477 } |
1446 // Mark as finalized before resolving type parameter upper bounds and member | 1478 // Mark as finalized before resolving type parameter upper bounds and member |
1447 // types in order to break cycles. | 1479 // types in order to break cycles. |
1448 cls.Finalize(); | 1480 cls.Finalize(); |
1449 // Finalize bounds even if running in production mode, so that a snapshot | 1481 // Finalize bounds even if running in production mode, so that a snapshot |
1450 // contains them. | 1482 // contains them. |
1451 ResolveAndFinalizeUpperBounds(cls); | 1483 FinalizeUpperBounds(cls); |
1452 ResolveAndFinalizeMemberTypes(cls); | 1484 ResolveAndFinalizeMemberTypes(cls); |
1453 // Run additional checks after all types are finalized. | 1485 // Run additional checks after all types are finalized. |
1454 if (cls.is_const()) { | 1486 if (cls.is_const()) { |
1455 CheckForLegalConstClass(cls); | 1487 CheckForLegalConstClass(cls); |
1456 } | 1488 } |
1457 // Add this class to the direct subclasses of the superclass, unless the | 1489 // Add this class to the direct subclasses of the superclass, unless the |
1458 // superclass is Object. | 1490 // superclass is Object. |
1459 if (!super_type.IsNull() && !super_type.IsObjectType()) { | 1491 if (!super_type.IsNull() && !super_type.IsObjectType()) { |
1460 ASSERT(!super_class.IsNull()); | 1492 ASSERT(!super_class.IsNull()); |
1461 super_class.AddDirectSubclass(cls); | 1493 super_class.AddDirectSubclass(cls); |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1935 void ClassFinalizer::ReportError(const char* format, ...) { | 1967 void ClassFinalizer::ReportError(const char* format, ...) { |
1936 va_list args; | 1968 va_list args; |
1937 va_start(args, format); | 1969 va_start(args, format); |
1938 const Error& error = Error::Handle( | 1970 const Error& error = Error::Handle( |
1939 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); | 1971 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); |
1940 va_end(args); | 1972 va_end(args); |
1941 ReportError(error); | 1973 ReportError(error); |
1942 } | 1974 } |
1943 | 1975 |
1944 } // namespace dart | 1976 } // namespace dart |
OLD | NEW |