Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(567)

Side by Side Diff: runtime/vm/object.cc

Issue 2831073004: Use trail in type tests involving the call function (fixes #29405). (Closed)
Patch Set: add comment Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/object.h ('k') | tests/language/regress_29405_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 6429 matching lines...) Expand 10 before | Expand all | Expand 10 after
6440 this_fun = this_fun.InstantiateSignatureFrom(Object::null_type_arguments(), 6440 this_fun = this_fun.InstantiateSignatureFrom(Object::null_type_arguments(),
6441 Object::null_type_arguments(), 6441 Object::null_type_arguments(),
6442 Heap::kOld); 6442 Heap::kOld);
6443 } 6443 }
6444 Function& other_fun = Function::Handle(other.raw()); 6444 Function& other_fun = Function::Handle(other.raw());
6445 if (!other_fun.HasInstantiatedSignature()) { 6445 if (!other_fun.HasInstantiatedSignature()) {
6446 other_fun = other_fun.InstantiateSignatureFrom( 6446 other_fun = other_fun.InstantiateSignatureFrom(
6447 Object::null_type_arguments(), Object::null_type_arguments(), 6447 Object::null_type_arguments(), Object::null_type_arguments(),
6448 Heap::kOld); 6448 Heap::kOld);
6449 } 6449 }
6450 if (!this_fun.TypeTest(kIsSubtypeOf, other_fun, bound_error, Heap::kOld)) { 6450 if (!this_fun.TypeTest(kIsSubtypeOf, other_fun, bound_error, NULL,
6451 Heap::kOld)) {
6451 // For more informative error reporting, use the location of the other 6452 // For more informative error reporting, use the location of the other
6452 // function here, since the caller will use the location of this function. 6453 // function here, since the caller will use the location of this function.
6453 *bound_error = LanguageError::NewFormatted( 6454 *bound_error = LanguageError::NewFormatted(
6454 *bound_error, // A bound error if non null. 6455 *bound_error, // A bound error if non null.
6455 Script::Handle(other.script()), other.token_pos(), Report::AtLocation, 6456 Script::Handle(other.script()), other.token_pos(), Report::AtLocation,
6456 Report::kError, Heap::kNew, 6457 Report::kError, Heap::kNew,
6457 "signature type '%s' of function '%s' is not a subtype of signature " 6458 "signature type '%s' of function '%s' is not a subtype of signature "
6458 "type '%s' of function '%s'\n", 6459 "type '%s' of function '%s'\n",
6459 String::Handle(UserVisibleSignature()).ToCString(), 6460 String::Handle(UserVisibleSignature()).ToCString(),
6460 String::Handle(UserVisibleName()).ToCString(), 6461 String::Handle(UserVisibleName()).ToCString(),
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
6515 // If test_kind == kIsMoreSpecificThan, checks if the type of the specified 6516 // If test_kind == kIsMoreSpecificThan, checks if the type of the specified
6516 // parameter of this function is more specific than the type of the specified 6517 // parameter of this function is more specific than the type of the specified
6517 // parameter of the other function. 6518 // parameter of the other function.
6518 // Note that we do not apply contravariance of parameter types, but covariance 6519 // Note that we do not apply contravariance of parameter types, but covariance
6519 // of both parameter types and result type. 6520 // of both parameter types and result type.
6520 bool Function::TestParameterType(TypeTestKind test_kind, 6521 bool Function::TestParameterType(TypeTestKind test_kind,
6521 intptr_t parameter_position, 6522 intptr_t parameter_position,
6522 intptr_t other_parameter_position, 6523 intptr_t other_parameter_position,
6523 const Function& other, 6524 const Function& other,
6524 Error* bound_error, 6525 Error* bound_error,
6526 TrailPtr bound_trail,
6525 Heap::Space space) const { 6527 Heap::Space space) const {
6526 const AbstractType& other_param_type = 6528 const AbstractType& other_param_type =
6527 AbstractType::Handle(other.ParameterTypeAt(other_parameter_position)); 6529 AbstractType::Handle(other.ParameterTypeAt(other_parameter_position));
6528 if (other_param_type.IsDynamicType()) { 6530 if (other_param_type.IsDynamicType()) {
6529 return true; 6531 return true;
6530 } 6532 }
6531 const AbstractType& param_type = 6533 const AbstractType& param_type =
6532 AbstractType::Handle(ParameterTypeAt(parameter_position)); 6534 AbstractType::Handle(ParameterTypeAt(parameter_position));
6533 if (param_type.IsDynamicType()) { 6535 if (param_type.IsDynamicType()) {
6534 return test_kind == kIsSubtypeOf; 6536 return test_kind == kIsSubtypeOf;
6535 } 6537 }
6536 if (test_kind == kIsSubtypeOf) { 6538 if (test_kind == kIsSubtypeOf) {
6537 if (!param_type.IsSubtypeOf(other_param_type, bound_error, NULL, space) && 6539 if (!param_type.IsSubtypeOf(other_param_type, bound_error, bound_trail,
6538 !other_param_type.IsSubtypeOf(param_type, bound_error, NULL, space)) { 6540 space) &&
6541 !other_param_type.IsSubtypeOf(param_type, bound_error, bound_trail,
6542 space)) {
6539 return false; 6543 return false;
6540 } 6544 }
6541 } else { 6545 } else {
6542 ASSERT(test_kind == kIsMoreSpecificThan); 6546 ASSERT(test_kind == kIsMoreSpecificThan);
6543 if (!param_type.IsMoreSpecificThan(other_param_type, bound_error, NULL, 6547 if (!param_type.IsMoreSpecificThan(other_param_type, bound_error,
6544 space)) { 6548 bound_trail, space)) {
6545 return false; 6549 return false;
6546 } 6550 }
6547 } 6551 }
6548 return true; 6552 return true;
6549 } 6553 }
6550 6554
6551 6555
6552 bool Function::HasSameTypeParametersAndBounds(const Function& other) const { 6556 bool Function::HasSameTypeParametersAndBounds(const Function& other) const {
6553 Thread* thread = Thread::Current(); 6557 Thread* thread = Thread::Current();
6554 Zone* zone = thread->zone(); 6558 Zone* zone = thread->zone();
(...skipping 24 matching lines...) Expand all
6579 } 6583 }
6580 } 6584 }
6581 } 6585 }
6582 return true; 6586 return true;
6583 } 6587 }
6584 6588
6585 6589
6586 bool Function::TypeTest(TypeTestKind test_kind, 6590 bool Function::TypeTest(TypeTestKind test_kind,
6587 const Function& other, 6591 const Function& other,
6588 Error* bound_error, 6592 Error* bound_error,
6593 TrailPtr bound_trail,
6589 Heap::Space space) const { 6594 Heap::Space space) const {
6590 const intptr_t num_fixed_params = num_fixed_parameters(); 6595 const intptr_t num_fixed_params = num_fixed_parameters();
6591 const intptr_t num_opt_pos_params = NumOptionalPositionalParameters(); 6596 const intptr_t num_opt_pos_params = NumOptionalPositionalParameters();
6592 const intptr_t num_opt_named_params = NumOptionalNamedParameters(); 6597 const intptr_t num_opt_named_params = NumOptionalNamedParameters();
6593 const intptr_t other_num_fixed_params = other.num_fixed_parameters(); 6598 const intptr_t other_num_fixed_params = other.num_fixed_parameters();
6594 const intptr_t other_num_opt_pos_params = 6599 const intptr_t other_num_opt_pos_params =
6595 other.NumOptionalPositionalParameters(); 6600 other.NumOptionalPositionalParameters();
6596 const intptr_t other_num_opt_named_params = 6601 const intptr_t other_num_opt_named_params =
6597 other.NumOptionalNamedParameters(); 6602 other.NumOptionalNamedParameters();
6598 // This function requires the same arguments or less and accepts the same 6603 // This function requires the same arguments or less and accepts the same
(...skipping 18 matching lines...) Expand all
6617 Zone* zone = thread->zone(); 6622 Zone* zone = thread->zone();
6618 // Check the result type. 6623 // Check the result type.
6619 const AbstractType& other_res_type = 6624 const AbstractType& other_res_type =
6620 AbstractType::Handle(zone, other.result_type()); 6625 AbstractType::Handle(zone, other.result_type());
6621 if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) { 6626 if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) {
6622 const AbstractType& res_type = AbstractType::Handle(zone, result_type()); 6627 const AbstractType& res_type = AbstractType::Handle(zone, result_type());
6623 if (res_type.IsVoidType()) { 6628 if (res_type.IsVoidType()) {
6624 return false; 6629 return false;
6625 } 6630 }
6626 if (test_kind == kIsSubtypeOf) { 6631 if (test_kind == kIsSubtypeOf) {
6627 if (!res_type.IsSubtypeOf(other_res_type, bound_error, NULL, space) && 6632 if (!res_type.IsSubtypeOf(other_res_type, bound_error, bound_trail,
6628 !other_res_type.IsSubtypeOf(res_type, bound_error, NULL, space)) { 6633 space) &&
6634 !other_res_type.IsSubtypeOf(res_type, bound_error, bound_trail,
6635 space)) {
6629 return false; 6636 return false;
6630 } 6637 }
6631 } else { 6638 } else {
6632 ASSERT(test_kind == kIsMoreSpecificThan); 6639 ASSERT(test_kind == kIsMoreSpecificThan);
6633 if (!res_type.IsMoreSpecificThan(other_res_type, bound_error, NULL, 6640 if (!res_type.IsMoreSpecificThan(other_res_type, bound_error, bound_trail,
6634 space)) { 6641 space)) {
6635 return false; 6642 return false;
6636 } 6643 }
6637 } 6644 }
6638 } 6645 }
6639 // Check the types of fixed and optional positional parameters. 6646 // Check the types of fixed and optional positional parameters.
6640 for (intptr_t i = 0; i < (other_num_fixed_params - other_num_ignored_params + 6647 for (intptr_t i = 0; i < (other_num_fixed_params - other_num_ignored_params +
6641 other_num_opt_pos_params); 6648 other_num_opt_pos_params);
6642 i++) { 6649 i++) {
6643 if (!TestParameterType(test_kind, i + num_ignored_params, 6650 if (!TestParameterType(test_kind, i + num_ignored_params,
6644 i + other_num_ignored_params, other, bound_error, 6651 i + other_num_ignored_params, other, bound_error,
6645 space)) { 6652 bound_trail, space)) {
6646 return false; 6653 return false;
6647 } 6654 }
6648 } 6655 }
6649 // Check the names and types of optional named parameters. 6656 // Check the names and types of optional named parameters.
6650 if (other_num_opt_named_params == 0) { 6657 if (other_num_opt_named_params == 0) {
6651 return true; 6658 return true;
6652 } 6659 }
6653 // Check that for each optional named parameter of type T of the other 6660 // Check that for each optional named parameter of type T of the other
6654 // function type, there exists an optional named parameter of this function 6661 // function type, there exists an optional named parameter of this function
6655 // type with an identical name and with a type S that is a either a subtype 6662 // type with an identical name and with a type S that is a either a subtype
6656 // or supertype of T (if test_kind == kIsSubtypeOf) or that is more specific 6663 // or supertype of T (if test_kind == kIsSubtypeOf) or that is more specific
6657 // than T (if test_kind == kIsMoreSpecificThan). 6664 // than T (if test_kind == kIsMoreSpecificThan).
6658 // Note that SetParameterNameAt() guarantees that names are symbols, so we 6665 // Note that SetParameterNameAt() guarantees that names are symbols, so we
6659 // can compare their raw pointers. 6666 // can compare their raw pointers.
6660 const int num_params = num_fixed_params + num_opt_named_params; 6667 const int num_params = num_fixed_params + num_opt_named_params;
6661 const int other_num_params = 6668 const int other_num_params =
6662 other_num_fixed_params + other_num_opt_named_params; 6669 other_num_fixed_params + other_num_opt_named_params;
6663 bool found_param_name; 6670 bool found_param_name;
6664 String& other_param_name = String::Handle(zone); 6671 String& other_param_name = String::Handle(zone);
6665 for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { 6672 for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) {
6666 other_param_name = other.ParameterNameAt(i); 6673 other_param_name = other.ParameterNameAt(i);
6667 ASSERT(other_param_name.IsSymbol()); 6674 ASSERT(other_param_name.IsSymbol());
6668 found_param_name = false; 6675 found_param_name = false;
6669 for (intptr_t j = num_fixed_params; j < num_params; j++) { 6676 for (intptr_t j = num_fixed_params; j < num_params; j++) {
6670 ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol()); 6677 ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol());
6671 if (ParameterNameAt(j) == other_param_name.raw()) { 6678 if (ParameterNameAt(j) == other_param_name.raw()) {
6672 found_param_name = true; 6679 found_param_name = true;
6673 if (!TestParameterType(test_kind, j, i, other, bound_error, space)) { 6680 if (!TestParameterType(test_kind, j, i, other, bound_error, bound_trail,
6681 space)) {
6674 return false; 6682 return false;
6675 } 6683 }
6676 break; 6684 break;
6677 } 6685 }
6678 } 6686 }
6679 if (!found_param_name) { 6687 if (!found_param_name) {
6680 return false; 6688 return false;
6681 } 6689 }
6682 } 6690 }
6683 return true; 6691 return true;
(...skipping 9157 matching lines...) Expand 10 before | Expand all | Expand 10 after
15841 Function::Handle(zone, Type::Cast(instantiated_other).signature()); 15849 Function::Handle(zone, Type::Cast(instantiated_other).signature());
15842 Function& sig_fun = Function::Handle(zone, Closure::Cast(*this).function()); 15850 Function& sig_fun = Function::Handle(zone, Closure::Cast(*this).function());
15843 if (!sig_fun.HasInstantiatedSignature()) { 15851 if (!sig_fun.HasInstantiatedSignature()) {
15844 const TypeArguments& instantiator_type_arguments = TypeArguments::Handle( 15852 const TypeArguments& instantiator_type_arguments = TypeArguments::Handle(
15845 zone, Closure::Cast(*this).instantiator_type_arguments()); 15853 zone, Closure::Cast(*this).instantiator_type_arguments());
15846 const TypeArguments& function_type_arguments = TypeArguments::Handle( 15854 const TypeArguments& function_type_arguments = TypeArguments::Handle(
15847 zone, Closure::Cast(*this).function_type_arguments()); 15855 zone, Closure::Cast(*this).function_type_arguments());
15848 sig_fun = sig_fun.InstantiateSignatureFrom( 15856 sig_fun = sig_fun.InstantiateSignatureFrom(
15849 instantiator_type_arguments, function_type_arguments, Heap::kOld); 15857 instantiator_type_arguments, function_type_arguments, Heap::kOld);
15850 } 15858 }
15851 return sig_fun.IsSubtypeOf(other_signature, bound_error, Heap::kOld); 15859 return sig_fun.IsSubtypeOf(other_signature, bound_error, NULL, Heap::kOld);
15852 } 15860 }
15853 TypeArguments& type_arguments = TypeArguments::Handle(zone); 15861 TypeArguments& type_arguments = TypeArguments::Handle(zone);
15854 if (cls.NumTypeArguments() > 0) { 15862 if (cls.NumTypeArguments() > 0) {
15855 type_arguments = GetTypeArguments(); 15863 type_arguments = GetTypeArguments();
15856 ASSERT(type_arguments.IsNull() || type_arguments.IsCanonical()); 15864 ASSERT(type_arguments.IsNull() || type_arguments.IsCanonical());
15857 // The number of type arguments in the instance must be greater or equal to 15865 // The number of type arguments in the instance must be greater or equal to
15858 // the number of type arguments expected by the instance class. 15866 // the number of type arguments expected by the instance class.
15859 // A discrepancy is allowed for closures, which borrow the type argument 15867 // A discrepancy is allowed for closures, which borrow the type argument
15860 // vector of their instantiator, which may be of a subclass of the class 15868 // vector of their instantiator, which may be of a subclass of the class
15861 // defining the closure. Truncating the vector to the correct length on 15869 // defining the closure. Truncating the vector to the correct length on
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
15896 } 15904 }
15897 if (!sig_fun.HasInstantiatedSignature()) { 15905 if (!sig_fun.HasInstantiatedSignature()) {
15898 const TypeArguments& function_type_arguments = 15906 const TypeArguments& function_type_arguments =
15899 TypeArguments::Handle(zone, sig_fun.type_parameters()); 15907 TypeArguments::Handle(zone, sig_fun.type_parameters());
15900 // No bound error possible, since the instance exists. 15908 // No bound error possible, since the instance exists.
15901 sig_fun = sig_fun.InstantiateSignatureFrom( 15909 sig_fun = sig_fun.InstantiateSignatureFrom(
15902 type_arguments, function_type_arguments, Heap::kOld); 15910 type_arguments, function_type_arguments, Heap::kOld);
15903 } 15911 }
15904 const Function& other_signature = 15912 const Function& other_signature =
15905 Function::Handle(zone, Type::Cast(instantiated_other).signature()); 15913 Function::Handle(zone, Type::Cast(instantiated_other).signature());
15906 if (sig_fun.IsSubtypeOf(other_signature, bound_error, Heap::kOld)) { 15914 if (sig_fun.IsSubtypeOf(other_signature, bound_error, NULL, Heap::kOld)) {
15907 return true; 15915 return true;
15908 } 15916 }
15909 } 15917 }
15910 } 15918 }
15911 if (!instantiated_other.IsType()) { 15919 if (!instantiated_other.IsType()) {
15912 return false; 15920 return false;
15913 } 15921 }
15914 other_class = instantiated_other.type_class(); 15922 other_class = instantiated_other.type_class();
15915 if (IsNull()) { 15923 if (IsNull()) {
15916 ASSERT(cls.IsNullClass()); 15924 ASSERT(cls.IsNullClass());
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after
16342 16350
16343 bool AbstractType::TestAndAddBuddyToTrail(TrailPtr* trail, 16351 bool AbstractType::TestAndAddBuddyToTrail(TrailPtr* trail,
16344 const AbstractType& buddy) const { 16352 const AbstractType& buddy) const {
16345 if (*trail == NULL) { 16353 if (*trail == NULL) {
16346 *trail = new Trail(Thread::Current()->zone(), 4); 16354 *trail = new Trail(Thread::Current()->zone(), 4);
16347 } else { 16355 } else {
16348 const intptr_t len = (*trail)->length(); 16356 const intptr_t len = (*trail)->length();
16349 ASSERT((len % 2) == 0); 16357 ASSERT((len % 2) == 0);
16350 const bool this_is_typeref = IsTypeRef(); 16358 const bool this_is_typeref = IsTypeRef();
16351 const bool buddy_is_typeref = buddy.IsTypeRef(); 16359 const bool buddy_is_typeref = buddy.IsTypeRef();
16352 ASSERT(this_is_typeref || buddy_is_typeref); 16360 // Note that at least one of 'this' and 'buddy' should be a typeref, with
16361 // one exception, when the class of the 'this' type implements the 'call'
16362 // method, thereby possibly creating a recursive type (see regress_29405).
16353 for (intptr_t i = 0; i < len; i += 2) { 16363 for (intptr_t i = 0; i < len; i += 2) {
16354 if ((((*trail)->At(i).raw() == this->raw()) || 16364 if ((((*trail)->At(i).raw() == this->raw()) ||
16355 (buddy_is_typeref && (*trail)->At(i).Equals(*this))) && 16365 (buddy_is_typeref && (*trail)->At(i).Equals(*this))) &&
16356 (((*trail)->At(i + 1).raw() == buddy.raw()) || 16366 (((*trail)->At(i + 1).raw() == buddy.raw()) ||
16357 (this_is_typeref && (*trail)->At(i + 1).Equals(buddy)))) { 16367 (this_is_typeref && (*trail)->At(i + 1).Equals(buddy)))) {
16358 return true; 16368 return true;
16359 } 16369 }
16360 } 16370 }
16361 } 16371 }
16362 (*trail)->Add(*this); 16372 (*trail)->Add(*this);
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
16704 if (other_is_dart_function_type || other.IsFunctionType()) { 16714 if (other_is_dart_function_type || other.IsFunctionType()) {
16705 if (IsFunctionType()) { 16715 if (IsFunctionType()) {
16706 if (other_is_dart_function_type) { 16716 if (other_is_dart_function_type) {
16707 return true; 16717 return true;
16708 } 16718 }
16709 const Function& other_fun = 16719 const Function& other_fun =
16710 Function::Handle(zone, Type::Cast(other).signature()); 16720 Function::Handle(zone, Type::Cast(other).signature());
16711 // Check for two function types. 16721 // Check for two function types.
16712 const Function& fun = 16722 const Function& fun =
16713 Function::Handle(zone, Type::Cast(*this).signature()); 16723 Function::Handle(zone, Type::Cast(*this).signature());
16714 return fun.TypeTest(test_kind, other_fun, bound_error, space); 16724 return fun.TypeTest(test_kind, other_fun, bound_error, bound_trail,
16725 space);
16715 } 16726 }
16716 // Check if type S has a call() method of function type T. 16727 // Check if type S has a call() method of function type T.
16717 const Function& call_function = 16728 const Function& call_function =
16718 Function::Handle(zone, type_cls.LookupCallFunctionForTypeTest()); 16729 Function::Handle(zone, type_cls.LookupCallFunctionForTypeTest());
16719 if (!call_function.IsNull()) { 16730 if (!call_function.IsNull()) {
16720 if (other_is_dart_function_type || 16731 if (other_is_dart_function_type) {
16721 call_function.TypeTest( 16732 return true;
16733 }
16734 // Shortcut the test involving the call function if the
16735 // pair <this, other> is already in the trail.
16736 if (TestAndAddBuddyToTrail(&bound_trail, other)) {
16737 return true;
16738 }
16739 if (call_function.TypeTest(
16722 test_kind, Function::Handle(zone, Type::Cast(other).signature()), 16740 test_kind, Function::Handle(zone, Type::Cast(other).signature()),
16723 bound_error, space)) { 16741 bound_error, bound_trail, space)) {
16724 return true; 16742 return true;
16725 } 16743 }
16726 } 16744 }
16727 } 16745 }
16728 if (IsFunctionType()) { 16746 if (IsFunctionType()) {
16729 return false; 16747 return false;
16730 } 16748 }
16731 return type_cls.TypeTest(test_kind, TypeArguments::Handle(zone, arguments()), 16749 return type_cls.TypeTest(test_kind, TypeArguments::Handle(zone, arguments()),
16732 Class::Handle(zone, other.type_class()), 16750 Class::Handle(zone, other.type_class()),
16733 TypeArguments::Handle(zone, other.arguments()), 16751 TypeArguments::Handle(zone, other.arguments()),
(...skipping 6556 matching lines...) Expand 10 before | Expand all | Expand 10 after
23290 return UserTag::null(); 23308 return UserTag::null();
23291 } 23309 }
23292 23310
23293 23311
23294 const char* UserTag::ToCString() const { 23312 const char* UserTag::ToCString() const {
23295 const String& tag_label = String::Handle(label()); 23313 const String& tag_label = String::Handle(label());
23296 return tag_label.ToCString(); 23314 return tag_label.ToCString();
23297 } 23315 }
23298 23316
23299 } // namespace dart 23317 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/object.h ('k') | tests/language/regress_29405_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698