Add unit tests for assignment and invalid field access.

Change-Id: I8b755ae0078d6353e24834cd15603091d681114c
Bug: skia:10766
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319698
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 0f81684..fdf6618 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -69,6 +69,7 @@
   "$_tests/sksl/errors/ArgumentModifiers.sksl",
   "$_tests/sksl/errors/AssignmentTypeMismatch.sksl",
   "$_tests/sksl/errors/BadCaps.sksl",
+  "$_tests/sksl/errors/BadFieldAccess.sksl",
   "$_tests/sksl/errors/BadIndex.sksl",
   "$_tests/sksl/errors/BadModifiers.sksl",
   "$_tests/sksl/errors/BinaryTypeCoercion.sksl",
@@ -145,7 +146,7 @@
   "$_tests/sksl/shared/ArrayConstructors.sksl",
   "$_tests/sksl/shared/ArrayIndexTypes.sksl",
   "$_tests/sksl/shared/ArrayTypes.sksl",
-  "$_tests/sksl/shared/AssignmentTypeMatch.sksl",
+  "$_tests/sksl/shared/Assignment.sksl",
   "$_tests/sksl/shared/BoolFolding.sksl",
   "$_tests/sksl/shared/Caps.sksl",
   "$_tests/sksl/shared/CastsRoundTowardZero.sksl",
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index f92c6b3..68802c8 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -2483,7 +2483,7 @@
         }
     }
     fErrors.error(base->fOffset, "type '" + baseType.displayName() + "' does not have a field "
-                                 "named '" + field + "");
+                                 "named '" + field + "'");
     return nullptr;
 }
 
