Index: runtime/vm/exceptions.cc |
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc |
index 84ca37720496f8442425588e4c5d245e21ce67ea..e55edd09ed81a978509aac840f7d5169a903a741 100644 |
--- a/runtime/vm/exceptions.cc |
+++ b/runtime/vm/exceptions.cc |
@@ -10,6 +10,7 @@ |
#include "vm/dart_entry.h" |
#include "vm/debugger.h" |
#include "vm/flags.h" |
+#include "vm/log.h" |
#include "vm/object.h" |
#include "vm/object_store.h" |
#include "vm/stack_frame.h" |
@@ -23,9 +24,6 @@ DEFINE_FLAG(bool, print_stacktrace_at_throw, false, |
"Prints a stack trace everytime a throw occurs."); |
-const char* Exceptions::kCastErrorDstName = "type cast"; |
- |
- |
class StacktraceBuilder : public ValueObject { |
public: |
StacktraceBuilder() { } |
@@ -371,8 +369,8 @@ static void ThrowExceptionHelper(Thread* thread, |
ASSERT(handler_pc != 0); |
if (FLAG_print_stacktrace_at_throw) { |
- OS::Print("Exception '%s' thrown:\n", exception.ToCString()); |
- OS::Print("%s\n", stacktrace.ToCString()); |
+ THR_Print("Exception '%s' thrown:\n", exception.ToCString()); |
+ THR_Print("%s\n", stacktrace.ToCString()); |
} |
if (handler_exists) { |
// Found a dart handler for the exception, jump to it. |
@@ -434,18 +432,20 @@ RawInstance* Exceptions::NewInstance(const char* class_name) { |
// Allocate, initialize, and throw a TypeError or CastError. |
// If error_msg is not null, throw a TypeError, even for a type cast. |
void Exceptions::CreateAndThrowTypeError(TokenPosition location, |
- const String& src_type_name, |
- const String& dst_type_name, |
+ const AbstractType& src_type, |
+ const AbstractType& dst_type, |
const String& dst_name, |
- const String& error_msg) { |
- const Array& args = Array::Handle(Array::New(7)); |
+ const String& bound_error_msg) { |
+ ASSERT(!dst_name.IsNull()); // Pass Symbols::Empty() instead. |
+ Zone* zone = Thread::Current()->zone(); |
+ const Array& args = Array::Handle(zone, Array::New(4)); |
ExceptionType exception_type = |
- (error_msg.IsNull() && dst_name.Equals(kCastErrorDstName)) ? |
- kCast : kType; |
+ (bound_error_msg.IsNull() && |
+ (dst_name.raw() == Symbols::InTypeCast().raw())) ? kCast : kType; |
DartFrameIterator iterator; |
- const Script& script = Script::Handle(GetCallerScript(&iterator)); |
+ const Script& script = Script::Handle(zone, GetCallerScript(&iterator)); |
intptr_t line; |
intptr_t column = -1; |
if (script.HasSource()) { |
@@ -454,32 +454,64 @@ void Exceptions::CreateAndThrowTypeError(TokenPosition location, |
script.GetTokenLocation(location, &line, NULL); |
} |
// Initialize '_url', '_line', and '_column' arguments. |
- args.SetAt(0, String::Handle(script.url())); |
- args.SetAt(1, Smi::Handle(Smi::New(line))); |
- args.SetAt(2, Smi::Handle(Smi::New(column))); |
+ args.SetAt(0, String::Handle(zone, script.url())); |
+ args.SetAt(1, Smi::Handle(zone, Smi::New(line))); |
+ args.SetAt(2, Smi::Handle(zone, Smi::New(column))); |
+ |
+ // Construct '_errorMsg'. |
+ GrowableHandlePtrArray<const String> pieces(zone, 20); |
- // Initialize '_srcType', '_dstType', '_dstName', and '_errorMsg'. |
- args.SetAt(3, src_type_name); |
- args.SetAt(4, dst_type_name); |
- args.SetAt(5, dst_name); |
- args.SetAt(6, error_msg); |
+ // Print bound error first, if any. |
+ if (!bound_error_msg.IsNull() && (bound_error_msg.Length() > 0)) { |
+ pieces.Add(bound_error_msg); |
+ pieces.Add(Symbols::NewLine()); |
+ } |
+ |
+ // If dst_type is malformed or malbounded, only print the embedded error. |
+ if (!dst_type.IsNull()) { |
+ const LanguageError& error = LanguageError::Handle(zone, dst_type.error()); |
+ if (!error.IsNull()) { |
+ // Print the embedded error only. |
+ pieces.Add(String::Handle(zone, Symbols::New(error.ToErrorCString()))); |
+ pieces.Add(Symbols::NewLine()); |
+ } else { |
+ // Describe the type error. |
+ if (!src_type.IsNull()) { |
+ pieces.Add(Symbols::TypeQuote()); |
+ pieces.Add(String::Handle(zone, src_type.UserVisibleName())); |
+ pieces.Add(Symbols::QuoteIsNotASubtypeOf()); |
+ } |
+ pieces.Add(Symbols::TypeQuote()); |
+ pieces.Add(String::Handle(zone, dst_type.UserVisibleName())); |
+ pieces.Add(Symbols::SingleQuote()); |
+ if (exception_type == kCast) { |
+ pieces.Add(dst_name); |
+ } else if (dst_name.Length() > 0) { |
+ pieces.Add(Symbols::SpaceOfSpace()); |
+ pieces.Add(Symbols::SingleQuote()); |
+ pieces.Add(dst_name); |
+ pieces.Add(Symbols::SingleQuote()); |
+ } |
+ // Print URIs of src and dst types. |
+ pieces.Add(Symbols::SpaceWhereNewLine()); |
+ if (!src_type.IsNull()) { |
+ pieces.Add(String::Handle(zone, src_type.EnumerateURIs())); |
+ } |
+ if (!dst_type.IsDynamicType() && !dst_type.IsVoidType()) { |
+ pieces.Add(String::Handle(zone, dst_type.EnumerateURIs())); |
+ } |
+ } |
+ } |
+ const String& error_msg = |
+ String::Handle(zone, Symbols::FromConcatAll(pieces)); |
+ args.SetAt(3, error_msg); |
// Type errors in the core library may be difficult to diagnose. |
// Print type error information before throwing the error when debugging. |
if (FLAG_print_stacktrace_at_throw) { |
- if (!error_msg.IsNull()) { |
- OS::Print("%s\n", error_msg.ToCString()); |
- } |
- OS::Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ", |
- String::Handle(script.url()).ToCString(), line, column); |
- if (!dst_name.IsNull() && (dst_name.Length() > 0)) { |
- OS::Print("type '%s' is not a subtype of type '%s' of '%s'.\n", |
- src_type_name.ToCString(), |
- dst_type_name.ToCString(), |
- dst_name.ToCString()); |
- } else { |
- OS::Print("type error.\n"); |
- } |
+ THR_Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ", |
+ String::Handle(zone, script.url()).ToCString(), line, column); |
+ THR_Print("%s\n", error_msg.ToCString()); |
} |
// Throw TypeError or CastError instance. |