Add WGSL support for indexed-swizzle lvalues.

Assignments like `vec.wzyx[r] = value;` are not natively supported
by WGSL, since `vec.wzyx` is not an lvalue in WGSL.
However, we already had a transform pass for these for use in
SPIR-V and Raster Pipeline. WGSL now uses this transform as well.

This change exposed a subtle long-standing issue--the Context
used in a CodeGenerator, by default, was missing various fields,
such as a ProgramConfig. They were missing because the front-end
moves them from the Context into the Program at the end of
compilation, but occasionally the back-end needs to create new IR,
and while assembling IR, we expect these fields to be populated.
e.g. this would cause checks like `type->isAllowedInES2()` to fail
when inside the backend, because the "strict ES2" flag is stored
inside the ProgramConfig.

The CodeGenerator base class now assembles a fully-populated
Context during construction. This mirrors a very similar fix
which was needed in SkRP codegen: http://review.skia.org/656437

Change-Id: Ia4670aba2f9fdccc484c96cccb656feb09926e9f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/706522
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index b6cbda2..8a51c77 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -426,6 +426,8 @@
   "shared/PrefixExpressionsES3.sksl",
   "shared/StructArrayFollowedByScalar.sksl",
   "shared/Structs.sksl",
+  "shared/SwizzleIndexLookup.sksl",
+  "shared/SwizzleIndexStore.sksl",
   "shared/TernaryComplexNesting.sksl",
   "shared/TernaryExpression.sksl",
   "shared/TernaryNesting.sksl",
diff --git a/resources/sksl/BUILD.bazel b/resources/sksl/BUILD.bazel
index 290f70f..fcc6177 100644
--- a/resources/sksl/BUILD.bazel
+++ b/resources/sksl/BUILD.bazel
@@ -1104,6 +1104,8 @@
         "shared/PrefixExpressionsES3.sksl",
         "shared/StructArrayFollowedByScalar.sksl",
         "shared/Structs.sksl",
+        "shared/SwizzleIndexLookup.sksl",
+        "shared/SwizzleIndexStore.sksl",
         "shared/TernaryComplexNesting.sksl",
         "shared/TernaryExpression.sksl",
         "shared/TernaryNesting.sksl",
diff --git a/src/sksl/codegen/SkSLCodeGenerator.h b/src/sksl/codegen/SkSLCodeGenerator.h
index fd58648..14a6bd5 100644
--- a/src/sksl/codegen/SkSLCodeGenerator.h
+++ b/src/sksl/codegen/SkSLCodeGenerator.h
@@ -8,6 +8,8 @@
 #ifndef SKSL_CODEGENERATOR
 #define SKSL_CODEGENERATOR
 
+#include "src/sksl/SkSLContext.h"
+#include "src/sksl/SkSLModifiersPool.h"
 #include "src/sksl/SkSLOutputStream.h"
 #include "src/sksl/ir/SkSLProgram.h"
 
@@ -19,12 +21,19 @@
  */
 class CodeGenerator {
 public:
-    CodeGenerator(const Context* context, const Program* program, OutputStream* out)
-    : fContext(*context)
-    , fProgram(*program)
-    , fOut(out) {}
+    CodeGenerator(const Context* context, const Program* program, OutputStream* stream)
+            : fProgram(*program)
+            , fContext(fProgram.fContext->fTypes,
+                       fProgram.fContext->fCaps,
+                       *fProgram.fContext->fErrors)
+            , fOut(stream) {
+        fContext.fModifiersPool = &fModifiersPool;
+        fContext.fConfig = fProgram.fConfig.get();
+        fContext.fModule = fProgram.fContext->fModule;
+        fContext.fSymbolTable = fProgram.fSymbols;
+    }
 
-    virtual ~CodeGenerator() {}
+    virtual ~CodeGenerator() = default;
 
     virtual bool generateCode() = 0;
 
@@ -48,8 +57,9 @@
     static constexpr float kSharpenTexturesBias = -.475f;
 #endif
 
-    const Context& fContext;
     const Program& fProgram;
+    Context fContext;
+    ModifiersPool fModifiersPool;
     OutputStream* fOut;
 };
 
diff --git a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
index d53a05d..043d487 100644
--- a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
@@ -60,6 +60,7 @@
 #include "src/sksl/ir/SkSLVarDeclarations.h"
 #include "src/sksl/ir/SkSLVariable.h"
 #include "src/sksl/ir/SkSLVariableReference.h"
+#include "src/sksl/transform/SkSLTransform.h"
 
 #include <algorithm>
 #include <cstddef>
