Better type determiner errors.

This CL adds the source info into the type determiner errors so they
will include line and column number if available. If the line number is
0 then it's considered the source info is missing and it is not emitted.

Add line and colummn to type determiner errors

Change-Id: I18764a71db80082fd31c8509c5e9b193800f1d95
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19105
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index aa1c58e..4ccdbb4 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -49,13 +49,19 @@
 
 namespace tint {
 
-TypeDeterminer::TypeDeterminer(Context* ctx) : ctx_(*ctx) {
-  // TODO(dsinclair): Temporary usage to avoid compiler warning
-  static_cast<void>(ctx_.type_mgr());
-}
+TypeDeterminer::TypeDeterminer(Context* ctx) : ctx_(*ctx) {}
 
 TypeDeterminer::~TypeDeterminer() = default;
 
+void TypeDeterminer::set_error(const Source& src, const std::string& msg) {
+  error_ = "";
+  if (src.line > 0) {
+    error_ +=
+        std::to_string(src.line) + ":" + std::to_string(src.column) + ": ";
+  }
+  error_ += msg;
+}
+
 bool TypeDeterminer::Determine(ast::Module* mod) {
   for (const auto& var : mod->global_variables()) {
     variable_stack_.set_global(var->name(), var.get());
@@ -209,7 +215,7 @@
     return DetermineResultType(v->variable()->constructor());
   }
 
-  error_ = "unknown statement type for type determination";
+  set_error(stmt->source(), "unknown statement type for type determination");
   return false;
 }
 
@@ -253,7 +259,7 @@
     return DetermineUnaryOp(expr->AsUnaryOp());
   }
 
-  error_ = "unknown expression for type determination";
+  set_error(expr->source(), "unknown expression for type determination");
   return false;
 }
 
@@ -272,7 +278,7 @@
     expr->set_result_type(ctx_.type_mgr().Get(
         std::make_unique<ast::type::VectorType>(m->type(), m->rows())));
   } else {
-    error_ = "invalid parent type in array accessor";
+    set_error(expr->source(), "invalid parent type in array accessor");
     return false;
   }
   return true;
@@ -308,7 +314,7 @@
 bool TypeDeterminer::DetermineIdentifier(ast::IdentifierExpression* expr) {
   if (expr->name().size() > 1) {
     // TODO(dsinclair): Handle imports
-    error_ = "imports not handled in type determination";
+    set_error(expr->source(), "imports not handled in type determination");
     return false;
   }
 
@@ -348,7 +354,7 @@
       return true;
     }
 
-    error_ = "struct member not found";
+    set_error(expr->source(), "struct member not found");
     return false;
   }
   if (data_type->IsVector()) {
@@ -363,7 +369,7 @@
     return true;
   }
 
-  error_ = "invalid type in member accessor";
+  set_error(expr->source(), "invalid type in member accessor");
   return false;
 }
 
@@ -470,7 +476,7 @@
     case ast::UnaryMethod::kIsFinite:
     case ast::UnaryMethod::kIsNormal: {
       if (expr->params().empty()) {
-        error_ = "incorrect number of parameters";
+        set_error(expr->source(), "incorrect number of parameters");
         return false;
       }
 
@@ -493,13 +499,14 @@
     }
     case ast::UnaryMethod::kOuterProduct: {
       if (expr->params().size() != 2) {
-        error_ = "incorrect number of parameters for outer product";
+        set_error(expr->source(),
+                  "incorrect number of parameters for outer product");
         return false;
       }
       auto param0_type = expr->params()[0]->result_type();
       auto param1_type = expr->params()[1]->result_type();
       if (!param0_type->IsVector() || !param1_type->IsVector()) {
-        error_ = "invalid parameter type for outer product";
+        set_error(expr->source(), "invalid parameter type for outer product");
         return false;
       }
       expr->set_result_type(
diff --git a/src/type_determiner.h b/src/type_determiner.h
index 1870b4c..8f50a9e 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -83,6 +83,8 @@
   bool DetermineVariableStorageClass(ast::Statement* stmt);
 
  private:
+  void set_error(const Source& src, const std::string& msg);
+
   bool DetermineArrayAccessor(ast::ArrayAccessorExpression* expr);
   bool DetermineAs(ast::AsExpression* expr);
   bool DetermineBinary(ast::BinaryExpression* expr);
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 1fe0895..98997fc 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -58,6 +58,18 @@
 namespace tint {
 namespace {
 
+class FakeStmt : public ast::Statement {
+ public:
+  bool IsValid() const override { return true; }
+  void to_str(std::ostream&, size_t) const override {}
+};
+
+class FakeExpr : public ast::Expression {
+ public:
+  bool IsValid() const override { return true; }
+  void to_str(std::ostream&, size_t) const override {}
+};
+
 class TypeDeterminerTest : public testing::Test {
  public:
   void SetUp() { td_ = std::make_unique<TypeDeterminer>(&ctx_); }
@@ -69,6 +81,23 @@
   std::unique_ptr<TypeDeterminer> td_;
 };
 
+TEST_F(TypeDeterminerTest, Error_WithEmptySource) {
+  FakeStmt s;
+  s.set_source(Source{0, 0});
+
+  EXPECT_FALSE(td()->DetermineResultType(&s));
+  EXPECT_EQ(td()->error(), "unknown statement type for type determination");
+}
+
+TEST_F(TypeDeterminerTest, Stmt_Error_Unknown) {
+  FakeStmt s;
+  s.set_source(Source{2, 30});
+
+  EXPECT_FALSE(td()->DetermineResultType(&s));
+  EXPECT_EQ(td()->error(),
+            "2:30: unknown statement type for type determination");
+}
+
 TEST_F(TypeDeterminerTest, Stmt_Assign) {
   ast::type::F32Type f32;
   ast::type::I32Type i32;
@@ -410,6 +439,14 @@
   EXPECT_TRUE(init_ptr->result_type()->IsI32());
 }
 
+TEST_F(TypeDeterminerTest, Expr_Error_Unknown) {
+  FakeExpr e;
+  e.set_source(Source{2, 30});
+
+  EXPECT_FALSE(td()->DetermineResultType(&e));
+  EXPECT_EQ(td()->error(), "2:30: unknown expression for type determination");
+}
+
 TEST_F(TypeDeterminerTest, Expr_ArrayAccessor_Array) {
   ast::type::I32Type i32;
   ast::type::F32Type f32;