Fix for loops with multiple init-variables in Metal.
This is structured differently than the GLSL fix, due to the different
semantics of array-types in Metal.
Change-Id: I27ad11539bbbb96abb0686d5686b8fcd2f5dd6d1
Bug: skia:11860
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/396916
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
index cb6b81e..9647907 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
@@ -1876,12 +1876,26 @@
return;
}
- this->write("for (");
+ bool closeForLoopScope = false;
if (f.initializer() && !f.initializer()->isEmpty()) {
- this->writeStatement(*f.initializer());
+ if (f.initializer()->is<Block>()) {
+ // Our initializer-statement could potentially contain multiple variables of differing
+ // type (e.g. `int` and `int[4]`). In Metal, there isn't a clean way to express this in
+ // the for's init-statement block, since we use `array<T, N>` type for our arrays.
+ // Instead, we synthesize a scope and declare those variables right above the for loop.
+ this->writeLine("{");
+ ++fIndentation;
+ this->writeStatement(*f.initializer());
+ this->write("for (; ");
+ closeForLoopScope = true;
+ } else {
+ this->write("for (");
+ this->writeStatement(*f.initializer());
+ }
} else {
- this->write("; ");
+ this->write("for (; ");
}
+
if (f.test()) {
this->writeExpression(*f.test(), Precedence::kTopLevel);
}
@@ -1891,6 +1905,12 @@
}
this->write(") ");
this->writeStatement(*f.statement());
+
+ if (closeForLoopScope) {
+ --fIndentation;
+ this->writeLine("");
+ this->writeLine("}");
+ }
}
void MetalCodeGenerator::writeDoStatement(const DoStatement& d) {