Remove string_view + string_view concatenation function.

std::string is less permissive than SkSL::String about concatenation.
This change is a step towards eliminating SkSL::String.
(We couldn't continue using this technique for std::string, as it's
undefined behavior to add our own methods inside namespace std.)

Change-Id: I21e421182be23d3033f827758ea2b2c01fa99d26
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/503341
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/include/private/SkSLString.h b/include/private/SkSLString.h
index 6fc6cc8..a3f37e7 100644
--- a/include/private/SkSLString.h
+++ b/include/private/SkSLString.h
@@ -46,8 +46,6 @@
     using INHERITED = std::string;
 };
 
-String operator+(std::string_view left, std::string_view right);
-
 bool stod(std::string_view s, SKSL_FLOAT* value);
 bool stoi(std::string_view s, SKSL_INT* value);
 
diff --git a/src/sksl/SkSLAnalysis.cpp b/src/sksl/SkSLAnalysis.cpp
index 10d8682..d7d787e 100644
--- a/src/sksl/SkSLAnalysis.cpp
+++ b/src/sksl/SkSLAnalysis.cpp
@@ -249,8 +249,8 @@
                 VariableReference& varRef = expr.as<VariableReference>();
                 const Variable* var = varRef.variable();
                 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
-                    fErrors->error(expr.fLine,
-                                   "cannot modify immutable variable '" + var->name() + "'");
+                    fErrors->error(expr.fLine, "cannot modify immutable variable '" +
+                                               SkSL::String(var->name()) + "'");
                 } else {
                     SkASSERT(fAssignedVar == nullptr);
                     fAssignedVar = &varRef;
@@ -373,7 +373,8 @@
     // Report an error.
     SkASSERT(var);
     if (errors) {
-        errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
+        errors->error(stmt.fLine, "variable '" + SkSL::String(var->name()) +
+                                  "' must be created in a scope");
     }
     return true;
 }
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 4666e50..78203a5 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -469,7 +469,7 @@
 std::unique_ptr<Expression> Compiler::convertIdentifier(int line, std::string_view name) {
     const Symbol* result = (*fSymbolTable)[name];
     if (!result) {
-        this->errorReporter().error(line, "unknown identifier '" + name + "'");
+        this->errorReporter().error(line, "unknown identifier '" + SkSL::String(name) + "'");
         return nullptr;
     }
     switch (result->kind()) {
@@ -743,7 +743,7 @@
     if (pos.line() >= 1) {
         fErrorText += skstd::to_string(pos.line()) + ": ";
     }
-    fErrorText += msg + "\n";
+    fErrorText += SkSL::String(msg) + "\n";
 }
 
 String Compiler::errorText(bool showCount) {
diff --git a/src/sksl/SkSLDSLParser.cpp b/src/sksl/SkSLDSLParser.cpp
index 62e1d28..14b4935 100644
--- a/src/sksl/SkSLDSLParser.cpp
+++ b/src/sksl/SkSLDSLParser.cpp
@@ -126,12 +126,13 @@
         // Some tokens are always invalid, so we detect and report them here.
         switch (token.fKind) {
             case Token::Kind::TK_RESERVED:
-                this->error(token, "'" + this->text(token) + "' is a reserved word");
+                this->error(token, "'" + SkSL::String(this->text(token)) + "' is a reserved word");
                 token.fKind = Token::Kind::TK_IDENTIFIER;  // reduces additional follow-up errors
                 break;
 
             case Token::Kind::TK_BAD_OCTAL:
-                this->error(token, "'" + this->text(token) + "' is not a valid octal number");
+                this->error(token, "'" + SkSL::String(this->text(token)) +
+                                   "' is not a valid octal number");
                 break;
 
             default:
@@ -205,7 +206,7 @@
     }
     if (IsBuiltinType(this->text(*result))) {
         this->error(*result, "expected an identifier, but found type '" +
-                             this->text(*result) + "'");
+                             SkSL::String(this->text(*result)) + "'");
         this->fEncounteredFatalError = true;
         return false;
     }
@@ -328,7 +329,7 @@
         // We don't currently do anything different between require, enable, and warn
         dsl::AddExtension(this->text(name));
     } else {
-        this->error(start, "unsupported directive '" + this->text(start) + "'");
+        this->error(start, "unsupported directive '" + SkSL::String(this->text(start)) + "'");
     }
 }
 