@@ -995,7 +996,13 @@
     if (e.is<IndexExpression>()) {
         const IndexExpression& idx = e.as<IndexExpression>();
         if (idx.base()->type().isVector()) {
-            return std::make_unique<VectorComponentLValue>(this->assembleIndexExpression(idx));
+            if (std::unique_ptr<Expression> rewrite =
+                        Transform::RewriteIndexedSwizzle(fContext, idx)) {
+                return std::make_unique<VectorComponentLValue>(
+                        this->assembleExpression(*rewrite, Precedence::kAssignment));
+            } else {
+                return std::make_unique<VectorComponentLValue>(this->assembleIndexExpression(idx));
+            }
         } else {
             return std::make_unique<PointerLValue>(this->assembleIndexExpression(idx));
         }
diff --git a/tests/sksl/shared/SwizzleIndexLookup.wgsl b/tests/sksl/shared/SwizzleIndexLookup.wgsl
new file mode 100644
index 0000000..dd45d38
--- /dev/null
+++ b/tests/sksl/shared/SwizzleIndexLookup.wgsl
@@ -0,0 +1,114 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+struct _GlobalUniforms {
+    colorGreen: vec4<f32>,
+    colorRed: vec4<f32>,
+    testMatrix3x3: mat3x3<f32>,
+    testMatrix4x4: mat4x4<f32>,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+fn test3x3_b() -> bool {
+    var expected: vec3<f32> = vec3<f32>(3.0, 2.0, 1.0);
+    {
+        var c: i32 = 0;
+        loop {
+            if c < 3 {
+                {
+                    var vec: vec3<f32> = _globalUniforms.testMatrix3x3[c];
+                    {
+                        var r: i32 = 0;
+                        loop {
+                            if r < 3 {
+                                {
+                                    if (vec.zyx[r] != expected[r]) {
+                                        {
+                                            return false;
+                                        }
+                                    }
+                                }
+                            } else {
+                                break;
+                            }
+                            continuing {
+                                r = r + i32(1);
+                            }
+                        }
+                    }
+                    expected = expected + 3.0;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                c = c + i32(1);
+            }
+        }
+    }
+    return true;
+}
+fn test4x4_b() -> bool {
+    var expected: vec4<f32> = vec4<f32>(4.0, 3.0, 2.0, 1.0);
+    {
+        var c: i32 = 0;
+        loop {
+            if c < 4 {
+                {
+                    var vec: vec4<f32> = _globalUniforms.testMatrix4x4[c];
+                    {
+                        var r: i32 = 0;
+                        loop {
+                            if r < 4 {
+                                {
+                                    if (vec.wzyx[r] != expected[r]) {
+                                        {
+                                            return false;
+                                        }
+                                    }
+                                }
+                            } else {
+                                break;
+                            }
+                            continuing {
+                                r = r + i32(1);
+                            }
+                        }
+                    }
+                    expected = expected + 4.0;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                c = c + i32(1);
+            }
+        }
+    }
+    return true;
+}
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var _skTemp0: vec4<f32>;
+    var _skTemp1: bool;
+    let _skTemp2 = test3x3_b();
+    if _skTemp2 {
+        let _skTemp3 = test4x4_b();
+        _skTemp1 = _skTemp3;
+    } else {
+        _skTemp1 = false;
+    }
+    if _skTemp1 {
+        _skTemp0 = _globalUniforms.colorGreen;
+    } else {
+        _skTemp0 = _globalUniforms.colorRed;
+    }
+    return _skTemp0;
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}
diff --git a/tests/sksl/shared/SwizzleIndexStore.wgsl b/tests/sksl/shared/SwizzleIndexStore.wgsl
new file mode 100644
index 0000000..370c0fc
--- /dev/null
+++ b/tests/sksl/shared/SwizzleIndexStore.wgsl
@@ -0,0 +1,118 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+struct _GlobalUniforms {
+    colorGreen: vec4<f32>,
+    colorRed: vec4<f32>,
+    testMatrix3x3: mat3x3<f32>,
+    testMatrix4x4: mat4x4<f32>,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+fn test3x3_b() -> bool {
+    var expected: vec3<f32> = vec3<f32>(3.0, 2.0, 1.0);
+    var vec: vec3<f32>;
+    {
+        var c: i32 = 0;
+        loop {
+            if c < 3 {
+                {
+                    {
+                        var r: i32 = 0;
+                        loop {
+                            if r < 3 {
+                                {
+                                    let _skTemp0 = vec3<i32>(2, 1, 0)[r];
+                                    vec[_skTemp0] = _globalUniforms.testMatrix3x3[c][r];
+                                }
+                            } else {
+                                break;
+                            }
+                            continuing {
+                                r = r + i32(1);
+                            }
+                        }
+                    }
+                    if (any(vec != expected)) {
+                        {
+                            return false;
+                        }
+                    }
+                    expected = expected + 3.0;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                c = c + i32(1);
+            }
+        }
+    }
+    return true;
+}
+fn test4x4_b() -> bool {
+    var expected: vec4<f32> = vec4<f32>(4.0, 3.0, 2.0, 1.0);
+    var vec: vec4<f32>;
+    {
+        var c: i32 = 0;
+        loop {
+            if c < 4 {
+                {
+                    {
+                        var r: i32 = 0;
+                        loop {
+                            if r < 4 {
+                                {
+                                    let _skTemp1 = vec4<i32>(3, 2, 1, 0)[r];
+                                    vec[_skTemp1] = _globalUniforms.testMatrix4x4[c][r];
+                                }
+                            } else {
+                                break;
+                            }
+                            continuing {
+                                r = r + i32(1);
+                            }
+                        }
+                    }
+                    if (any(vec != expected)) {
+                        {
+                            return false;
+                        }
+                    }
+                    expected = expected + 4.0;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                c = c + i32(1);
+            }
+        }
+    }
+    return true;
+}
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var _skTemp2: vec4<f32>;
+    var _skTemp3: bool;
+    let _skTemp4 = test3x3_b();
+    if _skTemp4 {
+        let _skTemp5 = test4x4_b();
+        _skTemp3 = _skTemp5;
+    } else {
+        _skTemp3 = false;
+    }
+    if _skTemp3 {
+        _skTemp2 = _globalUniforms.colorGreen;
+    } else {
+        _skTemp2 = _globalUniforms.colorRed;
+    }
+    return _skTemp2;
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}