Add Convert/Make factory functions to FieldAccess.

Change-Id: Ib1f5296c017374b833654f988ff89d11d8f78b4d
Bug: skia:11342
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/380458
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index ade9b3f..0f174d4 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -821,12 +821,12 @@
                                                    VariableReference::RefKind::kWrite);
     };
     auto Field = [&](const Variable* var, int idx) -> std::unique_ptr<Expression> {
-        return std::make_unique<FieldAccess>(Ref(var), idx,
-                                             FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
+        return FieldAccess::Make(fContext, Ref(var), idx,
+                                 FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
     };
     auto Pos = [&]() -> std::unique_ptr<Expression> {
-        return std::make_unique<FieldAccess>(WRef(skPerVertex), 0,
-                                             FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
+        return FieldAccess::Make(fContext, WRef(skPerVertex), 0,
+                                 FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
     };
     auto Adjust = [&]() -> std::unique_ptr<Expression> {
         return fRTAdjustInterfaceBlock ? Field(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex)
@@ -1577,9 +1577,8 @@
             const Field* field = &result->as<Field>();
             auto base = std::make_unique<VariableReference>(offset, &field->owner(),
                                                             VariableReference::RefKind::kRead);
-            return std::make_unique<FieldAccess>(std::move(base),
-                                                 field->fieldIndex(),
-                                                 FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
+            return FieldAccess::Make(fContext, std::move(base), field->fieldIndex(),
+                                     FieldAccess::OwnerKind::kAnonymousInterfaceBlock);
         }
         case Symbol::Kind::kType: {
             const Type* t = &result->as<Type>();
@@ -1837,21 +1836,6 @@
     return PrefixExpression::Convert(fContext, expression.getOperator(), std::move(base));
 }
 
-std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base,
-                                                      StringFragment field) {
-    const Type& baseType = base->type();
-    auto fields = baseType.fields();
-    for (size_t i = 0; i < fields.size(); i++) {
-        if (fields[i].fName == field) {
-            return std::unique_ptr<Expression>(new FieldAccess(std::move(base), (int) i));
-        }
-    }
-    this->errorReporter().error(
-            base->fOffset,
-            "type '" + baseType.displayName() + "' does not have a field named '" + field + "'");
-    return nullptr;
-}
-
 // Swizzles are complicated due to constant components. The most difficult case is a mask like
 // '.x1w0'. A naive approach might turn that into 'float4(base.x, 1, base.w, 0)', but that evaluates
 // 'base' twice. We instead group the swizzle mask ('xw') and constants ('1, 0') together and use a
@@ -2045,12 +2029,10 @@
     if (baseType == *fContext.fTypes.fSkCaps) {
         return Setting::Convert(fContext, fieldNode.fOffset, field);
     }
-    switch (baseType.typeKind()) {
-        case Type::TypeKind::kStruct:
-            return this->convertField(std::move(base), field);
-        default:
-            return this->convertSwizzle(std::move(base), field);
+    if (baseType.isStruct()) {
+        return FieldAccess::Convert(fContext, std::move(base), field);
     }
+    return this->convertSwizzle(std::move(base), field);
 }
 
 std::unique_ptr<Expression> IRGenerator::convertScopeExpression(const ASTNode& scopeNode) {
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index 6d32357..9c67af0 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -345,7 +345,7 @@
             return expression.clone();
         case Expression::Kind::kFieldAccess: {
             const FieldAccess& f = expression.as<FieldAccess>();
-            return std::make_unique<FieldAccess>(expr(f.base()), f.fieldIndex(), f.ownerKind());
+            return FieldAccess::Make(*fContext, expr(f.base()), f.fieldIndex(), f.ownerKind());
         }
         case Expression::Kind::kFunctionCall: {
             const FunctionCall& funcCall = expression.as<FunctionCall>();
diff --git a/src/sksl/SkSLRehydrator.cpp b/src/sksl/SkSLRehydrator.cpp
index 107fd7c..8007c92 100644
--- a/src/sksl/SkSLRehydrator.cpp
+++ b/src/sksl/SkSLRehydrator.cpp
@@ -469,7 +469,7 @@
             std::unique_ptr<Expression> base = this->expression();
             int index = this->readU8();
             FieldAccess::OwnerKind ownerKind = (FieldAccess::OwnerKind) this->readU8();
-            return std::make_unique<FieldAccess>(std::move(base), index, ownerKind);
+            return FieldAccess::Make(fContext, std::move(base), index, ownerKind);
         }
         case Rehydrator::kFloatLiteral_Command: {
             const Type* type = this->type();
diff --git a/src/sksl/dsl/priv/DSLWriter.cpp b/src/sksl/dsl/priv/DSLWriter.cpp
index c4a7f0b..7d5bd8b 100644
--- a/src/sksl/dsl/priv/DSLWriter.cpp
+++ b/src/sksl/dsl/priv/DSLWriter.cpp
@@ -135,7 +135,7 @@
 
 std::unique_ptr<SkSL::Expression> DSLWriter::ConvertField(std::unique_ptr<Expression> base,
                                                           const char* name) {
-    return IRGenerator().convertField(std::move(base), name);
+    return FieldAccess::Convert(Context(), std::move(base), name);
 }
 
 std::unique_ptr<SkSL::Expression> DSLWriter::ConvertIndex(std::unique_ptr<Expression> base,
diff --git a/src/sksl/ir/SkSLFieldAccess.cpp b/src/sksl/ir/SkSLFieldAccess.cpp
new file mode 100644
index 0000000..3be4ca1
--- /dev/null
+++ b/src/sksl/ir/SkSLFieldAccess.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/sksl/SkSLContext.h"
+#include "src/sksl/ir/SkSLFieldAccess.h"
+
+namespace SkSL {
+
+std::unique_ptr<Expression> FieldAccess::Convert(const Context& context,
+                                                 std::unique_ptr<Expression> base,
+                                                 StringFragment field) {
+    const Type& baseType = base->type();
+    if (baseType.isStruct()) {
+        const std::vector<Type::Field>& fields = baseType.fields();
+        for (size_t i = 0; i < fields.size(); i++) {
+            if (fields[i].fName == field) {
+                return FieldAccess::Make(context, std::move(base), (int) i);
+            }
+        }
+    }
+
+    context.fErrors.error(base->fOffset, "type '" + baseType.displayName() +
+                                         "' does not have a field named '" + field + "'");
+    return nullptr;
+}
+
+std::unique_ptr<Expression> FieldAccess::Make(const Context& context,
+                                              std::unique_ptr<Expression> base,
+                                              int fieldIndex,
+                                              OwnerKind ownerKind) {
+    SkASSERT(base->type().isStruct());
+    SkASSERT(fieldIndex >= 0);
+    SkASSERT(fieldIndex < (int) base->type().fields().size());
+    return std::make_unique<FieldAccess>(std::move(base), fieldIndex, ownerKind);
+}
+
+}  // namespace SkSL
diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h
index 3291c11..6e9d941 100644
--- a/src/sksl/ir/SkSLFieldAccess.h
+++ b/src/sksl/ir/SkSLFieldAccess.h
@@ -36,6 +36,17 @@
     , fOwnerKind(ownerKind)
     , fBase(std::move(base)) {}
 
+    // Returns a field-access expression; reports errors via the ErrorReporter.
+    static std::unique_ptr<Expression> Convert(const Context& context,
+                                               std::unique_ptr<Expression> base,
+                                               StringFragment field);
+
+    // Returns a field-access expression; reports errors via ASSERT.
+    static std::unique_ptr<Expression> Make(const Context& context,
+                                            std::unique_ptr<Expression> base,
+                                            int fieldIndex,
+                                            OwnerKind ownerKind = OwnerKind::kDefault);
+
     std::unique_ptr<Expression>& base() {
         return fBase;
     }