Remove module-scope let deprecation.

This CL moves module-scope let from a deprecation to an error.

Change-Id: Iffecbb667cf79515234b6510ce7c5bbbb6e673bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/108862
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/docs/tint/origin-trial-changes.md b/docs/tint/origin-trial-changes.md
index 5d36a13..decf3c5 100644
--- a/docs/tint/origin-trial-changes.md
+++ b/docs/tint/origin-trial-changes.md
@@ -7,6 +7,7 @@
 * `textureDimensions()`, `textureNumLayers()` and `textureNumLevels()` now return unsigned integers / vectors. [tint:1526](crbug.com/tint/1526)
 * The `@stage` attribute has been removed. The short forms should be used
   instead (`@vertex`, `@fragment`, or `@compute`). [tint:1503](crbug.com/tint/1503)
+* Module-scope `let` is now an error. Use module-scope `const` instead. [tint:1580](crbug.com/tint/1584)
 
 ### New features
 
diff --git a/src/dawn/native/IndirectDrawValidationEncoder.cpp b/src/dawn/native/IndirectDrawValidationEncoder.cpp
index e8e4e1b..2bfa5d0 100644
--- a/src/dawn/native/IndirectDrawValidationEncoder.cpp
+++ b/src/dawn/native/IndirectDrawValidationEncoder.cpp
@@ -56,16 +56,16 @@
 // various failure modes.
 static const char sRenderValidationShaderSource[] = R"(
 
-            let kNumDrawIndirectParams = 4u;
+            const kNumDrawIndirectParams = 4u;
 
-            let kIndexCountEntry = 0u;
-            let kFirstIndexEntry = 2u;
+            const kIndexCountEntry = 0u;
+            const kFirstIndexEntry = 2u;
 
             // Bitmasks for BatchInfo::flags
