wgsl: Deprecate 'const' for 'let'

Renamed with:
https://github.com/gpuweb/gpuweb/pull/1574

Bug: tint:699
Change-Id: I4dda868abe4c5bc0cba46bc81d9eb297a0663717
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/47141
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/module_clone_test.cc b/src/ast/module_clone_test.cc
index 9f741de..4c5dd1c 100644
--- a/src/ast/module_clone_test.cc
+++ b/src/ast/module_clone_test.cc
@@ -33,8 +33,8 @@
   m1 : array<u32>;
 };
 
-const c0 : i32 = 10;
-const c1 : bool = true;
+let c0 : i32 = 10;
+let c1 : bool = true;
 
 type t0 = [[stride(16)]] array<vec4<f32>>;
 type t1 = array<vec4<f32>>;
@@ -102,7 +102,7 @@
   f1(1.0, 2);
 }
 
-const declaration_order_check_0 : i32 = 1;
+let declaration_order_check_0 : i32 = 1;
 
 type declaration_order_check_1 = f32;
 
@@ -110,7 +110,7 @@
 
 type declaration_order_check_2 = f32;
 
-const declaration_order_check_3 : i32 = 1;
+let declaration_order_check_3 : i32 = 1;
 
 )");
 
diff --git a/src/ast/variable.h b/src/ast/variable.h
index 5f809e8..b8f50e2 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -46,9 +46,9 @@
 ///       var computed_depth : i32;
 ///       var area : i32 = compute_area(width, height);
 ///
-/// 2. A "const" declaration is a name for a typed value.  Examples:
+/// 2. A "let" declaration is a name for a typed value.  Examples:
 ///
-///       const twice_depth : i32 = width + width;  // Must have initializer
+///       let twice_depth : i32 = width + width;  // Must have initializer
 ///
 /// 3. A formal parameter to a function is a name for a typed value to
 ///    be passed into a function.  Example:
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 16012fe..d576935 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -4948,7 +4948,7 @@
   //
   //    var temp : type = src_vector;
   //    temp[index] = component;
-  //    const result : type = temp;
+  //    let result : type = temp;
   //
   // Then use result everywhere the original SPIR-V id is used.  Using a const
   // like this avoids constantly reloading the value many times.
@@ -4989,7 +4989,7 @@
   //
   //    var temp : type = composite;
   //    temp[index].x = object;
-  //    const result : type = temp;
+  //    let result : type = temp;
   //
   // Then use result everywhere the original SPIR-V id is used.  Using a const
   // like this avoids constantly reloading the value many times.
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index 4ce36f0..b224788 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -584,6 +584,8 @@
     return {Token::Type::kImport, source, "import"};
   if (str == "in")
     return {Token::Type::kIn, source, "in"};
+  if (str == "let")
+    return {Token::Type::kLet, source, "let"};
   if (str == "loop")
     return {Token::Type::kLoop, source, "loop"};
   if (str == "mat2x2")
@@ -709,8 +711,6 @@
     return {Token::Type::kReservedKeyword, source, "i16"};
   if (str == "i64")
     return {Token::Type::kReservedKeyword, source, "i64"};
-  if (str == "let")
-    return {Token::Type::kReservedKeyword, source, "let"};
   if (str == "premerge")
     return {Token::Type::kReservedKeyword, source, "premerge"};
   if (str == "regardless")
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index 1d80b29..bb2ba86 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -476,6 +476,7 @@
         TokenData{"image", Token::Type::kImage},
         TokenData{"import", Token::Type::kImport},
         TokenData{"in", Token::Type::kIn},
+        TokenData{"let", Token::Type::kLet},
         TokenData{"loop", Token::Type::kLoop},
         TokenData{"mat2x2", Token::Type::kMat2x2},
         TokenData{"mat2x3", Token::Type::kMat2x3},
@@ -547,7 +548,6 @@
                                          "i8",
                                          "i16",
                                          "i64",
