• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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/ir/SkSLType.h"
9 
10 #include "include/private/base/SkTo.h"
11 #include "src/base/SkEnumBitMask.h"
12 #include "src/base/SkMathPriv.h"
13 #include "src/base/SkSafeMath.h"
14 #include "src/core/SkTHash.h"
15 #include "src/sksl/SkSLBuiltinTypes.h"
16 #include "src/sksl/SkSLConstantFolder.h"
17 #include "src/sksl/SkSLContext.h"
18 #include "src/sksl/SkSLErrorReporter.h"
19 #include "src/sksl/SkSLProgramSettings.h"
20 #include "src/sksl/SkSLString.h"
21 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
22 #include "src/sksl/ir/SkSLConstructorCompoundCast.h"
23 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
24 #include "src/sksl/ir/SkSLExpression.h"
25 #include "src/sksl/ir/SkSLLayout.h"
26 #include "src/sksl/ir/SkSLModifierFlags.h"
27 #include "src/sksl/ir/SkSLSymbolTable.h"
28 
29 #include <algorithm>
30 #include <cstdint>
31 #include <limits>
32 #include <optional>
33 #include <string_view>
34 #include <utility>
35 
36 using namespace skia_private;
37 
38 namespace SkSL {
39 
40 static constexpr int kMaxStructDepth = 8;
41 
42 class AliasType final : public Type {
43 public:
AliasType(std::string_view name,const Type & targetType)44     AliasType(std::string_view name, const Type& targetType)
45             : INHERITED(name, targetType.abbreviatedName(), targetType.typeKind())
46             , fTargetType(targetType) {}
47 
resolve() const48     const Type& resolve() const override {
49         return fTargetType;
50     }
51 
componentType() const52     const Type& componentType() const override {
53         return fTargetType.componentType();
54     }
55 
numberKind() const56     NumberKind numberKind() const override {
57         return fTargetType.numberKind();
58     }
59 
priority() const60     int priority() const override {
61         return fTargetType.priority();
62     }
63 
columns() const64     int columns() const override {
65         return fTargetType.columns();
66     }
67 
rows() const68     int rows() const override {
69         return fTargetType.rows();
70     }
71 
bitWidth() const72     int bitWidth() const override {
73         return fTargetType.bitWidth();
74     }
75 
isAllowedInES2() const76     bool isAllowedInES2() const override {
77         return fTargetType.isAllowedInES2();
78     }
79 
slotCount() const80     size_t slotCount() const override {
81         return fTargetType.slotCount();
82     }
83 
slotType(size_t n) const84     const Type& slotType(size_t n) const override {
85         return fTargetType.slotType(n);
86     }
87 
dimensions() const88     SpvDim_ dimensions() const override {
89         return fTargetType.dimensions();
90     }
91 
isDepth() const92     bool isDepth() const override {
93         return fTargetType.isDepth();
94     }
95 
isArrayedTexture() const96     bool isArrayedTexture() const override {
97         return fTargetType.isArrayedTexture();
98     }
99 
isScalar() const100     bool isScalar() const override {
101         return fTargetType.isScalar();
102     }
103 
isLiteral() const104     bool isLiteral() const override {
105         return fTargetType.isLiteral();
106     }
107 
isVector() const108     bool isVector() const override {
109         return fTargetType.isVector();
110     }
111 
isMatrix() const112     bool isMatrix() const override {
113         return fTargetType.isMatrix();
114     }
115 
isArray() const116     bool isArray() const override {
117         return fTargetType.isArray();
118     }
119 
isUnsizedArray() const120     bool isUnsizedArray() const override {
121         return fTargetType.isUnsizedArray();
122     }
123 
isStruct() const124     bool isStruct() const override {
125         return fTargetType.isStruct();
126     }
127 
isInterfaceBlock() const128     bool isInterfaceBlock() const override {
129         return fTargetType.isInterfaceBlock();
130     }
131 
isMultisampled() const132     bool isMultisampled() const override {
133         return fTargetType.isMultisampled();
134     }
135 
textureAccess() const136     TextureAccess textureAccess() const override {
137         return fTargetType.textureAccess();
138     }
139 
coercibleTypes() const140     SkSpan<const Type* const> coercibleTypes() const override {
141         return fTargetType.coercibleTypes();
142     }
143 
144 private:
145     using INHERITED = Type;
146 
147     const Type& fTargetType;
148 };
149 
150 class ArrayType final : public Type {
151 public:
152     inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
153 
ArrayType(std::string_view name,const char * abbrev,const Type & componentType,int count,bool isBuiltin)154     ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count,
155               bool isBuiltin)
156             : INHERITED(name, abbrev, kTypeKind)
157             , fComponentType(componentType)
158             , fCount(count)
159             , fIsBuiltin(isBuiltin) {
160         SkASSERT(count > 0 || count == kUnsizedArray);
161         // Disallow multi-dimensional arrays.
162         SkASSERT(!componentType.is<ArrayType>());
163     }
164 
isArray() const165     bool isArray() const override {
166         return true;
167     }
168 
isBuiltin() const169     bool isBuiltin() const override {
170         return fIsBuiltin;
171     }
172 
isOrContainsArray() const173     bool isOrContainsArray() const override {
174         return true;
175     }
176 
isOrContainsAtomic() const177     bool isOrContainsAtomic() const override {
178         return fComponentType.isOrContainsAtomic();
179     }
180 
isUnsizedArray() const181     bool isUnsizedArray() const override {
182         return fCount == kUnsizedArray;
183     }
184 
isOrContainsUnsizedArray() const185     bool isOrContainsUnsizedArray() const override {
186         return this->isUnsizedArray() || fComponentType.isOrContainsUnsizedArray();
187     }
188 
componentType() const189     const Type& componentType() const override {
190         return fComponentType;
191     }
192 
columns() const193     int columns() const override {
194         return fCount;
195     }
196 
bitWidth() const197     int bitWidth() const override {
198         return fComponentType.bitWidth();
199     }
200 
isAllowedInES2() const201     bool isAllowedInES2() const override {
202         return fComponentType.isAllowedInES2();
203     }
204 
isAllowedInUniform(Position * errorPosition) const205     bool isAllowedInUniform(Position* errorPosition) const override {
206         return fComponentType.isAllowedInUniform(errorPosition);
207     }
208 
slotCount() const209     size_t slotCount() const override {
210         SkASSERT(fCount != kUnsizedArray);
211         SkASSERT(fCount > 0);
212         return fCount * fComponentType.slotCount();
213     }
214 
slotType(size_t n) const215     const Type& slotType(size_t n) const override {
216         SkASSERT(fCount == kUnsizedArray || n < this->slotCount());
217         return fComponentType.slotType(n % fComponentType.slotCount());
218     }
219 
220 private:
221     using INHERITED = Type;
222 
223     const Type& fComponentType;
224     int fCount;
225     bool fIsBuiltin;
226 };
227 
228 class GenericType final : public Type {
229 public:
230     inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
231 
GenericType(const char * name,SkSpan<const Type * const> coercibleTypes,const Type * slotType)232     GenericType(const char* name, SkSpan<const Type* const> coercibleTypes, const Type* slotType)
233             : INHERITED(name, "G", kTypeKind)
234             , fSlotType(slotType) {
235         fNumTypes = coercibleTypes.size();
236         SkASSERT(fNumTypes <= std::size(fCoercibleTypes));
237         std::copy(coercibleTypes.begin(), coercibleTypes.end(), fCoercibleTypes);
238     }
239 
coercibleTypes() const240     SkSpan<const Type* const> coercibleTypes() const override {
241         return SkSpan(fCoercibleTypes, fNumTypes);
242     }
243 
slotType(size_t) const244     const Type& slotType(size_t) const override {
245         return *fSlotType;
246     }
247 
248 private:
249     using INHERITED = Type;
250 
251     const Type* fCoercibleTypes[9];
252     const Type* fSlotType;
253     size_t fNumTypes;
254 };
255 
256 class LiteralType : public Type {
257 public:
258     inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
259 
LiteralType(const char * name,const Type & scalarType,int8_t priority)260     LiteralType(const char* name, const Type& scalarType, int8_t priority)
261             : INHERITED(name, "L", kTypeKind)
262             , fScalarType(scalarType)
263             , fPriority(priority) {}
264 
scalarTypeForLiteral() const265     const Type& scalarTypeForLiteral() const override {
266         return fScalarType;
267     }
268 
priority() const269     int priority() const override {
270         return fPriority;
271     }
272 
columns() const273     int columns() const override {
274         return 1;
275     }
276 
rows() const277     int rows() const override {
278         return 1;
279     }
280 
numberKind() const281     NumberKind numberKind() const override {
282         return fScalarType.numberKind();
283     }
284 
bitWidth() const285     int bitWidth() const override {
286         return fScalarType.bitWidth();
287     }
288 
minimumValue() const289     double minimumValue() const override {
290         return fScalarType.minimumValue();
291     }
292 
maximumValue() const293     double maximumValue() const override {
294         return fScalarType.maximumValue();
295     }
296 
isScalar() const297     bool isScalar() const override {
298         return true;
299     }
300 
isLiteral() const301     bool isLiteral() const override {
302         return true;
303     }
304 
slotCount() const305     size_t slotCount() const override {
306         return 1;
307     }
308 
slotType(size_t n) const309     const Type& slotType(size_t n) const override {
310         SkASSERT(n == 0);
311         return fScalarType;
312     }
313 
314 private:
315     using INHERITED = Type;
316 
317     const Type& fScalarType;
318     int8_t fPriority;
319 };
320 
321 
322 class ScalarType final : public Type {
323 public:
324     inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
325 
ScalarType(std::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)326     ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
327                int8_t bitWidth)
328             : INHERITED(name, abbrev, kTypeKind)
329             , fNumberKind(numberKind)
330             , fPriority(priority)
331             , fBitWidth(bitWidth) {}
332 
numberKind() const333     NumberKind numberKind() const override {
334         return fNumberKind;
335     }
336 
priority() const337     int priority() const override {
338         return fPriority;
339     }
340 
bitWidth() const341     int bitWidth() const override {
342         return fBitWidth;
343     }
344 
columns() const345     int columns() const override {
346         return 1;
347     }
348 
rows() const349     int rows() const override {
350         return 1;
351     }
352 
isScalar() const353     bool isScalar() const override {
354         return true;
355     }
356 
isAllowedInES2() const357     bool isAllowedInES2() const override {
358         return fNumberKind != NumberKind::kUnsigned;
359     }
360 
isAllowedInUniform(Position *) const361     bool isAllowedInUniform(Position*) const override {
362         return fNumberKind != NumberKind::kBoolean;
363     }
364 
slotCount() const365     size_t slotCount() const override {
366         return 1;
367     }
368 
slotType(size_t n) const369     const Type& slotType(size_t n) const override {
370         SkASSERT(n == 0);
371         return *this;
372     }
373 
374     using int_limits = std::numeric_limits<int32_t>;
375     using short_limits = std::numeric_limits<int16_t>;
376     using uint_limits = std::numeric_limits<uint32_t>;
377     using ushort_limits = std::numeric_limits<uint16_t>;
378     using float_limits = std::numeric_limits<float>;
379 
380     /** Returns the maximum value that can fit in the type. */
minimumValue() const381     double minimumValue() const override {
382         switch (this->numberKind()) {
383             case NumberKind::kSigned:
384                 return this->highPrecision() ? int_limits::lowest()
385                                              : short_limits::lowest();
386 
387             case NumberKind::kUnsigned:
388                 return 0;
389 
390             case NumberKind::kFloat:
391             default:
392                 return float_limits::lowest();
393         }
394     }
395 
396     /** Returns the maximum value that can fit in the type. */
maximumValue() const397     double maximumValue() const override {
398         switch (this->numberKind()) {
399             case NumberKind::kSigned:
400                 return this->highPrecision() ? int_limits::max()
401                                              : short_limits::max();
402 
403             case NumberKind::kUnsigned:
404                 return this->highPrecision() ? uint_limits::max()
405                                              : ushort_limits::max();
406 
407             case NumberKind::kFloat:
408             default:
409                 return float_limits::max();
410         }
411     }
412 
413 private:
414     using INHERITED = Type;
415 
416     NumberKind fNumberKind;
417     int8_t fPriority;
418     int8_t fBitWidth;
419 };
420 
421 class AtomicType final : public Type {
422 public:
423     inline static constexpr TypeKind kTypeKind = TypeKind::kAtomic;
424 
AtomicType(std::string_view name,const char * abbrev)425     AtomicType(std::string_view name, const char* abbrev) : INHERITED(name, abbrev, kTypeKind) {}
426 
isAllowedInES2() const427     bool isAllowedInES2() const override { return false; }
428 
isAllowedInUniform(Position *) const429     bool isAllowedInUniform(Position*) const override { return false; }
430 
isOrContainsAtomic() const431     bool isOrContainsAtomic() const override { return true; }
432 
slotType(size_t n) const433     const Type& slotType(size_t n) const override {
434         SkASSERT(n == 0);
435         return *this;
436     }
437 
438 private:
439     using INHERITED = Type;
440 };
441 
442 class MatrixType final : public Type {
443 public:
444     inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
445 
MatrixType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)446     MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
447                int8_t columns, int8_t rows)
448             : INHERITED(name, abbrev, kTypeKind)
449             , fComponentType(componentType.as<ScalarType>())
450             , fColumns(columns)
451             , fRows(rows) {
452         SkASSERT(columns >= 2 && columns <= 4);
453         SkASSERT(rows >= 2 && rows <= 4);
454     }
455 
componentType() const456     const ScalarType& componentType() const override {
457         return fComponentType;
458     }
459 
columns() const460     int columns() const override {
461         return fColumns;
462     }
463 
rows() const464     int rows() const override {
465         return fRows;
466     }
467 
bitWidth() const468     int bitWidth() const override {
469         return this->componentType().bitWidth();
470     }
471 
isMatrix() const472     bool isMatrix() const override {
473         return true;
474     }
475 
isAllowedInES2() const476     bool isAllowedInES2() const override {
477         return fColumns == fRows;
478     }
479 
slotCount() const480     size_t slotCount() const override {
481         return fColumns * fRows;
482     }
483 
slotType(size_t n) const484     const Type& slotType(size_t n) const override {
485         SkASSERT(n < this->slotCount());
486         return fComponentType;
487     }
488 
489 private:
490     using INHERITED = Type;
491 
492     const ScalarType& fComponentType;
493     int8_t fColumns;
494     int8_t fRows;
495 };
496 
497 class TextureType final : public Type {
498 public:
499     inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
500 
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,TextureAccess textureAccess)501     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
502                 bool isMultisampled, TextureAccess textureAccess)
503             : INHERITED(name, "T", kTypeKind)
504             , fDimensions(dimensions)
505             , fIsDepth(isDepth)
506             , fIsArrayed(isArrayed)
507             , fIsMultisampled(isMultisampled)
508             , fTextureAccess(textureAccess) {}
509 
dimensions() const510     SpvDim_ dimensions() const override {
511         return fDimensions;
512     }
513 
isDepth() const514     bool isDepth() const override {
515         return fIsDepth;
516     }
517 
isArrayedTexture() const518     bool isArrayedTexture() const override {
519         return fIsArrayed;
520     }
521 
isMultisampled() const522     bool isMultisampled() const override {
523         return fIsMultisampled;
524     }
525 
textureAccess() const526     TextureAccess textureAccess() const override {
527         return fTextureAccess;
528     }
529 
slotType(size_t n) const530     const Type& slotType(size_t n) const override {
531         SkASSERT(n == 0);
532         return *this;
533     }
534 
535 private:
536     using INHERITED = Type;
537 
538     SpvDim_ fDimensions;
539     bool fIsDepth;
540     bool fIsArrayed;
541     bool fIsMultisampled;
542     TextureAccess fTextureAccess;
543 };
544 
545 class SamplerType final : public Type {
546 public:
547     inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
548 
SamplerType(const char * name,const Type & textureType)549     SamplerType(const char* name, const Type& textureType)
550             : INHERITED(name, "Z", kTypeKind)
551             , fTextureType(textureType.as<TextureType>()) {
552         // Samplers require sampled texture access.
553         SkASSERT(this->textureAccess() == TextureAccess::kSample);
554         // Subpass inputs cannot be sampled.
555         SkASSERT(this->dimensions() != SpvDimSubpassData);
556     }
557 
textureType() const558     const TextureType& textureType() const override {
559         return fTextureType;
560     }
561 
dimensions() const562     SpvDim_ dimensions() const override {
563         return fTextureType.dimensions();
564     }
565 
isDepth() const566     bool isDepth() const override {
567         return fTextureType.isDepth();
568     }
569 
isArrayedTexture() const570     bool isArrayedTexture() const override {
571         return fTextureType.isArrayedTexture();
572     }
573 
isMultisampled() const574     bool isMultisampled() const override {
575         return fTextureType.isMultisampled();
576     }
577 
textureAccess() const578     TextureAccess textureAccess() const override {
579         return fTextureType.textureAccess();
580     }
581 
slotType(size_t n) const582     const Type& slotType(size_t n) const override {
583         SkASSERT(n == 0);
584         return *this;
585     }
586 
587 private:
588     using INHERITED = Type;
589 
590     const TextureType& fTextureType;
591 };
592 
593 class StructType final : public Type {
594 public:
595     inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
596 
StructType(Position pos,std::string_view name,TArray<Field> fields,int nestingDepth,bool interfaceBlock,bool isBuiltin)597     StructType(Position pos, std::string_view name, TArray<Field> fields, int nestingDepth,
598                bool interfaceBlock, bool isBuiltin)
599             : INHERITED(std::move(name), "S", kTypeKind, pos)
600             , fFields(std::move(fields))
601             , fNestingDepth(nestingDepth)
602             , fInterfaceBlock(interfaceBlock)
603             , fIsBuiltin(isBuiltin) {
604         for (const Field& f : fFields) {
605             fContainsArray        = fContainsArray        || f.fType->isOrContainsArray();
606             fContainsUnsizedArray = fContainsUnsizedArray || f.fType->isOrContainsUnsizedArray();
607             fContainsAtomic       = fContainsAtomic       || f.fType->isOrContainsAtomic();
608             fIsAllowedInES2       = fIsAllowedInES2       && f.fType->isAllowedInES2();
609         }
610         for (const Field& f : fFields) {
611             Position errorPosition = f.fPosition;
612             if (!f.fType->isAllowedInUniform(&errorPosition)) {
613                 fUniformErrorPosition = errorPosition;
614                 break;
615             }
616         }
617         if (!fContainsUnsizedArray) {
618             for (const Field& f : fFields) {
619                 fSlotCount += f.fType->slotCount();
620             }
621         }
622     }
623 
fields() const624     SkSpan<const Field> fields() const override {
625         return fFields;
626     }
627 
isStruct() const628     bool isStruct() const override {
629         return true;
630     }
631 
isInterfaceBlock() const632     bool isInterfaceBlock() const override {
633         return fInterfaceBlock;
634     }
635 
isBuiltin() const636     bool isBuiltin() const override {
637         return fIsBuiltin;
638     }
639 
isAllowedInES2() const640     bool isAllowedInES2() const override {
641         return fIsAllowedInES2;
642     }
643 
isAllowedInUniform(Position * errorPosition) const644     bool isAllowedInUniform(Position* errorPosition) const override {
645         if (errorPosition != nullptr) {
646             *errorPosition = fUniformErrorPosition;
647         }
648         return !fUniformErrorPosition.valid();
649     }
650 
isOrContainsArray() const651     bool isOrContainsArray() const override {
652         return fContainsArray;
653     }
654 
isOrContainsUnsizedArray() const655     bool isOrContainsUnsizedArray() const override {
656         return fContainsUnsizedArray;
657     }
658 
isOrContainsAtomic() const659     bool isOrContainsAtomic() const override {
660         return fContainsAtomic;
661     }
662 
slotCount() const663     size_t slotCount() const override {
664         SkASSERT(!fContainsUnsizedArray);
665         return fSlotCount;
666     }
667 
structNestingDepth() const668     int structNestingDepth() const override {
669         return fNestingDepth;
670     }
671 
slotType(size_t n) const672     const Type& slotType(size_t n) const override {
673         for (const Field& field : fFields) {
674             size_t fieldSlots = field.fType->slotCount();
675             if (n < fieldSlots) {
676                 return field.fType->slotType(n);
677             } else {
678                 n -= fieldSlots;
679             }
680         }
681         SkDEBUGFAIL("slot index out of range");
682         return *this;
683     }
684 
685 private:
686     using INHERITED = Type;
687 
688     TArray<Field> fFields;
689     size_t fSlotCount = 0;
690     int fNestingDepth = 0;
691     Position fUniformErrorPosition = {};
692     bool fInterfaceBlock = false;
693     bool fContainsArray = false;
694     bool fContainsUnsizedArray = false;
695     bool fContainsAtomic = false;
696     bool fIsBuiltin = false;
697     bool fIsAllowedInES2 = true;
698 };
699 
700 class VectorType final : public Type {
701 public:
702     inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
703 
VectorType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns)704     VectorType(std::string_view name, const char* abbrev, const Type& componentType,
705                int8_t columns)
706             : INHERITED(name, abbrev, kTypeKind)
707             , fComponentType(componentType.as<ScalarType>())
708             , fColumns(columns) {
709         SkASSERT(columns >= 2 && columns <= 4);
710     }
711 
componentType() const712     const ScalarType& componentType() const override {
713         return fComponentType;
714     }
715 
columns() const716     int columns() const override {
717         return fColumns;
718     }
719 
rows() const720     int rows() const override {
721         return 1;
722     }
723 
bitWidth() const724     int bitWidth() const override {
725         return this->componentType().bitWidth();
726     }
727 
isVector() const728     bool isVector() const override {
729         return true;
730     }
731 
isAllowedInES2() const732     bool isAllowedInES2() const override {
733         return fComponentType.isAllowedInES2();
734     }
735 
isAllowedInUniform(Position * errorPosition) const736     bool isAllowedInUniform(Position* errorPosition) const override {
737         return fComponentType.isAllowedInUniform(errorPosition);
738     }
739 
slotCount() const740     size_t slotCount() const override {
741         return fColumns;
742     }
743 
slotType(size_t n) const744     const Type& slotType(size_t n) const override {
745         SkASSERT(n < SkToSizeT(fColumns));
746         return fComponentType;
747     }
748 
749 private:
750     using INHERITED = Type;
751 
752     const ScalarType& fComponentType;
753     int8_t fColumns;
754 };
755 
getArrayName(int arraySize) const756 std::string Type::getArrayName(int arraySize) const {
757     std::string_view name = this->name();
758     if (arraySize == kUnsizedArray) {
759         return String::printf("%.*s[]", (int)name.size(), name.data());
760     }
761     return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
762 }
763 
MakeAliasType(std::string_view name,const Type & targetType)764 std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
765     return std::make_unique<AliasType>(std::move(name), targetType);
766 }
767 
MakeArrayType(const Context & context,std::string_view name,const Type & componentType,int columns)768 std::unique_ptr<Type> Type::MakeArrayType(const Context& context,
769                                           std::string_view name,
770                                           const Type& componentType,
771                                           int columns) {
772     return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
773                                        componentType, columns, context.fConfig->fIsBuiltinCode);
774 }
775 
MakeGenericType(const char * name,SkSpan<const Type * const> types,const Type * slotType)776 std::unique_ptr<Type> Type::MakeGenericType(const char* name,
777                                             SkSpan<const Type* const> types,
778                                             const Type* slotType) {
779     return std::make_unique<GenericType>(name, types, slotType);
780 }
781 
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)782 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
783                                             int8_t priority) {
784     return std::make_unique<LiteralType>(name, scalarType, priority);
785 }
786 
MakeMatrixType(std::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)787 std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
788                                            const Type& componentType, int columns, int8_t rows) {
789     return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
790 }
791 
MakeSamplerType(const char * name,const Type & textureType)792 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
793     return std::make_unique<SamplerType>(name, textureType);
794 }
795 
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)796 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
797                                             Type::TypeKind typeKind) {
798     return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
799 }
800 
MakeScalarType(std::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)801 std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
802                                            Type::NumberKind numberKind, int8_t priority,
803                                            int8_t bitWidth) {
804     return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
805 }
806 
MakeAtomicType(std::string_view name,const char * abbrev)807 std::unique_ptr<Type> Type::MakeAtomicType(std::string_view name, const char* abbrev) {
808     return std::make_unique<AtomicType>(name, abbrev);
809 }
810 
MakeStructType(const Context & context,Position pos,std::string_view name,TArray<Field> fields,bool interfaceBlock)811 std::unique_ptr<Type> Type::MakeStructType(const Context& context,
812                                            Position pos,
813                                            std::string_view name,
814                                            TArray<Field> fields,
815                                            bool interfaceBlock) {
816     const char* const structOrIB  = interfaceBlock ? "interface block" : "struct";
817     const char* const aStructOrIB = interfaceBlock ? "an interface block" : "a struct";
818 
819     if (fields.empty()) {
820         context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
821                                     "' must contain at least one field");
822     }
823     size_t slots = 0;
824 
825     THashSet<std::string_view> fieldNames;
826     for (const Field& field : fields) {
827         // Add this field name to our set; if the set doesn't grow, we found a duplicate.
828         int numFieldNames = fieldNames.count();
829         fieldNames.add(field.fName);
830         if (fieldNames.count() == numFieldNames) {
831             context.fErrors->error(field.fPosition, "field '" + std::string(field.fName) +
832                                                     "' was already defined in the same " +
833                                                     std::string(structOrIB) + " ('" +
834                                                     std::string(name) + "')");
835         }
836         if (field.fModifierFlags != ModifierFlag::kNone) {
837             std::string desc = field.fModifierFlags.description();
838             context.fErrors->error(field.fPosition, "modifier '" + desc + "' is not permitted on " +
839                                                     std::string(aStructOrIB) + " field");
840         }
841         if (field.fLayout.fFlags & LayoutFlag::kBinding) {
842             context.fErrors->error(field.fPosition, "layout qualifier 'binding' is not permitted "
843                                                     "on " + std::string(aStructOrIB) + " field");
844         }
845         if (field.fLayout.fFlags & LayoutFlag::kSet) {
846             context.fErrors->error(field.fPosition, "layout qualifier 'set' is not permitted on " +
847                                                     std::string(aStructOrIB) + " field");
848         }
849 
850         if (field.fType->isVoid()) {
851             context.fErrors->error(field.fPosition, "type 'void' is not permitted in " +
852                                                     std::string(aStructOrIB));
853         }
854         if (field.fType->isOpaque() && !field.fType->isAtomic()) {
855             context.fErrors->error(field.fPosition, "opaque type '" + field.fType->displayName() +
856                                                     "' is not permitted in " +
857                                                     std::string(aStructOrIB));
858         }
859         if (field.fType->isOrContainsUnsizedArray()) {
860             if (!interfaceBlock) {
861                 // Reject unsized arrays anywhere in structs.
862                 context.fErrors->error(field.fPosition, "unsized arrays are not permitted here");
863             }
864         } else {
865             // If we haven't already exceeded the struct size limit...
866             if (slots < kVariableSlotLimit) {
867                 // ... see if this field causes us to exceed the size limit.
868                 slots = SkSafeMath::Add(slots, field.fType->slotCount());
869                 if (slots >= kVariableSlotLimit) {
870                     context.fErrors->error(pos, std::string(structOrIB) + " is too large");
871                 }
872             }
873         }
874     }
875     int nestingDepth = 0;
876     for (const Field& field : fields) {
877         nestingDepth = std::max(nestingDepth, field.fType->structNestingDepth());
878     }
879     if (nestingDepth >= kMaxStructDepth) {
880         context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
881                                     "' is too deeply nested");
882     }
883     return std::make_unique<StructType>(pos, name, std::move(fields), nestingDepth + 1,
884                                         interfaceBlock, context.fConfig->fIsBuiltinCode);
885 }
886 
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,TextureAccess textureAccess)887 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
888                                             bool isArrayedTexture, bool isMultisampled,
889                                             TextureAccess textureAccess) {
890     return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
891                                          isMultisampled, textureAccess);
892 }
893 
MakeVectorType(std::string_view name,const char * abbrev,const Type & componentType,int columns)894 std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
895                                            const Type& componentType, int columns) {
896     return std::make_unique<VectorType>(name, abbrev, componentType, columns);
897 }
898 
coercionCost(const Type & other) const899 CoercionCost Type::coercionCost(const Type& other) const {
900     if (this->matches(other)) {
901         return CoercionCost::Free();
902     }
903     if (this->typeKind() == other.typeKind() &&
904         (this->isVector() || this->isMatrix() || this->isArray())) {
905         // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
906         if (this->isMatrix() && (this->rows() != other.rows())) {
907             return CoercionCost::Impossible();
908         }
909         if (this->columns() != other.columns()) {
910             return CoercionCost::Impossible();
911         }
912         return this->componentType().coercionCost(other.componentType());
913     }
914     if (this->isNumber() && other.isNumber()) {
915         if (this->isLiteral() && this->isInteger()) {
916             return CoercionCost::Free();
917         } else if (this->numberKind() != other.numberKind()) {
918             return CoercionCost::Impossible();
919         } else if (other.priority() >= this->priority()) {
920             return CoercionCost::Normal(other.priority() - this->priority());
921         } else {
922             return CoercionCost::Narrowing(this->priority() - other.priority());
923         }
924     }
925     if (fTypeKind == TypeKind::kGeneric) {
926         SkSpan<const Type* const> types = this->coercibleTypes();
927         for (size_t i = 0; i < types.size(); i++) {
928             if (types[i]->matches(other)) {
929                 return CoercionCost::Normal((int) i + 1);
930             }
931         }
932     }
933     return CoercionCost::Impossible();
934 }
935 
applyQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const936 const Type* Type::applyQualifiers(const Context& context,
937                                   ModifierFlags* modifierFlags,
938                                   Position pos) const {
939     const Type* type;
940     type = this->applyPrecisionQualifiers(context, modifierFlags, pos);
941     type = type->applyAccessQualifiers(context, modifierFlags, pos);
942     return type;
943 }
944 
applyPrecisionQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const945 const Type* Type::applyPrecisionQualifiers(const Context& context,
946                                            ModifierFlags* modifierFlags,
947                                            Position pos) const {
948     ModifierFlags precisionQualifiers = *modifierFlags & (ModifierFlag::kHighp |
949                                                           ModifierFlag::kMediump |
950                                                           ModifierFlag::kLowp);
951     if (precisionQualifiers == ModifierFlag::kNone) {
952         // No precision qualifiers here. Return the type as-is.
953         return this;
954     }
955 
956     if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
957         // We want to discourage precision modifiers internally. Instead, use the type that
958         // corresponds to the precision you need. (e.g. half vs float, short vs int)
959         context.fErrors->error(pos, "precision qualifiers are not allowed");
960         return context.fTypes.fPoison.get();
961     }
962 
963     if (SkPopCount(precisionQualifiers.value()) > 1) {
964         context.fErrors->error(pos, "only one precision qualifier can be used");
965         return context.fTypes.fPoison.get();
966     }
967 
968     // We're going to return a whole new type, so the modifier bits can be cleared out.
969     *modifierFlags &= ~(ModifierFlag::kHighp |
970                         ModifierFlag::kMediump |
971                         ModifierFlag::kLowp);
972 
973     const Type& component = this->componentType();
974     if (component.highPrecision()) {
975         if (precisionQualifiers & ModifierFlag::kHighp) {
976             // Type is already high precision, and we are requesting high precision. Return as-is.
977             return this;
978         }
979 
980         // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
981         // Ascertain the mediump equivalent type for this type, if any.
982         const Type* mediumpType;
983         switch (component.numberKind()) {
984             case Type::NumberKind::kFloat:
985                 mediumpType = context.fTypes.fHalf.get();
986                 break;
987 
988             case Type::NumberKind::kSigned:
989                 mediumpType = context.fTypes.fShort.get();
990                 break;
991 
992             case Type::NumberKind::kUnsigned:
993                 mediumpType = context.fTypes.fUShort.get();
994                 break;
995 
996             default:
997                 mediumpType = context.fTypes.fPoison.get();
998                 break;
999         }
1000 
1001         if (mediumpType) {
1002             // Convert the mediump component type into the final vector/matrix/array type as needed.
1003             return this->isArray()
1004                     ? context.fSymbolTable->addArrayDimension(context, mediumpType, this->columns())
1005                     : &mediumpType->toCompound(context, this->columns(), this->rows());
1006         }
1007     }
1008 
1009     context.fErrors->error(pos, "type '" + this->displayName() +
1010                                 "' does not support precision qualifiers");
1011     return context.fTypes.fPoison.get();
1012 }
1013 
applyAccessQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const1014 const Type* Type::applyAccessQualifiers(const Context& context,
1015                                         ModifierFlags* modifierFlags,
1016                                         Position pos) const {
1017     ModifierFlags accessQualifiers = *modifierFlags & (ModifierFlag::kReadOnly |
1018                                                        ModifierFlag::kWriteOnly);
1019 
1020     // We're going to return a whole new type, so the modifier bits must be cleared out.
1021     *modifierFlags &= ~(ModifierFlag::kReadOnly |
1022                         ModifierFlag::kWriteOnly);
1023 
1024     if (this->matches(*context.fTypes.fTexture2D)) {
1025         // We require all texture2Ds to be qualified with `readonly` or `writeonly`.
1026         // (Read-write textures are not yet supported in WGSL.)
1027         if (accessQualifiers == ModifierFlag::kReadOnly) {
1028             return context.fTypes.fReadOnlyTexture2D.get();
1029         }
1030         if (accessQualifiers == ModifierFlag::kWriteOnly) {
1031             return context.fTypes.fWriteOnlyTexture2D.get();
1032         }
1033         context.fErrors->error(
1034                 pos,
1035                 accessQualifiers
1036                         ? "'readonly' and 'writeonly' qualifiers cannot be combined"
1037                         : "'texture2D' requires a 'readonly' or 'writeonly' access qualifier");
1038         return this;
1039     }
1040 
1041     if (accessQualifiers) {
1042         context.fErrors->error(pos, "type '" + this->displayName() + "' does not support "
1043                                     "qualifier '" + accessQualifiers.description() + "'");
1044     }
1045 
1046     return this;
1047 }
1048 
toCompound(const Context & context,int columns,int rows) const1049 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
1050     SkASSERT(this->isScalar());
1051     if (columns == 1 && rows == 1) {
1052         return *this;
1053     }
1054     if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
1055         switch (rows) {
1056             case 1:
1057                 switch (columns) {
1058                     case 1: return *context.fTypes.fFloat;
1059                     case 2: return *context.fTypes.fFloat2;
1060                     case 3: return *context.fTypes.fFloat3;
1061                     case 4: return *context.fTypes.fFloat4;
1062                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1063                 }
1064             case 2:
1065                 switch (columns) {
1066                     case 2: return *context.fTypes.fFloat2x2;
1067                     case 3: return *context.fTypes.fFloat3x2;
1068                     case 4: return *context.fTypes.fFloat4x2;
1069                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1070                 }
1071             case 3:
1072                 switch (columns) {
1073                     case 2: return *context.fTypes.fFloat2x3;
1074                     case 3: return *context.fTypes.fFloat3x3;
1075                     case 4: return *context.fTypes.fFloat4x3;
1076                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1077                 }
1078             case 4:
1079                 switch (columns) {
1080                     case 2: return *context.fTypes.fFloat2x4;
1081                     case 3: return *context.fTypes.fFloat3x4;
1082                     case 4: return *context.fTypes.fFloat4x4;
1083                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1084                 }
1085             default: SK_ABORT("unsupported row count (%d)", rows);
1086         }
1087     } else if (this->matches(*context.fTypes.fHalf)) {
1088         switch (rows) {
1089             case 1:
1090                 switch (columns) {
1091                     case 1: return *context.fTypes.fHalf;
1092                     case 2: return *context.fTypes.fHalf2;
1093                     case 3: return *context.fTypes.fHalf3;
1094                     case 4: return *context.fTypes.fHalf4;
1095                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1096                 }
1097             case 2:
1098                 switch (columns) {
1099                     case 2: return *context.fTypes.fHalf2x2;
1100                     case 3: return *context.fTypes.fHalf3x2;
1101                     case 4: return *context.fTypes.fHalf4x2;
1102                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1103                 }
1104             case 3:
1105                 switch (columns) {
1106                     case 2: return *context.fTypes.fHalf2x3;
1107                     case 3: return *context.fTypes.fHalf3x3;
1108                     case 4: return *context.fTypes.fHalf4x3;
1109                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1110                 }
1111             case 4:
1112                 switch (columns) {
1113                     case 2: return *context.fTypes.fHalf2x4;
1114                     case 3: return *context.fTypes.fHalf3x4;
1115                     case 4: return *context.fTypes.fHalf4x4;
1116                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1117                 }
1118             default: SK_ABORT("unsupported row count (%d)", rows);
1119         }
1120     } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
1121         switch (rows) {
1122             case 1:
1123                 switch (columns) {
1124                     case 1: return *context.fTypes.fInt;
1125                     case 2: return *context.fTypes.fInt2;
1126                     case 3: return *context.fTypes.fInt3;
1127                     case 4: return *context.fTypes.fInt4;
1128                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1129                 }
1130             default: SK_ABORT("unsupported row count (%d)", rows);
1131         }
1132     } else if (this->matches(*context.fTypes.fShort)) {
1133         switch (rows) {
1134             case 1:
1135                 switch (columns) {
1136                     case 1: return *context.fTypes.fShort;
1137                     case 2: return *context.fTypes.fShort2;
1138                     case 3: return *context.fTypes.fShort3;
1139                     case 4: return *context.fTypes.fShort4;
1140                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1141                 }
1142             default: SK_ABORT("unsupported row count (%d)", rows);
1143         }
1144     } else if (this->matches(*context.fTypes.fUInt)) {
1145         switch (rows) {
1146             case 1:
1147                 switch (columns) {
1148                     case 1: return *context.fTypes.fUInt;
1149                     case 2: return *context.fTypes.fUInt2;
1150                     case 3: return *context.fTypes.fUInt3;
1151                     case 4: return *context.fTypes.fUInt4;
1152                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1153                 }
1154             default: SK_ABORT("unsupported row count (%d)", rows);
1155         }
1156     } else if (this->matches(*context.fTypes.fUShort)) {
1157         switch (rows) {
1158             case 1:
1159                 switch (columns) {
1160                     case 1: return *context.fTypes.fUShort;
1161                     case 2: return *context.fTypes.fUShort2;
1162                     case 3: return *context.fTypes.fUShort3;
1163                     case 4: return *context.fTypes.fUShort4;
1164                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1165                 }
1166             default: SK_ABORT("unsupported row count (%d)", rows);
1167         }
1168     } else if (this->matches(*context.fTypes.fBool)) {
1169         switch (rows) {
1170             case 1:
1171                 switch (columns) {
1172                     case 1: return *context.fTypes.fBool;
1173                     case 2: return *context.fTypes.fBool2;
1174                     case 3: return *context.fTypes.fBool3;
1175                     case 4: return *context.fTypes.fBool4;
1176                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1177                 }
1178             default: SK_ABORT("unsupported row count (%d)", rows);
1179         }
1180     }
1181     SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
1182     return *context.fTypes.fVoid;
1183 }
1184 
clone(const Context & context,SymbolTable * symbolTable) const1185 const Type* Type::clone(const Context& context, SymbolTable* symbolTable) const {
1186     // Many types are built-ins, and exist in every SymbolTable by default.
1187     if (this->isInRootSymbolTable()) {
1188         return this;
1189     }
1190     // If we are compiling a program, and the type comes from the program's module, it is safe to
1191     // assume that the type is in-scope anywhere in the program without actually recursing through
1192     // the SymbolTable hierarchy to prove it.
1193     if (!context.fConfig->fIsBuiltinCode && this->isBuiltin()) {
1194         return this;
1195     }
1196     // Even if the type isn't a built-in, it might already exist in the SymbolTable. Search by name.
1197     const Symbol* existingSymbol = symbolTable->find(this->name());
1198     if (existingSymbol != nullptr) {
1199         const Type* existingType = &existingSymbol->as<Type>();
1200         SkASSERT(existingType->typeKind() == this->typeKind());
1201         return existingType;
1202     }
1203     // This type actually needs to be cloned into the destination SymbolTable.
1204     switch (this->typeKind()) {
1205         case TypeKind::kArray: {
1206             return symbolTable->addArrayDimension(context, &this->componentType(), this->columns());
1207         }
1208         case TypeKind::kStruct: {
1209             // We are cloning an existing struct, so there's no need to call MakeStructType and
1210             // fully error-check it again.
1211             const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
1212             SkSpan<const Field> fieldSpan = this->fields();
1213             return symbolTable->add(
1214                     context,
1215                     std::make_unique<StructType>(this->fPosition,
1216                                                  *name,
1217                                                  TArray<Field>(fieldSpan.data(), fieldSpan.size()),
1218                                                  this->structNestingDepth(),
1219                                                  /*interfaceBlock=*/this->isInterfaceBlock(),
1220                                                  /*isBuiltin=*/context.fConfig->fIsBuiltinCode));
1221         }
1222         default:
1223             SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
1224             return nullptr;
1225     }
1226 }
1227 
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const1228 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
1229                                                    const Context& context) const {
1230     if (!expr || expr->isIncomplete(context)) {
1231         return nullptr;
1232     }
1233     if (expr->type().matches(*this)) {
1234         return expr;
1235     }
1236 
1237     const Position pos = expr->fPosition;
1238     const ProgramSettings& settings = context.fConfig->fSettings;
1239     if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
1240         context.fErrors->error(pos, "expected '" + this->displayName() + "', but found '" +
1241                                     expr->type().displayName() + "'");
1242         return nullptr;
1243     }
1244 
1245     if (this->isScalar()) {
1246         return ConstructorScalarCast::Make(context, pos, *this, std::move(expr));
1247     }
1248     if (this->isVector() || this->isMatrix()) {
1249         return ConstructorCompoundCast::Make(context, pos, *this, std::move(expr));
1250     }
1251     if (this->isArray()) {
1252         return ConstructorArrayCast::Make(context, pos, *this, std::move(expr));
1253     }
1254     context.fErrors->error(pos, "cannot construct '" + this->displayName() + "'");
1255     return nullptr;
1256 }
1257 
isAllowedInES2(const Context & context) const1258 bool Type::isAllowedInES2(const Context& context) const {
1259     return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
1260 }
1261 
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const1262 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
1263     bool foundError = false;
1264     const Type& baseType = this->componentType();
1265     if (baseType.isNumber()) {
1266         // Replace constant expressions with their corresponding values.
1267         const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
1268         if (valueExpr->supportsConstantValues()) {
1269             // Iterate over every constant subexpression in the value.
1270             int numSlots = valueExpr->type().slotCount();
1271             for (int slot = 0; slot < numSlots; ++slot) {
1272                 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
1273                 // Check for Literal values that are out of range for the base type.
1274                 if (slotVal.has_value() &&
1275                     baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fPosition)) {
1276                     foundError = true;
1277                 }
1278             }
1279         }
1280     }
1281 
1282     // We don't need range checks for floats or booleans; any matched-type value is acceptable.
1283     return foundError;
1284 }
1285 
checkForOutOfRangeLiteral(const Context & context,double value,Position pos) const1286 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const {
1287     SkASSERT(this->isScalar());
1288     if (!this->isNumber()) {
1289        return false;
1290     }
1291     if (value >= this->minimumValue() && value <= this->maximumValue()) {
1292         return false;
1293     }
1294     // We found a value that can't fit in our type. Flag it as an error.
1295     context.fErrors->error(pos, SkSL::String::printf("value is out of range for type '%s': %.0f",
1296                                                      this->displayName().c_str(),
1297                                                      value));
1298     return true;
1299 }
1300 
checkIfUsableInArray(const Context & context,Position arrayPos) const1301 bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
1302     if (this->isArray()) {
1303         context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
1304         return false;
1305     }
1306     if (this->isVoid()) {
1307         context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
1308         return false;
1309     }
1310     if (this->isOpaque() && !this->isAtomic()) {
1311         context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
1312                                          "' may not be used in an array");
1313         return false;
1314     }
1315     return true;
1316 }
1317 
convertArraySize(const Context & context,Position arrayPos,std::unique_ptr<Expression> size) const1318 SKSL_INT Type::convertArraySize(const Context& context,
1319                                 Position arrayPos,
1320                                 std::unique_ptr<Expression> size) const {
1321     size = context.fTypes.fInt->coerceExpression(std::move(size), context);
1322     if (!size) {
1323         return 0;
1324     }
1325     SKSL_INT count;
1326     if (!ConstantFolder::GetConstantInt(*size, &count)) {
1327         context.fErrors->error(size->fPosition, "array size must be an integer");
1328         return 0;
1329     }
1330     return this->convertArraySize(context, arrayPos, size->fPosition, count);
1331 }
1332 
convertArraySize(const Context & context,Position arrayPos,Position sizePos,SKSL_INT size) const1333 SKSL_INT Type::convertArraySize(const Context& context,
1334                                 Position arrayPos,
1335                                 Position sizePos,
1336                                 SKSL_INT size) const {
1337     if (!this->checkIfUsableInArray(context, arrayPos)) {
1338         // `checkIfUsableInArray` will generate an error for us.
1339         return 0;
1340     }
1341     if (size <= 0) {
1342         context.fErrors->error(sizePos, "array size must be positive");
1343         return 0;
1344     }
1345     // We can't get a meaningful slot count if the interior type contains an unsized array; we'll
1346     // assert if we try. Unsized arrays should only occur in a handful of limited cases (e.g. an
1347     // interface block with a trailing buffer), and will never be valid in a runtime effect.
1348     if (!this->isOrContainsUnsizedArray()) {
1349         if (SkSafeMath::Mul(this->slotCount(), size) > kVariableSlotLimit) {
1350             context.fErrors->error(sizePos, "array size is too large");
1351             return 0;
1352         }
1353     }
1354     return size;
1355 }
1356 
description() const1357 std::string Field::description() const {
1358     return fLayout.paddedDescription() + fModifierFlags.paddedDescription() + fType->displayName() +
1359            ' ' + std::string(fName) + ';';
1360 }
1361 
1362 }  // namespace SkSL
1363