@@ -660,7 +661,8 @@
         }
     }
     if (fields.empty()) {
-        this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
+        this->error(name, "struct '" + SkSL::String(this->text(name)) +
+                          "' must contain at least one field");
     }
     return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
 }
@@ -717,7 +719,7 @@
     std::string_view resultFrag = this->text(resultToken);
     SKSL_INT resultValue;
     if (!SkSL::stoi(resultFrag, &resultValue)) {
-        this->error(resultToken, "value in layout is too large: " + resultFrag);
+        this->error(resultToken, "value in layout is too large: " + SkSL::String(resultFrag));
         return -1;
     }
     return resultValue;
@@ -870,7 +872,7 @@
         return skstd::nullopt;
     }
     if (!IsType(this->text(type))) {
-        this->error(type, ("no type named '" + this->text(type) + "'").c_str());
+        this->error(type, ("no type named '" + SkSL::String(this->text(type)) + "'").c_str());
         return skstd::nullopt;
     }
     DSLType result(this->text(type), modifiers, this->position(type));
@@ -897,7 +899,7 @@
         // we only get into interfaceBlock if we found a top-level identifier which was not a type.
         // 99% of the time, the user was not actually intending to create an interface block, so
         // it's better to report it as an unknown type
-        this->error(typeName, "no type named '" + this->text(typeName) + "'");
+        this->error(typeName, "no type named '" + SkSL::String(this->text(typeName)) + "'");
         return false;
     }
     this->nextToken();
@@ -957,7 +959,7 @@
     }
     this->expect(Token::Kind::TK_SEMICOLON, "';'");
     if (fields.empty()) {
-        this->error(typeName, "interface block '" + this->text(typeName) +
+        this->error(typeName, "interface block '" + SkSL::String(this->text(typeName)) +
                               "' must contain at least one member");
     } else {
         dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
@@ -1720,7 +1722,8 @@
             // identifiers that directly follow the float
             Token id = this->nextRawToken();
             if (id.fKind == Token::Kind::TK_IDENTIFIER) {
-                return this->swizzle(next.fLine, std::move(base), field + this->text(id));
+                return this->swizzle(next.fLine, std::move(base),
+                                     SkSL::String(field) + this->text(id));
             } else if (field.empty()) {
                 this->error(next, "expected field name or swizzle mask after '.'");
                 return {{DSLExpression::Poison()}};
@@ -1750,7 +1753,8 @@
         case Token::Kind::TK_MINUSMINUS:
             return std::move(base)--;
         default: {
-            this->error(next,  "expected expression suffix, but found '" + this->text(next) + "'");
+            this->error(next, "expected expression suffix, but found '" +
+                              SkSL::String(this->text(next)) + "'");
             return {};
         }
     }
@@ -1802,7 +1806,7 @@
         }
         default:
             this->nextToken();
-            this->error(t, "expected expression, but found '" + this->text(t) + "'");
+            this->error(t, "expected expression, but found '" + SkSL::String(this->text(t)) + "'");
             fEncounteredFatalError = true;
             break;
     }
@@ -1817,7 +1821,7 @@
     }
     std::string_view s = this->text(t);
     if (!SkSL::stoi(s, dest)) {
-        this->error(t, "integer is too large: " + s);
+        this->error(t, "integer is too large: " + SkSL::String(s));
         return false;
     }
     return true;
@@ -1831,7 +1835,7 @@
     }
     std::string_view s = this->text(t);
     if (!SkSL::stod(s, dest)) {
-        this->error(t, "floating-point value is too large: " + s);
+        this->error(t, "floating-point value is too large: " + SkSL::String(s));
         return false;
     }
     return true;
@@ -1848,7 +1852,8 @@
             *dest = false;
             return true;
         default:
