blob: 7d7978a14bd1dd1ebcc99af902200416f223b335 [file] [log] [blame]
Michael Ludwig8f3a8362020-06-29 17:27:00 -04001/*
2 * Copyright 2020 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/sksl/SkSLAnalysis.h"
9
John Stiles106e0cd2021-09-07 11:43:51 -040010#include "include/private/SkFloatingPoint.h"
Ethan Nicholasdaed2592021-03-04 14:30:25 -050011#include "include/private/SkSLModifiers.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050012#include "include/private/SkSLProgramElement.h"
Brian Osman1298bc42020-06-30 13:39:35 -040013#include "include/private/SkSLSampleUsage.h"
Ethan Nicholas24c17722021-03-09 13:10:59 -050014#include "include/private/SkSLStatement.h"
Ethan Nicholas4a5e22a2021-08-13 17:29:51 -040015#include "include/sksl/SkSLErrorReporter.h"
Brian Osman00185012021-02-04 16:07:11 -050016#include "src/sksl/SkSLCompiler.h"
Brian Osman448b2d52021-09-23 11:36:15 -040017#include "src/sksl/SkSLConstantFolder.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040018#include "src/sksl/analysis/SkSLProgramVisitor.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040019#include "src/sksl/ir/SkSLExpression.h"
20#include "src/sksl/ir/SkSLProgram.h"
Ethan Nicholas17807552021-10-01 09:42:36 -040021#include "src/sksl/transform/SkSLProgramWriter.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040022
23// ProgramElements
Michael Ludwig8f3a8362020-06-29 17:27:00 -040024#include "src/sksl/ir/SkSLExtension.h"
25#include "src/sksl/ir/SkSLFunctionDefinition.h"
26#include "src/sksl/ir/SkSLInterfaceBlock.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040027#include "src/sksl/ir/SkSLVarDeclarations.h"
28
29// Statements
30#include "src/sksl/ir/SkSLBlock.h"
31#include "src/sksl/ir/SkSLBreakStatement.h"
32#include "src/sksl/ir/SkSLContinueStatement.h"
33#include "src/sksl/ir/SkSLDiscardStatement.h"
34#include "src/sksl/ir/SkSLDoStatement.h"
35#include "src/sksl/ir/SkSLExpressionStatement.h"
36#include "src/sksl/ir/SkSLForStatement.h"
37#include "src/sksl/ir/SkSLIfStatement.h"
38#include "src/sksl/ir/SkSLNop.h"
39#include "src/sksl/ir/SkSLReturnStatement.h"
40#include "src/sksl/ir/SkSLSwitchStatement.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040041
42// Expressions
43#include "src/sksl/ir/SkSLBinaryExpression.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040044#include "src/sksl/ir/SkSLChildCall.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040045#include "src/sksl/ir/SkSLConstructor.h"
John Stilese1182782021-03-30 22:09:37 -040046#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
John Stiles5abb9e12021-04-06 13:47:19 -040047#include "src/sksl/ir/SkSLConstructorMatrixResize.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040048#include "src/sksl/ir/SkSLExternalFunctionCall.h"
Brian Osmanbe0b3b72021-01-06 14:27:35 -050049#include "src/sksl/ir/SkSLExternalFunctionReference.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040050#include "src/sksl/ir/SkSLFieldAccess.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040051#include "src/sksl/ir/SkSLFunctionCall.h"
52#include "src/sksl/ir/SkSLFunctionReference.h"
53#include "src/sksl/ir/SkSLIndexExpression.h"
John Stiles98c1f822020-09-09 14:18:53 -040054#include "src/sksl/ir/SkSLInlineMarker.h"
John Stiles7591d4b2021-09-13 13:32:06 -040055#include "src/sksl/ir/SkSLLiteral.h"
Michael Ludwig8f3a8362020-06-29 17:27:00 -040056#include "src/sksl/ir/SkSLPostfixExpression.h"
57#include "src/sksl/ir/SkSLPrefixExpression.h"
58#include "src/sksl/ir/SkSLSetting.h"
59#include "src/sksl/ir/SkSLSwizzle.h"
60#include "src/sksl/ir/SkSLTernaryExpression.h"
61#include "src/sksl/ir/SkSLTypeReference.h"
62#include "src/sksl/ir/SkSLVariableReference.h"
63
64namespace SkSL {
65
66namespace {
67
Brian Osmaneb0f29d2021-08-04 11:34:16 -040068// Visitor that determines the merged SampleUsage for a given child in the program.
Brian Osman1298bc42020-06-30 13:39:35 -040069class MergeSampleUsageVisitor : public ProgramVisitor {
Michael Ludwig8f3a8362020-06-29 17:27:00 -040070public:
Brian Osmaneb0f29d2021-08-04 11:34:16 -040071 MergeSampleUsageVisitor(const Context& context,
72 const Variable& child,
73 bool writesToSampleCoords)
74 : fContext(context), fChild(child), fWritesToSampleCoords(writesToSampleCoords) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -040075
Brian Osman1298bc42020-06-30 13:39:35 -040076 SampleUsage visit(const Program& program) {
77 fUsage = SampleUsage(); // reset to none
John Stilesd7ab4502020-09-24 22:41:00 -040078 INHERITED::visit(program);
Brian Osman1298bc42020-06-30 13:39:35 -040079 return fUsage;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040080 }
81
Brian Osman8cdf28f2021-05-24 09:52:39 -040082 int elidedSampleCoordCount() const { return fElidedSampleCoordCount; }
83
Michael Ludwig8f3a8362020-06-29 17:27:00 -040084protected:
John Stiles933abe32020-08-28 11:58:40 -040085 const Context& fContext;
Brian Osmaneb0f29d2021-08-04 11:34:16 -040086 const Variable& fChild;
Brian Osman4d571112021-04-27 09:10:10 -040087 const bool fWritesToSampleCoords;
Brian Osman1298bc42020-06-30 13:39:35 -040088 SampleUsage fUsage;
Brian Osman8cdf28f2021-05-24 09:52:39 -040089 int fElidedSampleCoordCount = 0;
Michael Ludwig8f3a8362020-06-29 17:27:00 -040090
91 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -040092 // Looking for child(...)
93 if (e.is<ChildCall>() && &e.as<ChildCall>().child() == &fChild) {
94 // Determine the type of call at this site, and merge it with the accumulated state
95 const ExpressionArray& arguments = e.as<ChildCall>().arguments();
96 SkASSERT(arguments.size() >= 1);
97
98 const Expression* maybeCoords = arguments[0].get();
99 if (maybeCoords->type() == *fContext.fTypes.fFloat2) {
100 // If the coords are a direct reference to the program's sample-coords, and those
101 // coords are never modified, we can conservatively turn this into PassThrough
102 // sampling. In all other cases, we consider it Explicit.
103 if (!fWritesToSampleCoords && maybeCoords->is<VariableReference>() &&
104 maybeCoords->as<VariableReference>().variable()->modifiers().fLayout.fBuiltin ==
105 SK_MAIN_COORDS_BUILTIN) {
Brian Osman1298bc42020-06-30 13:39:35 -0400106 fUsage.merge(SampleUsage::PassThrough());
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400107 ++fElidedSampleCoordCount;
108 } else {
109 fUsage.merge(SampleUsage::Explicit());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400110 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400111 } else {
112 // child(inputColor) or child(srcColor, dstColor) -> PassThrough
113 fUsage.merge(SampleUsage::PassThrough());
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400114 }
115 }
116
John Stilesd7ab4502020-09-24 22:41:00 -0400117 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400118 }
119
John Stiles7571f9e2020-09-02 22:42:33 -0400120 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400121};
122
Brian Osman92aac1e2020-08-05 16:48:58 -0400123// Visitor that searches through the program for references to a particular builtin variable
124class BuiltinVariableVisitor : public ProgramVisitor {
125public:
126 BuiltinVariableVisitor(int builtin) : fBuiltin(builtin) {}
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400127
128 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400129 if (e.is<VariableReference>()) {
John Stiles403a3632020-08-20 12:11:48 -0400130 const VariableReference& var = e.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400131 return var.variable()->modifiers().fLayout.fBuiltin == fBuiltin;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400132 }
John Stilesd7ab4502020-09-24 22:41:00 -0400133 return INHERITED::visitExpression(e);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400134 }
135
Brian Osman92aac1e2020-08-05 16:48:58 -0400136 int fBuiltin;
137
John Stiles7571f9e2020-09-02 22:42:33 -0400138 using INHERITED = ProgramVisitor;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400139};
140
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400141// Visitor that searches for child calls from a function other than main()
Brian Osman04d79fc2021-07-02 13:25:35 -0400142class SampleOutsideMainVisitor : public ProgramVisitor {
143public:
144 SampleOutsideMainVisitor() {}
145
146 bool visitExpression(const Expression& e) override {
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400147 if (e.is<ChildCall>()) {
148 return true;
Brian Osman04d79fc2021-07-02 13:25:35 -0400149 }
150 return INHERITED::visitExpression(e);
151 }
152
153 bool visitProgramElement(const ProgramElement& p) override {
154 return p.is<FunctionDefinition>() &&
155 !p.as<FunctionDefinition>().declaration().isMain() &&
156 INHERITED::visitProgramElement(p);
157 }
158
159 using INHERITED = ProgramVisitor;
160};
161
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400162// Visitor that counts the number of nodes visited
163class NodeCountVisitor : public ProgramVisitor {
164public:
John Stiles2c1e4922020-10-01 09:14:14 -0400165 NodeCountVisitor(int limit) : fLimit(limit) {}
166
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400167 int visit(const Statement& s) {
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400168 this->visitStatement(s);
169 return fCount;
170 }
171
172 bool visitExpression(const Expression& e) override {
173 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500174 return (fCount >= fLimit) || INHERITED::visitExpression(e);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400175 }
176
177 bool visitProgramElement(const ProgramElement& p) override {
178 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500179 return (fCount >= fLimit) || INHERITED::visitProgramElement(p);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400180 }
181
182 bool visitStatement(const Statement& s) override {
183 ++fCount;
John Stiles9b9415e2020-11-23 14:48:06 -0500184 return (fCount >= fLimit) || INHERITED::visitStatement(s);
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400185 }
186
187private:
John Stiles2c1e4922020-10-01 09:14:14 -0400188 int fCount = 0;
189 int fLimit;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400190
John Stiles7571f9e2020-09-02 22:42:33 -0400191 using INHERITED = ProgramVisitor;
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400192};
193
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400194class VariableWriteVisitor : public ProgramVisitor {
195public:
196 VariableWriteVisitor(const Variable* var)
197 : fVar(var) {}
198
199 bool visit(const Statement& s) {
200 return this->visitStatement(s);
201 }
202
203 bool visitExpression(const Expression& e) override {
Brian Osman79457ef2020-09-24 15:01:27 -0400204 if (e.is<VariableReference>()) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400205 const VariableReference& ref = e.as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400206 if (ref.variable() == fVar &&
207 (ref.refKind() == VariableReference::RefKind::kWrite ||
208 ref.refKind() == VariableReference::RefKind::kReadWrite ||
209 ref.refKind() == VariableReference::RefKind::kPointer)) {
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400210 return true;
211 }
212 }
John Stilesd7ab4502020-09-24 22:41:00 -0400213 return INHERITED::visitExpression(e);
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400214 }
215
216private:
217 const Variable* fVar;
218
John Stiles7571f9e2020-09-02 22:42:33 -0400219 using INHERITED = ProgramVisitor;
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400220};
221
John Stilesa976da72020-09-25 23:06:26 -0400222// If a caller doesn't care about errors, we can use this trivial reporter that just counts up.
223class TrivialErrorReporter : public ErrorReporter {
224public:
John Stilesbb8cf582021-08-26 23:34:59 -0400225 ~TrivialErrorReporter() override { this->reportPendingErrors({}); }
Ethan Nicholas32724122021-09-07 13:49:07 -0400226 void handleError(skstd::string_view, PositionInfo) override {}
John Stilesa976da72020-09-25 23:06:26 -0400227};
228
John Stilesdce4d3e2020-09-25 14:35:13 -0400229// This isn't actually using ProgramVisitor, because it only considers a subset of the fields for
230// any given expression kind. For instance, when indexing an array (e.g. `x[1]`), we only want to
231// know if the base (`x`) is assignable; the index expression (`1`) doesn't need to be.
232class IsAssignableVisitor {
233public:
John Stilesb21fac22020-12-04 15:36:49 -0500234 IsAssignableVisitor(ErrorReporter* errors) : fErrors(errors) {}
John Stilesdce4d3e2020-09-25 14:35:13 -0400235
John Stilesb21fac22020-12-04 15:36:49 -0500236 bool visit(Expression& expr, Analysis::AssignmentInfo* info) {
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500237 int oldErrorCount = fErrors->errorCount();
John Stilesdce4d3e2020-09-25 14:35:13 -0400238 this->visitExpression(expr);
John Stilesb21fac22020-12-04 15:36:49 -0500239 if (info) {
240 info->fAssignedVar = fAssignedVar;
John Stilesb21fac22020-12-04 15:36:49 -0500241 }
Ethan Nicholas67a0a8a2021-01-13 12:36:02 -0500242 return fErrors->errorCount() == oldErrorCount;
John Stilesdce4d3e2020-09-25 14:35:13 -0400243 }
244
245 void visitExpression(Expression& expr) {
246 switch (expr.kind()) {
247 case Expression::Kind::kVariableReference: {
248 VariableReference& varRef = expr.as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400249 const Variable* var = varRef.variable();
Brian Osmane49703f2021-04-19 11:15:24 -0400250 if (var->modifiers().fFlags & (Modifiers::kConst_Flag | Modifiers::kUniform_Flag)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400251 fErrors->error(expr.fLine,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400252 "cannot modify immutable variable '" + var->name() + "'");
John Stilesb21fac22020-12-04 15:36:49 -0500253 } else {
254 SkASSERT(fAssignedVar == nullptr);
255 fAssignedVar = &varRef;
John Stilesdce4d3e2020-09-25 14:35:13 -0400256 }
257 break;
258 }
259 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400260 this->visitExpression(*expr.as<FieldAccess>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400261 break;
262
263 case Expression::Kind::kSwizzle: {
264 const Swizzle& swizzle = expr.as<Swizzle>();
265 this->checkSwizzleWrite(swizzle);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400266 this->visitExpression(*swizzle.base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400267 break;
268 }
John Stiles47c0a742021-02-09 09:30:35 -0500269 case Expression::Kind::kIndex:
270 this->visitExpression(*expr.as<IndexExpression>().base());
John Stilesdce4d3e2020-09-25 14:35:13 -0400271 break;
John Stiles47c0a742021-02-09 09:30:35 -0500272
Ethan Nicholasc898d042021-08-28 19:53:34 -0400273 case Expression::Kind::kPoison:
274 break;
275
John Stilesdce4d3e2020-09-25 14:35:13 -0400276 default:
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400277 fErrors->error(expr.fLine, "cannot assign to this expression");
John Stilesdce4d3e2020-09-25 14:35:13 -0400278 break;
279 }
280 }
281
282private:
283 void checkSwizzleWrite(const Swizzle& swizzle) {
284 int bits = 0;
John Stiles6e88e042021-02-19 14:09:38 -0500285 for (int8_t idx : swizzle.components()) {
286 SkASSERT(idx >= SwizzleComponent::X && idx <= SwizzleComponent::W);
John Stilesdce4d3e2020-09-25 14:35:13 -0400287 int bit = 1 << idx;
288 if (bits & bit) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400289 fErrors->error(swizzle.fLine,
John Stilesa976da72020-09-25 23:06:26 -0400290 "cannot write to the same swizzle field more than once");
John Stilesdce4d3e2020-09-25 14:35:13 -0400291 break;
292 }
293 bits |= bit;
294 }
295 }
296
John Stilesa976da72020-09-25 23:06:26 -0400297 ErrorReporter* fErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500298 VariableReference* fAssignedVar = nullptr;
John Stilesdce4d3e2020-09-25 14:35:13 -0400299
300 using INHERITED = ProgramVisitor;
301};
302
John Stilesa6841be2020-08-06 14:11:56 -0400303} // namespace
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400304
305////////////////////////////////////////////////////////////////////////////////
306// Analysis
307
Brian Osman4d571112021-04-27 09:10:10 -0400308SampleUsage Analysis::GetSampleUsage(const Program& program,
Brian Osman293497e2021-08-24 14:08:50 -0400309 const Variable& child,
Brian Osman8cdf28f2021-05-24 09:52:39 -0400310 bool writesToSampleCoords,
311 int* elidedSampleCoordCount) {
Brian Osman293497e2021-08-24 14:08:50 -0400312 MergeSampleUsageVisitor visitor(*program.fContext, child, writesToSampleCoords);
Brian Osman8cdf28f2021-05-24 09:52:39 -0400313 SampleUsage result = visitor.visit(program);
314 if (elidedSampleCoordCount) {
315 *elidedSampleCoordCount += visitor.elidedSampleCoordCount();
316 }
317 return result;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400318}
319
Brian Osman92aac1e2020-08-05 16:48:58 -0400320bool Analysis::ReferencesBuiltin(const Program& program, int builtin) {
321 BuiltinVariableVisitor visitor(builtin);
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400322 return visitor.visit(program);
323}
324
Brian Osman92aac1e2020-08-05 16:48:58 -0400325bool Analysis::ReferencesSampleCoords(const Program& program) {
326 return Analysis::ReferencesBuiltin(program, SK_MAIN_COORDS_BUILTIN);
327}
328
329bool Analysis::ReferencesFragCoords(const Program& program) {
330 return Analysis::ReferencesBuiltin(program, SK_FRAGCOORD_BUILTIN);
331}
332
Brian Osman04d79fc2021-07-02 13:25:35 -0400333bool Analysis::CallsSampleOutsideMain(const Program& program) {
334 SampleOutsideMainVisitor visitor;
335 return visitor.visit(program);
336}
337
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400338bool Analysis::DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors) {
339 // A variable declaration can create either a lone VarDeclaration or an unscoped Block
340 // containing multiple VarDeclaration statements. We need to detect either case.
341 const Variable* var;
342 if (stmt.is<VarDeclaration>()) {
343 // The single-variable case. No blocks at all.
344 var = &stmt.as<VarDeclaration>().var();
345 } else if (stmt.is<Block>()) {
346 // The multiple-variable case: an unscoped, non-empty block...
347 const Block& block = stmt.as<Block>();
348 if (block.isScope() || block.children().empty()) {
349 return false;
350 }
351 // ... holding a variable declaration.
352 const Statement& innerStmt = *block.children().front();
353 if (!innerStmt.is<VarDeclaration>()) {
354 return false;
355 }
356 var = &innerStmt.as<VarDeclaration>().var();
357 } else {
358 // This statement wasn't a variable declaration. No problem.
359 return false;
360 }
361
362 // Report an error.
363 SkASSERT(var);
364 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400365 errors->error(stmt.fLine, "variable '" + var->name() + "' must be created in a scope");
Ethan Nicholas98eae1e2021-09-01 14:37:29 -0400366 }
367 return true;
368}
369
John Stiles9b9415e2020-11-23 14:48:06 -0500370int Analysis::NodeCountUpToLimit(const FunctionDefinition& function, int limit) {
371 return NodeCountVisitor{limit}.visit(*function.body());
Ethan Nicholas6e0fa402020-08-20 14:08:23 -0400372}
373
Ethan Nicholas765d2fe2020-08-26 08:29:55 -0400374bool Analysis::StatementWritesToVariable(const Statement& stmt, const Variable& var) {
375 return VariableWriteVisitor(&var).visit(stmt);
376}
377
John Stilesb21fac22020-12-04 15:36:49 -0500378bool Analysis::IsAssignable(Expression& expr, AssignmentInfo* info, ErrorReporter* errors) {
John Stilesa976da72020-09-25 23:06:26 -0400379 TrivialErrorReporter trivialErrors;
John Stilesb21fac22020-12-04 15:36:49 -0500380 return IsAssignableVisitor{errors ? errors : &trivialErrors}.visit(expr, info);
John Stilesdce4d3e2020-09-25 14:35:13 -0400381}
382
John Stilesbb8cf582021-08-26 23:34:59 -0400383bool Analysis::UpdateVariableRefKind(Expression* expr,
384 VariableReference::RefKind kind,
385 ErrorReporter* errors) {
John Stiles516704b2021-02-26 15:01:57 -0500386 Analysis::AssignmentInfo info;
387 if (!Analysis::IsAssignable(*expr, &info, errors)) {
388 return false;
389 }
390 if (!info.fAssignedVar) {
John Stilesbb8cf582021-08-26 23:34:59 -0400391 if (errors) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400392 errors->error(expr->fLine, "can't assign to expression '" + expr->description() + "'");
John Stilesbb8cf582021-08-26 23:34:59 -0400393 }
John Stiles516704b2021-02-26 15:01:57 -0500394 return false;
395 }
396 info.fAssignedVar->setRefKind(kind);
397 return true;
398}
399
John Stilesc30fbca2020-11-19 16:25:49 -0500400bool Analysis::IsTrivialExpression(const Expression& expr) {
John Stiles7591d4b2021-09-13 13:32:06 -0400401 return expr.is<Literal>() ||
John Stilesc30fbca2020-11-19 16:25:49 -0500402 expr.is<VariableReference>() ||
403 (expr.is<Swizzle>() &&
404 IsTrivialExpression(*expr.as<Swizzle>().base())) ||
405 (expr.is<FieldAccess>() &&
406 IsTrivialExpression(*expr.as<FieldAccess>().base())) ||
John Stiles2938eea2021-04-01 18:58:25 -0400407 (expr.isAnyConstructor() &&
408 expr.asAnyConstructor().argumentSpan().size() == 1 &&
409 IsTrivialExpression(*expr.asAnyConstructor().argumentSpan().front())) ||
410 (expr.isAnyConstructor() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500411 expr.isConstantOrUniform()) ||
412 (expr.is<IndexExpression>() &&
John Stiles7591d4b2021-09-13 13:32:06 -0400413 expr.as<IndexExpression>().index()->isIntLiteral() &&
John Stilesc30fbca2020-11-19 16:25:49 -0500414 IsTrivialExpression(*expr.as<IndexExpression>().base()));
415}
416
John Stiles5676c572021-03-08 17:10:52 -0500417bool Analysis::IsSameExpressionTree(const Expression& left, const Expression& right) {
John Stiles95d0bad2021-03-01 17:02:28 -0500418 if (left.kind() != right.kind() || left.type() != right.type()) {
419 return false;
420 }
421
John Stiles5676c572021-03-08 17:10:52 -0500422 // This isn't a fully exhaustive list of expressions by any stretch of the imagination; for
423 // instance, `x[y+1] = x[y+1]` isn't detected because we don't look at BinaryExpressions.
424 // Since this is intended to be used for optimization purposes, handling the common cases is
425 // sufficient.
John Stiles95d0bad2021-03-01 17:02:28 -0500426 switch (left.kind()) {
John Stiles7591d4b2021-09-13 13:32:06 -0400427 case Expression::Kind::kLiteral:
428 return left.as<Literal>().value() == right.as<Literal>().value();
John Stiles5676c572021-03-08 17:10:52 -0500429
John Stiles7384b372021-04-01 13:48:15 -0400430 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400431 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400432 case Expression::Kind::kConstructorCompound:
433 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400434 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400435 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400436 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400437 case Expression::Kind::kConstructorStruct:
John Stiles268a73f2021-04-07 12:30:22 -0400438 case Expression::Kind::kConstructorSplat: {
John Stilesfd7252f2021-04-04 22:24:40 -0400439 if (left.kind() != right.kind()) {
440 return false;
441 }
John Stiles7384b372021-04-01 13:48:15 -0400442 const AnyConstructor& leftCtor = left.asAnyConstructor();
443 const AnyConstructor& rightCtor = right.asAnyConstructor();
444 const auto leftSpan = leftCtor.argumentSpan();
445 const auto rightSpan = rightCtor.argumentSpan();
446 if (leftSpan.size() != rightSpan.size()) {
John Stiles5676c572021-03-08 17:10:52 -0500447 return false;
448 }
John Stiles7384b372021-04-01 13:48:15 -0400449 for (size_t index = 0; index < leftSpan.size(); ++index) {
450 if (!IsSameExpressionTree(*leftSpan[index], *rightSpan[index])) {
John Stiles5676c572021-03-08 17:10:52 -0500451 return false;
452 }
453 }
454 return true;
455 }
John Stiles95d0bad2021-03-01 17:02:28 -0500456 case Expression::Kind::kFieldAccess:
457 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
John Stiles5676c572021-03-08 17:10:52 -0500458 IsSameExpressionTree(*left.as<FieldAccess>().base(),
459 *right.as<FieldAccess>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500460
461 case Expression::Kind::kIndex:
John Stiles5676c572021-03-08 17:10:52 -0500462 return IsSameExpressionTree(*left.as<IndexExpression>().index(),
463 *right.as<IndexExpression>().index()) &&
464 IsSameExpressionTree(*left.as<IndexExpression>().base(),
465 *right.as<IndexExpression>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500466
467 case Expression::Kind::kSwizzle:
468 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
John Stiles5676c572021-03-08 17:10:52 -0500469 IsSameExpressionTree(*left.as<Swizzle>().base(), *right.as<Swizzle>().base());
John Stiles95d0bad2021-03-01 17:02:28 -0500470
471 case Expression::Kind::kVariableReference:
472 return left.as<VariableReference>().variable() ==
473 right.as<VariableReference>().variable();
474
475 default:
476 return false;
477 }
478}
479
Brian Osmanea485e52021-01-15 13:20:32 -0500480class ES2IndexingVisitor : public ProgramVisitor {
481public:
482 ES2IndexingVisitor(ErrorReporter& errors) : fErrors(errors) {}
483
484 bool visitStatement(const Statement& s) override {
485 if (s.is<ForStatement>()) {
486 const ForStatement& f = s.as<ForStatement>();
487 SkASSERT(f.initializer() && f.initializer()->is<VarDeclaration>());
488 const Variable* var = &f.initializer()->as<VarDeclaration>().var();
489 auto [iter, inserted] = fLoopIndices.insert(var);
490 SkASSERT(inserted);
491 bool result = this->visitStatement(*f.statement());
492 fLoopIndices.erase(iter);
493 return result;
494 }
495 return INHERITED::visitStatement(s);
496 }
497
498 bool visitExpression(const Expression& e) override {
499 if (e.is<IndexExpression>()) {
500 const IndexExpression& i = e.as<IndexExpression>();
John Stiles2dfbf992021-10-06 20:06:41 -0400501 if (!Analysis::IsConstantIndexExpression(*i.index(), &fLoopIndices)) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400502 fErrors.error(i.fLine, "index expression must be constant");
Brian Osmanea485e52021-01-15 13:20:32 -0500503 return true;
504 }
505 }
506 return INHERITED::visitExpression(e);
507 }
508
509 using ProgramVisitor::visitProgramElement;
510
511private:
512 ErrorReporter& fErrors;
513 std::set<const Variable*> fLoopIndices;
514 using INHERITED = ProgramVisitor;
515};
516
Brian Osmanea485e52021-01-15 13:20:32 -0500517void Analysis::ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors) {
518 ES2IndexingVisitor visitor(errors);
519 visitor.visitProgramElement(pe);
520}
521
John Stiles2ecc5952021-09-01 14:41:36 -0400522void Analysis::VerifyStaticTestsAndExpressions(const Program& program) {
523 class TestsAndExpressions : public ProgramVisitor {
John Stiles0fc6bed2021-09-01 11:35:59 -0400524 public:
John Stiles2ecc5952021-09-01 14:41:36 -0400525 TestsAndExpressions(const Context& ctx) : fContext(ctx) {}
John Stiles0fc6bed2021-09-01 11:35:59 -0400526
527 using ProgramVisitor::visitProgramElement;
528
529 bool visitStatement(const Statement& stmt) override {
John Stiles2ecc5952021-09-01 14:41:36 -0400530 if (!fContext.fConfig->fSettings.fPermitInvalidStaticTests) {
531 switch (stmt.kind()) {
532 case Statement::Kind::kIf:
533 if (stmt.as<IfStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400534 fContext.fErrors->error(stmt.fLine, "static if has non-static test");
John Stiles2ecc5952021-09-01 14:41:36 -0400535 }
536 break;
John Stiles0fc6bed2021-09-01 11:35:59 -0400537
John Stiles2ecc5952021-09-01 14:41:36 -0400538 case Statement::Kind::kSwitch:
539 if (stmt.as<SwitchStatement>().isStatic()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400540 fContext.fErrors->error(stmt.fLine,
John Stiles2ecc5952021-09-01 14:41:36 -0400541 "static switch has non-static test");
542 }
543 break;
John Stiles0fc6bed2021-09-01 11:35:59 -0400544
John Stiles2ecc5952021-09-01 14:41:36 -0400545 default:
546 break;
547 }
John Stiles0fc6bed2021-09-01 11:35:59 -0400548 }
549 return INHERITED::visitStatement(stmt);
550 }
551
John Stiles2ecc5952021-09-01 14:41:36 -0400552 bool visitExpression(const Expression& expr) override {
553 switch (expr.kind()) {
554 case Expression::Kind::kFunctionCall: {
555 const FunctionDeclaration& decl = expr.as<FunctionCall>().function();
556 if (!decl.isBuiltin() && !decl.definition()) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400557 fContext.fErrors->error(expr.fLine, "function '" + decl.description() +
558 "' is not defined");
John Stiles2ecc5952021-09-01 14:41:36 -0400559 }
560 break;
561 }
562 case Expression::Kind::kExternalFunctionReference:
563 case Expression::Kind::kFunctionReference:
Brian Osman3099f792021-09-01 13:12:16 -0400564 case Expression::Kind::kMethodReference:
John Stiles2ecc5952021-09-01 14:41:36 -0400565 case Expression::Kind::kTypeReference:
566 SkDEBUGFAIL("invalid reference-expr, should have been reported by coerce()");
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400567 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -0400568 break;
569 default:
570 if (expr.type() == *fContext.fTypes.fInvalid) {
Ethan Nicholas89cfde12021-09-27 11:20:34 -0400571 fContext.fErrors->error(expr.fLine, "invalid expression");
John Stiles2ecc5952021-09-01 14:41:36 -0400572 }
573 break;
574 }
575 return INHERITED::visitExpression(expr);
John Stiles0fc6bed2021-09-01 11:35:59 -0400576 }
577
578 private:
579 using INHERITED = ProgramVisitor;
John Stiles2ecc5952021-09-01 14:41:36 -0400580 const Context& fContext;
John Stiles0fc6bed2021-09-01 11:35:59 -0400581 };
582
John Stiles0fc6bed2021-09-01 11:35:59 -0400583 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
John Stiles2ecc5952021-09-01 14:41:36 -0400584 TestsAndExpressions visitor{*program.fContext};
John Stilesbcaacec2021-10-06 20:06:55 -0400585 for (const std::unique_ptr<ProgramElement>& element : program.fOwnedElements) {
John Stiles2ecc5952021-09-01 14:41:36 -0400586 visitor.visitProgramElement(*element);
John Stiles0fc6bed2021-09-01 11:35:59 -0400587 }
588}
589
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400590////////////////////////////////////////////////////////////////////////////////
591// ProgramVisitor
592
Brian Osman133724c2020-10-28 14:14:39 -0400593bool ProgramVisitor::visit(const Program& program) {
594 for (const ProgramElement* pe : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -0400595 if (this->visitProgramElement(*pe)) {
John Stiles933abe32020-08-28 11:58:40 -0400596 return true;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400597 }
598 }
John Stiles933abe32020-08-28 11:58:40 -0400599 return false;
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400600}
601
John Stiles48b25582021-03-11 14:26:42 -0500602template <typename T> bool TProgramVisitor<T>::visitExpression(typename T::Expression& e) {
John Stiles70b82422020-09-30 10:55:12 -0400603 switch (e.kind()) {
John Stiles6d023462021-10-06 12:51:10 -0400604 case Expression::Kind::kCodeString:
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500605 case Expression::Kind::kExternalFunctionReference:
Ethan Nicholase6592142020-09-08 10:22:09 -0400606 case Expression::Kind::kFunctionReference:
John Stiles7591d4b2021-09-13 13:32:06 -0400607 case Expression::Kind::kLiteral:
Brian Osman3099f792021-09-01 13:12:16 -0400608 case Expression::Kind::kMethodReference:
Ethan Nicholas549c6b82021-06-25 12:31:44 -0400609 case Expression::Kind::kPoison:
Ethan Nicholase6592142020-09-08 10:22:09 -0400610 case Expression::Kind::kSetting:
611 case Expression::Kind::kTypeReference:
612 case Expression::Kind::kVariableReference:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400613 // Leaf expressions return false
614 return false;
John Stiles70b82422020-09-30 10:55:12 -0400615
Ethan Nicholase6592142020-09-08 10:22:09 -0400616 case Expression::Kind::kBinary: {
John Stiles70b82422020-09-30 10:55:12 -0400617 auto& b = e.template as<BinaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500618 return (b.left() && this->visitExpressionPtr(b.left())) ||
619 (b.right() && this->visitExpressionPtr(b.right()));
John Stiles70b82422020-09-30 10:55:12 -0400620 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400621 case Expression::Kind::kChildCall: {
622 // We don't visit the child variable itself, just the arguments
623 auto& c = e.template as<ChildCall>();
624 for (auto& arg : c.arguments()) {
625 if (arg && this->visitExpressionPtr(arg)) { return true; }
626 }
627 return false;
628 }
John Stiles7384b372021-04-01 13:48:15 -0400629 case Expression::Kind::kConstructorArray:
John Stilese3ae9682021-08-05 10:35:01 -0400630 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400631 case Expression::Kind::kConstructorCompound:
632 case Expression::Kind::kConstructorCompoundCast:
John Stiles2938eea2021-04-01 18:58:25 -0400633 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400634 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400635 case Expression::Kind::kConstructorScalarCast:
John Stilesd47330f2021-04-08 23:25:52 -0400636 case Expression::Kind::kConstructorSplat:
637 case Expression::Kind::kConstructorStruct: {
John Stiles7384b372021-04-01 13:48:15 -0400638 auto& c = e.asAnyConstructor();
639 for (auto& arg : c.argumentSpan()) {
John Stiles48b25582021-03-11 14:26:42 -0500640 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400641 }
John Stiles70b82422020-09-30 10:55:12 -0400642 return false;
643 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400644 case Expression::Kind::kExternalFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400645 auto& c = e.template as<ExternalFunctionCall>();
Ethan Nicholas6e86ec92020-09-30 14:29:56 -0400646 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -0500647 if (this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400648 }
John Stiles70b82422020-09-30 10:55:12 -0400649 return false;
650 }
John Stilesd7ab4502020-09-24 22:41:00 -0400651 case Expression::Kind::kFieldAccess:
John Stiles48b25582021-03-11 14:26:42 -0500652 return this->visitExpressionPtr(e.template as<FieldAccess>().base());
John Stiles70b82422020-09-30 10:55:12 -0400653
Ethan Nicholase6592142020-09-08 10:22:09 -0400654 case Expression::Kind::kFunctionCall: {
John Stiles70b82422020-09-30 10:55:12 -0400655 auto& c = e.template as<FunctionCall>();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400656 for (auto& arg : c.arguments()) {
John Stiles48b25582021-03-11 14:26:42 -0500657 if (arg && this->visitExpressionPtr(arg)) { return true; }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400658 }
John Stiles70b82422020-09-30 10:55:12 -0400659 return false;
660 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400661 case Expression::Kind::kIndex: {
John Stiles70b82422020-09-30 10:55:12 -0400662 auto& i = e.template as<IndexExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500663 return this->visitExpressionPtr(i.base()) || this->visitExpressionPtr(i.index());
John Stiles70b82422020-09-30 10:55:12 -0400664 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400665 case Expression::Kind::kPostfix:
John Stiles48b25582021-03-11 14:26:42 -0500666 return this->visitExpressionPtr(e.template as<PostfixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400667
Ethan Nicholase6592142020-09-08 10:22:09 -0400668 case Expression::Kind::kPrefix:
John Stiles48b25582021-03-11 14:26:42 -0500669 return this->visitExpressionPtr(e.template as<PrefixExpression>().operand());
John Stiles70b82422020-09-30 10:55:12 -0400670
Brian Osman010ce6a2020-10-19 16:34:10 -0400671 case Expression::Kind::kSwizzle: {
672 auto& s = e.template as<Swizzle>();
John Stiles48b25582021-03-11 14:26:42 -0500673 return s.base() && this->visitExpressionPtr(s.base());
Brian Osman010ce6a2020-10-19 16:34:10 -0400674 }
John Stiles70b82422020-09-30 10:55:12 -0400675
Ethan Nicholase6592142020-09-08 10:22:09 -0400676 case Expression::Kind::kTernary: {
John Stiles70b82422020-09-30 10:55:12 -0400677 auto& t = e.template as<TernaryExpression>();
John Stiles48b25582021-03-11 14:26:42 -0500678 return this->visitExpressionPtr(t.test()) ||
679 (t.ifTrue() && this->visitExpressionPtr(t.ifTrue())) ||
680 (t.ifFalse() && this->visitExpressionPtr(t.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400681 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400682 default:
683 SkUNREACHABLE;
684 }
685}
686
John Stiles48b25582021-03-11 14:26:42 -0500687template <typename T> bool TProgramVisitor<T>::visitStatement(typename T::Statement& s) {
John Stiles70b82422020-09-30 10:55:12 -0400688 switch (s.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Statement::Kind::kBreak:
690 case Statement::Kind::kContinue:
691 case Statement::Kind::kDiscard:
John Stiles98c1f822020-09-09 14:18:53 -0400692 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -0400693 case Statement::Kind::kNop:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400694 // Leaf statements just return false
695 return false;
John Stiles70b82422020-09-30 10:55:12 -0400696
Ethan Nicholase6592142020-09-08 10:22:09 -0400697 case Statement::Kind::kBlock:
John Stiles70b82422020-09-30 10:55:12 -0400698 for (auto& stmt : s.template as<Block>().children()) {
John Stiles48b25582021-03-11 14:26:42 -0500699 if (stmt && this->visitStatementPtr(stmt)) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -0400700 return true;
701 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400702 }
703 return false;
John Stiles70b82422020-09-30 10:55:12 -0400704
John Stilesa0e56e32021-03-03 13:14:37 -0500705 case Statement::Kind::kSwitchCase: {
706 auto& sc = s.template as<SwitchCase>();
John Stiles48b25582021-03-11 14:26:42 -0500707 if (sc.value() && this->visitExpressionPtr(sc.value())) {
John Stilesa0e56e32021-03-03 13:14:37 -0500708 return true;
709 }
John Stiles48b25582021-03-11 14:26:42 -0500710 return this->visitStatementPtr(sc.statement());
John Stilesa0e56e32021-03-03 13:14:37 -0500711 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400712 case Statement::Kind::kDo: {
John Stiles70b82422020-09-30 10:55:12 -0400713 auto& d = s.template as<DoStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500714 return this->visitExpressionPtr(d.test()) || this->visitStatementPtr(d.statement());
John Stiles70b82422020-09-30 10:55:12 -0400715 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400716 case Statement::Kind::kExpression:
John Stiles48b25582021-03-11 14:26:42 -0500717 return this->visitExpressionPtr(s.template as<ExpressionStatement>().expression());
John Stiles70b82422020-09-30 10:55:12 -0400718
Ethan Nicholase6592142020-09-08 10:22:09 -0400719 case Statement::Kind::kFor: {
John Stiles70b82422020-09-30 10:55:12 -0400720 auto& f = s.template as<ForStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500721 return (f.initializer() && this->visitStatementPtr(f.initializer())) ||
722 (f.test() && this->visitExpressionPtr(f.test())) ||
723 (f.next() && this->visitExpressionPtr(f.next())) ||
724 this->visitStatementPtr(f.statement());
John Stiles70b82422020-09-30 10:55:12 -0400725 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400726 case Statement::Kind::kIf: {
John Stiles70b82422020-09-30 10:55:12 -0400727 auto& i = s.template as<IfStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500728 return (i.test() && this->visitExpressionPtr(i.test())) ||
729 (i.ifTrue() && this->visitStatementPtr(i.ifTrue())) ||
730 (i.ifFalse() && this->visitStatementPtr(i.ifFalse()));
John Stiles70b82422020-09-30 10:55:12 -0400731 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400732 case Statement::Kind::kReturn: {
John Stiles70b82422020-09-30 10:55:12 -0400733 auto& r = s.template as<ReturnStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500734 return r.expression() && this->visitExpressionPtr(r.expression());
John Stiles70b82422020-09-30 10:55:12 -0400735 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400736 case Statement::Kind::kSwitch: {
John Stiles70b82422020-09-30 10:55:12 -0400737 auto& sw = s.template as<SwitchStatement>();
John Stiles48b25582021-03-11 14:26:42 -0500738 if (this->visitExpressionPtr(sw.value())) {
John Stiles70b82422020-09-30 10:55:12 -0400739 return true;
740 }
John Stiles48b25582021-03-11 14:26:42 -0500741 for (auto& c : sw.cases()) {
742 if (this->visitStatementPtr(c)) {
John Stiles70b82422020-09-30 10:55:12 -0400743 return true;
744 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400745 }
John Stiles70b82422020-09-30 10:55:12 -0400746 return false;
747 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400748 case Statement::Kind::kVarDeclaration: {
John Stiles70b82422020-09-30 10:55:12 -0400749 auto& v = s.template as<VarDeclaration>();
John Stiles48b25582021-03-11 14:26:42 -0500750 return v.value() && this->visitExpressionPtr(v.value());
John Stiles70b82422020-09-30 10:55:12 -0400751 }
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400752 default:
753 SkUNREACHABLE;
754 }
755}
756
John Stiles48b25582021-03-11 14:26:42 -0500757template <typename T> bool TProgramVisitor<T>::visitProgramElement(typename T::ProgramElement& pe) {
John Stiles70b82422020-09-30 10:55:12 -0400758 switch (pe.kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400759 case ProgramElement::Kind::kExtension:
John Stiles569249b2020-11-03 12:18:22 -0500760 case ProgramElement::Kind::kFunctionPrototype:
John Stilesd39aec02020-12-03 10:42:26 -0500761 case ProgramElement::Kind::kInterfaceBlock:
Ethan Nicholase6592142020-09-08 10:22:09 -0400762 case ProgramElement::Kind::kModifiers:
John Stilesdc75a972020-11-25 16:24:55 -0500763 case ProgramElement::Kind::kStructDefinition:
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400764 // Leaf program elements just return false by default
765 return false;
John Stiles70b82422020-09-30 10:55:12 -0400766
Ethan Nicholase6592142020-09-08 10:22:09 -0400767 case ProgramElement::Kind::kFunction:
John Stiles48b25582021-03-11 14:26:42 -0500768 return this->visitStatementPtr(pe.template as<FunctionDefinition>().body());
John Stiles70b82422020-09-30 10:55:12 -0400769
Brian Osmanc0213602020-10-06 14:43:32 -0400770 case ProgramElement::Kind::kGlobalVar:
John Stiles48b25582021-03-11 14:26:42 -0500771 return this->visitStatementPtr(pe.template as<GlobalVarDeclaration>().declaration());
John Stiles70b82422020-09-30 10:55:12 -0400772
Michael Ludwig8f3a8362020-06-29 17:27:00 -0400773 default:
774 SkUNREACHABLE;
775 }
776}
777
John Stiles48b25582021-03-11 14:26:42 -0500778template class TProgramVisitor<ProgramVisitorTypes>;
779template class TProgramVisitor<ProgramWriterTypes>;
John Stiles70b82422020-09-30 10:55:12 -0400780
John Stilesa6841be2020-08-06 14:11:56 -0400781} // namespace SkSL