[type-determiner] return false when type determining an undeclared function

Change-Id: Ia7e43be64675528037f92026a6c239d1e5220fc0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/26941
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index de26661..6cf1791 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -511,6 +511,15 @@
       return false;
     }
   }
+
+  if (!expr->func()->result_type()) {
+    auto func_name = expr->func()->AsIdentifier()->name();
+    set_error(
+        expr->source(),
+        "v-0005: function must be declared before use: '" + func_name + "'");
+    return false;
+  }
+
   expr->set_result_type(expr->func()->result_type());
   return true;
 }
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 87d0d73..092e947 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -387,6 +387,34 @@
   EXPECT_TRUE(expr_ptr->result_type()->IsF32());
 }
 
+TEST_F(TypeDeterminerTest, Stmt_Call_undeclared) {
+  // fn main() -> void {func(); return; }
+  // fn func() -> void { return; }
+  ast::type::F32Type f32;
+  ast::ExpressionList call_params;
+  auto call_expr = std::make_unique<ast::CallExpression>(
+      Source{12, 34}, std::make_unique<ast::IdentifierExpression>("func"),
+      std::move(call_params));
+  ast::VariableList params0;
+  auto func_main =
+      std::make_unique<ast::Function>("main", std::move(params0), &f32);
+  auto main_body = std::make_unique<ast::BlockStatement>();
+  main_body->append(std::make_unique<ast::CallStatement>(std::move(call_expr)));
+  main_body->append(std::make_unique<ast::ReturnStatement>());
+  func_main->set_body(std::move(main_body));
+  mod()->AddFunction(std::move(func_main));
+
+  auto func = std::make_unique<ast::Function>("func", std::move(params0), &f32);
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::ReturnStatement>());
+  func->set_body(std::move(body));
+  mod()->AddFunction(std::move(func));
+
+  EXPECT_FALSE(td()->Determine()) << td()->error();
+  EXPECT_EQ(td()->error(),
+            "12:34: v-0005: function must be declared before use: 'func'");
+}
+
 TEST_F(TypeDeterminerTest, Stmt_VariableDecl) {
   ast::type::I32Type i32;
   auto var =
diff --git a/test/function-must-be-declared-before-use-fail.wgsl b/test/function-must-be-declared-before-use-fail.wgsl
new file mode 100644
index 0000000..91cfaef
--- /dev/null
+++ b/test/function-must-be-declared-before-use-fail.wgsl
@@ -0,0 +1,23 @@
+# Copyright 2020 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+fn main() -> void {
+    var a:f32 = func1();
+    return;
+}
+
+fn func1() -> f32 {
+    var a:i32 = 2.1;
+    return a;
+}