Store the type of the most recent error from messages and microtasks

Change-Id: Id7434f885f7e6976d0bfb2367fedc518de975ed9
diff --git a/dart_message_handler.cc b/dart_message_handler.cc
index e898c74..d06b933 100644
--- a/dart_message_handler.cc
+++ b/dart_message_handler.cc
@@ -18,6 +18,7 @@
     : handled_first_message_(false),
       isolate_exited_(false),
       isolate_had_uncaught_exception_error_(false),
+      isolate_last_error_(kNoError),
       task_runner_(nullptr) {}
 
 DartMessageHandler::~DartMessageHandler() {
@@ -90,6 +91,7 @@
   }
 
   if (error) {
+    isolate_last_error_ = GetErrorHandleType(result);
     if (Dart_IsError(result)) {
       // Remember that we had an uncaught exception error.
       isolate_had_uncaught_exception_error_ = true;
diff --git a/dart_message_handler.h b/dart_message_handler.h
index 4225cea..d174fa9 100644
--- a/dart_message_handler.h
+++ b/dart_message_handler.h
@@ -9,6 +9,7 @@
 #include "lib/ftl/memory/ref_ptr.h"
 #include "lib/ftl/memory/weak_ptr.h"
 #include "lib/ftl/tasks/task_runner.h"
+#include "lib/tonic/logging/dart_error.h"
 
 namespace tonic {
 class DartState;
@@ -29,6 +30,10 @@
     return isolate_had_uncaught_exception_error_;
   }
 
+  DartErrorHandleType isolate_last_error() const {
+    return isolate_last_error_;
+  }
+
  protected:
   // Called from an unknown thread for each message.
   void OnMessage(DartState* dart_state);
@@ -48,6 +53,7 @@
   bool handled_first_message_;
   bool isolate_exited_;
   bool isolate_had_uncaught_exception_error_;
+  DartErrorHandleType isolate_last_error_;
   ftl::RefPtr<ftl::TaskRunner> task_runner_;
 
  private:
diff --git a/dart_microtask_queue.cc b/dart_microtask_queue.cc
index 86f69fc..6a97d79 100644
--- a/dart_microtask_queue.cc
+++ b/dart_microtask_queue.cc
@@ -16,6 +16,8 @@
 
 typedef std::vector<DartPersistentValue> MicrotaskQueue;
 
+DartErrorHandleType g_last_error = kNoError;
+
 static MicrotaskQueue& GetQueue() {
   static MicrotaskQueue* queue = new MicrotaskQueue();
   return *queue;
@@ -37,8 +39,16 @@
       if (!dart_state.get())
         continue;
       DartState::Scope dart_scope(dart_state.get());
-      DartInvokeVoid(callback.value());
+      Dart_Handle result = DartInvokeVoid(callback.value());
+      DartErrorHandleType error = GetErrorHandleType(result);
+      if (error != kNoError)
+        g_last_error = error;
     }
   }
 }
+
+DartErrorHandleType DartMicrotaskQueue::GetLastError() {
+  return g_last_error;
+}
+
 }
diff --git a/dart_microtask_queue.h b/dart_microtask_queue.h
index 32fe4c4..34b4db4 100644
--- a/dart_microtask_queue.h
+++ b/dart_microtask_queue.h
@@ -6,6 +6,7 @@
 #define LIB_TONIC_DART_MICROTASK_QUEUE_H_
 
 #include "dart/runtime/include/dart_api.h"
+#include "lib/tonic/logging/dart_error.h"
 
 namespace tonic {
 
@@ -13,6 +14,7 @@
  public:
   static void ScheduleMicrotask(Dart_Handle callback);
   static void RunMicrotasks();
+  static DartErrorHandleType GetLastError();
 };
 
 }  // namespace tonic
diff --git a/logging/dart_error.cc b/logging/dart_error.cc
index 835f528..1483ddf 100644
--- a/logging/dart_error.cc
+++ b/logging/dart_error.cc
@@ -19,4 +19,16 @@
   return false;
 }
 
+DartErrorHandleType GetErrorHandleType(Dart_Handle handle) {
+  if (Dart_IsCompilationError(handle)) {
+    return kCompilationErrorType;
+  } else if (Dart_IsApiError(handle)) {
+    return kApiErrorType;
+  } else if (Dart_IsError(handle)) {
+    return kUnknownErrorType;
+  } else {
+    return kNoError;
+  }
+}
+
 }  // namespace tonic
diff --git a/logging/dart_error.h b/logging/dart_error.h
index a890670..f06ddec 100644
--- a/logging/dart_error.h
+++ b/logging/dart_error.h
@@ -15,6 +15,15 @@
 
 bool LogIfError(Dart_Handle handle);
 
+enum DartErrorHandleType {
+  kNoError,
+  kUnknownErrorType,
+  kApiErrorType,
+  kCompilationErrorType,
+};
+
+DartErrorHandleType GetErrorHandleType(Dart_Handle handle);
+
 }  // namespace tonic
 
 #endif  // LIB_TONIC_DART_ERROR_H_