-                                         "let",
                                          "premerge",
                                          "typedef",
                                          "u8",
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 6eda22c..79a7335 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -306,7 +306,7 @@
       return Failure::kErrored;
 
     if (gc.matched) {
-      if (!expect("constant declaration", Token::Type::kSemicolon))
+      if (!expect("let declaration", Token::Type::kSemicolon))
         return Failure::kErrored;
 
       builder_.AST().AddGlobalVariable(gc.value);
@@ -418,10 +418,17 @@
 //  : variable_decoration_list* CONST variable_ident_decl EQUAL const_expr
 Maybe<ast::Variable*> ParserImpl::global_constant_decl(
     ast::DecorationList& decos) {
-  if (!match(Token::Type::kConst))
-    return Failure::kNoMatch;
+  if (!match(Token::Type::kLet)) {
+    Source source;
+    if (match(Token::Type::kConst, &source)) {
+      // crbug.com/tint/699: 'const' renamed to 'let'
+      deprecated(source, "use 'let' instead of 'const'");
+    } else {
+      return Failure::kNoMatch;
+    }
+  }
 
-  const char* use = "constant declaration";
+  const char* use = "let declaration";
 
   auto decl = expect_variable_ident_decl(use);
   if (decl.errored)
@@ -1555,19 +1562,29 @@
 //   | variable_decl EQUAL logical_or_expression
 //   | CONST variable_ident_decl EQUAL logical_or_expression
 Maybe<ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
-  if (match(Token::Type::kConst)) {
-    auto decl = expect_variable_ident_decl("constant declaration");
+  bool is_const = match(Token::Type::kLet);
+  if (!is_const) {
+    Source source;
+    if (match(Token::Type::kConst, &source)) {
+      // crbug.com/tint/699: 'const' renamed to 'let'
+      deprecated(source, "use 'let' instead of 'const'");
+      is_const = true;
+    }
+  }
+
+  if (is_const) {
+    auto decl = expect_variable_ident_decl("let declaration");
     if (decl.errored)
       return Failure::kErrored;
 
-    if (!expect("constant declaration", Token::Type::kEqual))
+    if (!expect("let declaration", Token::Type::kEqual))
       return Failure::kErrored;
 
     auto constructor = logical_or_expression();
     if (constructor.errored)
       return Failure::kErrored;
     if (!constructor.matched)
-      return add_error(peek(), "missing constructor for const declaration");
+      return add_error(peek(), "missing constructor for let declaration");
 
     auto* var = create<ast::Variable>(
         decl->source,                             // source
@@ -2746,7 +2763,7 @@
   if (lit.errored)
     return Failure::kErrored;
   if (!lit.matched)
-    return add_error(peek(), "unable to parse const literal");
+    return add_error(peek(), "unable to parse constant literal");
 
   return create<ast::ScalarConstructorExpression>(source, lit.value);
 }
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc
index 0b9d2f4..ee1822b 100644
--- a/src/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -71,7 +71,7 @@
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(e.errored);
   ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:14: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
@@ -89,7 +89,7 @@
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(e.errored);
   ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:11: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:11: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
@@ -98,7 +98,7 @@
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(e.errored);
   ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:15: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:15: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index 58f5b82..843309a 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -172,24 +172,24 @@
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) {
-  EXPECT("fn f() { const >; }",
-         "test.wgsl:1:16 error: expected identifier for constant declaration\n"
-         "fn f() { const >; }\n"
-         "               ^\n");
+  EXPECT("fn f() { let >; }",
+         "test.wgsl:1:14 error: expected identifier for let declaration\n"
+         "fn f() { let >; }\n"
+         "             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) {
-  EXPECT("fn f() { const a : i32; }",
-         "test.wgsl:1:23 error: expected '=' for constant declaration\n"
-         "fn f() { const a : i32; }\n"
-         "                      ^\n");
+  EXPECT("fn f() { let a : i32; }",
+         "test.wgsl:1:21 error: expected '=' for let declaration\n"
+         "fn f() { let a : i32; }\n"
+         "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingConstructor) {
-  EXPECT("fn f() { const a : i32 = >; }",
-         "test.wgsl:1:26 error: missing constructor for const declaration\n"
-         "fn f() { const a : i32 = >; }\n"
-         "                         ^\n");
+  EXPECT("fn f() { let a : i32 = >; }",
+         "test.wgsl:1:24 error: missing constructor for let declaration\n"
+         "fn f() { let a : i32 = >; }\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ContinueStmtMissingSemicolon) {
@@ -468,7 +468,7 @@
 }
 
 TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
-  EXPECT(R"(const bar : vec2<f32> = vec2<f32>(1., 2.);
+  EXPECT(R"(let bar : vec2<f32> = vec2<f32>(1., 2.);
   var a : f32 = bar[0];
   return;
 })",
@@ -482,45 +482,45 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
-  EXPECT("const ^ : i32 = 1;",
-         "test.wgsl:1:7 error: expected identifier for constant declaration\n"
-         "const ^ : i32 = 1;\n"
-         "      ^\n");
+  EXPECT("let ^ : i32 = 1;",
+         "test.wgsl:1:5 error: expected identifier for let declaration\n"
+         "let ^ : i32 = 1;\n"
+         "    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
-  EXPECT("const i : i32 = 1",
-         "test.wgsl:1:18 error: expected ';' for constant declaration\n"
-         "const i : i32 = 1\n"
-         "                 ^\n");
+  EXPECT("let i : i32 = 1",
+         "test.wgsl:1:16 error: expected ';' for let declaration\n"
+         "let i : i32 = 1\n"
+         "               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
-  EXPECT("const i : vec2<i32> = vec2<i32>;",
-         "test.wgsl:1:32 error: expected '(' for type constructor\n"
-         "const i : vec2<i32> = vec2<i32>;\n"
-         "                               ^\n");
+  EXPECT("let i : vec2<i32> = vec2<i32>;",
+         "test.wgsl:1:30 error: expected '(' for type constructor\n"
+         "let i : vec2<i32> = vec2<i32>;\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
-  EXPECT("const i : vec2<i32> = vec2<i32>(1., 2.;",
-         "test.wgsl:1:39 error: expected ')' for type constructor\n"
-         "const i : vec2<i32> = vec2<i32>(1., 2.;\n"
-         "                                      ^\n");
+  EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
+         "test.wgsl:1:37 error: expected ')' for type constructor\n"
+         "let i : vec2<i32> = vec2<i32>(1., 2.;\n"
+         "                                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingAssignment) {
-  EXPECT("const i : vec2<i32>;",
-         "test.wgsl:1:20 error: expected '=' for constant declaration\n"
-         "const i : vec2<i32>;\n"
-         "                   ^\n");
+  EXPECT("let i : vec2<i32>;",
+         "test.wgsl:1:18 error: expected '=' for let declaration\n"
+         "let i : vec2<i32>;\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
-  EXPECT("const i : vec2<i32> = vec2<i32>(!);",
-         "test.wgsl:1:33 error: unable to parse const literal\n"
-         "const i : vec2<i32> = vec2<i32>(!);\n"
-         "                                ^\n");
+  EXPECT("let i : vec2<i32> = vec2<i32>(!);",
+         "test.wgsl:1:31 error: unable to parse constant literal\n"
+         "let i : vec2<i32> = vec2<i32>(!);\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
@@ -528,8 +528,8 @@
 
   std::stringstream src;
   std::stringstream mkr;
-  src << "const i : i32 = ";
-  mkr << "                ";
+  src << "let i : i32 = ";
+  mkr << "              ";
   for (size_t i = 0; i < kMaxDepth + 8; i++) {
     src << "f32(";
     if (i < kMaxDepth) {
@@ -544,24 +544,24 @@
   }
   src << ";";
   std::stringstream err;
-  err << "test.wgsl:1:529 error: maximum parser recursive depth reached\n"
+  err << "test.wgsl:1:527 error: maximum parser recursive depth reached\n"
       << src.str() << "\n"
       << mkr.str() << "\n";
   EXPECT(src.str().c_str(), err.str().c_str());
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
-  EXPECT("const i : vec2<i32> = vec2<i32> 1, 2);",
-         "test.wgsl:1:33 error: expected '(' for type constructor\n"
-         "const i : vec2<i32> = vec2<i32> 1, 2);\n"
-         "                                ^\n");
+  EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
+         "test.wgsl:1:31 error: expected '(' for type constructor\n"
+         "let i : vec2<i32> = vec2<i32> 1, 2);\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
-  EXPECT("const i : vec2<i32> = vec2<i32>(1, 2;",
-         "test.wgsl:1:37 error: expected ')' for type constructor\n"
-         "const i : vec2<i32> = vec2<i32>(1, 2;\n"
-         "                                    ^\n");
+  EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
+         "test.wgsl:1:35 error: expected ')' for type constructor\n"
+         "let i : vec2<i32> = vec2<i32>(1, 2;\n"
+         "                                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingLessThan) {
diff --git a/src/reader/wgsl/parser_impl_for_stmt_test.cc b/src/reader/wgsl/parser_impl_for_stmt_test.cc
index 2db196b..3e16a26 100644
--- a/src/reader/wgsl/parser_impl_for_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_for_stmt_test.cc
@@ -73,8 +73,8 @@
 
 // Test a for loop declaring a const variable in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementConstDecl) {
-  std::string for_str = "for (const i: i32 = 0 ;;) { }";
-  std::string loop_str = "{ const i: i32 = 0; loop { } }";
+  std::string for_str = "for (let i: i32 = 0 ;;) { }";
+  std::string loop_str = "{ let i: i32 = 0; loop { } }";
 
   TestForLoop(loop_str, for_str);
 }
@@ -215,8 +215,8 @@
 
 // Test a for loop with an invalid initializer statement.
 TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
-  std::string for_str = "for (const x: i32;;) { }";
-  std::string error_str = "1:18: expected '=' for constant declaration";
+  std::string for_str = "for (let x: i32;;) { }";
+  std::string error_str = "1:16: expected '=' for let declaration";
 
   TestForWithError(for_str, error_str);
 }
@@ -266,8 +266,8 @@
 
 // Test a for loop with an invalid body.
 TEST_F(ForStmtErrorTest, InvalidBody) {
-  std::string for_str = "for (;;) { const x: i32; }";
-  std::string error_str = "1:24: expected '=' for constant declaration";
+  std::string for_str = "for (;;) { let x: i32; }";
+  std::string error_str = "1:22: expected '=' for let declaration";
 
   TestForWithError(for_str, error_str);
 }
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 11d5c93..3a72f04 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -20,7 +20,7 @@
 namespace {
 
 TEST_F(ParserImplTest, GlobalConstantDecl) {
-  auto p = parser("const a : f32 = 1.");
+  auto p = parser("let a : f32 = 1.");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -36,9 +36,9 @@
   EXPECT_TRUE(e->declared_type()->Is<type::F32>());
 
   EXPECT_EQ(e->source().range.begin.line, 1u);
-  EXPECT_EQ(e->source().range.begin.column, 7u);
+  EXPECT_EQ(e->source().range.begin.column, 5u);
   EXPECT_EQ(e->source().range.end.line, 1u);
-  EXPECT_EQ(e->source().range.end.column, 8u);
+  EXPECT_EQ(e->source().range.end.column, 6u);
 
   ASSERT_NE(e->constructor(), nullptr);
   EXPECT_TRUE(e->constructor()->Is<ast::ConstructorExpression>());
@@ -47,7 +47,7 @@
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
-  auto p = parser("const a: f32 1.");
+  auto p = parser("let a : f32 1.");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -56,11 +56,11 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: expected '=' for constant declaration");
+  EXPECT_EQ(p->error(), "1:13: expected '=' for let declaration");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) {
-  auto p = parser("const a: invalid = 1.");
+  auto p = parser("let a : invalid = 1.");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -69,11 +69,11 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
+  EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
-  auto p = parser("const a: f32 = if (a) {}");
+  auto p = parser("let a : f32 = if (a) {}");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -82,11 +82,11 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:16: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:15: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
-  auto p = parser("const a: f32 =");
+  auto p = parser("let a : f32 =");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -95,11 +95,11 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:15: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:14: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_ConstantId) {
-  auto p = parser("[[constant_id(7)]] const a : f32 = 1.");
+  auto p = parser("[[constant_id(7)]] let a : f32 = 1.");
   auto decos = p->decoration_list();
   EXPECT_FALSE(decos.errored);
   EXPECT_TRUE(decos.matched);
@@ -116,9 +116,9 @@
   EXPECT_TRUE(e->declared_type()->Is<type::F32>());
 
   EXPECT_EQ(e->source().range.begin.line, 1u);
-  EXPECT_EQ(e->source().range.begin.column, 26u);
+  EXPECT_EQ(e->source().range.begin.column, 24u);
   EXPECT_EQ(e->source().range.end.line, 1u);
-  EXPECT_EQ(e->source().range.end.column, 27u);
+  EXPECT_EQ(e->source().range.end.column, 25u);
 
   ASSERT_NE(e->constructor(), nullptr);
   EXPECT_TRUE(e->constructor()->Is<ast::ConstructorExpression>());
@@ -128,7 +128,7 @@
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_ConstantId_Missing) {
-  auto p = parser("[[constant_id()]] const a : f32 = 1.");
+  auto p = parser("[[constant_id()]] let a : f32 = 1.");
   auto decos = p->decoration_list();
   EXPECT_TRUE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -144,7 +144,7 @@
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_ConstantId_Invalid) {
-  auto p = parser("[[constant_id(-7)]] const a : f32 = 1.");
+  auto p = parser("[[constant_id(-7)]] let a : f32 = 1.");
   auto decos = p->decoration_list();
   EXPECT_TRUE(decos.errored);
   EXPECT_FALSE(decos.matched);
@@ -158,6 +158,23 @@
   EXPECT_EQ(p->error(), "1:15: constant_id decoration must be positive");
 }
 
+TEST_F(ParserImplTest, GlobalConstantDec_ConstantId_Const) {
+  auto p = parser("const a : i32 = 1");
+  auto decos = p->decoration_list();
+  EXPECT_FALSE(decos.errored);
+  EXPECT_FALSE(decos.matched);
+
+  auto e = p->global_constant_decl(decos.value);
+  EXPECT_TRUE(e.matched);
+  EXPECT_FALSE(e.errored);
+  EXPECT_EQ(
+      p->builder().Diagnostics().str(),
+      R"(test.wgsl:1:1 warning: use of deprecated language feature: use 'let' instead of 'const'
+const a : i32 = 1
+^^^^^
+)");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace reader
diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc
index ab7f6d4..6c187e1 100644
--- a/src/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_decl_test.cc
@@ -52,7 +52,7 @@
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
-  auto p = parser("const a : i32 = 2;");
+  auto p = parser("let a : i32 = 2;");
   p->expect_global_decl();
   ASSERT_FALSE(p->has_error()) << p->error();
 
@@ -64,17 +64,17 @@
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
-  auto p = parser("const a : vec2<i32>;");
+  auto p = parser("let a : vec2<i32>;");
   p->expect_global_decl();
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:20: expected '=' for constant declaration");
+  EXPECT_EQ(p->error(), "1:18: expected '=' for let declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
-  auto p = parser("const a : vec2<i32> = vec2<i32>(1, 2)");
+  auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
   p->expect_global_decl();
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:38: expected ';' for constant declaration");
+  EXPECT_EQ(p->error(), "1:36: expected ';' for let declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
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 831d115..7c2df95 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -152,7 +152,7 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:20: unable to parse const literal");
+  EXPECT_EQ(p->error(), "1:20: unable to parse constant literal");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
index c3e4d27..bfbf6e8 100644
--- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -138,8 +138,8 @@
   EXPECT_TRUE(e->variable()->constructor()->Is<ast::ConstructorExpression>());
 }
 
-TEST_F(ParserImplTest, VariableStmt_Const) {
-  auto p = parser("const a : i32 = 1");
+TEST_F(ParserImplTest, VariableStmt_Let) {
+  auto p = parser("let a : i32 = 1");
   auto e = p->variable_stmt();
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
@@ -148,49 +148,62 @@
   ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
 
   ASSERT_EQ(e->source().range.begin.line, 1u);
-  ASSERT_EQ(e->source().range.begin.column, 7u);
+  ASSERT_EQ(e->source().range.begin.column, 5u);
   ASSERT_EQ(e->source().range.end.line, 1u);
-  ASSERT_EQ(e->source().range.end.column, 8u);
+  ASSERT_EQ(e->source().range.end.column, 6u);
 }
 
-TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {
-  auto p = parser("const a : invalid = 1");
+TEST_F(ParserImplTest, VariableStmt_Let_InvalidVarIdent) {
+  auto p = parser("let a : invalid = 1");
   auto e = p->variable_stmt();
   EXPECT_FALSE(e.matched);
   EXPECT_TRUE(e.errored);
   EXPECT_EQ(e.value, nullptr);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:11: unknown constructed type 'invalid'");
+  EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
 }
 
-TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) {
-  auto p = parser("const a : i32 1");
+TEST_F(ParserImplTest, VariableStmt_Let_MissingEqual) {
+  auto p = parser("let a : i32 1");
   auto e = p->variable_stmt();
   EXPECT_FALSE(e.matched);
   EXPECT_TRUE(e.errored);
   EXPECT_EQ(e.value, nullptr);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:15: expected '=' for constant declaration");
+  EXPECT_EQ(p->error(), "1:13: expected '=' for let declaration");
 }
 
-TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) {
-  auto p = parser("const a : i32 =");
+TEST_F(ParserImplTest, VariableStmt_Let_MissingConstructor) {
+  auto p = parser("let a : i32 =");
   auto e = p->variable_stmt();
   EXPECT_FALSE(e.matched);
   EXPECT_TRUE(e.errored);
   EXPECT_EQ(e.value, nullptr);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: missing constructor for const declaration");
+  EXPECT_EQ(p->error(), "1:14: missing constructor for let declaration");
 }
 
-TEST_F(ParserImplTest, VariableStmt_Const_InvalidConstructor) {
-  auto p = parser("const a : i32 = if (a) {}");
+TEST_F(ParserImplTest, VariableStmt_Let_InvalidConstructor) {
+  auto p = parser("let a : i32 = if (a) {}");
   auto e = p->variable_stmt();
   EXPECT_FALSE(e.matched);
   EXPECT_TRUE(e.errored);
   EXPECT_EQ(e.value, nullptr);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:17: missing constructor for const declaration");
+  EXPECT_EQ(p->error(), "1:15: missing constructor for let declaration");
+}
+
+TEST_F(ParserImplTest, VariableStmt_Const) {
+  auto p = parser("const a : i32 = 1");
+  auto e = p->variable_stmt();
+  EXPECT_TRUE(e.matched);
+  EXPECT_FALSE(e.errored);
+  EXPECT_EQ(
+      p->builder().Diagnostics().str(),
+      R"(test.wgsl:1:1 warning: use of deprecated language feature: use 'let' instead of 'const'
+const a : i32 = 1
+^^^^^
+)");
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc
index cf28d6e..a89c2ef 100644
--- a/src/reader/wgsl/token.cc
+++ b/src/reader/wgsl/token.cc
@@ -221,6 +221,8 @@
       return "import";
     case Token::Type::kIn:
       return "in";
+    case Token::Type::kLet:
+      return "let";
     case Token::Type::kLoop:
       return "loop";
     case Token::Type::kMat2x2:
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h
index e7de5da..6e4581f 100644
--- a/src/reader/wgsl/token.h
+++ b/src/reader/wgsl/token.h
@@ -229,6 +229,8 @@
     kImport,
     /// A 'in'
     kIn,
+    /// A 'let'
+    kLet,
     /// A 'loop'
     kLoop,
     /// A 'mat2x2'
@@ -574,6 +576,8 @@
   bool IsImport() const { return type_ == Type::kImport; }
   /// @returns true if token is a 'in'
   bool IsIn() const { return type_ == Type::kIn; }
+  /// @returns true if token is a 'let'
+  bool IsLet() const { return type_ == Type::kLet; }
   /// @returns true if token is a 'loop'
   bool IsLoop() const { return type_ == Type::kLoop; }
   /// @returns true if token is a 'mat2x2'
diff --git a/src/resolver/assignment_validation_test.cc b/src/resolver/assignment_validation_test.cc
index 0b248d1..83dbeec 100644
--- a/src/resolver/assignment_validation_test.cc
+++ b/src/resolver/assignment_validation_test.cc
@@ -48,7 +48,7 @@
 TEST_F(ResolverAssignmentValidationTest,
        AssignThroughPointerWrongeStoreType_Fail) {
   // var a : f32;
-  // const b : ptr<function,f32> = a;
+  // let b : ptr<function,f32> = a;
   // b = 2;
   const auto priv = ast::StorageClass::kFunction;
   auto* var_a = Var("a", ty.f32(), priv);
@@ -211,7 +211,7 @@
 
 TEST_F(ResolverAssignmentValidationTest, AssignThroughPointer_Pass) {
   // var a :i32;
-  // const b : ptr<function,i32> = a;
+  // let b : ptr<function,i32> = a;
   // b = 2;
   const auto func = ast::StorageClass::kFunction;
   auto* var_a = Var("a", ty.i32(), func, Expr(2), {});
@@ -229,7 +229,7 @@
 
 TEST_F(ResolverAssignmentValidationTest, AssignToConstant_Fail) {
   // {
-  //  const a :i32 = 2;
+  //  let a : i32 = 2;
   //  a = 2
   // }
   auto* var = Const("a", ty.i32(), Expr(2));
diff --git a/src/resolver/function_validation_test.cc b/src/resolver/function_validation_test.cc
index 77c06f0..76ae8f5 100644
--- a/src/resolver/function_validation_test.cc
+++ b/src/resolver/function_validation_test.cc
@@ -259,7 +259,7 @@
 
 TEST_F(ResolverFunctionValidationTest, FunctionConstInitWithParam) {
   // fn foo(bar : f32){
-  //   const baz : f32 = bar;
+  //   let baz : f32 = bar;
   // }
 
   auto* bar = Var("bar", ty.f32(), ast::StorageClass::kFunction);
diff --git a/src/resolver/type_validation_test.cc b/src/resolver/type_validation_test.cc
index 848e998..a5dd6bb 100644
--- a/src/resolver/type_validation_test.cc
+++ b/src/resolver/type_validation_test.cc
@@ -78,7 +78,7 @@
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
-  // const global_var: f32;
+  // let global_var: f32;
   GlobalConst(Source{{12, 34}}, "global_var", ty.f32());
 
   EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index bafd6c6..5205480 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -26,20 +26,20 @@
   auto* src = R"(
 var<storage> a : array<f32, 3>;
 
-const c : u32 = 1u;
+let c : u32 = 1u;
 
 fn f() {
-  const b : ptr<storage, f32> = a[c];
+  let b : ptr<storage, f32> = a[c];
 }
 )";
 
   auto* expect = R"(
 var<storage> a : array<f32, 3>;
 
-const c : u32 = 1u;
+let c : u32 = 1u;
 
 fn f() {
-  const b : ptr<storage, f32> = a[min(u32(c), 2u)];
+  let b : ptr<storage, f32> = a[min(u32(c), 2u)];
 }
 )";
 
@@ -499,7 +499,7 @@
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(BoundArrayAccessorsTest, DISABLED_Vector_Constant_Id_Clamps) {
-  // [[constant_id(1300)]] const idx : i32;
+  // [[constant_id(1300)]] let idx : i32;
   // var a : vec3<f32>
   // var b : f32 = a[idx]
   //
@@ -508,7 +508,7 @@
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(BoundArrayAccessorsTest, DISABLED_Array_Constant_Id_Clamps) {
-  // [[constant_id(1300)]] const idx : i32;
+  // [[constant_id(1300)]] let idx : i32;
   // var a : array<f32, 4>
   // var b : f32 = a[idx]
   //
@@ -517,7 +517,7 @@
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(BoundArrayAccessorsTest, DISABLED_Matrix_Column_Constant_Id_Clamps) {
-  // [[constant_id(1300)]] const idx : i32;
+  // [[constant_id(1300)]] let idx : i32;
   // var a : mat3x2<f32>
   // var b : f32 = a[idx][1]
   //
@@ -526,7 +526,7 @@
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(BoundArrayAccessorsTest, DISABLED_Matrix_Row_Constant_Id_Clamps) {
-  // [[constant_id(1300)]] const idx : i32;
+  // [[constant_id(1300)]] let idx : i32;
   // var a : mat3x2<f32>
   // var b : f32 = a[1][idx]
   //
diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc
index 855f21a..ec986d5 100644
--- a/src/transform/canonicalize_entry_point_io_test.cc
+++ b/src/transform/canonicalize_entry_point_io_test.cc
@@ -44,9 +44,9 @@
 
 [[stage(fragment)]]
 fn frag_main(tint_symbol_1 : tint_symbol_5) {
-  const coord : vec4<f32> = tint_symbol_1.coord;
-  const loc1 : f32 = tint_symbol_1.loc1;
-  const loc2 : vec4<u32> = tint_symbol_1.loc2;
+  let coord : vec4<f32> = tint_symbol_1.coord;
+  let loc1 : f32 = tint_symbol_1.loc1;
+  let loc2 : vec4<u32> = tint_symbol_1.loc2;
   var col : f32 = (coord.x * loc1);
 }
 )";
@@ -76,7 +76,7 @@
 
 [[stage(fragment)]]
 fn frag_main(tint_symbol_1 : tint_symbol_4) {
-  const loc1 : myf32 = tint_symbol_1.loc1;
+  let loc1 : myf32 = tint_symbol_1.loc1;
   var x : myf32 = loc1;
 }
 )";
@@ -156,9 +156,9 @@
 
 [[stage(fragment)]]
 fn frag_main(tint_symbol_6 : tint_symbol_10) {
-  const builtins : FragBuiltins = FragBuiltins(tint_symbol_6.coord);
-  const locations : FragLocations = FragLocations(tint_symbol_6.loc1, tint_symbol_6.loc2);
-  const loc0 : f32 = tint_symbol_6.loc0;
+  let builtins : FragBuiltins = FragBuiltins(tint_symbol_6.coord);
+  let locations : FragLocations = FragLocations(tint_symbol_6.loc1, tint_symbol_6.loc2);
+  let loc0 : f32 = tint_symbol_6.loc0;
   var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
 }
 )";
@@ -283,7 +283,7 @@
 
 [[stage(fragment)]]
 fn frag_main1(tint_symbol_4 : tint_symbol_6) {
-  const inputs : FragmentInput = FragmentInput(tint_symbol_4.value, tint_symbol_4.mul);
+  let inputs : FragmentInput = FragmentInput(tint_symbol_4.value, tint_symbol_4.mul);
   var x : f32 = foo(inputs);
 }
 
@@ -296,7 +296,7 @@
 
 [[stage(fragment)]]
 fn frag_main2(tint_symbol_10 : tint_symbol_11) {
-  const inputs : FragmentInput = FragmentInput(tint_symbol_10.value, tint_symbol_10.mul);
+  let inputs : FragmentInput = FragmentInput(tint_symbol_10.value, tint_symbol_10.mul);
   var x : f32 = foo(inputs);
 }
 )";
@@ -356,7 +356,7 @@
 
 [[stage(fragment)]]
 fn frag_main1(tint_symbol_4 : tint_symbol_6) {
-  const inputs : FragmentInput = FragmentInput(tint_symbol_4.col1, tint_symbol_4.col2);
+  let inputs : FragmentInput = FragmentInput(tint_symbol_4.col1, tint_symbol_4.col2);
   global_inputs = inputs;
   var r : f32 = foo();
   var g : f32 = bar();
@@ -434,9 +434,9 @@
 
 [[stage(fragment)]]
 fn frag_main(tint_symbol_6 : tint_symbol_9) -> tint_symbol_10 {
-  const inputs : MyFragmentInput = MyFragmentInput(tint_symbol_6.col1, tint_symbol_6.col2);
+  let inputs : MyFragmentInput = MyFragmentInput(tint_symbol_6.col1, tint_symbol_6.col2);
   var x : myf32 = foo(inputs);
-  const tint_symbol_13 : FragmentOutput = MyFragmentOutput(x, inputs.col2);
+  let tint_symbol_13 : FragmentOutput = MyFragmentOutput(x, inputs.col2);
   return tint_symbol_10(tint_symbol_13.col1, tint_symbol_13.col2);
 }
 )";
@@ -492,8 +492,8 @@
 
 [[stage(fragment)]]
 fn frag_main(tint_symbol_5 : tint_symbol_7) -> tint_symbol_8 {
-  const inputs : FragmentInput = FragmentInput(tint_symbol_5.value, tint_symbol_5.coord);
-  const tint_symbol_10 : FragmentOutput = FragmentOutput((inputs.coord.x * inputs.value));
+  let inputs : FragmentInput = FragmentInput(tint_symbol_5.value, tint_symbol_5.coord);
+  let tint_symbol_10 : FragmentOutput = FragmentOutput((inputs.coord.x * inputs.value));
   return tint_symbol_8(tint_symbol_10.value);
 }
 )";
diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc
index 1075433..ccfecf9 100644
--- a/src/transform/first_index_offset_test.cc
+++ b/src/transform/first_index_offset_test.cc
@@ -102,7 +102,7 @@
 [[builtin(vertex_index)]] var<in> tint_first_index_offset_vert_idx : u32;
 
 fn test() -> u32 {
-  const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
+  let vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
   return vert_idx;
 }
 
@@ -150,7 +150,7 @@
 [[builtin(instance_index)]] var<in> tint_first_index_offset_inst_idx : u32;
 
 fn test() -> u32 {
-  const inst_idx : u32 = (tint_first_index_offset_inst_idx + tint_first_index_data.tint_first_instance_index);
+  let inst_idx : u32 = (tint_first_index_offset_inst_idx + tint_first_index_data.tint_first_instance_index);
   return inst_idx;
 }
 
@@ -202,8 +202,8 @@
 [[builtin(vertex_index)]] var<in> tint_first_index_offset_vert_idx : u32;
 
 fn test() -> u32 {
-  const instance_idx : u32 = (tint_first_index_offset_instance_idx + tint_first_index_data.tint_first_instance_index);
-  const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
+  let instance_idx : u32 = (tint_first_index_offset_instance_idx + tint_first_index_data.tint_first_instance_index);
+  let vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
   return (instance_idx + vert_idx);
 }
 
@@ -255,7 +255,7 @@
 [[builtin(vertex_index)]] var<in> tint_first_index_offset_vert_idx : u32;
 
 fn func1() -> u32 {
-  const vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
+  let vert_idx : u32 = (tint_first_index_offset_vert_idx + tint_first_index_data.tint_first_vertex_index);
   return vert_idx;
 }
 
diff --git a/src/transform/hlsl_test.cc b/src/transform/hlsl_test.cc
index 2a61b40..75f2390 100644
--- a/src/transform/hlsl_test.cc
+++ b/src/transform/hlsl_test.cc
@@ -41,7 +41,7 @@
   var f1 : f32 = 2.0;
   var f2 : f32 = 3.0;
   var f3 : f32 = 4.0;
-  const tint_symbol_1 : array<f32, 4> = array<f32, 4>(f0, f1, f2, f3);
+  let tint_symbol_1 : array<f32, 4> = array<f32, 4>(f0, f1, f2, f3);
   var i : f32 = tint_symbol_1[2];
 }
 )";
@@ -74,7 +74,7 @@
 
 [[stage(vertex)]]
 fn main() {
-  const tint_symbol_1 : S = S(1, 2.0, vec3<f32>());
+  let tint_symbol_1 : S = S(1, 2.0, vec3<f32>());
   var x : f32 = tint_symbol_1.b;
 }
 )";
@@ -95,9 +95,9 @@
   auto* expect = R"(
 [[stage(vertex)]]
 fn main() {
-  const tint_symbol_1 : array<f32, 2> = array<f32, 2>(1.0, 2.0);
-  const tint_symbol_2 : array<f32, 2> = array<f32, 2>(3.0, 4.0);
-  const tint_symbol_3 : array<array<f32, 2>, 2> = array<array<f32, 2>, 2>(tint_symbol_1, tint_symbol_2);
+  let tint_symbol_1 : array<f32, 2> = array<f32, 2>(1.0, 2.0);
+  let tint_symbol_2 : array<f32, 2> = array<f32, 2>(3.0, 4.0);
+  let tint_symbol_3 : array<array<f32, 2>, 2> = array<array<f32, 2>, 2>(tint_symbol_1, tint_symbol_2);
   var i : f32 = tint_symbol_3[0][1];
 }
 )";
@@ -146,9 +146,9 @@
 
 [[stage(vertex)]]
 fn main() {
-  const tint_symbol_1 : S1 = S1(2);
-  const tint_symbol_4 : S2 = S2(1, tint_symbol_1, 3);
-  const tint_symbol_8 : S3 = S3(tint_symbol_4);
+  let tint_symbol_1 : S1 = S1(2);
+  let tint_symbol_4 : S2 = S2(1, tint_symbol_1, 3);
+  let tint_symbol_8 : S3 = S3(tint_symbol_4);
   var x : i32 = tint_symbol_8.a.b.a;
 }
 )";
@@ -185,11 +185,11 @@
 
 [[stage(vertex)]]
 fn main() {
-  const tint_symbol_1 : S1 = S1(1);
-  const tint_symbol_4 : S1 = S1(2);
-  const tint_symbol_5 : S1 = S1(3);
-  const tint_symbol_6 : array<S1, 3> = array<S1, 3>(tint_symbol_1, tint_symbol_4, tint_symbol_5);
-  const tint_symbol_7 : S2 = S2(tint_symbol_6);
+  let tint_symbol_1 : S1 = S1(1);
+  let tint_symbol_4 : S1 = S1(2);
+  let tint_symbol_5 : S1 = S1(3);
+  let tint_symbol_6 : array<S1, 3> = array<S1, 3>(tint_symbol_1, tint_symbol_4, tint_symbol_5);
+  let tint_symbol_7 : S2 = S2(tint_symbol_6);
   var x : i32 = tint_symbol_7.a[1].a;
 }
 )";
@@ -213,9 +213,9 @@
   var local_str : S = S(1, 2.0, 3);
 }
 
-const module_arr : array<f32, 4> = array<f32, 4>(0.0, 1.0, 2.0, 3.0);
+let module_arr : array<f32, 4> = array<f32, 4>(0.0, 1.0, 2.0, 3.0);
 
-const module_str : S = S(1, 2.0, 3);
+let module_str : S = S(1, 2.0, 3);
 )";
 
   auto* expect = src;
@@ -241,7 +241,7 @@
 
 [[stage(vertex)]]
 fn main() {
-  const transform : mat2x2<f32> = ubo.transform;
+  let transform : mat2x2<f32> = ubo.transform;
   var coord : vec2<f32> = array<vec2<f32>, 3>(
       vec2<f32>(-1.0,  1.0),
       vec2<f32>( 1.0,  1.0),
@@ -265,8 +265,8 @@
 
 [[stage(vertex)]]
 fn main() {
-  const transform : mat2x2<f32> = ubo.transform;
-  const tint_symbol_1 : array<vec2<f32>, 3> = array<vec2<f32>, 3>(vec2<f32>(-1.0, 1.0), vec2<f32>(1.0, 1.0), vec2<f32>(-1.0, -1.0));
+  let transform : mat2x2<f32> = ubo.transform;
+  let tint_symbol_1 : array<vec2<f32>, 3> = array<vec2<f32>, 3>(vec2<f32>(-1.0, 1.0), vec2<f32>(1.0, 1.0), vec2<f32>(-1.0, -1.0));
   var coord : vec2<f32> = tint_symbol_1[vertex_index];
   position = vec4<f32>((transform * coord), 0.0, 1.0);
 }
diff --git a/src/transform/spirv.cc b/src/transform/spirv.cc
index 427421c..bb4f7ae 100644
--- a/src/transform/spirv.cc
+++ b/src/transform/spirv.cc
@@ -101,7 +101,7 @@
   //
   // [[stage(fragment)]]
   // fn frag_main() {
-  //   const samples : FragmentInput(sample_index, sample_mask_in);
+  //   let samples : FragmentInput(sample_index, sample_mask_in);
   //   var output : FragmentOutput = FragmentOutput(1.0,
   //                                                samples.sample_mask_in);
   //   frag_main_ret(output);
diff --git a/src/transform/spirv_test.cc b/src/transform/spirv_test.cc
index 5c365a5..391ca2f 100644
--- a/src/transform/spirv_test.cc
+++ b/src/transform/spirv_test.cc
@@ -214,7 +214,7 @@
 
 [[stage(fragment)]]
 fn frag_main() {
-  const tint_symbol_7 : FragmentInput = FragmentInput(tint_symbol_4, tint_symbol_5);
+  let tint_symbol_7 : FragmentInput = FragmentInput(tint_symbol_4, tint_symbol_5);
   var col : f32 = (tint_symbol_7.coord.x * tint_symbol_7.value);
 }
 )";
@@ -328,7 +328,7 @@
 
 [[stage(vertex)]]
 fn vert_main() {
-  const tint_symbol_8 : Interface = Interface(tint_symbol_3);
+  let tint_symbol_8 : Interface = Interface(tint_symbol_3);
   tint_symbol_5(tint_symbol_8);
   return;
 }
@@ -377,7 +377,7 @@
 
 [[stage(fragment)]]
 fn frag_main() {
-  const tint_symbol_9 : Interface = Interface(tint_symbol_7);
+  let tint_symbol_9 : Interface = Interface(tint_symbol_7);
   var x : f32 = tint_symbol_9.value;
 }
 )";
@@ -431,7 +431,7 @@
 
 [[stage(fragment)]]
 fn frag_main() {
-  const tint_symbol_11 : FragmentInput = FragmentInput(tint_symbol_5, tint_symbol_6);
+  let tint_symbol_11 : FragmentInput = FragmentInput(tint_symbol_5, tint_symbol_6);
   tint_symbol_8(FragmentOutput((tint_symbol_11.coord.x * tint_symbol_11.value)));
   return;
 }
diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc
index accad83..d9e77da 100644
--- a/src/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/writer/spirv/builder_accessor_expression_test.cc
@@ -304,7 +304,7 @@
   //   a : f32
   //   b : f32
   // }
-  // const ident : my_struct = my_struct();
+  // let ident : my_struct = my_struct();
   // ident.b
 
   auto* s = Structure("my_struct", {
@@ -343,7 +343,7 @@
   //   inner : inner_struct
   // }
   //
-  // const ident : my_struct = my_struct();
+  // let ident : my_struct = my_struct();
   // ident.inner.a
   auto* inner_struct = Structure("Inner", {
                                               Member("a", ty.f32()),
@@ -748,7 +748,7 @@
 }
 
 TEST_F(BuilderTest, Accessor_Array_Of_Vec) {
-  // const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+  // let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
   //   vec2<f32>(0.0, 0.5),
   //   vec2<f32>(-0.5, -0.5),
   //   vec2<f32>(0.5, -0.5));
@@ -797,7 +797,7 @@
 }
 
 TEST_F(BuilderTest, Accessor_Const_Vec) {
-  // const pos : vec2<f32> = vec2<f32>(0.0, 0.5);
+  // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
   // pos[1]
 
   auto* var = GlobalConst("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
@@ -826,7 +826,7 @@
 }
 
 TEST_F(BuilderTest, DISABLED_Accessor_Array_NonPointer) {
-  // const a : array<f32, 3>;
+  // let a : array<f32, 3>;
   // a[2]
   //
   // This has to generate an OpConstantExtract and will need to read the 3 value
diff --git a/src/writer/spirv/builder_function_variable_test.cc b/src/writer/spirv/builder_function_variable_test.cc
index 8d87df3..1f4217a 100644
--- a/src/writer/spirv/builder_function_variable_test.cc
+++ b/src/writer/spirv/builder_function_variable_test.cc
@@ -137,7 +137,7 @@
 
 TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
   // var v : f32 = 1.0;
-  // const v2 : f32 = v; // Should generate the load
+  // let v2 : f32 = v; // Should generate the load
 
   auto* v = Global("v", ty.f32(), ast::StorageClass::kFunction, Expr(1.f));
 
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 6bc8413..22285c0 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -588,7 +588,7 @@
   }
 
   if (var->is_const()) {
-    out_ << "const";
+    out_ << "let";
   } else {
     out_ << "var";
     if (sem->StorageClass() != ast::StorageClass::kNone &&
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index d091291..878fd6b 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -92,7 +92,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(const a : f32 = 1.0;
+  EXPECT_EQ(gen.result(), R"(let a : f32 = 1.0;
 )");
 }
 
diff --git a/test/triangle.wgsl b/test/triangle.wgsl
index 1baca52..263cb6c 100644
--- a/test/triangle.wgsl
+++ b/test/triangle.wgsl
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 // Vertex shader
-const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
     vec2<f32>(0.0, 0.5),
     vec2<f32>(-0.5, -0.5),
     vec2<f32>(0.5, -0.5));