-            this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
+            this->error(t, "expected 'true' or 'false', but found '" +
+                           SkSL::String(this->text(t)) + "'");
             return false;
     }
 }
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index 6fccb25..9f1e445 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -712,7 +712,7 @@
         // Still, discard our output and generate an error.
         SkDEBUGFAIL("inliner found non-void function that fails to return a value on any path");
         fContext->fErrors->error(function.fLine, "inliner found non-void function '" +
-                                                 function.declaration().name() +
+                                                 SkSL::String(function.declaration().name()) +
                                                  "' that fails to return a value on any path");
         inlinedCall = {};
     }
diff --git a/src/sksl/SkSLString.cpp b/src/sksl/SkSLString.cpp
index 5cab6f9..fe236e3 100644
--- a/src/sksl/SkSLString.cpp
+++ b/src/sksl/SkSLString.cpp
@@ -119,9 +119,6 @@
     return result;
 }
 
-String operator+(std::string_view left, std::string_view right) {
-    return String(left) + right;
-}
 
 bool stod(std::string_view s, SKSL_FLOAT* value) {
     std::string str(s.data(), s.size());
diff --git a/src/sksl/analysis/SkSLFinalizationChecks.cpp b/src/sksl/analysis/SkSLFinalizationChecks.cpp
index f47afe2..cab5ddd 100644
--- a/src/sksl/analysis/SkSLFinalizationChecks.cpp
+++ b/src/sksl/analysis/SkSLFinalizationChecks.cpp
@@ -51,8 +51,9 @@
         // To avoid overzealous error reporting, only trigger the error at the first place where the
         // global limit is exceeded.
         if (prevSlotsUsed < kVariableSlotLimit && fGlobalSlotsUsed >= kVariableSlotLimit) {
-            fContext.fErrors->error(decl.fLine, "global variable '" + decl.var().name() +
-                                                "' exceeds the size limit");
+            fContext.fErrors->error(decl.fLine,
+                                    "global variable '" + SkSL::String(decl.var().name()) +
+                                    "' exceeds the size limit");
         }
     }
 
@@ -70,8 +71,9 @@
                 ProgramUsage::VariableCounts counts = fUsage.get(*param);
                 if (counts.fWrite <= 0) {
                     fContext.fErrors->error(funcDecl.fLine,
-                                            "function '" + funcDecl.name() + "' never assigns a "
-                                            "value to out parameter '" + param->name() + "'");
+                                            "function '" + SkSL::String(funcDecl.name()) +
+                                            "' never assigns a value to out parameter '" +
+                                            param->name() + "'");
                 }
             }
         }
diff --git a/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp b/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
index d01ec48..1f53023 100644
--- a/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
@@ -1033,7 +1033,7 @@
         }
         this->writeTypePrecision(*type);
         this->writeType(*type);
-        this->write(" " + param->name());
+        this->write(" " + SkSL::String(param->name()));
         for (int s : sizes) {
             this->write("[" + skstd::to_string(s) + "]");
         }
@@ -1121,7 +1121,7 @@
         return;
     }
     this->writeModifiers(intf.variable().modifiers(), true);
-    this->writeLine(intf.typeName() + " {");
+    this->writeLine(SkSL::String(intf.typeName()) + " {");
     fIndentation++;
     const Type* structType = &intf.variable().type();
     if (structType->isArray()) {
@@ -1131,7 +1131,7 @@
         this->writeModifiers(f.fModifiers, false);
         this->writeTypePrecision(*f.fType);
         this->writeType(*f.fType);
-        this->writeLine(" " + f.fName + ";");
+        this->writeLine(" " + SkSL::String(f.fName) + ";");
     }
     fIndentation--;
     this->write("}");
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
index c9207e2..91ecc41 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
@@ -90,7 +90,7 @@
 }
 
 void MetalCodeGenerator::writeExtension(const Extension& ext) {
-    this->writeLine("#extension " + ext.name() + " : enable");
+    this->writeLine("#extension " + SkSL::String(ext.name()) + " : enable");
 }
 
 String MetalCodeGenerator::typeName(const Type& type) {
@@ -117,7 +117,7 @@
 
 void MetalCodeGenerator::writeStructDefinition(const StructDefinition& s) {
     const Type& type = s.type();
-    this->writeLine("struct " + type.name() + " {");
+    this->writeLine("struct " + type.displayName() + " {");
     fIndentation++;
     this->writeFields(type.fields(), type.fLine);
     fIndentation--;
@@ -1977,7 +1977,7 @@
     }
     this->writeModifiers(intf.variable().modifiers());
     this->write("struct ");
-    this->writeLine(intf.typeName() + " {");
+    this->writeLine(SkSL::String(intf.typeName()) + " {");
     const Type* structType = &intf.variable().type();
     if (structType->isArray()) {
         structType = &structType->componentType();
@@ -1999,8 +1999,8 @@
         }
         fInterfaceBlockNameMap[&intf] = intf.instanceName();
     } else {
-        fInterfaceBlockNameMap[&intf] = *fProgram.fSymbols->takeOwnershipOfString("_anonInterface" +
-                skstd::to_string(fAnonInterfaceCount++));
+        fInterfaceBlockNameMap[&intf] = *fProgram.fSymbols->takeOwnershipOfString(
+                "_anonInterface" + skstd::to_string(fAnonInterfaceCount++));
     }
     this->writeLine(";");
 }
