Add GLSL distance support.

This CL adds support for the GLSL distance command.

Bug: tint:5
Change-Id: I0934d461ca6d4fca379849d8f41a33fb202c67ff
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/20060
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 9be841c..d0dd7ff 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -595,7 +595,8 @@
       name == "acos" || name == "atan" || name == "sinh" || name == "cosh" ||
       name == "tanh" || name == "asinh" || name == "acosh" || name == "atanh" ||
       name == "exp" || name == "log" || name == "exp2" || name == "log2" ||
-      name == "sqrt" || name == "inversesqrt" || name == "normalize") {
+      name == "sqrt" || name == "inversesqrt" || name == "normalize" ||
+      name == "length") {
     if (params.size() != 1) {
       error_ = "incorrect number of parameters for " + name +
                ". Expected 1 got " + std::to_string(params.size());
@@ -607,6 +608,7 @@
       return nullptr;
     }
 
+    auto* result_type = params[0]->result_type();
     if (name == "round") {
       *id = GLSLstd450Round;
     } else if (name == "roundeven") {
@@ -665,30 +667,18 @@
       *id = GLSLstd450InverseSqrt;
     } else if (name == "normalize") {
       *id = GLSLstd450Normalize;
+    } else if (name == "length") {
+      *id = GLSLstd450Length;
+
+      // Length returns a scalar of the same type as the parameter.
+      return result_type->is_float_scalar() ? result_type
+                                            : result_type->AsVector()->type();
     }
 
-    return params[0]->result_type();
-  } else if (name == "length") {
-    if (params.size() != 1) {
-      error_ = "incorrect number of parameters for " + name +
-               ". Expected 1 got " + std::to_string(params.size());
-      return nullptr;
-    }
-    if (!params[0]->result_type()->is_float_scalar_or_vector()) {
-      error_ = "incorrect type for " + name +
-               ". Requires a float scalar or a float vector";
-      return nullptr;
-    }
-
-    *id = GLSLstd450Length;
-    auto* result_type = params[0]->result_type();
-
-    // Length returns a scalar of the same type as the parameter.
-    return result_type->is_float_scalar() ? result_type
-                                          : result_type->AsVector()->type();
+    return result_type;
   } else if (name == "atan2" || name == "pow" || name == "fmin" ||
              name == "fmax" || name == "step" || name == "reflect" ||
-             name == "nmin" || name == "nmax") {
+             name == "nmin" || name == "nmax" || name == "distance") {
     if (params.size() != 2) {
       error_ = "incorrect number of parameters for " + name +
                ". Expected 2 got " + std::to_string(params.size());
@@ -705,6 +695,7 @@
       return nullptr;
     }
 
+    auto* result_type = params[0]->result_type();
     if (name == "atan2") {
       *id = GLSLstd450Atan2;
     } else if (name == "pow") {
@@ -721,9 +712,15 @@
       *id = GLSLstd450NMin;
     } else if (name == "nmax") {
       *id = GLSLstd450NMax;
+    } else if (name == "distance") {
+      *id = GLSLstd450Distance;
+
+      // Distance returns a scalar of the same type as the parameter.
+      return result_type->is_float_scalar() ? result_type
+                                            : result_type->AsVector()->type();
     }
 
-    return params[0]->result_type();
+    return result_type;
   }
 
   return nullptr;
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 4190218..b1c6cd8 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -1910,5 +1910,179 @@
                                          GLSLData{"nmin", GLSLstd450NMin},
                                          GLSLData{"nmax", GLSLstd450NMax}));
 
+TEST_F(TypeDeterminerTest, ImportData_Distance_Scalar) {
+  ast::type::F32Type f32;
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_NE(type, nullptr);
+  EXPECT_TRUE(type->is_float_scalar());
+  EXPECT_EQ(id, GLSLstd450Distance);
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Vector) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 3);
+
+  ast::ExpressionList vals_1;
+  vals_1.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_1.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_1.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 3.0f)));
+
+  ast::ExpressionList vals_2;
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 3.0f)));
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+      &vec, std::move(vals_1)));
+  params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+      &vec, std::move(vals_2)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_NE(type, nullptr);
+  EXPECT_TRUE(type->IsF32());
+  EXPECT_EQ(id, GLSLstd450Distance);
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_Integer) {
+  ast::type::I32Type i32;
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::IntLiteral>(&i32, 1)));
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::IntLiteral>(&i32, 2)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect type for distance. Requires float scalar or a float "
+            "vector values");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_NoParams) {
+  ast::ExpressionList params;
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect number of parameters for distance. Expected 2 got 0");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_OneParam) {
+  ast::type::F32Type f32;
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect number of parameters for distance. Expected 2 got 1");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_MismatchedParamCount) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec2(&f32, 2);
+  ast::type::VectorType vec3(&f32, 3);
+
+  ast::ExpressionList vals_1;
+  vals_1.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_1.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+
+  ast::ExpressionList vals_2;
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals_2.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 3.0f)));
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+      &vec2, std::move(vals_1)));
+  params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+      &vec3, std::move(vals_2)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(), "mismatched parameter types for distance");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_MismatchedParamType) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 3);
+
+  ast::ExpressionList vals;
+  vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 3.0f)));
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
+  params.push_back(
+      std::make_unique<ast::TypeConstructorExpression>(&vec, std::move(vals)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(), "mismatched parameter types for distance");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_Distance_Error_TooManyParams) {
+  ast::type::F32Type f32;
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+  params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type = td()->GetImportData("GLSL.std.450", "distance", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect number of parameters for distance. Expected 2 got 3");
+}
+
 }  // namespace
 }  // namespace tint