[fidl][errors] Rough start to error reporting in compilation

Change-Id: Iea57b9c06119d5f019e9e98366205940a21af7fd
diff --git a/system/host/fidl/compiler/main.cpp b/system/host/fidl/compiler/main.cpp
index 7ddb2c4..cfb524a 100644
--- a/system/host/fidl/compiler/main.cpp
+++ b/system/host/fidl/compiler/main.cpp
@@ -151,15 +151,11 @@
     fidl::Parser parser(&lexer, error_reporter);
     auto ast = parser.Parse();
     if (!parser.Ok()) {
-        error_reporter->PrintReports();
         return false;
     }
-
     if (!library->ConsumeFile(std::move(ast))) {
-        fprintf(stderr, "Parse failed!\n");
         return false;
     }
-
     return true;
 }
 
@@ -234,14 +230,15 @@
     std::map<fidl::StringView, std::unique_ptr<fidl::flat::Library>> compiled_libraries;
     const fidl::flat::Library* final_library = nullptr;
     for (const auto& source_manager : source_managers) {
-        auto library = std::make_unique<fidl::flat::Library>(&compiled_libraries);
+        auto library = std::make_unique<fidl::flat::Library>(&compiled_libraries, &error_reporter);
         for (const auto& source_file : source_manager.sources()) {
             if (!Parse(source_file, &identifier_table, &error_reporter, library.get())) {
+                error_reporter.PrintReports();
                 return 1;
             }
         }
         if (!library->Compile()) {
-            fprintf(stderr, "flat::Library resolution failed!\n");
+            error_reporter.PrintReports();
             return 1;
         }
         final_library = library.get();
diff --git a/system/host/fidl/include/fidl/flat_ast.h b/system/host/fidl/include/fidl/flat_ast.h
index 7bfd317..6446d76 100644
--- a/system/host/fidl/include/fidl/flat_ast.h
+++ b/system/host/fidl/include/fidl/flat_ast.h
@@ -14,6 +14,7 @@
 #include <set>
 #include <vector>
 
+#include "error_reporter.h"
 #include "raw_ast.h"
 #include "type_shape.h"
 
@@ -418,7 +419,8 @@
 
 class Library {
 public:
-    explicit Library(const std::map<StringView, std::unique_ptr<Library>>* dependencies);
+    Library(const std::map<StringView, std::unique_ptr<Library>>* dependencies,
+            ErrorReporter* error_reporter);
 
     bool ConsumeFile(std::unique_ptr<raw::File> file);
     bool Compile();
@@ -426,6 +428,8 @@
     StringView name() const { return library_name_.data(); }
 
 private:
+    bool Fail(StringView message);
+
     bool CompileCompoundIdentifier(const raw::CompoundIdentifier* compound_identifier,
                                    Name* name_out);
 
@@ -560,6 +564,8 @@
     // All Name and Decl pointers here are non-null and are owned by the
     // various foo_declarations_.
     std::map<const Name*, Decl*, PtrCompare<Name>> declarations_;
+
+    ErrorReporter* error_reporter_;
 };
 
 } // namespace flat
diff --git a/system/host/fidl/lib/flat_ast.cpp b/system/host/fidl/lib/flat_ast.cpp
index dd0c5a3..4eed33f 100644
--- a/system/host/fidl/lib/flat_ast.cpp
+++ b/system/host/fidl/lib/flat_ast.cpp
@@ -140,8 +140,15 @@
 // a struct declaration inside an interface out to the top level and
 // so on.
 
