Remove ScalarConstructorExpression

Just make Literal an expression. The ScalarConstructorExpression
provides no real value, aside from having a ConstructorExpression base
class that's common between ScalarConstructorExpression and
TypeConstructorExpression. TypeConstructorExpression will be folded into
CallExpression, so this hierarchy will serve no purpose.

First step in resolving the parser ambiguity of type-constructors vs
type-casts vs function calls.

Bug: tint:888
Change-Id: I2585d5ddbf6c0619a8f24c503e61ebf27c182ebe
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/68524
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index cc56039..0214c2c 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -286,8 +286,6 @@
     "ast/sampled_texture.h",
     "ast/sampler.cc",
     "ast/sampler.h",
-    "ast/scalar_constructor_expression.cc",
-    "ast/scalar_constructor_expression.h",
     "ast/sint_literal.cc",
     "ast/sint_literal.h",
     "ast/stage_decoration.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 97e92f6..34027d3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -150,8 +150,6 @@
   ast/sampled_texture.h
   ast/sampler.cc
   ast/sampler.h
-  ast/scalar_constructor_expression.cc
-  ast/scalar_constructor_expression.h
   ast/sint_literal.cc
   ast/sint_literal.h
   ast/stage_decoration.cc
@@ -631,7 +629,6 @@
     ast/return_statement_test.cc
     ast/sampled_texture_test.cc
     ast/sampler_test.cc
-    ast/scalar_constructor_expression_test.cc
     ast/sint_literal_test.cc
     ast/stage_decoration_test.cc
     ast/storage_texture_test.cc
diff --git a/src/ast/array.cc b/src/ast/array.cc
index e37de04..779a950 100644
--- a/src/ast/array.cc
+++ b/src/ast/array.cc
@@ -30,11 +30,8 @@
   if (auto* ident = size->As<IdentifierExpression>()) {
     return symbols.NameFor(ident->symbol);
   }
