writer/wgsl: Add paren around LHS of member accessors

When the LHS type is not one of the common expression types

Fixes operator precedence issues around pointers and member accesses.

Change-Id: I81b01c0c1050d087d5d68a93d15a66ee14b2fed6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51365
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index a9607b2..45a77b8 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -155,9 +155,20 @@
 }
 
 bool GeneratorImpl::EmitMemberAccessor(ast::MemberAccessorExpression* expr) {
+  bool paren_lhs =
+      !expr->structure()
+           ->IsAnyOf<ast::ArrayAccessorExpression, ast::CallExpression,
+                     ast::IdentifierExpression, ast::MemberAccessorExpression,
+                     ast::TypeConstructorExpression>();
+  if (paren_lhs) {
+    out_ << "(";
+  }
   if (!EmitExpression(expr->structure())) {
     return false;
   }
+  if (paren_lhs) {
+    out_ << ")";
+  }
 
   out_ << ".";
 
diff --git a/src/writer/wgsl/generator_impl_member_accessor_test.cc b/src/writer/wgsl/generator_impl_member_accessor_test.cc
index 1a28011..03fccc6 100644
--- a/src/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -34,6 +34,20 @@
   EXPECT_EQ(gen.result(), "str.mem");
 }
 
+TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor_OfDref) {
+  auto* s = Structure("Data", {Member("mem", ty.f32())});
+  Global("str", s, ast::StorageClass::kPrivate);
+
+  auto* p = Const("p", nullptr, AddressOf("str"));
+  auto* expr = MemberAccessor(Deref("p"), "mem");
+  WrapInFunction(p, expr);
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitExpression(expr)) << gen.error();
+  EXPECT_EQ(gen.result(), "(*(p)).mem");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace writer