@@ -2013,15 +2013,15 @@
         int fieldOffset = field.fModifiers.fLayout.fOffset;
         const Type* fieldType = field.fType;
         if (!MemoryLayout::LayoutIsSupported(*fieldType)) {
-            fContext.fErrors->error(parentLine, "type '" + fieldType->name() +
+            fContext.fErrors->error(parentLine, "type '" + SkSL::String(fieldType->name()) +
                                                 "' is not permitted here");
             return;
         }
         if (fieldOffset != -1) {
             if (currentOffset > fieldOffset) {
                 fContext.fErrors->error(parentLine,
-                        "offset of field '" + field.fName + "' must be at least " +
-                        skstd::to_string(currentOffset));
+                                        "offset of field '" + SkSL::String(field.fName) +
+                                        "' must be at least " + skstd::to_string(currentOffset));
                 return;
             } else if (currentOffset < fieldOffset) {
                 this->write("char pad");
@@ -2034,8 +2034,8 @@
             int alignment = memoryLayout.alignment(*fieldType);
             if (fieldOffset % alignment) {
                 fContext.fErrors->error(parentLine,
-                        "offset of field '" + field.fName + "' must be a multiple of " +
-                        skstd::to_string(alignment));
+                                        "offset of field '" + SkSL::String(field.fName) +
+                                        "' must be a multiple of " + skstd::to_string(alignment));
                 return;
             }
         }
@@ -2403,7 +2403,7 @@
         if (var.type().typeKind() == Type::TypeKind::kSampler) {
             // Samplers are represented as a "texture/sampler" duo in the global struct.
             visitor->visitTexture(var.type(), var.name());
-            visitor->visitSampler(var.type(), var.name() + SAMPLER_SUFFIX);
+            visitor->visitSampler(var.type(), SkSL::String(var.name()) + SAMPLER_SUFFIX);
             continue;
         }
 
diff --git a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
index 4fdc226..f0ef9d9 100644
--- a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
@@ -465,8 +465,8 @@
     for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
         const Type::Field& field = type.fields()[i];
         if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
-            fContext.fErrors->error(type.fLine, "type '" + field.fType->name() +
-                                    "' is not permitted here");
+            fContext.fErrors->error(type.fLine, "type '" + field.fType->displayName() +
+                                                "' is not permitted here");
             return;
         }
         size_t size = memoryLayout.size(*field.fType);
@@ -475,13 +475,13 @@
         if (fieldLayout.fOffset >= 0) {
             if (fieldLayout.fOffset < (int) offset) {
                 fContext.fErrors->error(type.fLine,
-                                        "offset of field '" + field.fName + "' must be at "
-                                        "least " + skstd::to_string(offset));
+                                        "offset of field '" + SkSL::String(field.fName) +
+                                        "' must be at least " + skstd::to_string(offset));
             }
             if (fieldLayout.fOffset % alignment) {
                 fContext.fErrors->error(type.fLine,
-                                        "offset of field '" + field.fName + "' must be a multiple"
-                                        " of " + skstd::to_string(alignment));
+                                        "offset of field '" + SkSL::String(field.fName) +
+                                        "' must be a multiple of " + skstd::to_string(alignment));
             }
             offset = fieldLayout.fOffset;
         } else {
@@ -569,7 +569,7 @@
         MemoryLayout::Standard otherStd = layout.fStd == MemoryLayout::Standard::k140_Standard
                                                   ? MemoryLayout::Standard::k430_Standard
                                                   : MemoryLayout::Standard::k140_Standard;
-        String otherKey = type->name() + skstd::to_string(otherStd);
+        String otherKey = type->displayName() + skstd::to_string(otherStd);
         SkASSERT(fTypeMap.find(otherKey) == fTypeMap.end());
 #endif
     }