-  if (auto* scalar = size->As<ScalarConstructorExpression>()) {
-    auto* literal = scalar->literal->As<IntLiteral>();
-    if (literal) {
-      return std::to_string(literal->ValueAsU32());
-    }
+  if (auto* literal = size->As<IntLiteral>()) {
+    return std::to_string(literal->ValueAsU32());
   }
   // This will never be exposed to the user as the Resolver will reject this
   // expression for array size.
diff --git a/src/ast/literal.h b/src/ast/literal.h
index df8db02..851b3ce 100644
--- a/src/ast/literal.h
+++ b/src/ast/literal.h
@@ -17,13 +17,13 @@
 
 #include <string>
 
-#include "src/ast/node.h"
+#include "src/ast/expression.h"
 
 namespace tint {
 namespace ast {
 
-/// Base class for a literal value
-class Literal : public Castable<Literal, Node> {
+/// Base class for a literal value expressions
+class Literal : public Castable<Literal, Expression> {
  public:
   ~Literal() override;
 
diff --git a/src/ast/scalar_constructor_expression.cc b/src/ast/scalar_constructor_expression.cc
deleted file mode 100644
index 8085188..0000000
--- a/src/ast/scalar_constructor_expression.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#include "src/ast/scalar_constructor_expression.h"
-
-#include "src/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::ScalarConstructorExpression);
-
-namespace tint {
-namespace ast {
-
-ScalarConstructorExpression::ScalarConstructorExpression(ProgramID pid,
-                                                         const Source& src,
-                                                         const Literal* lit)
-    : Base(pid, src), literal(lit) {
-  TINT_ASSERT(AST, literal);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, literal, program_id);
-}
-
-ScalarConstructorExpression::ScalarConstructorExpression(
-    ScalarConstructorExpression&&) = default;
-
-ScalarConstructorExpression::~ScalarConstructorExpression() = default;
-
-const ScalarConstructorExpression* ScalarConstructorExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* lit = ctx->Clone(literal);
-  return ctx->dst->create<ScalarConstructorExpression>(src, lit);
-}
-
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/scalar_constructor_expression.h b/src/ast/scalar_constructor_expression.h
deleted file mode 100644
index b80650e..0000000
--- a/src/ast/scalar_constructor_expression.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#ifndef SRC_AST_SCALAR_CONSTRUCTOR_EXPRESSION_H_
-#define SRC_AST_SCALAR_CONSTRUCTOR_EXPRESSION_H_
-
-#include "src/ast/constructor_expression.h"
-#include "src/ast/literal.h"
-
-namespace tint {
-namespace ast {
-
-/// A scalar constructor
-class ScalarConstructorExpression
-    : public Castable<ScalarConstructorExpression, ConstructorExpression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param literal the const literal
-  ScalarConstructorExpression(ProgramID pid,
-                              const Source& src,
-                              const Literal* literal);
-  /// Move constructor
-  ScalarConstructorExpression(ScalarConstructorExpression&&);
-  ~ScalarConstructorExpression() override;
-
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const ScalarConstructorExpression* Clone(CloneContext* ctx) const override;
-
-  /// The literal value
-  const Literal* const literal;
-};
-
-}  // namespace ast
-}  // namespace tint
-
-#endif  // SRC_AST_SCALAR_CONSTRUCTOR_EXPRESSION_H_
diff --git a/src/ast/scalar_constructor_expression_test.cc b/src/ast/scalar_constructor_expression_test.cc
deleted file mode 100644
index 1c184d5..0000000
--- a/src/ast/scalar_constructor_expression_test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#include "gtest/gtest-spi.h"
-#include "src/ast/test_helper.h"
-
-namespace tint {
-namespace ast {
-namespace {
-
-using ScalarConstructorExpressionTest = TestHelper;
-
-TEST_F(ScalarConstructorExpressionTest, Creation) {
-  auto* b = create<BoolLiteral>(true);
-  auto* c = create<ScalarConstructorExpression>(b);
-  EXPECT_EQ(c->literal, b);
-}
-
-TEST_F(ScalarConstructorExpressionTest, Creation_WithSource) {
-  SetSource(Source{Source::Location{20, 2}});
-  auto src = Expr(true)->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
-}
-
-TEST_F(ScalarConstructorExpressionTest, Assert_DifferentProgramID_Literal) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<ScalarConstructorExpression>(b2.create<BoolLiteral>(true));
-      },
-      "internal compiler error");
-}
-
-}  // namespace
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/traverse_expressions.h b/src/ast/traverse_expressions.h
index 28df9f2..97658f3 100644
--- a/src/ast/traverse_expressions.h
+++ b/src/ast/traverse_expressions.h
@@ -21,9 +21,9 @@
 #include "src/ast/binary_expression.h"
 #include "src/ast/bitcast_expression.h"
 #include "src/ast/call_expression.h"
+#include "src/ast/literal.h"
 #include "src/ast/member_accessor_expression.h"
 #include "src/ast/phony_expression.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/unary_op_expression.h"
 #include "src/utils/reverse.h"
@@ -122,8 +122,7 @@
       to_visit.push_back(member->structure);
     } else if (auto* unary = expr->As<ast::UnaryOpExpression>()) {
       to_visit.push_back(unary->expr);
-    } else if (expr->IsAnyOf<ast::ScalarConstructorExpression,
-                             ast::IdentifierExpression,
+    } else if (expr->IsAnyOf<ast::Literal, ast::IdentifierExpression,
                              ast::PhonyExpression>()) {
       // Leaf expression
     } else {
diff --git a/src/ast/workgroup_decoration_test.cc b/src/ast/workgroup_decoration_test.cc
index cbf7ee8..68b5b22 100644
--- a/src/ast/workgroup_decoration_test.cc
+++ b/src/ast/workgroup_decoration_test.cc
@@ -26,11 +26,9 @@
 TEST_F(WorkgroupDecorationTest, Creation_1param) {
   auto* d = WorkgroupSize(2);
   auto values = d->Values();
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(x_scalar);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
   EXPECT_EQ(values[1], nullptr);
   EXPECT_EQ(values[2], nullptr);
@@ -38,17 +36,12 @@
 TEST_F(WorkgroupDecorationTest, Creation_2param) {
   auto* d = WorkgroupSize(2, 4);
   auto values = d->Values();
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(x_scalar);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(y_scalar);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   EXPECT_EQ(values[2], nullptr);
 }
@@ -56,42 +49,28 @@
 TEST_F(WorkgroupDecorationTest, Creation_3param) {
   auto* d = WorkgroupSize(2, 4, 6);
   auto values = d->Values();
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(x_scalar);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(y_scalar);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_scalar = values[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(z_scalar);
-  ASSERT_TRUE(z_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(z_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 6u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+
+  ASSERT_TRUE(values[2]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[2]->As<ast::IntLiteral>()->ValueAsU32(), 6u);
 }
 
 TEST_F(WorkgroupDecorationTest, Creation_WithIdentifier) {
   auto* d = WorkgroupSize(2, 4, "depth");
   auto values = d->Values();
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(x_scalar);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(y_scalar);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_ident = values[2]->As<ast::IdentifierExpression>();
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+
+  auto* z_ident = As<ast::IdentifierExpression>(values[2]);
   ASSERT_TRUE(z_ident);
   EXPECT_EQ(Symbols().NameFor(z_ident->symbol), "depth");
 }
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index b602c0a..0ef2872 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -24,7 +24,6 @@
 #include "src/ast/location_decoration.h"
 #include "src/ast/module.h"
 #include "src/ast/override_decoration.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/sint_literal.h"
 #include "src/ast/uint_literal.h"
 #include "src/sem/array.h"
@@ -264,23 +263,7 @@
       continue;
     }
 
-    auto* expression = var->constructor;
-    auto* constructor = expression->As<ast::ConstructorExpression>();
-    if (constructor == nullptr) {
-      // This is invalid WGSL, but handling gracefully.
-      result[constant_id] = Scalar();
-      continue;
-    }
-
-    auto* scalar_constructor =
-        constructor->As<ast::ScalarConstructorExpression>();
-    if (scalar_constructor == nullptr) {
-      // This is invalid WGSL, but handling gracefully.
-      result[constant_id] = Scalar();
-      continue;
-    }
-
-    auto* literal = scalar_constructor->literal;
+    auto* literal = var->constructor->As<ast::Literal>();
     if (!literal) {
       // This is invalid WGSL, but handling gracefully.
       result[constant_id] = Scalar();
diff --git a/src/program_builder.cc b/src/program_builder.cc
index 7bea10b..f20b76a 100644
--- a/src/program_builder.cc
+++ b/src/program_builder.cc
@@ -114,10 +114,6 @@
 
 ProgramBuilder::TypesBuilder::TypesBuilder(ProgramBuilder* pb) : builder(pb) {}
 
-const ast::Statement* ProgramBuilder::WrapInStatement(const ast::Literal* lit) {
-  return WrapInStatement(create<ast::ScalarConstructorExpression>(lit));
-}
-
 const ast::Statement* ProgramBuilder::WrapInStatement(
     const ast::Expression* expr) {
   if (auto* ce = expr->As<ast::CallExpression>()) {
diff --git a/src/program_builder.h b/src/program_builder.h
index abe9a6e..2c13980 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -55,7 +55,6 @@
 #include "src/ast/return_statement.h"
 #include "src/ast/sampled_texture.h"
 #include "src/ast/sampler.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/sint_literal.h"
 #include "src/ast/stage_decoration.h"
 #include "src/ast/storage_texture.h"
@@ -1038,57 +1037,53 @@
   /// @param source the source information
   /// @param value the boolean value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(const Source& source,
-                                               bool value) {
-    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  const ast::Literal* Expr(const Source& source, bool value) {
+    return create<ast::BoolLiteral>(source, value);
   }
 
   /// @param value the boolean value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(bool value) {
-    return create<ast::ScalarConstructorExpression>(Literal(value));
+  const ast::BoolLiteral* Expr(bool value) {
+    return create<ast::BoolLiteral>(value);
   }
 
   /// @param source the source information
   /// @param value the float value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(const Source& source,
-                                               f32 value) {
-    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  const ast::FloatLiteral* Expr(const Source& source, f32 value) {
+    return create<ast::FloatLiteral>(source, value);
   }
 
   /// @param value the float value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(f32 value) {
-    return create<ast::ScalarConstructorExpression>(Literal(value));
+  const ast::FloatLiteral* Expr(f32 value) {
+    return create<ast::FloatLiteral>(value);
   }
 
   /// @param source the source information
   /// @param value the integer value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(const Source& source,
-                                               i32 value) {
-    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  const ast::Literal* Expr(const Source& source, i32 value) {
+    return create<ast::SintLiteral>(source, value);
   }
 
   /// @param value the integer value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(i32 value) {
-    return create<ast::ScalarConstructorExpression>(Literal(value));
+  const ast::SintLiteral* Expr(i32 value) {
+    return create<ast::SintLiteral>(value);
   }
 
   /// @param source the source information
   /// @param value the unsigned int value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(const Source& source,
-                                               u32 value) {
-    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  const ast::UintLiteral* Expr(const Source& source, u32 value) {
+    return create<ast::UintLiteral>(source, value);
   }
 
   /// @param value the unsigned int value
   /// @return a Scalar constructor for the given value
-  const ast::ScalarConstructorExpression* Expr(u32 value) {
-    return create<ast::ScalarConstructorExpression>(Literal(value));
+  const ast::UintLiteral* Expr(u32 value) {
+    return create<ast::UintLiteral>(value);
   }
 
   /// Converts `arg` to an `ast::Expression` using `Expr()`, then appends it to
@@ -2502,12 +2497,6 @@
   /// the type declaration has no resolved type.
   const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const;
 
-  /// Wraps the ast::Literal in a statement. This is used by tests that
-  /// construct a partial AST and require the Resolver to reach these
-  /// nodes.
-  /// @param lit the ast::Literal to be wrapped by an ast::Statement
-  /// @return the ast::Statement that wraps the ast::Statement
-  const ast::Statement* WrapInStatement(const ast::Literal* lit);
   /// Wraps the ast::Expression in a statement. This is used by tests that
   /// construct a partial AST and require the Resolver to reach these
   /// nodes.
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 9bea3af..21e51ae 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -2548,9 +2548,7 @@
       return source_expr;
     }
     case SkipReason::kPointSizeBuiltinValue: {
-      return {ty_.F32(),
-              create<ast::ScalarConstructorExpression>(
-                  Source{}, create<ast::FloatLiteral>(Source{}, 1.0f))};
+      return {ty_.F32(), create<ast::FloatLiteral>(Source{}, 1.0f)};
     }
     case SkipReason::kPointSizeBuiltinPointer:
       Fail() << "unhandled use of a pointer to the PointSize builtin, with ID: "
@@ -4477,8 +4475,7 @@
   auto current_type_id = composite_type_id;
 
   auto make_index = [this](uint32_t literal) {
-    return create<ast::ScalarConstructorExpression>(
-        Source{}, create<ast::UintLiteral>(Source{}, literal));
+    return create<ast::UintLiteral>(Source{}, literal);
   };
 
   // Build up a nested expression for the decomposition by walking down the type
@@ -4594,13 +4591,11 @@
 }
 
 const ast::Expression* FunctionEmitter::MakeTrue(const Source& source) const {
-  return create<ast::ScalarConstructorExpression>(
-      source, create<ast::BoolLiteral>(source, true));
+  return create<ast::BoolLiteral>(source, true);
 }
 
 const ast::Expression* FunctionEmitter::MakeFalse(const Source& source) const {
-  return create<ast::ScalarConstructorExpression>(
-      source, create<ast::BoolLiteral>(source, false));
+  return create<ast::BoolLiteral>(source, false);
 }
 
 TypedExpression FunctionEmitter::MakeVectorShuffle(
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 65a57c9..6ad62fd 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1353,34 +1353,30 @@
   for (auto& inst : module_->types_values()) {
     // These will be populated for a valid scalar spec constant.
     const Type* ast_type = nullptr;
-    ast::ScalarConstructorExpression* ast_expr = nullptr;
+    ast::Literal* ast_expr = nullptr;
 
     switch (inst.opcode()) {
       case SpvOpSpecConstantTrue:
       case SpvOpSpecConstantFalse: {
         ast_type = ConvertType(inst.type_id());
-        ast_expr = create<ast::ScalarConstructorExpression>(
-            Source{}, create<ast::BoolLiteral>(
-                          Source{}, inst.opcode() == SpvOpSpecConstantTrue));
+        ast_expr = create<ast::BoolLiteral>(
+            Source{}, inst.opcode() == SpvOpSpecConstantTrue);
         break;
       }
       case SpvOpSpecConstant: {
         ast_type = ConvertType(inst.type_id());
         const uint32_t literal_value = inst.GetSingleWordInOperand(0);
         if (ast_type->Is<I32>()) {
-          ast_expr = create<ast::ScalarConstructorExpression>(
-              Source{}, create<ast::SintLiteral>(
-                            Source{}, static_cast<int32_t>(literal_value)));
+          ast_expr = create<ast::SintLiteral>(
+              Source{}, static_cast<int32_t>(literal_value));
         } else if (ast_type->Is<U32>()) {
-          ast_expr = create<ast::ScalarConstructorExpression>(
-              Source{}, create<ast::UintLiteral>(
-                            Source{}, static_cast<uint32_t>(literal_value)));
+          ast_expr = create<ast::UintLiteral>(
+              Source{}, static_cast<uint32_t>(literal_value));
         } else if (ast_type->Is<F32>()) {
           float float_value;
           // Copy the bits so we can read them as a float.
           std::memcpy(&float_value, &literal_value, sizeof(float_value));
-          ast_expr = create<ast::ScalarConstructorExpression>(
-              Source{}, create<ast::FloatLiteral>(Source{}, float_value));
+          ast_expr = create<ast::FloatLiteral>(Source{}, float_value);
         } else {
           return Fail() << " invalid result type for OpSpecConstant "
                         << inst.PrettyPrint();
@@ -1981,26 +1977,20 @@
   // Currently "null<type>" is missing from the WGSL parser.
   // See https://bugs.chromium.org/p/tint/issues/detail?id=34
   if (ast_type->Is<U32>()) {
-    return {ty_.U32(), create<ast::ScalarConstructorExpression>(
-                           Source{}, create<ast::UintLiteral>(
-                                         source, spirv_const->GetU32()))};
+    return {ty_.U32(), create<ast::UintLiteral>(source, spirv_const->GetU32())};
   }
   if (ast_type->Is<I32>()) {
-    return {ty_.I32(), create<ast::ScalarConstructorExpression>(
-                           Source{}, create<ast::SintLiteral>(
-                                         source, spirv_const->GetS32()))};
+    return {ty_.I32(), create<ast::SintLiteral>(source, spirv_const->GetS32())};
   }
   if (ast_type->Is<F32>()) {
-    return {ty_.F32(), create<ast::ScalarConstructorExpression>(
-                           Source{}, create<ast::FloatLiteral>(
-                                         source, spirv_const->GetFloat()))};
+    return {ty_.F32(),
+            create<ast::FloatLiteral>(source, spirv_const->GetFloat())};
   }
   if (ast_type->Is<Bool>()) {
     const bool value = spirv_const->AsNullConstant()
                            ? false
                            : spirv_const->AsBoolConstant()->value();
-    return {ty_.Bool(), create<ast::ScalarConstructorExpression>(
-                            Source{}, create<ast::BoolLiteral>(source, value))};
+    return {ty_.Bool(), create<ast::BoolLiteral>(source, value)};
   }
   Fail() << "expected scalar constant";
   return {};
@@ -2021,20 +2011,16 @@
   type = type->UnwrapAlias();
 
   if (type->Is<Bool>()) {
-    return create<ast::ScalarConstructorExpression>(
-        Source{}, create<ast::BoolLiteral>(Source{}, false));
+    return create<ast::BoolLiteral>(Source{}, false);
   }
   if (type->Is<U32>()) {
-    return create<ast::ScalarConstructorExpression>(
-        Source{}, create<ast::UintLiteral>(Source{}, 0u));
+    return create<ast::UintLiteral>(Source{}, 0u);
   }
   if (type->Is<I32>()) {
-    return create<ast::ScalarConstructorExpression>(
-        Source{}, create<ast::SintLiteral>(Source{}, 0));
+    return create<ast::SintLiteral>(Source{}, 0);
   }
   if (type->Is<F32>()) {
-    return create<ast::ScalarConstructorExpression>(
-        Source{}, create<ast::FloatLiteral>(Source{}, 0.0f));
+    return create<ast::FloatLiteral>(Source{}, 0.0f);
   }
   if (type->Is<Alias>()) {
     // TODO(amaiorano): No type constructor for TypeName (yet?)
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index fdcb027..8e904bf 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -521,11 +521,12 @@
   if (decl.errored)
     return Failure::kErrored;
 
-  ast::ConstructorExpression* initializer = nullptr;
+  const ast::Expression* initializer = nullptr;
   if (match(Token::Type::kEqual)) {
     auto init = expect_const_expr();
-    if (init.errored)
+    if (init.errored) {
       return Failure::kErrored;
+    }
     initializer = std::move(init.value);
   }
 
@@ -2175,15 +2176,18 @@
   auto source = t.source();
 
   auto lit = const_literal();
-  if (lit.errored)
+  if (lit.errored) {
     return Failure::kErrored;
-  if (lit.matched)
-    return create<ast::ScalarConstructorExpression>(source, lit.value);
+  }
+  if (lit.matched) {
+    return lit.value;
+  }
 
   if (t.Is(Token::Type::kParenLeft)) {
     auto paren = expect_paren_rhs_stmt();
-    if (paren.errored)
+    if (paren.errored) {
       return Failure::kErrored;
+    }
 
     return paren.value;
   }
@@ -2869,23 +2873,25 @@
 // const_expr
 //   : type_decl PAREN_LEFT ((const_expr COMMA)? const_expr COMMA?)? PAREN_RIGHT
 //   | const_literal
-Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() {
+Expect<const ast::Expression*> ParserImpl::expect_const_expr() {
   auto t = peek();
   auto source = t.source();
   if (t.IsLiteral()) {
     auto lit = const_literal();
-    if (lit.errored)
+    if (lit.errored) {
       return Failure::kErrored;
-    if (!lit.matched)
+    }
+    if (!lit.matched) {
       return add_error(peek(), "unable to parse constant literal");
-
-    return create<ast::ScalarConstructorExpression>(source, lit.value);
+    }
+    return lit.value;
   } else if (!t.IsIdentifier() || get_type(t.to_str())) {
     if (peek_is(Token::Type::kParenLeft, 1) ||
         peek_is(Token::Type::kLessThan, 1)) {
       auto type = expect_type("const_expr");
-      if (type.errored)
+      if (type.errored) {
         return Failure::kErrored;
+      }
 
       auto params = expect_paren_block(
           "type constructor", [&]() -> Expect<ast::ExpressionList> {
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 40335aa..2da91e2 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -571,7 +571,7 @@
   Maybe<const ast::Literal*> const_literal();
   /// Parses a `const_expr` grammar element, erroring on parse failure.
   /// @returns the parsed constructor expression or nullptr on error
-  Expect<ast::ConstructorExpression*> expect_const_expr();
+  Expect<const ast::Expression*> expect_const_expr();
   /// Parses a `primary_expression` grammar element
   /// @returns the parsed expression or nullptr
   Maybe<const ast::Expression*> primary_expression();
diff --git a/src/reader/wgsl/parser_impl_additive_expression_test.cc b/src/reader/wgsl/parser_impl_additive_expression_test.cc
index f6643d4..fb66a73 100644
--- a/src/reader/wgsl/parser_impl_additive_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_additive_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
@@ -58,11 +55,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_and_expression_test.cc b/src/reader/wgsl/parser_impl_and_expression_test.cc
index 64f715c..73aa8de 100644
--- a/src/reader/wgsl/parser_impl_and_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_and_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, AndExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_argument_expression_list_test.cc b/src/reader/wgsl/parser_impl_argument_expression_list_test.cc
index bb73660..575ca43 100644
--- a/src/reader/wgsl/parser_impl_argument_expression_list_test.cc
+++ b/src/reader/wgsl/parser_impl_argument_expression_list_test.cc
@@ -46,7 +46,7 @@
 
   ASSERT_EQ(e.value.size(), 3u);
   ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
-  ASSERT_TRUE(e.value[1]->Is<ast::ConstructorExpression>());
+  ASSERT_TRUE(e.value[1]->Is<ast::Literal>());
   ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
 }
 
@@ -58,7 +58,7 @@
 
   ASSERT_EQ(e.value.size(), 2u);
   ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
-  ASSERT_TRUE(e.value[1]->Is<ast::ConstructorExpression>());
+  ASSERT_TRUE(e.value[1]->Is<ast::Literal>());
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingLeftParen) {
diff --git a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
index 7fe7097..38cdc7c 100644
--- a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc
@@ -35,13 +35,9 @@
   auto* ident = e->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(e->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->rhs->Is<ast::ScalarConstructorExpression>());
-
-  auto* init = e->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(init->literal, nullptr);
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 123);
+  ASSERT_NE(e->rhs, nullptr);
+  ASSERT_TRUE(e->rhs->Is<ast::SintLiteral>());
+  EXPECT_EQ(e->rhs->As<ast::SintLiteral>()->value, 123);
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
@@ -56,12 +52,9 @@
   ASSERT_NE(e->lhs, nullptr);
   ASSERT_NE(e->rhs, nullptr);
 
-  ASSERT_TRUE(e->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = e->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(init->literal, nullptr);
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 123);
+  ASSERT_NE(e->rhs, nullptr);
+  ASSERT_TRUE(e->rhs->Is<ast::SintLiteral>());
+  EXPECT_EQ(e->rhs->As<ast::SintLiteral>()->value, 123);
 
   ASSERT_TRUE(e->lhs->Is<ast::MemberAccessorExpression>());
   auto* mem = e->lhs->As<ast::MemberAccessorExpression>();
@@ -73,12 +66,9 @@
   ASSERT_TRUE(mem->structure->Is<ast::ArrayAccessorExpression>());
   auto* ary = mem->structure->As<ast::ArrayAccessorExpression>();
 
-  ASSERT_TRUE(ary->index->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(ary->index->Is<ast::ScalarConstructorExpression>());
-  init = ary->index->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(init->literal, nullptr);
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 2);
+  ASSERT_NE(ary->index, nullptr);
+  ASSERT_TRUE(ary->index->Is<ast::SintLiteral>());
+  EXPECT_EQ(ary->index->As<ast::SintLiteral>()->value, 2);
 
   ASSERT_TRUE(ary->array->Is<ast::MemberAccessorExpression>());
   mem = ary->array->As<ast::MemberAccessorExpression>();
@@ -110,12 +100,9 @@
   ASSERT_NE(e->lhs, nullptr);
   ASSERT_NE(e->rhs, nullptr);
 
-  ASSERT_TRUE(e->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = e->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(init->literal, nullptr);
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 123);
+  ASSERT_NE(e->rhs, nullptr);
+  ASSERT_TRUE(e->rhs->Is<ast::SintLiteral>());
+  EXPECT_EQ(e->rhs->As<ast::SintLiteral>()->value, 123);
 
   ASSERT_TRUE(e->lhs->Is<ast::PhonyExpression>());
 }
diff --git a/src/reader/wgsl/parser_impl_call_stmt_test.cc b/src/reader/wgsl/parser_impl_call_stmt_test.cc
index e38774f..edd8142 100644
--- a/src/reader/wgsl/parser_impl_call_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -55,7 +55,7 @@
   EXPECT_EQ(c->func->symbol, p->builder().Symbols().Get("a"));
 
   EXPECT_EQ(c->args.size(), 3u);
-  EXPECT_TRUE(c->args[0]->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteral>());
   EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
   EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
 }
@@ -74,7 +74,7 @@
   EXPECT_EQ(c->func->symbol, p->builder().Symbols().Get("a"));
 
   EXPECT_EQ(c->args.size(), 2u);
-  EXPECT_TRUE(c->args[0]->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteral>());
   EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
 }
 
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc
index a37f6e0..62e5e3f 100644
--- a/src/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -34,17 +34,11 @@
   ASSERT_EQ(t->values.size(), 2u);
   auto& v = t->values;
 
-  ASSERT_TRUE(v[0]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(v[0]->Is<ast::ScalarConstructorExpression>());
-  auto* c = v[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(c->literal->Is<ast::FloatLiteral>());
-  EXPECT_FLOAT_EQ(c->literal->As<ast::FloatLiteral>()->value, 1.);
+  ASSERT_TRUE(v[0]->Is<ast::FloatLiteral>());
+  EXPECT_FLOAT_EQ(v[0]->As<ast::FloatLiteral>()->value, 1.);
 
-  ASSERT_TRUE(v[1]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(v[1]->Is<ast::ScalarConstructorExpression>());
-  c = v[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(c->literal->Is<ast::FloatLiteral>());
-  EXPECT_FLOAT_EQ(c->literal->As<ast::FloatLiteral>()->value, 2.);
+  ASSERT_TRUE(v[1]->Is<ast::FloatLiteral>());
+  EXPECT_FLOAT_EQ(v[1]->As<ast::FloatLiteral>()->value, 2.);
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_Empty) {
@@ -75,8 +69,8 @@
   EXPECT_EQ(t->type->As<ast::Vector>()->width, 2u);
 
   ASSERT_EQ(t->values.size(), 2u);
-  ASSERT_TRUE(t->values[0]->Is<ast::ScalarConstructorExpression>());
-  ASSERT_TRUE(t->values[1]->Is<ast::ScalarConstructorExpression>());
+  ASSERT_TRUE(t->values[0]->Is<ast::Literal>());
+  ASSERT_TRUE(t->values[1]->Is<ast::Literal>());
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
@@ -121,11 +115,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->Is<ast::ScalarConstructorExpression>());
-  auto* c = e->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(c->literal->Is<ast::BoolLiteral>());
-  EXPECT_TRUE(c->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(e.value->Is<ast::BoolLiteral>());
+  EXPECT_TRUE(e.value->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
diff --git a/src/reader/wgsl/parser_impl_equality_expression_test.cc b/src/reader/wgsl/parser_impl_equality_expression_test.cc
index 8350e96..72db3a6 100644
--- a/src/reader/wgsl/parser_impl_equality_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_equality_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
@@ -58,11 +55,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc b/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
index bfcbf94..6fbf186 100644
--- a/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_function_decl_test.cc b/src/reader/wgsl/parser_impl_function_decl_test.cc
index 2ec9a8d..67131b8 100644
--- a/src/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decl_test.cc
@@ -71,23 +71,14 @@
 
   auto values = decorations[0]->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(y_scalar, nullptr);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 3u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 3u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_scalar = values[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(z_scalar, nullptr);
-  ASSERT_TRUE(z_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(z_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[2]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[2]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   auto* body = f->body;
   ASSERT_EQ(body->statements.size(), 1u);
@@ -119,23 +110,14 @@
   ASSERT_TRUE(decorations[0]->Is<ast::WorkgroupDecoration>());
   auto values = decorations[0]->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(y_scalar, nullptr);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 3u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 3u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_scalar = values[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(z_scalar, nullptr);
-  ASSERT_TRUE(z_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(z_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[2]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[2]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   ASSERT_TRUE(decorations[1]->Is<ast::StageDecoration>());
   EXPECT_EQ(decorations[1]->As<ast::StageDecoration>()->stage,
@@ -172,23 +154,14 @@
   ASSERT_TRUE(decos[0]->Is<ast::WorkgroupDecoration>());
   auto values = decos[0]->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(y_scalar, nullptr);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 3u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 3u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_scalar = values[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(z_scalar, nullptr);
-  ASSERT_TRUE(z_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(z_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[2]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[2]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   ASSERT_TRUE(decos[1]->Is<ast::StageDecoration>());
   EXPECT_EQ(decos[1]->As<ast::StageDecoration>()->stage,
diff --git a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
index 1a5924a..0b681c0 100644
--- a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
@@ -36,10 +36,10 @@
   ASSERT_TRUE(deco_0->Is<ast::WorkgroupDecoration>());
   const ast::Expression* x = deco_0->As<ast::WorkgroupDecoration>()->x;
   ASSERT_NE(x, nullptr);
-  auto* x_scalar = x->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
+  auto* x_literal = x->As<ast::Literal>();
+  ASSERT_NE(x_literal, nullptr);
+  ASSERT_TRUE(x_literal->Is<ast::IntLiteral>());
+  EXPECT_EQ(x_literal->As<ast::IntLiteral>()->ValueAsU32(), 2u);
 
   ASSERT_TRUE(deco_1->Is<ast::StageDecoration>());
   EXPECT_EQ(deco_1->As<ast::StageDecoration>()->stage,
diff --git a/src/reader/wgsl/parser_impl_function_decoration_test.cc b/src/reader/wgsl/parser_impl_function_decoration_test.cc
index 2fe6994..d63d272 100644
--- a/src/reader/wgsl/parser_impl_function_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decoration_test.cc
@@ -34,11 +34,8 @@
 
   auto values = func_deco->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   EXPECT_EQ(values[1], nullptr);
   EXPECT_EQ(values[2], nullptr);
@@ -57,17 +54,11 @@
 
   auto values = func_deco->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(y_scalar, nullptr);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 5u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 5u);
 
   EXPECT_EQ(values[2], nullptr);
 }
@@ -85,23 +76,14 @@
 
   auto values = func_deco->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_scalar = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(y_scalar, nullptr);
-  ASSERT_TRUE(y_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(y_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 5u);
+  ASSERT_TRUE(values[1]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[1]->As<ast::IntLiteral>()->ValueAsU32(), 5u);
 
-  ASSERT_NE(values[2], nullptr);
-  auto* z_scalar = values[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(z_scalar, nullptr);
-  ASSERT_TRUE(z_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(z_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 6u);
+  ASSERT_TRUE(values[2]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[2]->As<ast::IntLiteral>()->ValueAsU32(), 6u);
 }
 
 TEST_F(ParserImplTest, Decoration_Workgroup_WithIdent) {
@@ -117,11 +99,8 @@
 
   auto values = func_deco->As<ast::WorkgroupDecoration>()->Values();
 
-  ASSERT_NE(values[0], nullptr);
-  auto* x_scalar = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(x_scalar, nullptr);
-  ASSERT_TRUE(x_scalar->literal->Is<ast::IntLiteral>());
-  EXPECT_EQ(x_scalar->literal->As<ast::IntLiteral>()->ValueAsU32(), 4u);
+  ASSERT_TRUE(values[0]->Is<ast::IntLiteral>());
+  EXPECT_EQ(values[0]->As<ast::IntLiteral>()->ValueAsU32(), 4u);
 
   ASSERT_NE(values[1], nullptr);
   auto* y_ident = values[1]->As<ast::IdentifierExpression>();
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 308bd70..29fe795 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -42,7 +42,7 @@
   EXPECT_EQ(e->source.range.end.column, 6u);
 
   ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(e->constructor->Is<ast::Literal>());
 
   EXPECT_FALSE(
       ast::HasDecoration<ast::OverrideDecoration>(e.value->decorations));
@@ -69,7 +69,7 @@
   EXPECT_EQ(e->source.range.end.column, 6u);
 
   ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(e->constructor->Is<ast::Literal>());
 
   EXPECT_FALSE(
       ast::HasDecoration<ast::OverrideDecoration>(e.value->decorations));
@@ -137,7 +137,7 @@
   EXPECT_EQ(e->source.range.end.column, 22u);
 
   ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(e->constructor->Is<ast::Literal>());
 
   auto* override_deco =
       ast::GetDecoration<ast::OverrideDecoration>(e.value->decorations);
@@ -169,7 +169,7 @@
   EXPECT_EQ(e->source.range.end.column, 19u);
 
   ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(e->constructor->Is<ast::Literal>());
 
   auto* override_deco =
       ast::GetDecoration<ast::OverrideDecoration>(e.value->decorations);
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index c7c5630..9823c3f 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -63,8 +63,7 @@
   EXPECT_EQ(e->source.range.end.column, 15u);
 
   ASSERT_NE(e->constructor, nullptr);
-  ASSERT_TRUE(e->constructor->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->constructor->Is<ast::ScalarConstructorExpression>());
+  ASSERT_TRUE(e->constructor->Is<ast::FloatLiteral>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
diff --git a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
index 15b04aa..5f6d5da 100644
--- a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
index c2bbb2b..b394558 100644
--- a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
index 320bad6..5b1d884 100644
--- a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
index ad86047..c2ab2f1 100644
--- a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
@@ -58,11 +55,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
@@ -81,11 +75,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc
index 4a23abc..1d44f16 100644
--- a/src/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -45,29 +45,17 @@
 
   ASSERT_EQ(ty->values.size(), 4u);
   const auto& val = ty->values;
-  ASSERT_TRUE(val[0]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(val[0]->Is<ast::ScalarConstructorExpression>());
-  auto* ident = val[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(ident->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(ident->literal->As<ast::SintLiteral>()->value, 1);
+  ASSERT_TRUE(val[0]->Is<ast::SintLiteral>());
+  EXPECT_EQ(val[0]->As<ast::SintLiteral>()->value, 1);
 
-  ASSERT_TRUE(val[1]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(val[1]->Is<ast::ScalarConstructorExpression>());
-  ident = val[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(ident->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(ident->literal->As<ast::SintLiteral>()->value, 2);
+  ASSERT_TRUE(val[1]->Is<ast::SintLiteral>());
+  EXPECT_EQ(val[1]->As<ast::SintLiteral>()->value, 2);
 
-  ASSERT_TRUE(val[2]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(val[2]->Is<ast::ScalarConstructorExpression>());
-  ident = val[2]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(ident->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(ident->literal->As<ast::SintLiteral>()->value, 3);
+  ASSERT_TRUE(val[2]->Is<ast::SintLiteral>());
+  EXPECT_EQ(val[2]->As<ast::SintLiteral>()->value, 3);
 
-  ASSERT_TRUE(val[3]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(val[3]->Is<ast::ScalarConstructorExpression>());
-  ident = val[3]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(ident->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(ident->literal->As<ast::SintLiteral>()->value, 4);
+  ASSERT_TRUE(val[3]->Is<ast::SintLiteral>());
+  EXPECT_EQ(val[3]->As<ast::SintLiteral>()->value, 4);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
@@ -173,15 +161,11 @@
   auto values = constructor->values;
   ASSERT_EQ(values.size(), 2u);
 
-  ASSERT_TRUE(values[0]->Is<ast::ScalarConstructorExpression>());
-  auto* val0 = values[0]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(val0->literal->Is<ast::UintLiteral>());
-  EXPECT_EQ(val0->literal->As<ast::UintLiteral>()->value, 1u);
+  ASSERT_TRUE(values[0]->Is<ast::UintLiteral>());
+  EXPECT_EQ(values[0]->As<ast::UintLiteral>()->value, 1u);
 
-  ASSERT_TRUE(values[1]->Is<ast::ScalarConstructorExpression>());
-  auto* val1 = values[1]->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(val1->literal->Is<ast::FloatLiteral>());
-  EXPECT_EQ(val1->literal->As<ast::FloatLiteral>()->value, 2.f);
+  ASSERT_TRUE(values[1]->Is<ast::FloatLiteral>());
+  EXPECT_EQ(values[1]->As<ast::FloatLiteral>()->value, 2.f);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
@@ -191,11 +175,8 @@
   EXPECT_FALSE(e.errored);
   EXPECT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(e->Is<ast::ScalarConstructorExpression>());
-  auto* init = e->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  EXPECT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(e->Is<ast::BoolLiteral>());
+  EXPECT_TRUE(e->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) {
@@ -253,8 +234,7 @@
   ASSERT_TRUE(c->type->Is<ast::F32>());
   ASSERT_EQ(c->values.size(), 1u);
 
-  ASSERT_TRUE(c->values[0]->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(c->values[0]->Is<ast::ScalarConstructorExpression>());
+  ASSERT_TRUE(c->values[0]->Is<ast::IntLiteral>());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
@@ -269,8 +249,7 @@
 
   auto* c = e->As<ast::BitcastExpression>();
   ASSERT_TRUE(c->type->Is<ast::F32>());
-  ASSERT_TRUE(c->expr->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(c->expr->Is<ast::ScalarConstructorExpression>());
+  ASSERT_TRUE(c->expr->Is<ast::IntLiteral>());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingGreaterThan) {
diff --git a/src/reader/wgsl/parser_impl_relational_expression_test.cc b/src/reader/wgsl/parser_impl_relational_expression_test.cc
index 2bbfcbf..290fec3 100644
--- a/src/reader/wgsl/parser_impl_relational_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_relational_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
@@ -58,11 +55,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
@@ -81,11 +75,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
@@ -104,11 +95,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) {
diff --git a/src/reader/wgsl/parser_impl_shift_expression_test.cc b/src/reader/wgsl/parser_impl_shift_expression_test.cc
index 58675d6..1b6e73b 100644
--- a/src/reader/wgsl/parser_impl_shift_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_shift_expression_test.cc
@@ -35,11 +35,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
@@ -58,11 +55,8 @@
   auto* ident = rel->lhs->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(rel->rhs->Is<ast::ScalarConstructorExpression>());
-  auto* init = rel->rhs->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::BoolLiteral>());
-  ASSERT_TRUE(init->literal->As<ast::BoolLiteral>()->value);
+  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteral>());
+  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteral>()->value);
 }
 
 TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) {
diff --git a/src/reader/wgsl/parser_impl_singular_expression_test.cc b/src/reader/wgsl/parser_impl_singular_expression_test.cc
index 50afbb0..10c0e13 100644
--- a/src/reader/wgsl/parser_impl_singular_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_singular_expression_test.cc
@@ -34,11 +34,8 @@
   auto* ident = ary->array->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(ary->index->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(ary->index->Is<ast::ScalarConstructorExpression>());
-  auto* c = ary->index->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(c->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(c->literal->As<ast::SintLiteral>()->value, 1);
+  ASSERT_TRUE(ary->index->Is<ast::SintLiteral>());
+  EXPECT_EQ(ary->index->As<ast::SintLiteral>()->value, 1);
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_ExpressionIndex) {
@@ -119,7 +116,7 @@
   EXPECT_EQ(c->func->symbol, p->builder().Symbols().Get("test"));
 
   EXPECT_EQ(c->args.size(), 3u);
-  EXPECT_TRUE(c->args[0]->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteral>());
   EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
   EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
 }
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index 2035359..957ab07 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -455,9 +455,7 @@
   EXPECT_EQ(a->decorations.size(), 0u);
   EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
 
-  auto* count_expr = a->count->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  auto* size = count_expr->literal->As<ast::SintLiteral>();
+  auto* size = a->count->As<ast::SintLiteral>();
   ASSERT_NE(size, nullptr);
   EXPECT_EQ(size->ValueAsI32(), 5);
 }
@@ -477,9 +475,7 @@
   EXPECT_EQ(a->decorations.size(), 0u);
   EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
 
-  auto* count_expr = a->count->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  auto* size = count_expr->literal->As<ast::UintLiteral>();
+  auto* size = a->count->As<ast::UintLiteral>();
   ASSERT_NE(size, nullptr);
   EXPECT_EQ(size->ValueAsU32(), 5u);
 }
@@ -517,9 +513,7 @@
   ASSERT_FALSE(a->IsRuntimeArray());
   ASSERT_TRUE(a->type->Is<ast::F32>());
 
-  auto* count_expr = a->count->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  auto* size = count_expr->literal->As<ast::SintLiteral>();
+  auto* size = a->count->As<ast::SintLiteral>();
   ASSERT_NE(size, nullptr);
   EXPECT_EQ(size->ValueAsI32(), 5);
 
diff --git a/src/reader/wgsl/parser_impl_unary_expression_test.cc b/src/reader/wgsl/parser_impl_unary_expression_test.cc
index 4627366..177a97a 100644
--- a/src/reader/wgsl/parser_impl_unary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_unary_expression_test.cc
@@ -34,11 +34,8 @@
   auto* ident = ary->array->As<ast::IdentifierExpression>();
   EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(ary->index->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(ary->index->Is<ast::ScalarConstructorExpression>());
-  auto* init = ary->index->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  ASSERT_EQ(init->literal->As<ast::SintLiteral>()->value, 2);
+  ASSERT_TRUE(ary->index->Is<ast::SintLiteral>());
+  ASSERT_EQ(ary->index->As<ast::SintLiteral>()->value, 2);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Minus) {
@@ -53,12 +50,8 @@
   auto* u = e->As<ast::UnaryOpExpression>();
   ASSERT_EQ(u->op, ast::UnaryOp::kNegation);
 
-  ASSERT_TRUE(u->expr->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(u->expr->Is<ast::ScalarConstructorExpression>());
-
-  auto* init = u->expr->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 1);
+  ASSERT_TRUE(u->expr->Is<ast::SintLiteral>());
+  EXPECT_EQ(u->expr->As<ast::SintLiteral>()->value, 1);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_AddressOf) {
@@ -139,12 +132,8 @@
   auto* u = e->As<ast::UnaryOpExpression>();
   ASSERT_EQ(u->op, ast::UnaryOp::kNot);
 
-  ASSERT_TRUE(u->expr->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(u->expr->Is<ast::ScalarConstructorExpression>());
-
-  auto* init = u->expr->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 1);
+  ASSERT_TRUE(u->expr->Is<ast::SintLiteral>());
+  EXPECT_EQ(u->expr->As<ast::SintLiteral>()->value, 1);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
@@ -169,12 +158,8 @@
   auto* u = e->As<ast::UnaryOpExpression>();
   ASSERT_EQ(u->op, ast::UnaryOp::kComplement);
 
-  ASSERT_TRUE(u->expr->Is<ast::ConstructorExpression>());
-  ASSERT_TRUE(u->expr->Is<ast::ScalarConstructorExpression>());
-
-  auto* init = u->expr->As<ast::ScalarConstructorExpression>();
-  ASSERT_TRUE(init->literal->Is<ast::SintLiteral>());
-  EXPECT_EQ(init->literal->As<ast::SintLiteral>()->value, 1);
+  ASSERT_TRUE(u->expr->Is<ast::SintLiteral>());
+  EXPECT_EQ(u->expr->As<ast::SintLiteral>()->value, 1);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_PrefixPlusPlus) {
diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
index d9ec4ad..39e5e62 100644
--- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -55,7 +55,7 @@
   ASSERT_EQ(e->source.range.end.column, 6u);
 
   ASSERT_NE(e->variable->constructor, nullptr);
-  EXPECT_TRUE(e->variable->constructor->Is<ast::ConstructorExpression>());
+  EXPECT_TRUE(e->variable->constructor->Is<ast::Literal>());
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) {
diff --git a/src/resolver/function_validation_test.cc b/src/resolver/function_validation_test.cc
index ec44227..825b9ca 100644
--- a/src/resolver/function_validation_test.cc
+++ b/src/resolver/function_validation_test.cc
@@ -89,8 +89,7 @@
   // fn func { var a:i32 = 2; }
   auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
 
-  Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
-       ty.void_(),
+  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
        ast::StatementList{
            Decl(var),
        });
@@ -103,11 +102,11 @@
   // var foo:f32 = 3.14;
   // fn foo() -> void {}
 
-  auto* global_var = Var(Source{Source::Location{56, 78}}, "foo", ty.f32(),
+  auto* global_var = Var(Source{{56, 78}}, "foo", ty.f32(),
                          ast::StorageClass::kPrivate, Expr(3.14f));
   AST().AddGlobalVariable(global_var);
 
-  Func(Source{Source::Location{12, 34}}, "foo", ast::VariableList{}, ty.void_(),
+  Func(Source{{12, 34}}, "foo", ast::VariableList{}, ty.void_(),
        ast::StatementList{}, ast::DecorationList{});
 
   EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -121,9 +120,9 @@
   // fn foo() -> void {}
   // var<private> foo:f32 = 3.14;
 
-  Func(Source{Source::Location{12, 34}}, "foo", ast::VariableList{}, ty.void_(),
+  Func(Source{{12, 34}}, "foo", ast::VariableList{}, ty.void_(),
        ast::StatementList{}, ast::DecorationList{});
-  auto* global_var = Var(Source{Source::Location{56, 78}}, "foo", ty.f32(),
+  auto* global_var = Var(Source{{56, 78}}, "foo", ty.f32(),
                          ast::StorageClass::kPrivate, Expr(3.14f));
   AST().AddGlobalVariable(global_var);
 
@@ -143,7 +142,7 @@
   Func("func", ast::VariableList{}, ty.i32(),
        ast::StatementList{
            Decl(var),
-           Return(Source{Source::Location{12, 34}}, Expr("func")),
+           Return(Source{{12, 34}}, Expr("func")),
        },
        ast::DecorationList{});
 
@@ -162,7 +161,7 @@
        },
        ast::DecorationList{});
 
-  Func(Source{Source::Location{12, 34}}, "b", ast::VariableList{}, ty.i32(),
+  Func(Source{{12, 34}}, "b", ast::VariableList{}, ty.i32(),
        ast::StatementList{
            Return(2),
        },
@@ -244,7 +243,7 @@
 
   auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
 
-  Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{}, ty.i32(),
+  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
        ast::StatementList{
            Decl(var),
        },
@@ -259,8 +258,8 @@
        VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
   // fn func {}
 
-  Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
-       ty.void_(), ast::StatementList{});
+  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
+       ast::StatementList{});
 
   EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -269,7 +268,7 @@
        FunctionEndWithoutReturnStatementEmptyBody_Fail) {
   // fn func() -> int {}
 
-  Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{}, ty.i32(),
+  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
        ast::StatementList{}, ast::DecorationList{});
 
   EXPECT_FALSE(r()->Resolve());
@@ -294,7 +293,7 @@
   // fn func { return 2; }
   Func("func", ast::VariableList{}, ty.void_(),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, Expr(2)),
+           Return(Source{{12, 34}}, Expr(2)),
        },
        ast::DecorationList{});
 
@@ -311,7 +310,7 @@
   Func("v", {}, ty.void_(), {Return()});
   Func("func", {}, ty.void_(),
        {
-           Return(Call(Source{Source::Location{12, 34}}, "v")),
+           Return(Call(Source{{12, 34}}, "v")),
        });
 
   EXPECT_FALSE(r()->Resolve());
@@ -323,7 +322,7 @@
   // fn func() -> f32 { return; }
   Func("func", ast::VariableList{}, ty.f32(),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, nullptr),
+           Return(Source{{12, 34}}, nullptr),
        },
        ast::DecorationList{});
 
@@ -338,7 +337,7 @@
   // fn func() -> f32 { return 2.0; }
   Func("func", ast::VariableList{}, ty.f32(),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, Expr(2.f)),
+           Return(Source{{12, 34}}, Expr(2.f)),
        },
        ast::DecorationList{});
 
@@ -350,7 +349,7 @@
   // fn func() -> f32 { return 2; }
   Func("func", ast::VariableList{}, ty.f32(),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, Expr(2)),
+           Return(Source{{12, 34}}, Expr(2)),
        },
        ast::DecorationList{});
 
@@ -367,7 +366,7 @@
   auto* myf32 = Alias("myf32", ty.f32());
   Func("func", ast::VariableList{}, ty.Of(myf32),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, Expr(2.f)),
+           Return(Source{{12, 34}}, Expr(2.f)),
        },
        ast::DecorationList{});
 
@@ -381,7 +380,7 @@
   auto* myf32 = Alias("myf32", ty.f32());
   Func("func", ast::VariableList{}, ty.Of(myf32),
        ast::StatementList{
-           Return(Source{Source::Location{12, 34}}, Expr(2u)),
+           Return(Source{{12, 34}}, Expr(2u)),
        },
        ast::DecorationList{});
 
@@ -413,8 +412,7 @@
   // [[stage(fragment)]]
   // [[stage(vertex)]]
   // fn main() { return; }
-  Func(Source{Source::Location{12, 34}}, "main", ast::VariableList{},
-       ty.void_(),
+  Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
        ast::StatementList{
            Return(),
        },
@@ -537,7 +535,7 @@
   GlobalConst("x", ty.u32(), Expr(64u));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(1), Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(1), Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -554,7 +552,7 @@
   GlobalConst("y", ty.i32(), Expr(32));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr("x"), Expr(Source{Source::Location{12, 34}}, "y"))});
+        WorkgroupSize(Expr("x"), Expr(Source{{12, 34}}, "y"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -570,8 +568,7 @@
   GlobalConst("y", ty.u32(), Expr(8u));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr("x"), Expr("y"),
-                      Expr(Source{Source::Location{12, 34}}, 16))});
+        WorkgroupSize(Expr("x"), Expr("y"), Expr(Source{{12, 34}}, 16))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -585,8 +582,7 @@
 
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(create<ast::ScalarConstructorExpression>(
-            Source{Source::Location{12, 34}}, Literal(64.f)))});
+        WorkgroupSize(Literal(Source{{12, 34}}, 64.f))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -600,8 +596,7 @@
 
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(create<ast::ScalarConstructorExpression>(
-            Source{Source::Location{12, 34}}, Literal(-2)))});
+        WorkgroupSize(Literal(Source{{12, 34}}, -2))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -614,8 +609,7 @@
 
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(create<ast::ScalarConstructorExpression>(
-            Source{Source::Location{12, 34}}, Literal(0)))});
+        WorkgroupSize(Literal(Source{{12, 34}}, 0))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -629,7 +623,7 @@
   GlobalConst("x", ty.f32(), Expr(64.f));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -644,7 +638,7 @@
   GlobalConst("x", ty.i32(), Expr(-2));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -658,7 +652,7 @@
   GlobalConst("x", ty.i32(), Expr(0));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -674,7 +668,7 @@
               Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32()))));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -688,7 +682,7 @@
   Global("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64));
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{Source::Location{12, 34}}, "x"))});
+        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -701,8 +695,7 @@
   // fn main() {}
   Func("main", {}, ty.void_(), {},
        {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(
-            Construct(Source{Source::Location{12, 34}}, ty.i32(), 1))});
+        WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1))});
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 7808b8f..9dea45f 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2015,7 +2015,7 @@
         ws[i].value = 0;
         continue;
       }
-    } else if (!expr->Is<ast::ScalarConstructorExpression>()) {
+    } else if (!expr->Is<ast::Literal>()) {
       AddError(
           "workgroup_size argument must be either a literal or a "
           "module-scope constant",
@@ -2366,6 +2366,8 @@
       sem_expr = Constructor(ctor);
     } else if (auto* ident = expr->As<ast::IdentifierExpression>()) {
       sem_expr = Identifier(ident);
+    } else if (auto* literal = expr->As<ast::Literal>()) {
+      sem_expr = Literal(literal);
     } else if (auto* member = expr->As<ast::MemberAccessorExpression>()) {
       sem_expr = MemberAccessor(member);
     } else if (auto* unary = expr->As<ast::UnaryOpExpression>()) {
@@ -2421,8 +2423,7 @@
     if (!parent_raw_ty->Is<sem::Reference>()) {
       // TODO(bclayton): expand this to allow any const_expr expression
       // https://github.com/gpuweb/gpuweb/issues/1272
-      auto* scalar = idx->As<ast::ScalarConstructorExpression>();
-      if (!scalar || !scalar->literal->As<ast::IntLiteral>()) {
+      if (!idx->As<ast::IntLiteral>()) {
         AddError("index must be signed or unsigned integer literal",
                  idx->source);
         return nullptr;
@@ -2615,8 +2616,7 @@
       bool is_const_expr = true;
       ast::TraverseExpressions(
           arg->Declaration(), diagnostics_, [&](const ast::Expression* e) {
-            if (e->IsAnyOf<ast::ScalarConstructorExpression,
-                           ast::TypeConstructorExpression>()) {
+            if (e->IsAnyOf<ast::Literal, ast::TypeConstructorExpression>()) {
               return ast::TraverseAction::Descend;
             }
             is_const_expr = false;
@@ -2763,21 +2763,21 @@
     return builder_->create<sem::Expression>(expr, ty, current_statement_, val);
   }
 
-  if (auto* scalar_ctor = expr->As<ast::ScalarConstructorExpression>()) {
-    Mark(scalar_ctor->literal);
-    auto* ty = TypeOf(scalar_ctor->literal);
-    if (!ty) {
-      return nullptr;
-    }
-
-    auto val = EvaluateConstantValue(expr, ty);
-    return builder_->create<sem::Expression>(expr, ty, current_statement_, val);
-  }
-
   TINT_ICE(Resolver, diagnostics_) << "unexpected constructor expression type";
   return nullptr;
 }
 
+sem::Expression* Resolver::Literal(const ast::Literal* literal) {
+  auto* ty = TypeOf(literal);
+  if (!ty) {
+    return nullptr;
+  }
+
+  auto val = EvaluateConstantValue(literal, ty);
+  return builder_->create<sem::Expression>(literal, ty, current_statement_,
+                                           val);
+}
+
 bool Resolver::ValidateStructureConstructor(
     const ast::TypeConstructorExpression* ctor,
     const sem::Struct* struct_type) {
@@ -3783,7 +3783,7 @@
       }
 
       count_expr = var->Declaration()->constructor;
-    } else if (!count_expr->Is<ast::ScalarConstructorExpression>()) {
+    } else if (!count_expr->Is<ast::Literal>()) {
       AddError(
           "array size expression must be either a literal or a module-scope "
           "constant",
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index 5730a55..b75532e 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -177,6 +177,7 @@
   sem::Call* FunctionCall(const ast::CallExpression*);
   sem::Expression* Identifier(const ast::IdentifierExpression*);
   sem::Call* IntrinsicCall(const ast::CallExpression*, sem::IntrinsicType);
+  sem::Expression* Literal(const ast::Literal*);
   sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
   sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
 
@@ -375,9 +376,8 @@
 
   sem::Constant EvaluateConstantValue(const ast::Expression* expr,
                                       const sem::Type* type);
-  sem::Constant EvaluateConstantValue(
-      const ast::ScalarConstructorExpression* scalar_ctor,
-      const sem::Type* type);
+  sem::Constant EvaluateConstantValue(const ast::Literal* literal,
+                                      const sem::Type* type);
   sem::Constant EvaluateConstantValue(
       const ast::TypeConstructorExpression* type_ctor,
       const sem::Type* type);
diff --git a/src/resolver/resolver_constants.cc b/src/resolver/resolver_constants.cc
index fb59ff3..5541d64 100644
--- a/src/resolver/resolver_constants.cc
+++ b/src/resolver/resolver_constants.cc
@@ -29,7 +29,7 @@
 
 sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr,
                                               const sem::Type* type) {
-  if (auto* e = expr->As<ast::ScalarConstructorExpression>()) {
+  if (auto* e = expr->As<ast::Literal>()) {
     return EvaluateConstantValue(e, type);
   }
   if (auto* e = expr->As<ast::TypeConstructorExpression>()) {
@@ -38,10 +38,8 @@
   return {};
 }
 
-sem::Constant Resolver::EvaluateConstantValue(
-    const ast::ScalarConstructorExpression* scalar_ctor,
-    const sem::Type* type) {
-  auto* literal = scalar_ctor->literal;
+sem::Constant Resolver::EvaluateConstantValue(const ast::Literal* literal,
+                                              const sem::Type* type) {
   if (auto* lit = literal->As<ast::SintLiteral>()) {
     return {type, {lit->ValueAsI32()}};
   }
diff --git a/src/resolver/type_constructor_validation_test.cc b/src/resolver/type_constructor_validation_test.cc
index c369f0b..764d2ed 100644
--- a/src/resolver/type_constructor_validation_test.cc
+++ b/src/resolver/type_constructor_validation_test.cc
@@ -424,10 +424,7 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_type_match) {
   // array<u32, 3>(0u, 10u. 20u);
-  auto* tc =
-      array<u32, 3>(create<ast::ScalarConstructorExpression>(Literal(0u)),
-                    create<ast::ScalarConstructorExpression>(Literal(10u)),
-                    create<ast::ScalarConstructorExpression>(Literal(20u)));
+  auto* tc = array<u32, 3>(Literal(0u), Literal(10u), Literal(20u));
   WrapInFunction(tc);
 
   EXPECT_TRUE(r()->Resolve());
@@ -436,10 +433,8 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_type_Mismatch_U32F32) {
   // array<u32, 3>(0u, 1.0f, 20u);
-  auto* tc = array<u32, 3>(
-      create<ast::ScalarConstructorExpression>(Literal(0u)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Literal(20u)));
+  auto* tc =
+      array<u32, 3>(Literal(0u), Literal(Source{{12, 34}}, 1.0f), Literal(20u));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -451,8 +446,7 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_F32I32) {
   // array<f32, 1>(1);
-  auto* tc = array<f32, 1>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)));
+  auto* tc = array<f32, 1>(Literal(Source{{12, 34}}, 1));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -464,12 +458,8 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_U32I32) {
   // array<u32, 6>(1, 0u, 0u, 0u, 0u, 0u);
-  auto* tc = array<u32, 1>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      create<ast::ScalarConstructorExpression>(Literal(0u)),
-      create<ast::ScalarConstructorExpression>(Literal(0u)),
-      create<ast::ScalarConstructorExpression>(Literal(0u)),
-      create<ast::ScalarConstructorExpression>(Literal(0u)));
+  auto* tc = array<u32, 1>(Literal(Source{{12, 34}}, 1), Literal(0u),
+                           Literal(0u), Literal(0u), Literal(0u));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -481,7 +471,7 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_Vec2) {
   // array<i32, 3>(1, vec2<i32>());
-  auto* tc = array<i32, 3>(create<ast::ScalarConstructorExpression>(Literal(1)),
+  auto* tc = array<i32, 3>(Literal(1),
                            create<ast::TypeConstructorExpression>(
                                Source{{12, 34}}, ty.vec2<i32>(), ExprList()));
   WrapInFunction(tc);
@@ -555,10 +545,7 @@
        Expr_Constructor_Array_TooFewElements) {
   // array<i32, 4>(1, 2, 3);
   SetSource(Source::Location({12, 34}));
-  auto* tc =
-      array<i32, 4>(create<ast::ScalarConstructorExpression>(Literal(1)),
-                    create<ast::ScalarConstructorExpression>(Literal(2)),
-                    create<ast::ScalarConstructorExpression>(Literal(3)));
+  auto* tc = array<i32, 4>(Literal(1), Literal(2), Literal(3));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -572,11 +559,7 @@
   // array<i32, 4>(1, 2, 3, 4, 5);
   SetSource(Source::Location({12, 34}));
   auto* tc =
-      array<i32, 4>(create<ast::ScalarConstructorExpression>(Literal(1)),
-                    create<ast::ScalarConstructorExpression>(Literal(2)),
-                    create<ast::ScalarConstructorExpression>(Literal(3)),
-                    create<ast::ScalarConstructorExpression>(Literal(4)),
-                    create<ast::ScalarConstructorExpression>(Literal(5)));
+      array<i32, 4>(Literal(1), Literal(2), Literal(3), Literal(4), Literal(5));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -588,9 +571,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_Runtime) {
   // array<i32>(1);
-  auto* tc = array(
-      ty.i32(), nullptr,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)));
+  auto* tc = array(ty.i32(), nullptr, Literal(Source{{12, 34}}, 1));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -613,9 +594,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      1.0f);
+  auto* tc = vec2<f32>(Literal(Source{{12, 34}}, 1), 1.0f);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -626,8 +605,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<u32>(1u, create<ast::ScalarConstructorExpression>(
-                               Source{{12, 34}}, Literal(1)));
+  auto* tc = vec2<u32>(1u, Literal(Source{{12, 34}}, 1));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -638,9 +616,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<i32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1u)),
-      1);
+  auto* tc = vec2<i32>(Literal(Source{{12, 34}}, 1u), 1);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -651,8 +627,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<bool>(true, create<ast::ScalarConstructorExpression>(
-                                  Source{{12, 34}}, Literal(1)));
+  auto* tc = vec2<bool>(true, Literal(Source{{12, 34}}, 1));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -687,11 +662,9 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) {
-  auto* tc = vec2<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}},
-                                               Literal(1.0f)));
+  auto* tc = vec2<f32>(Literal(Source{{12, 34}}, 1.0f),
+                       Literal(Source{{12, 40}}, 1.0f),
+                       Literal(Source{{12, 46}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -718,8 +691,7 @@
        Expr_Constructor_Vec2_Error_TooManyArgumentsVectorAndScalar) {
   auto* tc = vec2<f32>(create<ast::TypeConstructorExpression>(
                            Source{{12, 34}}, ty.vec2<f32>(), ExprList()),
-                       create<ast::ScalarConstructorExpression>(
-                           Source{{12, 40}}, Literal(1.0f)));
+                       Literal(Source{{12, 40}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -833,9 +805,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<f32>(
-      1.0f, 1.0f,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)));
+  auto* tc = vec3<f32>(1.0f, 1.0f, Literal(Source{{12, 34}}, 1));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -846,10 +816,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<u32>(
-      1u,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      1u);
+  auto* tc = vec3<u32>(1u, Literal(Source{{12, 34}}, 1), 1u);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -860,10 +827,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<i32>(
-      1,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1u)),
-      1);
+  auto* tc = vec3<i32>(1, Literal(Source{{12, 34}}, 1u), 1);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -874,10 +838,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<bool>(
-      true,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      false);
+  auto* tc = vec3<bool>(true, Literal(Source{{12, 34}}, 1), false);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -900,10 +861,8 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3_Error_TooFewArgumentsScalar) {
-  auto* tc = vec3<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}},
-                                               Literal(1.0f)));
+  auto* tc = vec3<f32>(Literal(Source{{12, 34}}, 1.0f),
+                       Literal(Source{{12, 40}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -915,11 +874,8 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3_Error_TooManyArgumentsScalar) {
   auto* tc = vec3<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 52}},
-                                               Literal(1.0f)));
+      Literal(Source{{12, 34}}, 1.0f), Literal(Source{{12, 40}}, 1.0f),
+      Literal(Source{{12, 46}}, 1.0f), Literal(Source{{12, 52}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -956,12 +912,10 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3_Error_TooManyArgumentsVec2AndScalar) {
-  auto* tc = vec3<f32>(
-      create<ast::TypeConstructorExpression>(Source{{12, 34}}, ty.vec2<f32>(),
-                                             ExprList()),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}},
-                                               Literal(1.0f)));
+  auto* tc = vec3<f32>(create<ast::TypeConstructorExpression>(
+                           Source{{12, 34}}, ty.vec2<f32>(), ExprList()),
+                       Literal(Source{{12, 40}}, 1.0f),
+                       Literal(Source{{12, 46}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -974,8 +928,7 @@
        Expr_Constructor_Vec3_Error_TooManyArgumentsVec3) {
   auto* tc = vec3<f32>(create<ast::TypeConstructorExpression>(
                            Source{{12, 34}}, ty.vec3<f32>(), ExprList()),
-                       create<ast::ScalarConstructorExpression>(
-                           Source{{12, 40}}, Literal(1.0f)));
+                       Literal(Source{{12, 40}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1115,10 +1068,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<f32>(
-      1.0f, 1.0f,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      1.0f);
+  auto* tc = vec4<f32>(1.0f, 1.0f, Literal(Source{{12, 34}}, 1), 1.0f);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1129,10 +1079,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<u32>(
-      1u, 1u,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      1u);
+  auto* tc = vec4<u32>(1u, 1u, Literal(Source{{12, 34}}, 1), 1u);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1143,10 +1090,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<i32>(
-      1, 1,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1u)),
-      1);
+  auto* tc = vec4<i32>(1, 1, Literal(Source{{12, 34}}, 1u), 1);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1157,10 +1101,7 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<bool>(
-      true, false,
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1)),
-      true);
+  auto* tc = vec4<bool>(true, false, Literal(Source{{12, 34}}, 1), true);
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1171,11 +1112,9 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooFewArgumentsScalar) {
-  auto* tc = vec4<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}},
-                                               Literal(1.0f)));
+  auto* tc = vec4<f32>(Literal(Source{{12, 34}}, 1.0f),
+                       Literal(Source{{12, 40}}, 1.0f),
+                       Literal(Source{{12, 46}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1187,12 +1126,9 @@
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsScalar) {
   auto* tc = vec4<f32>(
-      create<ast::ScalarConstructorExpression>(Source{{12, 34}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 52}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 58}},
-                                               Literal(1.0f)));
+      Literal(Source{{12, 34}}, 1.0f), Literal(Source{{12, 40}}, 1.0f),
+      Literal(Source{{12, 46}}, 1.0f), Literal(Source{{12, 52}}, 1.0f),
+      Literal(Source{{12, 58}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1205,8 +1141,7 @@
        Expr_Constructor_Vec4_Error_TooFewArgumentsVec2AndScalar) {
   auto* tc = vec4<f32>(create<ast::TypeConstructorExpression>(
                            Source{{12, 34}}, ty.vec2<f32>(), ExprList()),
-                       create<ast::ScalarConstructorExpression>(
-                           Source{{12, 40}}, Literal(1.0f)));
+                       Literal(Source{{12, 40}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1217,13 +1152,11 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndScalars) {
-  auto* tc = vec4<f32>(
-      create<ast::TypeConstructorExpression>(Source{{12, 34}}, ty.vec2<f32>(),
-                                             ExprList()),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 52}},
-                                               Literal(1.0f)));
+  auto* tc = vec4<f32>(create<ast::TypeConstructorExpression>(
+                           Source{{12, 34}}, ty.vec2<f32>(), ExprList()),
+                       Literal(Source{{12, 40}}, 1.0f),
+                       Literal(Source{{12, 46}}, 1.0f),
+                       Literal(Source{{12, 52}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1238,8 +1171,7 @@
                            Source{{12, 34}}, ty.vec2<f32>(), ExprList()),
                        create<ast::TypeConstructorExpression>(
                            Source{{12, 40}}, ty.vec2<f32>(), ExprList()),
-                       create<ast::ScalarConstructorExpression>(
-                           Source{{12, 46}}, Literal(1.0f)));
+                       Literal(Source{{12, 46}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1278,12 +1210,10 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndScalars) {
-  auto* tc = vec4<f32>(
-      create<ast::TypeConstructorExpression>(Source{{12, 34}}, ty.vec3<f32>(),
-                                             ExprList()),
-      create<ast::ScalarConstructorExpression>(Source{{12, 40}}, Literal(1.0f)),
-      create<ast::ScalarConstructorExpression>(Source{{12, 46}},
-                                               Literal(1.0f)));
+  auto* tc = vec4<f32>(create<ast::TypeConstructorExpression>(
+                           Source{{12, 34}}, ty.vec3<f32>(), ExprList()),
+                       Literal(Source{{12, 40}}, 1.0f),
+                       Literal(Source{{12, 46}}, 1.0f));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1576,8 +1506,7 @@
   auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
   auto* tc = create<ast::TypeConstructorExpression>(
       Source{{12, 34}}, vec_type,
-      ExprList(1.0f, create<ast::ScalarConstructorExpression>(Source{{12, 40}},
-                                                              Literal(1u))));
+      ExprList(1.0f, Literal(Source{{12, 40}}, 1u)));
   WrapInFunction(tc);
 
   EXPECT_FALSE(r()->Resolve());
@@ -1767,8 +1696,7 @@
 
   ast::ExpressionList args;
   for (uint32_t i = 1; i <= param.columns; i++) {
-    args.push_back(
-        create<ast::ScalarConstructorExpression>(Source{{12, i}}, Literal(1u)));
+    args.push_back(Literal(Source{{12, i}}, 1u));
   }
 
   auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index bdad5fe..01f52d0 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -129,9 +129,7 @@
 TEST_F(ResolverValidationTest, Stmt_If_NonBool) {
   // if (1.23f) {}
 
-  WrapInFunction(If(create<ast::ScalarConstructorExpression>(Source{{12, 34}},
-                                                             Literal(1.23f)),
-                    Block()));
+  WrapInFunction(If(Literal(Source{{12, 34}}, 1.23f), Block()));
 
   EXPECT_FALSE(r()->Resolve());
 
@@ -142,10 +140,8 @@
 TEST_F(ResolverValidationTest, Stmt_Else_NonBool) {
   // else (1.23f) {}
 
-  WrapInFunction(If(Expr(true), Block(),
-                    Else(create<ast::ScalarConstructorExpression>(
-                             Source{{12, 34}}, Literal(1.23f)),
-                         Block())));
+  WrapInFunction(
+      If(Expr(true), Block(), Else(Literal(Source{{12, 34}}, 1.23f), Block())));
 
   EXPECT_FALSE(r()->Resolve());
 
diff --git a/src/transform/decompose_memory_access.cc b/src/transform/decompose_memory_access.cc
index a524ee4..32ff132 100644
--- a/src/transform/decompose_memory_access.cc
+++ b/src/transform/decompose_memory_access.cc
@@ -23,7 +23,6 @@
 #include "src/ast/assignment_statement.h"
 #include "src/ast/call_statement.h"
 #include "src/ast/disable_validation_decoration.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type_name.h"
 #include "src/ast/unary_op.h"
 #include "src/block_allocator.h"
@@ -331,13 +330,11 @@
   /// @param expr the expression to convert to an Offset
   /// @returns an Offset for the given ast::Expression
   const Offset* ToOffset(const ast::Expression* expr) {
-    if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-      if (auto* u32 = scalar->literal->As<ast::UintLiteral>()) {
-        return offsets_.Create<OffsetLiteral>(u32->value);
-      } else if (auto* i32 = scalar->literal->As<ast::SintLiteral>()) {
-        if (i32->value > 0) {
-          return offsets_.Create<OffsetLiteral>(i32->value);
-        }
+    if (auto* u32 = expr->As<ast::UintLiteral>()) {
+      return offsets_.Create<OffsetLiteral>(u32->value);
+    } else if (auto* i32 = expr->As<ast::SintLiteral>()) {
+      if (i32->value > 0) {
+        return offsets_.Create<OffsetLiteral>(i32->value);
       }
     }
     return offsets_.Create<OffsetExpr>(expr);
diff --git a/src/transform/fold_constants.cc b/src/transform/fold_constants.cc
index 271a930..773136f 100644
--- a/src/transform/fold_constants.cc
+++ b/src/transform/fold_constants.cc
@@ -81,7 +81,8 @@
     }
 
     if (ty->is_scalar()) {
-      return value.WithScalarAt(0, [&](auto&& s) { return ctx.dst->Expr(s); });
+      return value.WithScalarAt(
+          0, [&](auto&& s) -> const ast::Literal* { return ctx.dst->Expr(s); });
     }
 
     return nullptr;
diff --git a/src/transform/fold_trivial_single_use_lets.cc b/src/transform/fold_trivial_single_use_lets.cc
index 0427075..c83008c 100644
--- a/src/transform/fold_trivial_single_use_lets.cc
+++ b/src/transform/fold_trivial_single_use_lets.cc
@@ -37,8 +37,7 @@
     return nullptr;
   }
   auto* ctor = var->constructor;
-  if (!IsAnyOf<ast::IdentifierExpression, ast::ScalarConstructorExpression>(
-          ctor)) {
+  if (!IsAnyOf<ast::IdentifierExpression, ast::Literal>(ctor)) {
     return nullptr;
   }
   return var_decl;
diff --git a/src/transform/inline_pointer_lets.cc b/src/transform/inline_pointer_lets.cc
index 196c0d5..ea61615 100644
--- a/src/transform/inline_pointer_lets.cc
+++ b/src/transform/inline_pointer_lets.cc
@@ -46,7 +46,7 @@
   if (auto* a = expr->As<ast::ArrayAccessorExpression>()) {
     CollectSavedArrayIndices(program, a->array, cb);
 
-    if (!a->index->Is<ast::ScalarConstructorExpression>()) {
+    if (!a->index->Is<ast::Literal>()) {
       cb(a->index);
     }
     return;
diff --git a/src/transform/robustness.cc b/src/transform/robustness.cc
index 28cd0f9..b4465a3 100644
--- a/src/transform/robustness.cc
+++ b/src/transform/robustness.cc
@@ -189,7 +189,9 @@
 
     // Convert idx to an expression, so we can emit the new accessor.
     if (!idx.expr) {
-      idx.expr = idx.is_signed ? b.Expr(idx.i32) : b.Expr(idx.u32);
+      idx.expr = idx.is_signed
+                     ? static_cast<const ast::Expression*>(b.Expr(idx.i32))
+                     : static_cast<const ast::Expression*>(b.Expr(idx.u32));
     }
 
     // Clone arguments outside of create() call to have deterministic ordering
diff --git a/src/transform/transform_test.cc b/src/transform/transform_test.cc
index 001e54a..981f7d2 100644
--- a/src/transform/transform_test.cc
+++ b/src/transform/transform_test.cc
@@ -84,10 +84,7 @@
   ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
   ASSERT_EQ(arr->As<ast::Array>()->decorations.size(), 0u);
 
-  auto* count_expr =
-      arr->As<ast::Array>()->count->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  auto* size = count_expr->literal->As<ast::IntLiteral>();
+  auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteral>();
   ASSERT_NE(size, nullptr);
   EXPECT_EQ(size->ValueAsI32(), 2);
 }
@@ -107,10 +104,7 @@
                 ->stride,
             64u);
 
-  auto* count_expr =
-      arr->As<ast::Array>()->count->As<ast::ScalarConstructorExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  auto* size = count_expr->literal->As<ast::IntLiteral>();
+  auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteral>();
   ASSERT_NE(size, nullptr);
   EXPECT_EQ(size->ValueAsI32(), 2);
 }
diff --git a/src/writer/append_vector.cc b/src/writer/append_vector.cc
index 18ea614..9520cc9 100644
--- a/src/writer/append_vector.cc
+++ b/src/writer/append_vector.cc
@@ -85,7 +85,7 @@
     const auto num_supplied = vc->values.size();
     if (num_supplied == 0) {
       // Zero-value vector constructor. Populate with zeros
-      auto buildZero = [&]() -> const ast::ScalarConstructorExpression* {
+      auto buildZero = [&]() -> const ast::Literal* {
         if (packed_el_sem_ty->Is<sem::I32>()) {
           return b->Expr(0);
         } else if (packed_el_sem_ty->Is<sem::U32>()) {
diff --git a/src/writer/append_vector_test.cc b/src/writer/append_vector_test.cc
index 39d837c..26de490 100644
--- a/src/writer/append_vector_test.cc
+++ b/src/writer/append_vector_test.cc
@@ -249,9 +249,7 @@
   ASSERT_NE(vec_0004, nullptr);
   ASSERT_EQ(vec_0004->values.size(), 4u);
   for (size_t i = 0; i < 3; i++) {
-    auto* ctor = vec_0004->values[i]->As<ast::ScalarConstructorExpression>();
-    ASSERT_NE(ctor, nullptr);
-    auto* literal = As<ast::SintLiteral>(ctor->literal);
+    auto* literal = As<ast::SintLiteral>(vec_0004->values[i]);
     ASSERT_NE(literal, nullptr);
     EXPECT_EQ(literal->value, 0);
   }
diff --git a/src/writer/glsl/generator_impl.cc b/src/writer/glsl/generator_impl.cc
index 6e78944..16cbf30 100644
--- a/src/writer/glsl/generator_impl.cc
+++ b/src/writer/glsl/generator_impl.cc
@@ -1387,18 +1387,9 @@
 
 bool GeneratorImpl::EmitConstructor(std::ostream& out,
                                     const ast::ConstructorExpression* expr) {
-  if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    return EmitScalarConstructor(out, scalar);
-  }
   return EmitTypeConstructor(out, expr->As<ast::TypeConstructorExpression>());
 }
 
-bool GeneratorImpl::EmitScalarConstructor(
-    std::ostream& out,
-    const ast::ScalarConstructorExpression* expr) {
-  return EmitLiteral(out, expr->literal);
-}
-
 bool GeneratorImpl::EmitTypeConstructor(
     std::ostream& out,
     const ast::TypeConstructorExpression* expr) {
@@ -1486,6 +1477,9 @@
   if (auto* i = expr->As<ast::IdentifierExpression>()) {
     return EmitIdentifier(out, i);
   }
+  if (auto* l = expr->As<ast::Literal>()) {
+    return EmitLiteral(out, l);
+  }
   if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
     return EmitMemberAccessor(out, m);
   }
diff --git a/src/writer/glsl/generator_impl.h b/src/writer/glsl/generator_impl.h
index 7539da5..9258cae 100644
--- a/src/writer/glsl/generator_impl.h
+++ b/src/writer/glsl/generator_impl.h
@@ -198,12 +198,6 @@
   /// @param stmt the discard statement
   /// @returns true if the statement was successfully emitted
   bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles generating a scalar constructor
-  /// @param out the output of the expression stream
-  /// @param expr the scalar constructor expression
-  /// @returns true if the scalar constructor is emitted
-  bool EmitScalarConstructor(std::ostream& out,
-                             const ast::ScalarConstructorExpression* expr);
   /// Handles emitting a type constructor
   /// @param out the output of the expression stream
   /// @param expr the type constructor expression
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 2730c39..f01ce15 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -2114,18 +2114,9 @@
 
 bool GeneratorImpl::EmitConstructor(std::ostream& out,
                                     const ast::ConstructorExpression* expr) {
-  if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    return EmitScalarConstructor(out, scalar);
-  }
   return EmitTypeConstructor(out, expr->As<ast::TypeConstructorExpression>());
 }
 
-bool GeneratorImpl::EmitScalarConstructor(
-    std::ostream& out,
-    const ast::ScalarConstructorExpression* expr) {
-  return EmitLiteral(out, expr->literal);
-}
-
 bool GeneratorImpl::EmitTypeConstructor(
     std::ostream& out,
     const ast::TypeConstructorExpression* expr) {
@@ -2218,6 +2209,9 @@
   if (auto* i = expr->As<ast::IdentifierExpression>()) {
     return EmitIdentifier(out, i);
   }
+  if (auto* l = expr->As<ast::Literal>()) {
+    return EmitLiteral(out, l);
+  }
   if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
     return EmitMemberAccessor(out, m);
   }
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index 61b895d..67a4da5 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -227,12 +227,6 @@
   /// @param stmt the discard statement
   /// @returns true if the statement was successfully emitted
   bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles generating a scalar constructor
-  /// @param out the output of the expression stream
-  /// @param expr the scalar constructor expression
-  /// @returns true if the scalar constructor is emitted
-  bool EmitScalarConstructor(std::ostream& out,
-                             const ast::ScalarConstructorExpression* expr);
   /// Handles emitting a type constructor
   /// @param out the output of the expression stream
   /// @param expr the type constructor expression
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 2d7ad03..3f73586 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -1293,9 +1293,6 @@
 
 bool GeneratorImpl::EmitConstructor(std::ostream& out,
                                     const ast::ConstructorExpression* expr) {
-  if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    return EmitScalarConstructor(out, scalar);
-  }
   return EmitTypeConstructor(out, expr->As<ast::TypeConstructorExpression>());
 }
 
@@ -1387,12 +1384,6 @@
   return true;
 }
 
-bool GeneratorImpl::EmitScalarConstructor(
-    std::ostream& out,
-    const ast::ScalarConstructorExpression* expr) {
-  return EmitLiteral(out, expr->literal);
-}
-
 bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::Literal* lit) {
   if (auto* l = lit->As<ast::BoolLiteral>()) {
     out << (l->value ? "true" : "false");
@@ -1445,6 +1436,9 @@
   if (auto* i = expr->As<ast::IdentifierExpression>()) {
     return EmitIdentifier(out, i);
   }
+  if (auto* l = expr->As<ast::Literal>()) {
+    return EmitLiteral(out, l);
+  }
   if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
     return EmitMemberAccessor(out, m);
   }
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 5c68d31..5c59326 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -26,12 +26,12 @@
 #include "src/ast/break_statement.h"
 #include "src/ast/continue_statement.h"
 #include "src/ast/discard_statement.h"
+#include "src/ast/expression.h"
 #include "src/ast/if_statement.h"
 #include "src/ast/interpolate_decoration.h"
 #include "src/ast/loop_statement.h"
 #include "src/ast/member_accessor_expression.h"
 #include "src/ast/return_statement.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/switch_statement.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/unary_op_expression.h"
@@ -241,12 +241,6 @@
   /// @param stmt the statement to emit
   /// @returns true if the statement was successfully emitted
   bool EmitReturn(const ast::ReturnStatement* stmt);
-  /// Handles generating a scalar constructor
-  /// @param out the output of the expression stream
-  /// @param expr the scalar constructor expression
-  /// @returns true if the scalar constructor is emitted
-  bool EmitScalarConstructor(std::ostream& out,
-                             const ast::ScalarConstructorExpression* expr);
   /// Handles emitting a pipeline stage name
   /// @param out the output of the expression stream
   /// @param stage the stage to emit
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index d0340e9..a56e636 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -583,6 +583,9 @@
   if (auto* i = expr->As<ast::IdentifierExpression>()) {
     return GenerateIdentifierExpression(i);
   }
+  if (auto* l = expr->As<ast::Literal>()) {
+    return GenerateLiteralIfNeeded(nullptr, l);
+  }
   if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
     return GenerateAccessorExpression(m);
   }
@@ -757,13 +760,7 @@
 
   uint32_t init_id = 0;
   if (var->constructor) {
-    if (!var->constructor->Is<ast::ConstructorExpression>()) {
-      error_ = "scalar constructor expected";
-      return false;
-    }
-
-    init_id = GenerateConstructorExpression(
-        var, var->constructor->As<ast::ConstructorExpression>());
+    init_id = GenerateConstructorExpression(var, var->constructor);
     if (init_id == 0) {
       return false;
     }
@@ -931,14 +928,7 @@
   auto extract_id = extract.to_i();
 
   // If the index is a literal, we use OpCompositeExtract.
-  if (auto* scalar = expr->index->As<ast::ScalarConstructorExpression>()) {
-    auto* literal = scalar->literal->As<ast::IntLiteral>();
-    if (!literal) {
-      TINT_ICE(Writer, builder_.Diagnostics())
-          << "bad literal in array accessor";
-      return false;
-    }
-
+  if (auto* literal = expr->index->As<ast::IntLiteral>()) {
     if (!push_function_inst(spv::Op::OpCompositeExtract,
                             {Operand::Int(result_type_id), extract,
                              Operand::Int(info->source_id),
@@ -1264,11 +1254,10 @@
   return id;
 }
 
-uint32_t Builder::GenerateConstructorExpression(
-    const ast::Variable* var,
-    const ast::ConstructorExpression* expr) {
-  if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    return GenerateLiteralIfNeeded(var, scalar->literal);
+uint32_t Builder::GenerateConstructorExpression(const ast::Variable* var,
+                                                const ast::Expression* expr) {
+  if (auto* literal = expr->As<ast::Literal>()) {
+    return GenerateLiteralIfNeeded(var, literal);
   }
   if (auto* type = expr->As<ast::TypeConstructorExpression>()) {
     return GenerateTypeConstructorExpression(var, type);
@@ -1280,20 +1269,19 @@
 
 bool Builder::is_constructor_const(const ast::Expression* expr,
                                    bool is_global_init) {
-  auto* constructor = expr->As<ast::ConstructorExpression>();
-  if (constructor == nullptr) {
-    return false;
-  }
-  if (constructor->Is<ast::ScalarConstructorExpression>()) {
+  if (expr->Is<ast::Literal>()) {
     return true;
   }
 
-  auto* tc = constructor->As<ast::TypeConstructorExpression>();
+  auto* tc = expr->As<ast::TypeConstructorExpression>();
+  if (!tc) {
+    return false;
+  }
   auto* result_type = TypeOf(tc)->UnwrapRef();
   for (size_t i = 0; i < tc->values.size(); ++i) {
     auto* e = tc->values[i];
 
-    if (!e->Is<ast::ConstructorExpression>()) {
+    if (!e->IsAnyOf<ast::TypeConstructorExpression, ast::Literal>()) {
       if (is_global_init) {
         error_ = "constructor must be a constant expression";
         return false;
@@ -1307,13 +1295,13 @@
       return false;
     }
 
-    auto* sc = e->As<ast::ScalarConstructorExpression>();
-    if (result_type->Is<sem::Vector>() && sc == nullptr) {
+    auto* lit = e->As<ast::Literal>();
+    if (result_type->Is<sem::Vector>() && lit == nullptr) {
       return false;
     }
 
     // This should all be handled by |is_constructor_const| call above
-    if (sc == nullptr) {
+    if (lit == nullptr) {
       continue;
     }
 
@@ -1327,7 +1315,7 @@
     } else if (auto* str = subtype->As<sem::Struct>()) {
       subtype = str->Members()[i]->Type();
     }
-    if (subtype != TypeOf(sc)->UnwrapRef()) {
+    if (subtype != TypeOf(lit)->UnwrapRef()) {
       return false;
     }
   }
@@ -1409,8 +1397,7 @@
   for (auto* e : values) {
     uint32_t id = 0;
     if (constructor_is_const) {
-      id = GenerateConstructorExpression(nullptr,
-                                         e->As<ast::ConstructorExpression>());
+      id = GenerateConstructorExpression(nullptr, e);
     } else {
       id = GenerateExpression(e);
       id = GenerateLoadIfNeeded(TypeOf(e), id);
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 77d878f..4ceefa2 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -339,9 +339,8 @@
   /// @param var the variable generated for, nullptr if no variable associated.
   /// @param expr the expression to generate
   /// @returns the ID of the expression or 0 on failure.
-  uint32_t GenerateConstructorExpression(
-      const ast::Variable* var,
-      const ast::ConstructorExpression* expr);
+  uint32_t GenerateConstructorExpression(const ast::Variable* var,
+                                         const ast::Expression* expr);
   /// Generates a type constructor expression
   /// @param var the variable generated for, nullptr if no variable associated.
   /// @param init the expression to generate
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index c97669f..5d1a77e 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -131,6 +131,9 @@
   if (auto* i = expr->As<ast::IdentifierExpression>()) {
     return EmitIdentifier(out, i);
   }
+  if (auto* l = expr->As<ast::Literal>()) {
+    return EmitLiteral(out, l);
+  }
   if (auto* c = expr->As<ast::ConstructorExpression>()) {
     return EmitConstructor(out, c);
   }
@@ -242,9 +245,6 @@
 
 bool GeneratorImpl::EmitConstructor(std::ostream& out,
                                     const ast::ConstructorExpression* expr) {
-  if (auto* scalar = expr->As<ast::ScalarConstructorExpression>()) {
-    return EmitScalarConstructor(out, scalar);
-  }
   return EmitTypeConstructor(out, expr->As<ast::TypeConstructorExpression>());
 }
 
@@ -273,12 +273,6 @@
   return true;
 }
 
-bool GeneratorImpl::EmitScalarConstructor(
-    std::ostream& out,
-    const ast::ScalarConstructorExpression* expr) {
-  return EmitLiteral(out, expr->literal);
-}
-
 bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::Literal* lit) {
   if (auto* bl = lit->As<ast::BoolLiteral>()) {
     out << (bl->value ? "true" : "false");
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index c626d76..ca6a182 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -30,7 +30,6 @@
 #include "src/ast/loop_statement.h"
 #include "src/ast/member_accessor_expression.h"
 #include "src/ast/return_statement.h"
-#include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/switch_statement.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/unary_op_expression.h"
@@ -96,12 +95,11 @@
   /// @param stmt the statement
   /// @returns true if the statment was emitted successfully
   bool EmitCase(const ast::CaseStatement* stmt);
-  /// Handles generating a scalar constructor
+  /// Handles generating a literal expression
   /// @param out the output of the expression stream
-  /// @param expr the scalar constructor expression
-  /// @returns true if the scalar constructor is emitted
-  bool EmitScalarConstructor(std::ostream& out,
-                             const ast::ScalarConstructorExpression* expr);
+  /// @param expr the literal expression expression
+  /// @returns true if the literal expression is emitted
+  bool EmitLiteral(std::ostream& out, const ast::Literal* expr);
   /// Handles a continue statement
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted successfully
@@ -138,11 +136,6 @@
   /// @param stmt the discard statement
   /// @returns true if the statement was successfully emitted
   bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles a literal
-  /// @param out the output of the expression stream
-  /// @param lit the literal to emit
-  /// @returns true if the literal was successfully emitted
-  bool EmitLiteral(std::ostream& out, const ast::Literal* lit);
   /// Handles a loop statement
   /// @param stmt the statement to emit
   /// @returns true if the statement was emtited
diff --git a/src/writer/wgsl/generator_impl_literal_test.cc b/src/writer/wgsl/generator_impl_literal_test.cc
index e2244b1..0937fc8 100644
--- a/src/writer/wgsl/generator_impl_literal_test.cc
+++ b/src/writer/wgsl/generator_impl_literal_test.cc
@@ -59,7 +59,7 @@
   GeneratorImpl& gen = Build();
 
   std::stringstream out;
-  ASSERT_TRUE(gen.EmitScalarConstructor(out, v)) << gen.error();
+  ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
   EXPECT_EQ(out.str(), GetParam().expected);
 }
 
diff --git a/test/BUILD.gn b/test/BUILD.gn
index edd66b9..6c4b740 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -194,7 +194,6 @@
     "../src/ast/return_statement_test.cc",
     "../src/ast/sampled_texture_test.cc",
     "../src/ast/sampler_test.cc",
-    "../src/ast/scalar_constructor_expression_test.cc",
     "../src/ast/sint_literal_test.cc",
     "../src/ast/stage_decoration_test.cc",
     "../src/ast/storage_texture_test.cc",