-            let kDuplicateBaseVertexInstance = 1u;
-            let kIndexedDraw = 2u;
-            let kValidationEnabled = 4u;
-            let kIndirectFirstInstanceEnabled = 8u;
+            const kDuplicateBaseVertexInstance = 1u;
+            const kIndexedDraw = 2u;
+            const kValidationEnabled = 4u;
+            const kIndirectFirstInstanceEnabled = 8u;
 
             struct BatchInfo {
                 numIndexBufferElementsLow: u32,
diff --git a/src/dawn/native/QueryHelper.cpp b/src/dawn/native/QueryHelper.cpp
index d8f6481..0453242 100644
--- a/src/dawn/native/QueryHelper.cpp
+++ b/src/dawn/native/QueryHelper.cpp
@@ -64,7 +64,7 @@
             @group(0) @binding(1) var<storage, read> availability : AvailabilityArr;
             @group(0) @binding(2) var<uniform> params : TimestampParams;
 
-            let sizeofTimestamp : u32 = 8u;
+            const sizeofTimestamp : u32 = 8u;
 
             @compute @workgroup_size(8, 1, 1)
             fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3<u32>) {
diff --git a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
index 91332c6..5f3751a 100644
--- a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
+++ b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
@@ -440,17 +440,17 @@
     wgpu::ComputePipeline pipeline;
     {
         std::ostringstream shader;
-        shader << "let kArrayLength: u32 = " << kArrayLength << "u;\n";
+        shader << "const kArrayLength: u32 = " << kArrayLength << "u;\n";
         if (GetParam().mOOBRead) {
-            shader << "let kReadOffset: u32 = " << kOOBOffset << "u;\n";
+            shader << "const kReadOffset: u32 = " << kOOBOffset << "u;\n";
         } else {
-            shader << "let kReadOffset: u32 = 0u;\n";
+            shader << "const kReadOffset: u32 = 0u;\n";
         }
 
         if (GetParam().mOOBWrite) {
-            shader << "let kWriteOffset: u32 = " << kOOBOffset << "u;\n";
+            shader << "const kWriteOffset: u32 = " << kOOBOffset << "u;\n";
         } else {
-            shader << "let kWriteOffset: u32 = 0u;\n";
+            shader << "const kWriteOffset: u32 = 0u;\n";
         }
         switch (GetParam().mReadBufferUsage) {
             case wgpu::BufferUsage::Uniform:
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
index ac5743e..8339ac0 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
@@ -386,7 +386,7 @@
 }
 
 var<private> a: S;
-let e = 3;
+const e = 3;
 @group(1) @binding(1) var<uniform> b: S;
 fn f() {
   *&a = *&b;
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index dc02ca4..8803730 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -615,12 +615,11 @@
     Source source;
     if (match(Token::Type::kConst)) {
         use = "'const' declaration";
-    } else if (match(Token::Type::kLet, &source)) {
-        use = "'let' declaration";
-        deprecated(source, "module-scope 'let' has been replaced with 'const'");
     } else if (match(Token::Type::kOverride)) {
         use = "'override' declaration";
         is_overridable = true;
+    } else if (match(Token::Type::kLet, &source)) {
+        return add_error(source, "module-scope 'let' is invalid, use 'const'");
     } else {
         return Failure::kNoMatch;
     }
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index 8b8a634..6c4f14a 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -553,94 +553,11 @@
 )");
 }
 
-TEST_F(ParserImplErrorTest, GlobalDeclLetInvalidIdentifier) {
-    EXPECT(
-        "let ^ : i32 = 1;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let ^ : i32 = 1;
+TEST_F(ParserImplErrorTest, GlobalDeclLet) {
+    EXPECT("let a : i32 = 1;",
+           R"(test.wgsl:1:1 error: module-scope 'let' is invalid, use 'const'
+let a : i32 = 1;
 ^^^
-
-test.wgsl:1:5 error: expected identifier for 'let' declaration
-let ^ : i32 = 1;
-    ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingSemicolon) {
-    EXPECT(
-        "let i : i32 = 1",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : i32 = 1
-^^^
-
-test.wgsl:1:16 error: expected ';' for 'const' declaration
-let i : i32 = 1
-               ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingLParen) {
-    EXPECT(
-        "let i : vec2<i32> = vec2<i32>;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>;
-^^^
-
-test.wgsl:1:30 error: expected '(' for type initializer
-let i : vec2<i32> = vec2<i32>;
-                             ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetMissingRParen) {
-    EXPECT(
-        "let i : vec2<i32> = vec2<i32>(1., 2.;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(1., 2.;
-^^^
-
-test.wgsl:1:37 error: expected ')' for type initializer
-let i : vec2<i32> = vec2<i32>(1., 2.;
-                                    ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteral) {
-    EXPECT(
-        "let i : vec2<i32> = vec2<i32>(!);",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(!);
-^^^
-
-test.wgsl:1:32 error: unable to parse right side of ! expression
-let i : vec2<i32> = vec2<i32>(!);
-                               ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingLParen) {
-    EXPECT(
-        "let i : vec2<i32> = vec2<i32> 1, 2);",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32> 1, 2);
-^^^
-
-test.wgsl:1:31 error: expected '(' for type initializer
-let i : vec2<i32> = vec2<i32> 1, 2);
-                              ^
-)");
-}
-
-TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingRParen) {
-    EXPECT(
-        "let i : vec2<i32> = vec2<i32>(1, 2;",
-        R"(test.wgsl:1:1 warning: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-let i : vec2<i32> = vec2<i32>(1, 2;
-^^^
-
-test.wgsl:1:35 error: expected ')' for type initializer
-let i : vec2<i32> = vec2<i32>(1, 2;
-                                  ^
 )");
 }
 
diff --git a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 86e4383..c465e4b 100644
--- a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -24,79 +24,10 @@
     EXPECT_FALSE(attrs.errored);
     EXPECT_FALSE(attrs.matched);
     auto e = p->global_constant_decl(attrs.value);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-    auto* const_ = e.value->As<ast::Const>();
-    ASSERT_NE(const_, nullptr);
-
-    EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
-    ASSERT_NE(const_->type, nullptr);
-    EXPECT_TRUE(const_->type->Is<ast::F32>());
-
-    EXPECT_EQ(const_->source.range.begin.line, 1u);
-    EXPECT_EQ(const_->source.range.begin.column, 5u);
-    EXPECT_EQ(const_->source.range.end.line, 1u);
-    EXPECT_EQ(const_->source.range.end.column, 6u);
-
-    ASSERT_NE(const_->initializer, nullptr);
-    EXPECT_TRUE(const_->initializer->Is<ast::LiteralExpression>());
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_Inferred) {
-    auto p = parser("let a = 1.");
-    auto attrs = p->attribute_list();
-    EXPECT_FALSE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    auto e = p->global_constant_decl(attrs.value);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    EXPECT_TRUE(e.matched);
-    EXPECT_FALSE(e.errored);
-    auto* const_ = e.value->As<ast::Const>();
-    ASSERT_NE(const_, nullptr);
-
-    EXPECT_EQ(const_->symbol, p->builder().Symbols().Get("a"));
-    EXPECT_EQ(const_->type, nullptr);
-
-    EXPECT_EQ(const_->source.range.begin.line, 1u);
-    EXPECT_EQ(const_->source.range.begin.column, 5u);
-    EXPECT_EQ(const_->source.range.end.line, 1u);
-    EXPECT_EQ(const_->source.range.end.column, 6u);
-
-    ASSERT_NE(const_->initializer, nullptr);
-    EXPECT_TRUE(const_->initializer->Is<ast::LiteralExpression>());
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_InvalidExpression) {
-    auto p = parser("let a : f32 = if (a) {}");
-    auto attrs = p->attribute_list();
-    EXPECT_FALSE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    auto e = p->global_constant_decl(attrs.value);
     EXPECT_TRUE(p->has_error());
-    EXPECT_TRUE(e.errored);
     EXPECT_FALSE(e.matched);
-    EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(
-        p->error(),
-        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:15: missing initializer for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalLetDecl_MissingExpression) {
-    auto p = parser("let a : f32 =");
-    auto attrs = p->attribute_list();
-    EXPECT_FALSE(attrs.errored);
-    EXPECT_FALSE(attrs.matched);
-    auto e = p->global_constant_decl(attrs.value);
-    EXPECT_TRUE(p->has_error());
     EXPECT_TRUE(e.errored);
-    EXPECT_FALSE(e.matched);
-    EXPECT_EQ(e.value, nullptr);
-    EXPECT_EQ(
-        p->error(),
-        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:14: missing initializer for 'let' declaration)");
+    EXPECT_EQ(p->error(), "1:1: module-scope 'let' is invalid, use 'const'");
 }
 
 TEST_F(ParserImplTest, GlobalConstDecl) {
diff --git a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index 6c943c8..2f124d5 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -58,44 +58,11 @@
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalLet) {
     auto p = parser("let a : i32 = 2;");
-    p->global_decl();
-    ASSERT_FALSE(p->has_error()) << p->error();
-
-    auto program = p->program();
-    ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
-
-    auto* v = program.AST().GlobalVariables()[0];
-    EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingInitializer) {
-    auto p = parser("let a : vec2<i32>;");
-    p->global_decl();
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(
-        p->error(),
-        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:18: expected '=' for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_Invalid) {
-    auto p = parser("let a : vec2<i32> 1.0;");
-    p->global_decl();
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(
-        p->error(),
-        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:19: expected '=' for 'let' declaration)");
-}
-
-TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingSemicolon) {
-    auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
-    p->global_decl();
-    ASSERT_TRUE(p->has_error());
-    EXPECT_EQ(
-        p->error(),
-        R"(1:1: use of deprecated language feature: module-scope 'let' has been replaced with 'const'
-1:36: expected ';' for 'const' declaration)");
+    auto e = p->global_decl();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:1: module-scope 'let' is invalid, use 'const'");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/transform/single_entry_point_test.cc
index 7451090..e9fa68f 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/transform/single_entry_point_test.cc
@@ -240,32 +240,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(SingleEntryPointTest, WorkgroupSizeLetPreserved) {
-    auto* src = R"(
-let size : i32 = 1;
-
-@compute @workgroup_size(size)
-fn main() {
-}
-)";
-
-    auto* expect = R"(
-const size : i32 = 1;
-
-@compute @workgroup_size(size)
-fn main() {
-}
-)";
-
-    SingleEntryPoint::Config cfg("main");
-
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(SingleEntryPointTest, WorkgroupSizeConstPreserved) {
     auto* src = R"(
 const size : i32 = 1;
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/transform/unshadow_test.cc
index f5a8102..c731e76 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/transform/unshadow_test.cc
@@ -384,82 +384,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(UnshadowTest, LocalShadowsGlobalLet) {
-    auto* src = R"(
-let a : i32 = 1;
-
-fn X() {
-  var a = (a == 123);
-}
-
-fn Y() {
-  let a = (a == 321);
-}
-
-fn Z() {
-  const a = 321;
-}
-)";
-
-    auto* expect = R"(
-const a : i32 = 1;
-
-fn X() {
-  var a_1 = (a == 123);
-}
-
-fn Y() {
-  let a_2 = (a == 321);
-}
-
-fn Z() {
-  const a_3 = 321;
-}
-)";
-
-    auto got = Run<Unshadow>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(UnshadowTest, LocalShadowsGlobalLet_OutOfOrder) {
-    auto* src = R"(
-fn X() {
-  var a = (a == 123);
-}
-
-fn Y() {
-  let a = (a == 321);
-}
-
-fn Z() {
-  const a = 321;
-}
-
-let a : i32 = 1;
-)";
-
-    auto* expect = R"(
-fn X() {
-  var a_1 = (a == 123);
-}
-
-fn Y() {
-  let a_2 = (a == 321);
-}
-
-fn Z() {
-  const a_3 = 321;
-}
-
-const a : i32 = 1;
-)";
-
-    auto got = Run<Unshadow>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(UnshadowTest, LocalShadowsGlobalConst) {
     auto* src = R"(
 const a : i32 = 1;
@@ -732,46 +656,6 @@
     EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(UnshadowTest, ParamShadowsGlobalLet) {
-    auto* src = R"(
-let a : i32 = 1;
-
-fn F(a : bool) {
-}
-)";
-
-    auto* expect = R"(
-const a : i32 = 1;
-
-fn F(a_1 : bool) {
-}
-)";
-
-    auto got = Run<Unshadow>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
-TEST_F(UnshadowTest, ParamShadowsGlobalLet_OutOfOrder) {
-    auto* src = R"(
-fn F(a : bool) {
-}
-
-let a : i32 = 1;
-)";
-
-    auto* expect = R"(
-fn F(a_1 : bool) {
-}
-
-const a : i32 = 1;
-)";
-
-    auto got = Run<Unshadow>(src);
-
-    EXPECT_EQ(expect, str(got));
-}
-
 TEST_F(UnshadowTest, ParamShadowsGlobalConst) {
     auto* src = R"(
 const a : i32 = 1;
diff --git a/test/tint/benchmark/shadow-fragment.wgsl b/test/tint/benchmark/shadow-fragment.wgsl
index c2da838..53a3d57 100644
--- a/test/tint/benchmark/shadow-fragment.wgsl
+++ b/test/tint/benchmark/shadow-fragment.wgsl
@@ -1,4 +1,4 @@
-let shadowDepthTextureSize : f32 = 1024.0;
+const shadowDepthTextureSize : f32 = 1024.0;
 
 struct Scene {
   lightViewProjMatrix : mat4x4<f32>,