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

Unified Diff: runtime/vm/object.cc

Issue 66033006: Check type bounds of redirecting factories (issue 14699). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/object.cc
===================================================================
--- runtime/vm/object.cc (revision 30176)
+++ runtime/vm/object.cc (working copy)
@@ -4843,6 +4843,7 @@
bool Function::HasCompatibleParametersWith(const Function& other,
Error* bound_error) const {
ASSERT(FLAG_error_on_bad_override);
+ ASSERT((bound_error != NULL) && bound_error->IsNull());
// Check that this function's signature type is a subtype of the other
// function's signature type.
if (!TypeTest(kIsSubtypeOf, Object::null_abstract_type_arguments(),
@@ -11307,11 +11308,30 @@
RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
if (IsBoundedType()) {
- // TODO(regis): Should the bound be visible in the name for debug purposes
- // if name_visibility is kInternalName?
const AbstractType& type = AbstractType::Handle(
BoundedType::Cast(*this).type());
- return type.BuildName(name_visibility);
+ if (name_visibility == kUserVisibleName) {
+ return type.BuildName(kUserVisibleName);
+ }
+ String& type_name = String::Handle(type.BuildName(kInternalName));
+ type_name = String::Concat(type_name, Symbols::SpaceExtendsSpace());
+ // Building the bound name may lead into cycles.
+ const AbstractType& bound = AbstractType::Handle(
+ BoundedType::Cast(*this).bound());
+ String& bound_name = String::Handle();
+ if (bound.IsTypeParameter()) {
+ bound_name = TypeParameter::Cast(bound).name();
+ } else if (bound.IsType()) {
+ const Class& cls = Class::Handle(Type::Cast(bound).type_class());
+ bound_name = cls.Name();
+ if (Type::Cast(bound).arguments() != AbstractTypeArguments::null()) {
+ bound_name = String::Concat(bound_name, Symbols::OptimizedOut());
+ }
+ } else {
+ bound_name = String::New(Symbols::OptimizedOut());
+ }
+ type_name = String::Concat(type_name, bound_name);
+ return Symbols::New(type_name);
}
if (IsTypeParameter()) {
return TypeParameter::Cast(*this).name();
@@ -12070,62 +12090,49 @@
if (instantiator_type_arguments.IsNull()) {
return Type::DynamicType();
}
- // Bound checks may appear in the instantiator type arguments, as is the case
- // with a pair of type parameters of the same class referring to each other
- // via their bounds.
- AbstractType& type_arg = AbstractType::Handle(
- instantiator_type_arguments.TypeAt(index()));
- if (type_arg.IsBoundedType()) {
- const BoundedType& bounded_type = BoundedType::Cast(type_arg);
- // Bounds checking of a type is postponed to run time if the type is still
- // uninstantiated at compile time, or if the bound and the type are mutually
- // recursive. In the latter case, the type may already be instantiated.
- if (!bounded_type.IsInstantiated()) {
- ASSERT(AbstractType::Handle(bounded_type.bound()).IsInstantiated());
- type_arg = bounded_type.InstantiateFrom(AbstractTypeArguments::Handle(),
- bound_error);
- }
- }
- return type_arg.raw();
+ return instantiator_type_arguments.TypeAt(index());
}
bool TypeParameter::CheckBound(const AbstractType& bounded_type,
const AbstractType& upper_bound,
Error* bound_error) const {
- ASSERT((bound_error == NULL) || bound_error->IsNull());
+ ASSERT((bound_error != NULL) && bound_error->IsNull());
ASSERT(bounded_type.IsFinalized());
ASSERT(upper_bound.IsFinalized());
ASSERT(!bounded_type.IsMalformed());
if (bounded_type.IsSubtypeOf(upper_bound, bound_error)) {
return true;
}
- if ((bound_error != NULL) && bound_error->IsNull()) {
- // Report the bound error.
- const String& bounded_type_name = String::Handle(
- bounded_type.UserVisibleName());
- const String& upper_bound_name = String::Handle(
- upper_bound.UserVisibleName());
- const AbstractType& declared_bound = AbstractType::Handle(bound());
- const String& declared_bound_name = String::Handle(
- declared_bound.UserVisibleName());
- const String& type_param_name = String::Handle(UserVisibleName());
- const Class& cls = Class::Handle(parameterized_class());
- const String& class_name = String::Handle(cls.Name());
- const Script& script = Script::Handle(cls.script());
- // Since the bound may have been canonicalized, its token index is
- // meaningless, therefore use the token index of this type parameter.
- *bound_error = FormatError(
- *bound_error,
- script,
- token_pos(),
- "type parameter '%s' of class '%s' must extend bound '%s', "
- "but type argument '%s' is not a subtype of '%s'\n",
- type_param_name.ToCString(),
- class_name.ToCString(),
- declared_bound_name.ToCString(),
- bounded_type_name.ToCString(),
- upper_bound_name.ToCString());
+ if (bound_error->IsNull()) {
+ // Report the bound error only if both the bounded type and the upper bound
+ // are instantiated. Otherwise, we cannot tell yet it is a bound error.
+ if (bounded_type.IsInstantiated() && upper_bound.IsInstantiated()) {
+ const String& bounded_type_name = String::Handle(
+ bounded_type.UserVisibleName());
+ const String& upper_bound_name = String::Handle(
+ upper_bound.UserVisibleName());
+ const AbstractType& declared_bound = AbstractType::Handle(bound());
+ const String& declared_bound_name = String::Handle(
+ declared_bound.UserVisibleName());
+ const String& type_param_name = String::Handle(UserVisibleName());
+ const Class& cls = Class::Handle(parameterized_class());
+ const String& class_name = String::Handle(cls.Name());
+ const Script& script = Script::Handle(cls.script());
+ // Since the bound may have been canonicalized, its token index is
+ // meaningless, therefore use the token index of this type parameter.
+ *bound_error = FormatError(
+ *bound_error,
+ script,
+ token_pos(),
+ "type parameter '%s' of class '%s' must extend bound '%s', "
+ "but type argument '%s' is not a subtype of '%s'\n",
+ type_param_name.ToCString(),
+ class_name.ToCString(),
+ declared_bound_name.ToCString(),
+ bounded_type_name.ToCString(),
+ upper_bound_name.ToCString());
+ }
}
return false;
}
@@ -12218,18 +12225,17 @@
bool BoundedType::IsMalboundedWithError(Error* bound_error) const {
- if (!FLAG_enable_type_checks && !FLAG_error_on_bad_type) {
- return false;
- }
- const AbstractType& upper_bound = AbstractType::Handle(bound());
- if (upper_bound.IsMalformed()) {
- if (bound_error != NULL) {
- *bound_error = upper_bound.malformed_error();
- ASSERT(!bound_error->IsNull());
+ if (FLAG_enable_type_checks || FLAG_error_on_bad_type) {
+ const AbstractType& upper_bound = AbstractType::Handle(bound());
+ if (upper_bound.IsMalformed()) {
+ if (bound_error != NULL) {
+ *bound_error = upper_bound.malformed_error();
+ ASSERT(!bound_error->IsNull());
+ }
+ return true;
}
- return true;
}
- return false;
+ return AbstractType::Handle(type()).IsMalboundedWithError(bound_error);
}
@@ -12315,7 +12321,15 @@
bound_error);
}
if (bound_error->IsNull()) {
- type_param.CheckBound(bounded_type, upper_bound, bound_error);
+ if (!type_param.CheckBound(bounded_type, upper_bound, bound_error) &&
+ bound_error->IsNull()) {
+ // We cannot determine yet whether the bounded_type is below the
+ // upper_bound, because one or both of them is still uninstantiated.
+ ASSERT(!bounded_type.IsInstantiated() || !upper_bound.IsInstantiated());
+ // Postpone bound check by returning a new BoundedType with partially
+ // instantiated bounded_type and upper_bound, but keeping type_param.
+ bounded_type = BoundedType::New(bounded_type, upper_bound, type_param);
+ }
}
set_is_being_checked(false);
}
@@ -12373,19 +12387,22 @@
const char* BoundedType::ToCString() const {
- const char* format = "BoundedType: type %s; bound: %s; class: %s";
+ const char* format = "BoundedType: type %s; bound: %s; type param: %s of %s";
const char* type_cstr = String::Handle(AbstractType::Handle(
type()).Name()).ToCString();
const char* bound_cstr = String::Handle(AbstractType::Handle(
bound()).Name()).ToCString();
+ const char* type_param_cstr = String::Handle(TypeParameter::Handle(
+ type_parameter()).name()).ToCString();
const Class& cls = Class::Handle(TypeParameter::Handle(
type_parameter()).parameterized_class());
const char* cls_cstr =
cls.IsNull() ? " null" : String::Handle(cls.Name()).ToCString();
intptr_t len = OS::SNPrint(
- NULL, 0, format, type_cstr, bound_cstr, cls_cstr) + 1;
+ NULL, 0, format, type_cstr, bound_cstr, type_param_cstr, cls_cstr) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
- OS::SNPrint(chars, len, format, type_cstr, bound_cstr, cls_cstr);
+ OS::SNPrint(
+ chars, len, format, type_cstr, bound_cstr, type_param_cstr, cls_cstr);
return chars;
}
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698