@@ -608,8 +608,8 @@
                 break;
             case Type::TypeKind::kArray: {
                 if (!MemoryLayout::LayoutIsSupported(*type)) {
-                    fContext.fErrors->error(type->fLine,
-                                            "type '" + type->name() + "' is not permitted here");
+                    fContext.fErrors->error(type->fLine, "type '" + type->displayName() +
+                                                         "' is not permitted here");
                     return this->nextId(nullptr);
                 }
                 if (type->columns() > 0) {
@@ -677,7 +677,7 @@
 SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
     SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
     this->getType(type);
-    String key = type.name() + skstd::to_string(fDefaultLayout.fStd);
+    String key = type.displayName() + skstd::to_string(fDefaultLayout.fStd);
     SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
     return fImageTypeMap[key];
 }
@@ -2996,7 +2996,8 @@
     const Variable& intfVar = intf.variable();
     const Type& type = intfVar.type();
     if (!MemoryLayout::LayoutIsSupported(type)) {
-        fContext.fErrors->error(type.fLine, "type '" + type.name() + "' is not permitted here");
+        fContext.fErrors->error(type.fLine, "type '" + type.displayName() +
+                                            "' is not permitted here");
         return this->nextId(nullptr);
     }
     SpvStorageClass_ storageClass = get_storage_class(intf.variable(), SpvStorageClassFunction);
diff --git a/src/sksl/codegen/SkSLVMCodeGenerator.cpp b/src/sksl/codegen/SkSLVMCodeGenerator.cpp
index 7ab2a7f..591d450 100644
--- a/src/sksl/codegen/SkSLVMCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLVMCodeGenerator.cpp
@@ -669,7 +669,7 @@
     const FunctionDeclaration& decl = fn.declaration();
     int fnReturnValue = fDebugTrace ? this->getDebugFunctionInfo(decl) : -1;
 
-    size_t slot = this->createSlot("[" + decl.name() + "].result",
+    size_t slot = this->createSlot("[" + SkSL::String(decl.name()) + "].result",
                                    decl.returnType(),
                                    fn.fLine,
                                    fnReturnValue);
diff --git a/src/sksl/ir/SkSLExtension.h b/src/sksl/ir/SkSLExtension.h
index c795008..ea2baaa 100644
--- a/src/sksl/ir/SkSLExtension.h
+++ b/src/sksl/ir/SkSLExtension.h
@@ -32,7 +32,7 @@
     }
 
     String description() const override {
-        return "#extension " + this->name() + " : enable";
+        return "#extension " + SkSL::String(this->name()) + " : enable";
     }
 
 private:
diff --git a/src/sksl/ir/SkSLFunctionCall.cpp b/src/sksl/ir/SkSLFunctionCall.cpp
index 867331c..300d76d 100644
--- a/src/sksl/ir/SkSLFunctionCall.cpp
+++ b/src/sksl/ir/SkSLFunctionCall.cpp
@@ -886,7 +886,7 @@
             if (best) {
                 return FunctionCall::Convert(context, line, *best, std::move(arguments));
             }
-            String msg = "no match for " + functions[0]->name() + "(";
+            String msg = "no match for " + SkSL::String(functions[0]->name()) + "(";
             String separator;
             for (size_t i = 0; i < arguments.size(); i++) {
                 msg += separator;
@@ -939,7 +939,7 @@
 
     // Reject function calls with the wrong number of arguments.
     if (function.parameters().size() != arguments.size()) {
-        String msg = "call to '" + function.name() + "' expected " +
+        String msg = "call to '" + SkSL::String(function.name()) + "' expected " +
                      skstd::to_string(function.parameters().size()) + " argument";
         if (function.parameters().size() != 1) {
             msg += "s";
@@ -953,7 +953,7 @@
     FunctionDeclaration::ParamTypes types;
     const Type* returnType;
     if (!function.determineFinalTypes(arguments, &types, &returnType)) {
-        String msg = "no match for " + function.name() + "(";
+        String msg = "no match for " + SkSL::String(function.name()) + "(";
         String separator;
         for (const std::unique_ptr<Expression>& arg : arguments) {
             msg += separator;
diff --git a/src/sksl/ir/SkSLFunctionDeclaration.cpp b/src/sksl/ir/SkSLFunctionDeclaration.cpp
index bfb107e..c2c47c9 100644
--- a/src/sksl/ir/SkSLFunctionDeclaration.cpp
+++ b/src/sksl/ir/SkSLFunctionDeclaration.cpp
@@ -307,7 +307,7 @@
                 functions.push_back(&entry->as<FunctionDeclaration>());
                 break;
             default:
-                errors.error(line, "symbol '" + name + "' was already defined");
+                errors.error(line, "symbol '" + SkSL::String(name) + "' was already defined");
                 return false;
         }
         for (const FunctionDeclaration* other : functions) {
@@ -424,7 +424,8 @@
     // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
     const char* splitter = skstd::ends_with(name, '_') ? "x_" : "_";
     // Rename function to `funcname_returntypeparamtypes`.
-    String result = name + splitter + builtinMarker + this->returnType().abbreviatedName();
+    String result = SkSL::String(name) + splitter + builtinMarker +
+                    this->returnType().abbreviatedName();
     for (const Variable* p : this->parameters()) {
         result += p->type().abbreviatedName();
     }
diff --git a/src/sksl/ir/SkSLFunctionDefinition.cpp b/src/sksl/ir/SkSLFunctionDefinition.cpp
index a7566fb..76a0e41 100644
--- a/src/sksl/ir/SkSLFunctionDefinition.cpp
+++ b/src/sksl/ir/SkSLFunctionDefinition.cpp
@@ -154,9 +154,10 @@
                     // To avoid overzealous error reporting, only trigger the error at the first
                     // place where the stack limit is exceeded.
                     if (prevSlotsUsed < kVariableSlotLimit && fSlotsUsed >= kVariableSlotLimit) {
-                        fContext.fErrors->error(stmt.fLine, "variable '" +
-                                                            stmt.as<VarDeclaration>().var().name() +
-                                                            "' exceeds the stack size limit");
+                        fContext.fErrors->error(
+                                stmt.fLine,
+                                "variable '" + SkSL::String(stmt.as<VarDeclaration>().var().name())
+                                + "' exceeds the stack size limit");
                     }
                     break;
                 }
@@ -258,7 +259,7 @@
     }
 
     if (Analysis::CanExitWithoutReturningValue(function, *body)) {
-        context.fErrors->error(function.fLine, "function '" + function.name() +
+        context.fErrors->error(function.fLine, "function '" + SkSL::String(function.name()) +
                                                "' can exit without returning a value");
     }
 
diff --git a/src/sksl/ir/SkSLInterfaceBlock.h b/src/sksl/ir/SkSLInterfaceBlock.h
index 1937248..94932ff 100644
--- a/src/sksl/ir/SkSLInterfaceBlock.h
+++ b/src/sksl/ir/SkSLInterfaceBlock.h
@@ -85,7 +85,7 @@
         }
         result += "}";
         if (!this->instanceName().empty()) {
-            result += " " + this->instanceName();
+            result += " " + SkSL::String(this->instanceName());
             if (this->arraySize() > 0) {
                 String::appendf(&result, "[%d]", this->arraySize());
             }
diff --git a/src/sksl/ir/SkSLSetting.cpp b/src/sksl/ir/SkSLSetting.cpp
index f1370ef..25f717f 100644
--- a/src/sksl/ir/SkSLSetting.cpp
+++ b/src/sksl/ir/SkSLSetting.cpp
@@ -109,7 +109,7 @@
         return caps->type(context);
     }
 
-    context.fErrors->error(line, "unknown capability flag '" + name + "'");
+    context.fErrors->error(line, "unknown capability flag '" + SkSL::String(name) + "'");
     return nullptr;
 }
 
@@ -119,7 +119,7 @@
         return caps->value(context);
     }
 
-    context.fErrors->error(line, "unknown capability flag '" + name + "'");
+    context.fErrors->error(line, "unknown capability flag '" + SkSL::String(name) + "'");
     return nullptr;
 }
 
diff --git a/src/sksl/ir/SkSLSymbolTable.cpp b/src/sksl/ir/SkSLSymbolTable.cpp
index b355335..53e0c9c 100644
--- a/src/sksl/ir/SkSLSymbolTable.cpp
+++ b/src/sksl/ir/SkSLSymbolTable.cpp
@@ -94,7 +94,8 @@
     }
 
     if (!symbol->is<FunctionDeclaration>()) {
-        fContext.fErrors->error(symbol->fLine, "symbol '" + name + "' was already defined");
+        fContext.fErrors->error(symbol->fLine, "symbol '" + SkSL::String(name) +
+                                               "' was already defined");
         return;
     }
 