-Library::Library(const std::map<StringView, std::unique_ptr<Library>>* dependencies)
-    : dependencies_(dependencies) {
+bool Library::Fail(StringView message) {
+    auto formatted_message = std::string(message) + "\n";
+    error_reporter_->ReportError(formatted_message);
+    return false;
+}
+
+Library::Library(const std::map<StringView, std::unique_ptr<Library>>* dependencies,
+                 ErrorReporter* error_reporter)
+    : dependencies_(dependencies), error_reporter_(error_reporter) {
     for (const auto& dep : *dependencies_) {
         const std::unique_ptr<Library>& library = dep.second;
         const auto& declarations = library->declarations_;
@@ -160,15 +167,14 @@
         auto library_name = components[0]->location.data();
         auto iter = dependencies_->find(library_name);
         if (iter == dependencies_->end()) {
-            return false;
+            return Fail("Could not find identifier in library dependency");
         }
         const std::unique_ptr<Library>& library = iter->second;
         auto decl_name = components[1]->location;
         *name_out = Name(library.get(), {}, decl_name);
         return true;
     }
-    // TODO(TO-701) Handle longer names.
-    return false;
+    return Fail("TODO(TO-701) Handle nested declarations");
 }
 
 bool Library::ParseSize(std::unique_ptr<raw::Constant> raw_constant, Size* out_size) {
@@ -196,7 +202,7 @@
             return false;
         Size element_count;
         if (!ParseSize(std::move(array_type->element_count), &element_count))
-            return false;
+            return Fail("Unable to parse array element count");
         // TODO(kulakowski) Overflow checking.
         uint32_t size = element_count.Value() * element_type->size;
         *out_type = std::make_unique<ArrayType>(size, std::move(element_type), std::move(element_count));
@@ -210,7 +216,7 @@
         Size element_count = Size::Max();
         if (vector_type->maybe_element_count) {
             if (!ParseSize(std::move(vector_type->maybe_element_count), &element_count))
-                return false;
+                return Fail("Unable to parse vector size bound");
         }
         *out_type = std::make_unique<VectorType>(std::move(element_type), std::move(element_count), vector_type->nullability);
         break;
@@ -220,7 +226,7 @@
         Size element_count = Size::Max();
         if (string_type->maybe_element_count) {
             if (!ParseSize(std::move(string_type->maybe_element_count), &element_count))
-                return false;
+                return Fail("Unable to parse string size bound");
         }
         *out_type = std::make_unique<StringType>(std::move(element_count), string_type->nullability);
         break;
@@ -304,9 +310,9 @@
         auto ordinal_literal = std::move(method->ordinal);
         uint32_t value;
         if (!ParseIntegerLiteral<decltype(value)>(ordinal_literal.get(), &value))
-            return false;
+            return Fail("Unable to parse ordinal");
         if (value == 0u)
-            return false;
+            return Fail("Fidl ordinals cannot be 0");
         Ordinal ordinal(std::move(ordinal_literal), value);
 
         SourceLocation method_name = method->identifier->location;
@@ -394,7 +400,7 @@
         StringView current_name = library_name_.data();
         StringView new_name = library_name.data();
         if (current_name != new_name) {
-            return false;
+            return Fail("Two files in the library disagree about the name of the library");
         }
     } else {
         library_name_ = library_name;
@@ -546,7 +552,7 @@
         for (Decl* dep : deps) {
             inverse_dependencies[dep].push_back(decl);
         }
-    }
+   }
 
     // Start with all decls that have no incoming edges.
     std::vector<Decl*> decls_without_deps;
@@ -577,7 +583,7 @@
 
     if (declaration_order_.size() != degrees.size()) {
         // We didn't visit all the edges! There was a cycle.
-        return false;
+        return Fail("There is an includes-cycle in declarations");
     }
 
     assert(declaration_order_.size() != 0u);
@@ -612,7 +618,7 @@
     case types::PrimitiveSubtype::Float32:
     case types::PrimitiveSubtype::Float64:
         // These are not allowed as enum subtypes.
-        return false;
+        return Fail("Enums cannot be bools, statuses, or floats");
     }
 
     // TODO(TO-702) Validate values.
@@ -625,9 +631,9 @@
     Scope<uint32_t> ordinal_scope;
     for (auto& method : interface_declaration->methods) {
         if (!name_scope.Insert(method.name.data()))
-            return false;
+            return Fail("Multiple methods with the same name in an interface");
         if (!ordinal_scope.Insert(method.ordinal.Value()))
-            return false;
+            return Fail("Mulitple methods with the same ordinal in an interface");
         auto CreateMessage = [&](Interface::Method::Message* message) -> bool{
             Scope<StringView> scope;
             auto header_field_shape = FieldShape(TypeShape(16u, 4u));
@@ -635,7 +641,7 @@
             message_struct.push_back(&header_field_shape);
             for (auto& param : message->parameters) {
                 if (!scope.Insert(param.name.data()))
-                    return false;
+                    return Fail("Multiple parameters with the same name in a method");
                 if (!CompileType(param.type.get(), &param.fieldshape.Typeshape()))
                     return false;
                 message_struct.push_back(&param.fieldshape);
@@ -660,7 +666,7 @@
     std::vector<FieldShape*> fidl_struct;
     for (auto& member : struct_declaration->members) {
         if (!scope.Insert(member.name.data()))
-            return false;
+            return Fail("Multiple struct fields with the same name");
         if (!CompileType(member.type.get(), &member.fieldshape.Typeshape()))
             return false;
         fidl_struct.push_back(&member.fieldshape);
@@ -675,7 +681,7 @@
     Scope<StringView> scope;
     for (auto& member : union_declaration->members) {
         if (!scope.Insert(member.name.data()))
-            return false;
+            return Fail("Multiple union members with the same name");
         if (!CompileType(member.type.get(), &member.fieldshape.Typeshape()))
             return false;
     }
@@ -775,7 +781,7 @@
 bool Library::CompileRequestHandleType(flat::RequestHandleType* request_type, TypeShape* out_typeshape) {
     auto named_decl = LookupType(request_type->name);
     if (!named_decl || named_decl->kind != Decl::Kind::kInterface)
-        return false;
+        return Fail("Undefined reference in request handle name");
 
     *out_typeshape = kHandleTypeShape;
     return true;
@@ -793,17 +799,17 @@
 
     auto named_decl = LookupType(identifier_type->name);
     if (!named_decl)
-        return false;
+        return Fail("Undefined reference in identifier type name");
 
     switch (named_decl->kind) {
     case Decl::Kind::kConst: {
         // A constant isn't a type!
-        return false;
+        return Fail("The name of a constant was used where a type was expected");
     }
     case Decl::Kind::kEnum: {
         if (identifier_type->nullability == types::Nullability::Nullable) {
             // Enums aren't nullable!
-            return false;
+            return Fail("An enum was referred to as 'nullable'");
         } else {
             typeshape = static_cast<const Enum*>(named_decl)->typeshape;
         }