OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/become.h" | 10 #include "vm/become.h" |
(...skipping 1978 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1989 | 1989 |
1990 bool Class::IsInFullSnapshot() const { | 1990 bool Class::IsInFullSnapshot() const { |
1991 NoSafepointScope no_safepoint; | 1991 NoSafepointScope no_safepoint; |
1992 return raw_ptr()->library_->ptr()->is_in_fullsnapshot_; | 1992 return raw_ptr()->library_->ptr()->is_in_fullsnapshot_; |
1993 } | 1993 } |
1994 | 1994 |
1995 | 1995 |
1996 RawAbstractType* Class::RareType() const { | 1996 RawAbstractType* Class::RareType() const { |
1997 const Type& type = Type::Handle(Type::New( | 1997 const Type& type = Type::Handle(Type::New( |
1998 *this, Object::null_type_arguments(), TokenPosition::kNoSource)); | 1998 *this, Object::null_type_arguments(), TokenPosition::kNoSource)); |
1999 return ClassFinalizer::FinalizeType(*this, type, | 1999 return ClassFinalizer::FinalizeType(*this, type); |
2000 ClassFinalizer::kCanonicalize); | |
2001 } | 2000 } |
2002 | 2001 |
2003 | 2002 |
2004 RawAbstractType* Class::DeclarationType() const { | 2003 RawAbstractType* Class::DeclarationType() const { |
2005 const TypeArguments& args = TypeArguments::Handle(type_parameters()); | 2004 const TypeArguments& args = TypeArguments::Handle(type_parameters()); |
2006 const Type& type = | 2005 const Type& type = |
2007 Type::Handle(Type::New(*this, args, TokenPosition::kNoSource)); | 2006 Type::Handle(Type::New(*this, args, TokenPosition::kNoSource)); |
2008 return ClassFinalizer::FinalizeType(*this, type, | 2007 return ClassFinalizer::FinalizeType(*this, type); |
2009 ClassFinalizer::kCanonicalize); | |
2010 } | 2008 } |
2011 | 2009 |
2012 | 2010 |
2013 template <class FakeObject> | 2011 template <class FakeObject> |
2014 RawClass* Class::New() { | 2012 RawClass* Class::New() { |
2015 ASSERT(Object::class_class() != Class::null()); | 2013 ASSERT(Object::class_class() != Class::null()); |
2016 Class& result = Class::Handle(); | 2014 Class& result = Class::Handle(); |
2017 { | 2015 { |
2018 RawObject* raw = | 2016 RawObject* raw = |
2019 Object::Allocate(Class::kClassId, Class::InstanceSize(), Heap::kOld); | 2017 Object::Allocate(Class::kClassId, Class::InstanceSize(), Heap::kOld); |
(...skipping 1807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3827 // it would have to have all dynamic type arguments which is checked | 3825 // it would have to have all dynamic type arguments which is checked |
3828 // above. | 3826 // above. |
3829 return test_kind == Class::kIsSubtypeOf; | 3827 return test_kind == Class::kIsSubtypeOf; |
3830 } | 3828 } |
3831 return type_arguments.TypeTest(test_kind, other_type_arguments, | 3829 return type_arguments.TypeTest(test_kind, other_type_arguments, |
3832 from_index, num_type_params, bound_error, | 3830 from_index, num_type_params, bound_error, |
3833 bound_trail, space); | 3831 bound_trail, space); |
3834 } | 3832 } |
3835 if (other.IsDartFunctionClass()) { | 3833 if (other.IsDartFunctionClass()) { |
3836 // Check if type S has a call() method. | 3834 // Check if type S has a call() method. |
3837 Function& function = Function::Handle( | 3835 const Function& call_function = |
3838 zone, thsi.LookupDynamicFunctionAllowAbstract(Symbols::Call())); | 3836 Function::Handle(zone, thsi.LookupCallFunctionForTypeTest()); |
3839 if (function.IsNull()) { | 3837 if (!call_function.IsNull()) { |
3840 // Walk up the super_class chain. | |
3841 Class& cls = Class::Handle(zone, thsi.SuperClass()); | |
3842 while (!cls.IsNull() && function.IsNull()) { | |
3843 function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()); | |
3844 cls = cls.SuperClass(); | |
3845 } | |
3846 } | |
3847 if (!function.IsNull()) { | |
3848 return true; | 3838 return true; |
3849 } | 3839 } |
3850 } | 3840 } |
3851 // Check for 'direct super type' specified in the implements clause | 3841 // Check for 'direct super type' specified in the implements clause |
3852 // and check for transitivity at the same time. | 3842 // and check for transitivity at the same time. |
3853 Array& interfaces = Array::Handle(zone, thsi.interfaces()); | 3843 Array& interfaces = Array::Handle(zone, thsi.interfaces()); |
3854 AbstractType& interface = AbstractType::Handle(zone); | 3844 AbstractType& interface = AbstractType::Handle(zone); |
3855 Class& interface_class = Class::Handle(zone); | 3845 Class& interface_class = Class::Handle(zone); |
3856 TypeArguments& interface_args = TypeArguments::Handle(zone); | 3846 TypeArguments& interface_args = TypeArguments::Handle(zone); |
3857 Error& error = Error::Handle(zone); | 3847 Error& error = Error::Handle(zone); |
3858 for (intptr_t i = 0; i < interfaces.Length(); i++) { | 3848 for (intptr_t i = 0; i < interfaces.Length(); i++) { |
3859 interface ^= interfaces.At(i); | 3849 interface ^= interfaces.At(i); |
3860 if (!interface.IsFinalized()) { | 3850 if (!interface.IsFinalized()) { |
3861 // We may be checking bounds at finalization time and can encounter | 3851 // We may be checking bounds at finalization time and can encounter |
3862 // a still unfinalized interface. | 3852 // a still unfinalized interface. |
3863 if (interface.IsBeingFinalized()) { | 3853 if (interface.IsBeingFinalized()) { |
3864 // Interface is part of a still unfinalized recursive type graph. | 3854 // Interface is part of a still unfinalized recursive type graph. |
3865 // Skip it. The caller will create a bounded type to be checked at | 3855 // Skip it. The caller will create a bounded type to be checked at |
3866 // runtime if this type test returns false at compile time. | 3856 // runtime if this type test returns false at compile time. |
3867 continue; | 3857 continue; |
3868 } | 3858 } |
3869 ClassFinalizer::FinalizeType(thsi, interface, | 3859 ClassFinalizer::FinalizeType(thsi, interface); |
3870 ClassFinalizer::kCanonicalize); | |
3871 interfaces.SetAt(i, interface); | 3860 interfaces.SetAt(i, interface); |
3872 } | 3861 } |
3873 if (interface.IsMalbounded()) { | 3862 if (interface.IsMalbounded()) { |
3874 // Return the first bound error to the caller if it requests it. | 3863 // Return the first bound error to the caller if it requests it. |
3875 if ((bound_error != NULL) && bound_error->IsNull()) { | 3864 if ((bound_error != NULL) && bound_error->IsNull()) { |
3876 *bound_error = interface.error(); | 3865 *bound_error = interface.error(); |
3877 } | 3866 } |
3878 continue; // Another interface may work better. | 3867 continue; // Another interface may work better. |
3879 } | 3868 } |
3880 interface_class = interface.type_class(); | 3869 interface_class = interface.type_class(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3995 RawFunction* Class::LookupFunction(const String& name) const { | 3984 RawFunction* Class::LookupFunction(const String& name) const { |
3996 return LookupFunction(name, kAny); | 3985 return LookupFunction(name, kAny); |
3997 } | 3986 } |
3998 | 3987 |
3999 | 3988 |
4000 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { | 3989 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { |
4001 return LookupFunctionAllowPrivate(name, kAny); | 3990 return LookupFunctionAllowPrivate(name, kAny); |
4002 } | 3991 } |
4003 | 3992 |
4004 | 3993 |
| 3994 RawFunction* Class::LookupCallFunctionForTypeTest() const { |
| 3995 // If this class is not compiled yet, it is too early to lookup a call |
| 3996 // function. This case should only occur during bounds checking at compile |
| 3997 // time. Return null as if the call method did not exist, so the type test |
| 3998 // may return false, but without a bound error, and the bound check will get |
| 3999 // postponed to runtime. |
| 4000 if (!is_finalized()) { |
| 4001 return Function::null(); |
| 4002 } |
| 4003 Zone* zone = Thread::Current()->zone(); |
| 4004 Class& cls = Class::Handle(zone, raw()); |
| 4005 Function& call_function = Function::Handle(zone); |
| 4006 do { |
| 4007 ASSERT(cls.is_finalized()); |
| 4008 call_function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()); |
| 4009 cls = cls.SuperClass(); |
| 4010 } while (call_function.IsNull() && !cls.IsNull()); |
| 4011 if (!call_function.IsNull()) { |
| 4012 // Make sure the signature is finalized before using it in a type test. |
| 4013 ClassFinalizer::FinalizeSignature( |
| 4014 cls, call_function, ClassFinalizer::kFinalize); // No bounds checking. |
| 4015 } |
| 4016 return call_function.raw(); |
| 4017 } |
| 4018 |
| 4019 |
4005 // Returns true if 'prefix' and 'accessor_name' match 'name'. | 4020 // Returns true if 'prefix' and 'accessor_name' match 'name'. |
4006 static bool MatchesAccessorName(const String& name, | 4021 static bool MatchesAccessorName(const String& name, |
4007 const char* prefix, | 4022 const char* prefix, |
4008 intptr_t prefix_length, | 4023 intptr_t prefix_length, |
4009 const String& accessor_name) { | 4024 const String& accessor_name) { |
4010 intptr_t name_len = name.Length(); | 4025 intptr_t name_len = name.Length(); |
4011 intptr_t accessor_name_len = accessor_name.Length(); | 4026 intptr_t accessor_name_len = accessor_name.Length(); |
4012 | 4027 |
4013 if (name_len != (accessor_name_len + prefix_length)) { | 4028 if (name_len != (accessor_name_len + prefix_length)) { |
4014 return false; | 4029 return false; |
(...skipping 2775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6790 for (int i = kClosure; i < num_params; i++) { | 6805 for (int i = kClosure; i < num_params; i++) { |
6791 param_type = ParameterTypeAt(has_receiver - kClosure + i); | 6806 param_type = ParameterTypeAt(has_receiver - kClosure + i); |
6792 closure_function.SetParameterTypeAt(i, param_type); | 6807 closure_function.SetParameterTypeAt(i, param_type); |
6793 param_name = ParameterNameAt(has_receiver - kClosure + i); | 6808 param_name = ParameterNameAt(has_receiver - kClosure + i); |
6794 closure_function.SetParameterNameAt(i, param_name); | 6809 closure_function.SetParameterNameAt(i, param_name); |
6795 } | 6810 } |
6796 closure_function.set_kernel_function(kernel_function()); | 6811 closure_function.set_kernel_function(kernel_function()); |
6797 | 6812 |
6798 const Type& signature_type = Type::Handle(closure_function.SignatureType()); | 6813 const Type& signature_type = Type::Handle(closure_function.SignatureType()); |
6799 if (!signature_type.IsFinalized()) { | 6814 if (!signature_type.IsFinalized()) { |
6800 ClassFinalizer::FinalizeType(Class::Handle(Owner()), signature_type, | 6815 ClassFinalizer::FinalizeType(Class::Handle(Owner()), signature_type); |
6801 ClassFinalizer::kCanonicalize); | |
6802 } | 6816 } |
6803 set_implicit_closure_function(closure_function); | 6817 set_implicit_closure_function(closure_function); |
6804 ASSERT(closure_function.IsImplicitClosureFunction()); | 6818 ASSERT(closure_function.IsImplicitClosureFunction()); |
6805 return closure_function.raw(); | 6819 return closure_function.raw(); |
6806 } | 6820 } |
6807 | 6821 |
6808 | 6822 |
6809 void Function::DropUncompiledImplicitClosureFunction() const { | 6823 void Function::DropUncompiledImplicitClosureFunction() const { |
6810 if (implicit_closure_function() != Function::null()) { | 6824 if (implicit_closure_function() != Function::null()) { |
6811 const Function& func = Function::Handle(implicit_closure_function()); | 6825 const Function& func = Function::Handle(implicit_closure_function()); |
(...skipping 8943 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15755 instantiated_other = TypeRef::Cast(instantiated_other).type(); | 15769 instantiated_other = TypeRef::Cast(instantiated_other).type(); |
15756 } | 15770 } |
15757 if (instantiated_other.IsDynamicType()) { | 15771 if (instantiated_other.IsDynamicType()) { |
15758 return true; | 15772 return true; |
15759 } | 15773 } |
15760 } | 15774 } |
15761 other_type_arguments = instantiated_other.arguments(); | 15775 other_type_arguments = instantiated_other.arguments(); |
15762 const bool other_is_dart_function = instantiated_other.IsDartFunctionType(); | 15776 const bool other_is_dart_function = instantiated_other.IsDartFunctionType(); |
15763 if (other_is_dart_function || instantiated_other.IsFunctionType()) { | 15777 if (other_is_dart_function || instantiated_other.IsFunctionType()) { |
15764 // Check if this instance understands a call() method of a compatible type. | 15778 // Check if this instance understands a call() method of a compatible type. |
15765 Function& call = Function::Handle( | 15779 const Function& call_function = |
15766 zone, cls.LookupDynamicFunctionAllowAbstract(Symbols::Call())); | 15780 Function::Handle(zone, cls.LookupCallFunctionForTypeTest()); |
15767 if (call.IsNull()) { | 15781 if (!call_function.IsNull()) { |
15768 // Walk up the super_class chain. | |
15769 Class& super_cls = Class::Handle(zone, cls.SuperClass()); | |
15770 while (!super_cls.IsNull() && call.IsNull()) { | |
15771 call = super_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()); | |
15772 super_cls = super_cls.SuperClass(); | |
15773 } | |
15774 } | |
15775 if (!call.IsNull()) { | |
15776 if (other_is_dart_function) { | 15782 if (other_is_dart_function) { |
15777 return true; | 15783 return true; |
15778 } | 15784 } |
15779 const Function& other_signature = | 15785 const Function& other_signature = |
15780 Function::Handle(zone, Type::Cast(instantiated_other).signature()); | 15786 Function::Handle(zone, Type::Cast(instantiated_other).signature()); |
15781 if (call.IsSubtypeOf(type_arguments, other_signature, | 15787 if (call_function.IsSubtypeOf(type_arguments, other_signature, |
15782 other_type_arguments, bound_error, Heap::kOld)) { | 15788 other_type_arguments, bound_error, |
| 15789 Heap::kOld)) { |
15783 return true; | 15790 return true; |
15784 } | 15791 } |
15785 } | 15792 } |
15786 } | 15793 } |
15787 if (!instantiated_other.IsType()) { | 15794 if (!instantiated_other.IsType()) { |
15788 return false; | 15795 return false; |
15789 } | 15796 } |
15790 other_class = instantiated_other.type_class(); | 15797 other_class = instantiated_other.type_class(); |
15791 if (IsNull()) { | 15798 if (IsNull()) { |
15792 ASSERT(cls.IsNullClass()); | 15799 ASSERT(cls.IsNullClass()); |
(...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16574 const Function& other_fun = | 16581 const Function& other_fun = |
16575 Function::Handle(zone, Type::Cast(other).signature()); | 16582 Function::Handle(zone, Type::Cast(other).signature()); |
16576 // Check for two function types. | 16583 // Check for two function types. |
16577 const Function& fun = | 16584 const Function& fun = |
16578 Function::Handle(zone, Type::Cast(*this).signature()); | 16585 Function::Handle(zone, Type::Cast(*this).signature()); |
16579 return fun.TypeTest( | 16586 return fun.TypeTest( |
16580 test_kind, TypeArguments::Handle(zone, arguments()), other_fun, | 16587 test_kind, TypeArguments::Handle(zone, arguments()), other_fun, |
16581 TypeArguments::Handle(zone, other.arguments()), bound_error, space); | 16588 TypeArguments::Handle(zone, other.arguments()), bound_error, space); |
16582 } | 16589 } |
16583 // Check if type S has a call() method of function type T. | 16590 // Check if type S has a call() method of function type T. |
16584 Function& function = Function::Handle( | 16591 const Function& call_function = |
16585 zone, type_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call())); | 16592 Function::Handle(zone, type_cls.LookupCallFunctionForTypeTest()); |
16586 if (function.IsNull()) { | 16593 if (!call_function.IsNull()) { |
16587 // Walk up the super_class chain. | |
16588 Class& cls = Class::Handle(zone, type_cls.SuperClass()); | |
16589 while (!cls.IsNull() && function.IsNull()) { | |
16590 function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()); | |
16591 cls = cls.SuperClass(); | |
16592 } | |
16593 } | |
16594 if (!function.IsNull()) { | |
16595 if (other_is_dart_function_type || | 16594 if (other_is_dart_function_type || |
16596 function.TypeTest( | 16595 call_function.TypeTest( |
16597 test_kind, TypeArguments::Handle(zone, arguments()), | 16596 test_kind, TypeArguments::Handle(zone, arguments()), |
16598 Function::Handle(zone, Type::Cast(other).signature()), | 16597 Function::Handle(zone, Type::Cast(other).signature()), |
16599 TypeArguments::Handle(zone, other.arguments()), bound_error, | 16598 TypeArguments::Handle(zone, other.arguments()), bound_error, |
16600 space)) { | 16599 space)) { |
16601 return true; | 16600 return true; |
16602 } | 16601 } |
16603 } | 16602 } |
16604 } | 16603 } |
16605 if (IsFunctionType()) { | 16604 if (IsFunctionType()) { |
16606 return false; | 16605 return false; |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16877 ASSERT(num_type_args > 0); | 16876 ASSERT(num_type_args > 0); |
16878 // This type is not instantiated if it refers to type parameters. | 16877 // This type is not instantiated if it refers to type parameters. |
16879 // Although this type may still be unresolved, the type parameters it may | 16878 // Although this type may still be unresolved, the type parameters it may |
16880 // refer to are resolved by definition. We can therefore return the correct | 16879 // refer to are resolved by definition. We can therefore return the correct |
16881 // result even for an unresolved type. We just need to look at all type | 16880 // result even for an unresolved type. We just need to look at all type |
16882 // arguments and not just at the type parameters. | 16881 // arguments and not just at the type parameters. |
16883 if (HasResolvedTypeClass()) { | 16882 if (HasResolvedTypeClass()) { |
16884 const Class& cls = Class::Handle(type_class()); | 16883 const Class& cls = Class::Handle(type_class()); |
16885 len = cls.NumTypeParameters(); // Check the type parameters only. | 16884 len = cls.NumTypeParameters(); // Check the type parameters only. |
16886 } | 16885 } |
16887 return (len == 0) || args.IsSubvectorInstantiated(num_type_args - len, len); | 16886 return (len == 0) || |
| 16887 args.IsSubvectorInstantiated(num_type_args - len, len, trail); |
16888 } | 16888 } |
16889 | 16889 |
16890 | 16890 |
16891 RawAbstractType* Type::InstantiateFrom( | 16891 RawAbstractType* Type::InstantiateFrom( |
16892 const TypeArguments& instantiator_type_arguments, | 16892 const TypeArguments& instantiator_type_arguments, |
16893 Error* bound_error, | 16893 Error* bound_error, |
16894 TrailPtr instantiation_trail, | 16894 TrailPtr instantiation_trail, |
16895 TrailPtr bound_trail, | 16895 TrailPtr bound_trail, |
16896 Heap::Space space) const { | 16896 Heap::Space space) const { |
16897 Zone* zone = Thread::Current()->zone(); | 16897 Zone* zone = Thread::Current()->zone(); |
(...skipping 959 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17857 } | 17857 } |
17858 | 17858 |
17859 if (bounded_type.IsSubtypeOf(upper_bound, bound_error, bound_trail, space)) { | 17859 if (bounded_type.IsSubtypeOf(upper_bound, bound_error, bound_trail, space)) { |
17860 return true; | 17860 return true; |
17861 } | 17861 } |
17862 // Set bound_error if the caller is interested and if this is the first error. | 17862 // Set bound_error if the caller is interested and if this is the first error. |
17863 if ((bound_error != NULL) && bound_error->IsNull()) { | 17863 if ((bound_error != NULL) && bound_error->IsNull()) { |
17864 // Report the bound error only if both the bounded type and the upper bound | 17864 // Report the bound error only if both the bounded type and the upper bound |
17865 // are instantiated. Otherwise, we cannot tell yet it is a bound error. | 17865 // are instantiated. Otherwise, we cannot tell yet it is a bound error. |
17866 if (bounded_type.IsInstantiated() && upper_bound.IsInstantiated()) { | 17866 if (bounded_type.IsInstantiated() && upper_bound.IsInstantiated()) { |
| 17867 // There is another special case where we do not want to report a bound |
| 17868 // error yet: if the upper bound is a function type, but the bounded type |
| 17869 // is not and its class is not compiled yet, i.e. we cannot look for |
| 17870 // a call method yet. |
| 17871 if (!bounded_type.IsFunctionType() && upper_bound.IsFunctionType() && |
| 17872 bounded_type.HasResolvedTypeClass() && |
| 17873 !Class::Handle(bounded_type.type_class()).is_finalized()) { |
| 17874 return false; // Not a subtype yet, but no bound error yet. |
| 17875 } |
17867 const String& bounded_type_name = | 17876 const String& bounded_type_name = |
17868 String::Handle(bounded_type.UserVisibleName()); | 17877 String::Handle(bounded_type.UserVisibleName()); |
17869 const String& upper_bound_name = | 17878 const String& upper_bound_name = |
17870 String::Handle(upper_bound.UserVisibleName()); | 17879 String::Handle(upper_bound.UserVisibleName()); |
17871 const AbstractType& declared_bound = AbstractType::Handle(bound()); | 17880 const AbstractType& declared_bound = AbstractType::Handle(bound()); |
17872 const String& declared_bound_name = | 17881 const String& declared_bound_name = |
17873 String::Handle(declared_bound.UserVisibleName()); | 17882 String::Handle(declared_bound.UserVisibleName()); |
17874 const String& type_param_name = String::Handle(UserVisibleName()); | 17883 const String& type_param_name = String::Handle(UserVisibleName()); |
17875 const Class& cls = Class::Handle(parameterized_class()); | 17884 const Class& cls = Class::Handle(parameterized_class()); |
17876 const String& class_name = String::Handle(cls.Name()); | 17885 const String& class_name = String::Handle(cls.Name()); |
(...skipping 5093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
22970 return UserTag::null(); | 22979 return UserTag::null(); |
22971 } | 22980 } |
22972 | 22981 |
22973 | 22982 |
22974 const char* UserTag::ToCString() const { | 22983 const char* UserTag::ToCString() const { |
22975 const String& tag_label = String::Handle(label()); | 22984 const String& tag_label = String::Handle(label()); |
22976 return tag_label.ToCString(); | 22985 return tag_label.ToCString(); |
22977 } | 22986 } |
22978 | 22987 |
22979 } // namespace dart | 22988 } // namespace dart |
OLD | NEW |