[VM runtime] Only print ambiguous class names in type errors (fixes #33006).
Change-Id: I6e5e0564d438c267f0ca2733dd7a63b09b54a1b1
Reviewed-on: https://dart-review.googlesource.com/54628
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 3f577f6..b4bcec3 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -729,25 +729,19 @@
pieces.Add(dst_name);
pieces.Add(Symbols::SingleQuote());
}
- // Print URIs of src and dst types.
- // Do not print "where" when no URIs get printed.
- bool printed_where = false;
+ // Print ambiguous URIs of src and dst types.
+ URIs uris(zone, 12);
if (!src_type.IsNull()) {
- const String& uris = String::Handle(zone, src_type.EnumerateURIs());
- if (uris.Length() > Symbols::SpaceIsFromSpace().Length()) {
- printed_where = true;
- pieces.Add(Symbols::SpaceWhereNewLine());
- pieces.Add(uris);
- }
+ src_type.EnumerateURIs(&uris);
}
if (!dst_type.IsDynamicType() && !dst_type.IsVoidType()) {
- const String& uris = String::Handle(zone, dst_type.EnumerateURIs());
- if (uris.Length() > Symbols::SpaceIsFromSpace().Length()) {
- if (!printed_where) {
- pieces.Add(Symbols::SpaceWhereNewLine());
- }
- pieces.Add(uris);
- }
+ dst_type.EnumerateURIs(&uris);
+ }
+ const String& formatted_uris =
+ String::Handle(zone, AbstractType::PrintURIs(&uris));
+ if (formatted_uris.Length() > 0) {
+ pieces.Add(Symbols::SpaceWhereNewLine());
+ pieces.Add(formatted_uris);
}
}
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 3476896..caa190c 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5468,20 +5468,18 @@
return result.raw();
}
-RawString* TypeArguments::EnumerateURIs() const {
+void TypeArguments::EnumerateURIs(URIs* uris) const {
if (IsNull()) {
- return Symbols::Empty().raw();
+ return;
}
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
AbstractType& type = AbstractType::Handle(zone);
const intptr_t num_types = Length();
- const Array& pieces = Array::Handle(zone, Array::New(num_types));
for (intptr_t i = 0; i < num_types; i++) {
type = TypeAt(i);
- pieces.SetAt(i, String::Handle(zone, type.EnumerateURIs()));
+ type.EnumerateURIs(uris);
}
- return String::ConcatAll(pieces);
}
const char* TypeArguments::ToCString() const {
@@ -16346,10 +16344,9 @@
return NULL;
}
-RawString* AbstractType::EnumerateURIs() const {
+void AbstractType::EnumerateURIs(URIs* uris) const {
// AbstractType is an abstract class.
UNREACHABLE();
- return NULL;
}
RawAbstractType* AbstractType::OnlyBuddyInTrail(TrailPtr trail) const {
@@ -16421,6 +16418,52 @@
return false;
}
+void AbstractType::AddURI(URIs* uris, const String& name, const String& uri) {
+ ASSERT(uris != NULL);
+ const intptr_t len = uris->length();
+ ASSERT((len % 3) == 0);
+ bool print_uri = false;
+ for (intptr_t i = 0; i < len; i += 3) {
+ if (uris->At(i).Equals(name)) {
+ if (uris->At(i + 1).Equals(uri)) {
+ // Same name and same URI: no need to add this already listed URI.
+ return; // No state change is possible.
+ } else {
+ // Same name and different URI: the name is ambiguous, print both URIs.
+ print_uri = true;
+ uris->SetAt(i + 2, Symbols::print());
+ }
+ }
+ }
+ uris->Add(name);
+ uris->Add(uri);
+ if (print_uri) {
+ uris->Add(Symbols::print());
+ } else {
+ uris->Add(Symbols::Empty());
+ }
+}
+
+RawString* AbstractType::PrintURIs(URIs* uris) {
+ ASSERT(uris != NULL);
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ const intptr_t len = uris->length();
+ ASSERT((len % 3) == 0);
+ GrowableHandlePtrArray<const String> pieces(zone, 5 * (len / 3));
+ for (intptr_t i = 0; i < len; i += 3) {
+ // Only print URIs that have been marked.
+ if (uris->At(i + 2).raw() == Symbols::print().raw()) {
+ pieces.Add(Symbols::TwoSpaces());
+ pieces.Add(uris->At(i));
+ pieces.Add(Symbols::SpaceIsFromSpace());
+ pieces.Add(uris->At(i + 1));
+ pieces.Add(Symbols::NewLine());
+ }
+ }
+ return Symbols::FromConcatAll(thread, pieces);
+}
+
RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
ASSERT(name_visibility != kScrubbedName);
Thread* thread = Thread::Current();
@@ -17723,13 +17766,12 @@
}
#endif // DEBUG
-RawString* Type::EnumerateURIs() const {
+void Type::EnumerateURIs(URIs* uris) const {
if (IsDynamicType() || IsVoidType()) {
- return Symbols::Empty().raw();
+ return;
}
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- GrowableHandlePtrArray<const String> pieces(zone, 6);
if (IsFunctionType()) {
// The scope class and type arguments do not appear explicitly in the user
// visible name. The type arguments were used to instantiate the function
@@ -17737,26 +17779,22 @@
const Function& sig_fun = Function::Handle(zone, signature());
AbstractType& type = AbstractType::Handle(zone);
const intptr_t num_params = sig_fun.NumParameters();
- GrowableHandlePtrArray<const String> pieces(zone, num_params + 1);
for (intptr_t i = 0; i < num_params; i++) {
type = sig_fun.ParameterTypeAt(i);
- pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+ type.EnumerateURIs(uris);
}
// Handle result type last, since it appears last in the user visible name.
type = sig_fun.result_type();
- pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+ type.EnumerateURIs(uris);
} else {
const Class& cls = Class::Handle(zone, type_class());
- pieces.Add(Symbols::TwoSpaces());
- pieces.Add(String::Handle(zone, cls.UserVisibleName()));
- pieces.Add(Symbols::SpaceIsFromSpace());
+ const String& name = String::Handle(zone, cls.UserVisibleName());
const Library& library = Library::Handle(zone, cls.library());
- pieces.Add(String::Handle(zone, library.url()));
- pieces.Add(Symbols::NewLine());
+ const String& uri = String::Handle(zone, library.url());
+ AddURI(uris, name, uri);
const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
- pieces.Add(String::Handle(zone, type_args.EnumerateURIs()));
+ type_args.EnumerateURIs(uris);
}
- return Symbols::FromConcatAll(thread, pieces);
}
intptr_t Type::ComputeHash() const {
@@ -17993,22 +18031,17 @@
}
#endif // DEBUG
-RawString* TypeRef::EnumerateURIs() const {
+void TypeRef::EnumerateURIs(URIs* uris) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const AbstractType& ref_type = AbstractType::Handle(zone, type());
ASSERT(!ref_type.IsDynamicType() && !ref_type.IsVoidType());
- GrowableHandlePtrArray<const String> pieces(zone, 6);
const Class& cls = Class::Handle(zone, ref_type.type_class());
- pieces.Add(Symbols::TwoSpaces());
- pieces.Add(String::Handle(zone, cls.UserVisibleName()));
- // Break cycle by not printing type arguments, but '<optimized out>' instead.
- pieces.Add(Symbols::OptimizedOut());
- pieces.Add(Symbols::SpaceIsFromSpace());
+ const String& name = String::Handle(zone, cls.UserVisibleName());
const Library& library = Library::Handle(zone, cls.library());
- pieces.Add(String::Handle(zone, library.url()));
- pieces.Add(Symbols::NewLine());
- return Symbols::FromConcatAll(thread, pieces);
+ const String& uri = String::Handle(zone, library.url());
+ AddURI(uris, name, uri);
+ // Break cycle by not printing type arguments.
}
intptr_t TypeRef::Hash() const {
@@ -18225,12 +18258,10 @@
*bound_error, script, token_pos(), Report::AtLocation,
Report::kMalboundedType, Heap::kNew,
"type parameter '%s' of class '%s' must extend bound '%s', "
- "but type argument '%s' is not a subtype of '%s' where\n%s%s",
+ "but type argument '%s' is not a subtype of '%s'",
type_param_name.ToCString(), class_name.ToCString(),
declared_bound_name.ToCString(), bounded_type_name.ToCString(),
- upper_bound_name.ToCString(),
- String::Handle(bounded_type.EnumerateURIs()).ToCString(),
- String::Handle(upper_bound.EnumerateURIs()).ToCString());
+ upper_bound_name.ToCString());
}
}
return false;
@@ -18279,11 +18310,10 @@
return clone.raw();
}
-RawString* TypeParameter::EnumerateURIs() const {
+void TypeParameter::EnumerateURIs(URIs* uris) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
GrowableHandlePtrArray<const String> pieces(zone, 4);
- pieces.Add(Symbols::TwoSpaces());
pieces.Add(String::Handle(zone, name()));
Class& cls = Class::Handle(zone, parameterized_class());
if (cls.IsNull()) {
@@ -18296,12 +18326,12 @@
if (!cls.IsNull()) {
pieces.Add(Symbols::SpaceOfSpace());
pieces.Add(String::Handle(zone, cls.UserVisibleName()));
- pieces.Add(Symbols::SpaceIsFromSpace());
+ const String& name =
+ String::Handle(zone, Symbols::FromConcatAll(thread, pieces));
const Library& library = Library::Handle(zone, cls.library());
- pieces.Add(String::Handle(zone, library.url()));
+ const String& uri = String::Handle(zone, library.url());
+ AddURI(uris, name, uri);
}
- pieces.Add(Symbols::NewLine());
- return Symbols::FromConcatAll(thread, pieces);
}
intptr_t TypeParameter::ComputeHash() const {
@@ -18579,9 +18609,9 @@
return BoundedType::New(bounded_type, upper_bound, type_param);
}
-RawString* BoundedType::EnumerateURIs() const {
+void BoundedType::EnumerateURIs(URIs* uris) const {
// The bound does not appear in the user visible name.
- return AbstractType::Handle(type()).EnumerateURIs();
+ AbstractType::Handle(type()).EnumerateURIs(uris);
}
intptr_t BoundedType::ComputeHash() const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c23eda4..a422fe0 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -903,6 +903,12 @@
typedef ZoneGrowableHandlePtrArray<const AbstractType> Trail;
typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
+// A URIs array contains triplets of strings.
+// The first string in the triplet is a type name (usually a class).
+// The second string in the triplet is the URI of the type.
+// The third string in the triplet is "print" if the triplet should be printed.
+typedef ZoneGrowableHandlePtrArray<const String> URIs;
+
class Class : public Object {
public:
intptr_t instance_size() const {
@@ -5817,8 +5823,9 @@
// Canonicalize only if instantiated, otherwise returns 'this'.
RawTypeArguments* Canonicalize(TrailPtr trail = NULL) const;
- // Returns a formatted list of occurring type arguments with their URI.
- RawString* EnumerateURIs() const;
+ // Add the class name and URI of each type argument of this vector to the uris
+ // list and mark ambiguous triplets to be printed.
+ void EnumerateURIs(URIs* uris) const;
// Return 'this' if this type argument vector is instantiated, i.e. if it does
// not refer to type parameters. Otherwise, return a new type argument vector
@@ -6031,6 +6038,12 @@
// The receiver may be added several times, each time with a different buddy.
bool TestAndAddBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const;
+ // Add the pair <name, uri> to the list, if not already present.
+ static void AddURI(URIs* uris, const String& name, const String& uri);
+
+ // Return a formatted string of the uris.
+ static RawString* PrintURIs(URIs* uris);
+
// The name of this type, including the names of its type arguments, if any.
virtual RawString* Name() const { return BuildName(kInternalName); }
@@ -6040,8 +6053,9 @@
return BuildName(kUserVisibleName);
}
- // Returns a formatted list of occurring types with their URI.
- virtual RawString* EnumerateURIs() const;
+ // Add the class name and URI of each occuring type to the uris
+ // list and mark ambiguous triplets to be printed.
+ virtual void EnumerateURIs(URIs* uris) const;
virtual intptr_t Hash() const;
@@ -6247,7 +6261,7 @@
// Check if type is canonical.
virtual bool CheckIsCanonical(Thread* thread) const;
#endif // DEBUG
- virtual RawString* EnumerateURIs() const;
+ virtual void EnumerateURIs(URIs* uris) const;
virtual intptr_t Hash() const;
@@ -6400,7 +6414,7 @@
// Check if typeref is canonical.
virtual bool CheckIsCanonical(Thread* thread) const;
#endif // DEBUG
- virtual RawString* EnumerateURIs() const;
+ virtual void EnumerateURIs(URIs* uris) const;
virtual intptr_t Hash() const;
@@ -6490,7 +6504,7 @@
// Check if type parameter is canonical.
virtual bool CheckIsCanonical(Thread* thread) const { return true; }
#endif // DEBUG
- virtual RawString* EnumerateURIs() const;
+ virtual void EnumerateURIs(URIs* uris) const;
virtual intptr_t Hash() const;
@@ -6596,7 +6610,7 @@
// Check if bounded type is canonical.
virtual bool CheckIsCanonical(Thread* thread) const { return true; }
#endif // DEBUG
- virtual RawString* EnumerateURIs() const;
+ virtual void EnumerateURIs(URIs* uris) const;
virtual intptr_t Hash() const;