diff --git a/src/sksl/ir/SkSLType.cpp b/src/sksl/ir/SkSLType.cpp
index a0a2568..e1b4447 100644
--- a/src/sksl/ir/SkSLType.cpp
+++ b/src/sksl/ir/SkSLType.cpp
@@ -977,7 +977,7 @@
         return 0;
     }
     if (this->isOpaque()) {
-        context.fErrors->error(size->fLine, "opaque type '" + this->name() +
+        context.fErrors->error(size->fLine, "opaque type '" + SkSL::String(this->name()) +
                                             "' may not be used in an array");
         return 0;
     }
diff --git a/src/sksl/ir/SkSLVarDeclarations.cpp b/src/sksl/ir/SkSLVarDeclarations.cpp
index d1cd8b7..62ea0fe 100644
--- a/src/sksl/ir/SkSLVarDeclarations.cpp
+++ b/src/sksl/ir/SkSLVarDeclarations.cpp
@@ -129,23 +129,23 @@
     ErrorCheck(context, var.fLine, var.modifiers(), baseType, var.storage());
     if (value) {
         if (var.type().isOpaque()) {
-            context.fErrors->error(value->fLine,
-                    "opaque type '" + var.type().name() + "' cannot use initializer expressions");
+            context.fErrors->error(value->fLine, "opaque type '" + var.type().displayName() +
+                                                 "' cannot use initializer expressions");
             return false;
         }
         if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
             context.fErrors->error(value->fLine,
-                    "'in' variables cannot use initializer expressions");
+                                   "'in' variables cannot use initializer expressions");
             return false;
         }
         if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
             context.fErrors->error(value->fLine,
-                    "'uniform' variables cannot use initializer expressions");
+                                   "'uniform' variables cannot use initializer expressions");
             return false;
         }
         if (var.storage() == Variable::Storage::kInterfaceBlock) {
             context.fErrors->error(value->fLine,
-                    "initializers are not permitted on interface block fields");
+                                   "initializers are not permitted on interface block fields");
             return false;
         }
         value = var.type().coerceExpression(std::move(value), context);
@@ -160,21 +160,21 @@
         }
         if (!Analysis::IsConstantExpression(*value)) {
             context.fErrors->error(value->fLine,
-                    "'const' variable initializer must be a constant expression");
+                                   "'const' variable initializer must be a constant expression");
             return false;
         }
     }
     if (var.storage() == Variable::Storage::kInterfaceBlock) {
         if (var.type().isOpaque()) {
-            context.fErrors->error(var.fLine, "opaque type '" + var.type().name() +
-                    "' is not permitted in an interface block");
+            context.fErrors->error(var.fLine, "opaque type '" + var.type().displayName() +
+                                              "' is not permitted in an interface block");
             return false;
         }
     }
     if (var.storage() == Variable::Storage::kGlobal) {
         if (value && !Analysis::IsConstantExpression(*value)) {
             context.fErrors->error(value->fLine,
-                    "global variable initializer must be a constant expression");
+                                   "global variable initializer must be a constant expression");
             return false;
         }
     }