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; |
} |