resolver: Replace GetScalarConstExprValue with ConstantValueOf

ConstantValueOf() obtains the constant value from the logic in resolver_constants.cc. This is better tested, and is the foundation of Tint's constant folder.

Change-Id: I42036f3ff4ab684b4864cd69856de1715b38d246
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57702
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index a324667..8390108 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1643,9 +1643,13 @@
         auto* constructor = var->declaration->constructor();
         if (constructor) {
           // Resolve the constructor expression to use as the default value.
-          if (!GetScalarConstExprValue(constructor, &value)) {
+          auto val = ConstantValueOf(constructor);
+          if (!val.IsValid() || !val.Type()->Is<sem::I32>()) {
+            TINT_ICE(Resolver, diagnostics_)
+                << "failed to resolve workgroup_size constant value";
             return false;
           }
+          value = val.Elements()[0].i32;
         } else {
           // No constructor means this value must be overriden by the user.
           info->workgroup_size[i].value = 0;
@@ -1656,7 +1660,8 @@
         // We have a literal.
         Mark(scalar->literal());
 
-        if (!scalar->literal()->Is<ast::IntLiteral>()) {
+        auto* i32_literal = scalar->literal()->As<ast::IntLiteral>();
+        if (!i32_literal) {
           AddError(
               "workgroup_size parameter must be a literal i32 or an i32 "
               "module-scope constant",
@@ -1664,9 +1669,7 @@
           return false;
         }
 
-        if (!GetScalarConstExprValue(scalar, &value)) {
-          return false;
-        }
+        value = i32_literal->value_as_i32();
       }
 
       // Validate and set the default value for this dimension.
@@ -4028,40 +4031,6 @@
   return true;
 }
 
-template <typename T>
-bool Resolver::GetScalarConstExprValue(ast::Expression* expr, T* result) {
-  if (auto* type_constructor = expr->As<ast::TypeConstructorExpression>()) {
-    if (type_constructor->values().size() == 0) {
-      // Zero-valued constructor.
-      *result = static_cast<T>(0);
-      return true;
-    } else if (type_constructor->values().size() == 1) {
-      // Recurse into the constructor argument expression.
-      return GetScalarConstExprValue(type_constructor->values()[0], result);
-    } else {
-      TINT_ICE(Resolver, diagnostics_) << "malformed scalar type constructor";
-    }
-  } else if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    // Cast literal to result type.
-    if (auto* int_lit = scalar->literal()->As<ast::IntLiteral>()) {
-      *result = static_cast<T>(int_lit->value_as_u32());
-      return true;
-    } else if (auto* float_lit = scalar->literal()->As<ast::FloatLiteral>()) {
-      *result = static_cast<T>(float_lit->value());
-      return true;
-    } else if (auto* bool_lit = scalar->literal()->As<ast::BoolLiteral>()) {
-      *result = static_cast<T>(bool_lit->IsTrue());
-      return true;
-    } else {
-      TINT_ICE(Resolver, diagnostics_) << "unhandled scalar constructor";
-    }
-  } else {
-    TINT_ICE(Resolver, diagnostics_) << "unhandled constant expression";
-  }
-
-  return false;
-}
-
 template <typename F>
 bool Resolver::BlockScope(const ast::BlockStatement* block, F&& callback) {
   auto* sem_block = builder_->Sem().Get<sem::BlockStatement>(block);
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index 822d6bc..bd2bf62 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -394,13 +394,6 @@
                    const sem::Type* type,
                    std::string type_name = "");
 
-  /// Resolve the value of a scalar const_expr.
-  /// @param expr the expression
-  /// @param result pointer to the where the result will be stored
-  /// @returns true on success, false on error
-  template <typename T>
-  bool GetScalarConstExprValue(ast::Expression* expr, T* result);
-
   /// Constructs a new semantic BlockStatement with the given type and with
   /// #current_block_ as its parent, assigns this to #current_block_, and then
   /// calls `callback`. The original #current_block_ is restored on exit.