diff --git a/tests/sksl/errors/BadFieldAccess.sksl b/tests/sksl/errors/BadFieldAccess.sksl
new file mode 100644
index 0000000..a4010e8
--- /dev/null
+++ b/tests/sksl/errors/BadFieldAccess.sksl
@@ -0,0 +1,7 @@
+struct S { float f; };
+
+void not_a_field()    { S s; s.missing = 123; }
+void not_a_function() { S s; s.f(); }
+void not_a_bvec()     { S s; s.f = bool3(true); }
+void not_a_struct()   { S s; s.f.missing; }
+void not_an_array()   { S s; s.f[0]; }
diff --git a/tests/sksl/errors/golden/BadFieldAccess.glsl b/tests/sksl/errors/golden/BadFieldAccess.glsl
new file mode 100644
index 0000000..9c13c2b
--- /dev/null
+++ b/tests/sksl/errors/golden/BadFieldAccess.glsl
@@ -0,0 +1,8 @@
+### Compilation failed:
+
+error: 3: type 'S' does not have a field named 'missing'
+error: 4: not a function
+error: 5: type mismatch: '=' cannot operate on 'float', 'bool3'
+error: 6: too many components in swizzle mask 'missing'
+error: 7: expected array, but found 'float'
+5 errors
diff --git a/tests/sksl/shared/Assignment.sksl b/tests/sksl/shared/Assignment.sksl
new file mode 100644
index 0000000..136e822
--- /dev/null
+++ b/tests/sksl/shared/Assignment.sksl
@@ -0,0 +1,41 @@
+struct S  {
+    float f;
+    float af[5];
+    half4 h4;
+    half4 ah4[5];
+};
+
+void main() {
+    /* assign to scalar */               int i; i = 0;
+    /* assign to vector */               int4 i4; i4 = int4(1,2,3,4);
+    /* assign to matrix */               float3x3 f3x3; f3x3 = float3x3(1,2,3,4,5,6,7,8,9);
+    /* assign to swizzle */              half4 x; x.w = 0; x.yx = half2(0);
+    /* assign to array of scalar */      int ai[1]; ai[0] = 0;
+    /* assign to array of vector */      int4 ai4[1]; ai4[0] = int4(1,2,3,4);
+    /* assign to array of matrix */      half2x4 ah2x4[1]; ah2x4[0] = half2x4(1,2,3,4,5,6,7,8);
+    /* assign to array idx by lookup */  ai[0] = 0; ai[ai[0]] = 0;
+    /* assign to array swizzle */        float4 af4[1]; af4[0].x = 0; af4[0].ywxz = float4(1);
+    /* assign to struct variable */      S s; s.f = 0;
+    /* assign to struct array */         s.af[1] = 0;
+    /* assign to struct swizzle */       s.h4.zxy = half3(9);
+    /* assign to struct array swizzle */ s.ah4[2].yw = half2(5);
+
+// Not allowed natively in GLSL, but SkSL will turn these into valid GLSL expressions.
+    /* assign to folded ternary */       float l; float r; (true ? l : r) = 0;
+    /* assign to unary plus */           +s.f = 1; +s.af[0] = 2;
+                                         +s.h4 = half4(1); +s.ah4[0] = half4(2);
+
+    sk_FragColor = half(i).xxxx;
+    sk_FragColor = half4(i4);
+    sk_FragColor = half4(f3x3[0].xxyz);
+    sk_FragColor = x;
+    sk_FragColor = half(ai[0]).xxxx;
+    sk_FragColor = half4(ai4[0]);
+    sk_FragColor = ah2x4[0][0];
+    sk_FragColor = half4(af4[0]);
+    sk_FragColor = half(l).xxxx;
+    sk_FragColor = half(s.f).xxxx;
+    sk_FragColor = half(s.af[1]).xxxx;
+    sk_FragColor = s.h4;
+    sk_FragColor = s.ah4[0];
+}
diff --git a/tests/sksl/shared/AssignmentTypeMatch.sksl b/tests/sksl/shared/AssignmentTypeMatch.sksl
deleted file mode 100644
index 5aff659..0000000
--- a/tests/sksl/shared/AssignmentTypeMatch.sksl
+++ /dev/null
@@ -1 +0,0 @@
-void main() { float3 x = float3(0); x *= 1.0; }
diff --git a/tests/sksl/shared/golden/Assignment.glsl b/tests/sksl/shared/golden/Assignment.glsl
new file mode 100644
index 0000000..7acbcfe
--- /dev/null
+++ b/tests/sksl/shared/golden/Assignment.glsl
@@ -0,0 +1,45 @@
+
+out vec4 sk_FragColor;
+void main() {
+    vec4 x;
+    x.w = 0.0;
+    x.yx = vec2(0.0);
+    int ai[1];
+    ai[0] = 0;
+    ivec4 ai4[1];
+    ai4[0] = ivec4(1, 2, 3, 4);
+    mat2x4 ah2x4[1];
+    ah2x4[0] = mat2x4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
+    ai[0] = 0;
+    ai[ai[0]] = 0;
+    vec4 af4[1];
+    af4[0].x = 0.0;
+    af4[0].ywxz = vec4(1.0);
+    struct S {
+        float f;
+        float[5] af;
+        vec4 h4;
+        vec4[5] ah4;
+    } s;
+    s.f = 0.0;
+    s.af[1] = 0.0;
+    s.h4.zxy = vec3(9.0);
+    s.ah4[2].yw = vec2(5.0);
+    s.f = 1.0;
+    s.af[0] = 2.0;
+    s.h4 = vec4(1.0);
+    s.ah4[0] = vec4(2.0);
+    sk_FragColor = vec4(0.0);
+    sk_FragColor = vec4(ivec4(1, 2, 3, 4));
+    sk_FragColor = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)[0].xxyz;
+    sk_FragColor = x;
+    sk_FragColor = vec4(float(ai[0]));
+    sk_FragColor = vec4(ai4[0]);
+    sk_FragColor = ah2x4[0][0];
+    sk_FragColor = af4[0];
+    sk_FragColor = vec4(0.0);
+    sk_FragColor = vec4(s.f);
+    sk_FragColor = vec4(s.af[1]);
+    sk_FragColor = s.h4;
+    sk_FragColor = s.ah4[0];
+}
diff --git a/tests/sksl/shared/golden/Assignment.metal b/tests/sksl/shared/golden/Assignment.metal
new file mode 100644
index 0000000..d95a221
--- /dev/null
+++ b/tests/sksl/shared/golden/Assignment.metal
@@ -0,0 +1,54 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+using namespace metal;
+struct Inputs {
+};
+struct Outputs {
+    float4 sk_FragColor [[color(0)]];
+};
+fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+    Outputs _outputStruct;
+    thread Outputs* _out = &_outputStruct;
+    float4 x;
+    x.w = 0.0;
+    x.yx = float2(0.0);
+    int ai[1];
+    ai[0] = 0;
+    int4 ai4[1];
+    ai4[0] = int4(1, 2, 3, 4);
+    float2x4 ah2x4[1];
+    ah2x4[0] = float2x4(float4(1.0, 2.0, 3.0, 4.0), float4(5.0, 6.0, 7.0, 8.0));
+    ai[0] = 0;
+    ai[ai[0]] = 0;
+    float4 af4[1];
+    af4[0].x = 0.0;
+    af4[0].ywxz = float4(1.0);
+    struct S {
+        float f;
+        float af[5];
+        float4 h4;
+        float4 ah4[5];
+    } s;
+    s.f = 0.0;
+    s.af[1] = 0.0;
+    s.h4.zxy = float3(9.0);
+    s.ah4[2].yw = float2(5.0);
+    s.f = 1.0;
+    s.af[0] = 2.0;
+    s.h4 = float4(1.0);
+    s.ah4[0] = float4(2.0);
+    _out->sk_FragColor = float4(0.0);
+    _out->sk_FragColor = float4(int4(1, 2, 3, 4));
+    _out->sk_FragColor = float3x3(float3(1.0, 2.0, 3.0), float3(4.0, 5.0, 6.0), float3(7.0, 8.0, 9.0))[0].xxyz;
+    _out->sk_FragColor = x;
+    _out->sk_FragColor = float4(float(ai[0]));
+    _out->sk_FragColor = float4(ai4[0]);
+    _out->sk_FragColor = ah2x4[0][0];
+    _out->sk_FragColor = af4[0];
+    _out->sk_FragColor = float4(0.0);
+    _out->sk_FragColor = float4(s.f);
+    _out->sk_FragColor = float4(s.af[1]);
+    _out->sk_FragColor = s.h4;
+    _out->sk_FragColor = s.ah4[0];
+    return *_out;
+}
diff --git a/tests/sksl/shared/golden/AssignmentTypeMatch.glsl b/tests/sksl/shared/golden/AssignmentTypeMatch.glsl
deleted file mode 100644
index 2933520..0000000
--- a/tests/sksl/shared/golden/AssignmentTypeMatch.glsl
+++ /dev/null
@@ -1,3 +0,0 @@
-
-void main() {
-}
diff --git a/tests/sksl/shared/golden/AssignmentTypeMatch.metal b/tests/sksl/shared/golden/AssignmentTypeMatch.metal
deleted file mode 100644
index c18cef3..0000000
--- a/tests/sksl/shared/golden/AssignmentTypeMatch.metal
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <metal_stdlib>
-#include <simd/simd.h>
-using namespace metal;
-struct Inputs {
-};
-struct Outputs {
-    float4 sk_FragColor [[color(0)]];
-};
-fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
-    Outputs _outputStruct;
-    thread Outputs* _out = &_outputStruct;
-    return *_out;
-}