xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLType.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
isOrContainsBool() const80     bool isOrContainsBool() const override {
81         return fTargetType.isOrContainsBool();
82     }
83 
isOrContainsAtomic() const84     bool isOrContainsAtomic() const override {
85         return fTargetType.isOrContainsAtomic();
86     }
87 
slotCount() const88     size_t slotCount() const override {
89         return fTargetType.slotCount();
90     }
91 
slotType(size_t n) const92     const Type& slotType(size_t n) const override {
93         return fTargetType.slotType(n);
94     }
95 
dimensions() const96     SpvDim_ dimensions() const override {
97         return fTargetType.dimensions();
98     }
99 
isDepth() const100     bool isDepth() const override {
101         return fTargetType.isDepth();
102     }
103 
isArrayedTexture() const104     bool isArrayedTexture() const override {
105         return fTargetType.isArrayedTexture();
106     }
107 
isScalar() const108     bool isScalar() const override {
109         return fTargetType.isScalar();
110     }
111 
isLiteral() const112     bool isLiteral() const override {
113         return fTargetType.isLiteral();
114     }
115 
isVector() const116     bool isVector() const override {
117         return fTargetType.isVector();
118     }
119 
isMatrix() const120     bool isMatrix() const override {
121         return fTargetType.isMatrix();
122     }
123 
isArray() const124     bool isArray() const override {
125         return fTargetType.isArray();
126     }
127 
isUnsizedArray() const128     bool isUnsizedArray() const override {
129         return fTargetType.isUnsizedArray();
130     }
131 
isStruct() const132     bool isStruct() const override {
133         return fTargetType.isStruct();
134     }
135 
isInterfaceBlock() const136     bool isInterfaceBlock() const override {
137         return fTargetType.isInterfaceBlock();
138     }
139 
isMultisampled() const140     bool isMultisampled() const override {
141         return fTargetType.isMultisampled();
142     }
143 
textureAccess() const144     TextureAccess textureAccess() const override {
145         return fTargetType.textureAccess();
146     }
147 
coercibleTypes() const148     SkSpan<const Type* const> coercibleTypes() const override {
149         return fTargetType.coercibleTypes();
150     }
151 
152 private:
153     using INHERITED = Type;
154 
155     const Type& fTargetType;
156 };
157 
158 class ArrayType final : public Type {
159 public:
160     inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
161 
ArrayType(std::string_view name,const char * abbrev,const Type & componentType,int count,bool isBuiltin)162     ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count,
163               bool isBuiltin)
164             : INHERITED(name, abbrev, kTypeKind)
165             , fComponentType(componentType)
166             , fCount(count)
167             , fIsBuiltin(isBuiltin) {
168         SkASSERT(count > 0 || count == kUnsizedArray);
169         // Multi-dimensional arrays are disallowed.
170         SkASSERT(!componentType.is<ArrayType>());
171     }
172 
matches(const Type & otherType) const173     bool matches(const Type& otherType) const override {
174         const Type& that = otherType.resolve();
175         return that.isArray() && this->columns() == that.columns() &&
176                this->componentType().matches(that.componentType());
177     }
178 
isArray() const179     bool isArray() const override {
180         return true;
181     }
182 
isBuiltin() const183     bool isBuiltin() const override {
184         return fIsBuiltin;
185     }
186 
isOrContainsArray() const187     bool isOrContainsArray() const override {
188         return true;
189     }
190 
isOrContainsAtomic() const191     bool isOrContainsAtomic() const override {
192         return fComponentType.isOrContainsAtomic();
193     }
194 
isOrContainsBool() const195     bool isOrContainsBool() const override {
196         return fComponentType.isOrContainsBool();
197     }
198 
isUnsizedArray() const199     bool isUnsizedArray() const override {
200         return fCount == kUnsizedArray;
201     }
202 
isOrContainsUnsizedArray() const203     bool isOrContainsUnsizedArray() const override {
204         return this->isUnsizedArray() || fComponentType.isOrContainsUnsizedArray();
205     }
206 
componentType() const207     const Type& componentType() const override {
208         return fComponentType;
209     }
210 
columns() const211     int columns() const override {
212         return fCount;
213     }
214 
bitWidth() const215     int bitWidth() const override {
216         return fComponentType.bitWidth();
217     }
218 
isAllowedInES2() const219     bool isAllowedInES2() const override {
220         return fComponentType.isAllowedInES2();
221     }
222 
isAllowedInUniform(Position * errorPosition) const223     bool isAllowedInUniform(Position* errorPosition) const override {
224         return fComponentType.isAllowedInUniform(errorPosition);
225     }
226 
slotCount() const227     size_t slotCount() const override {
228         SkASSERT(fCount != kUnsizedArray);
229         SkASSERT(fCount > 0);
230         return fCount * fComponentType.slotCount();
231     }
232 
slotType(size_t n) const233     const Type& slotType(size_t n) const override {
234         SkASSERT(fCount == kUnsizedArray || n < this->slotCount());
235         return fComponentType.slotType(n % fComponentType.slotCount());
236     }
237 
238 private:
239     using INHERITED = Type;
240 
241     const Type& fComponentType;
242     int fCount;
243     bool fIsBuiltin;
244 };
245 
246 class GenericType final : public Type {
247 public:
248     inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
249 
GenericType(const char * name,SkSpan<const Type * const> coercibleTypes,const Type * slotType)250     GenericType(const char* name, SkSpan<const Type* const> coercibleTypes, const Type* slotType)
251             : INHERITED(name, "G", kTypeKind)
252             , fSlotType(slotType) {
253         fNumTypes = coercibleTypes.size();
254         SkASSERT(fNumTypes <= std::size(fCoercibleTypes));
255         std::copy(coercibleTypes.begin(), coercibleTypes.end(), fCoercibleTypes);
256     }
257 
coercibleTypes() const258     SkSpan<const Type* const> coercibleTypes() const override {
259         return SkSpan(fCoercibleTypes, fNumTypes);
260     }
261 
slotType(size_t) const262     const Type& slotType(size_t) const override {
263         return *fSlotType;
264     }
265 
266 private:
267     using INHERITED = Type;
268 
269     const Type* fCoercibleTypes[9];
270     const Type* fSlotType;
271     size_t fNumTypes;
272 };
273 
274 class LiteralType : public Type {
275 public:
276     inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
277 
LiteralType(const char * name,const Type & scalarType,int8_t priority)278     LiteralType(const char* name, const Type& scalarType, int8_t priority)
279             : INHERITED(name, "L", kTypeKind)
280             , fScalarType(scalarType)
281             , fPriority(priority) {}
282 
scalarTypeForLiteral() const283     const Type& scalarTypeForLiteral() const override {
284         return fScalarType;
285     }
286 
priority() const287     int priority() const override {
288         return fPriority;
289     }
290 
columns() const291     int columns() const override {
292         return 1;
293     }
294 
rows() const295     int rows() const override {
296         return 1;
297     }
298 
numberKind() const299     NumberKind numberKind() const override {
300         return fScalarType.numberKind();
301     }
302 
bitWidth() const303     int bitWidth() const override {
304         return fScalarType.bitWidth();
305     }
306 
minimumValue() const307     double minimumValue() const override {
308         return fScalarType.minimumValue();
309     }
310 
maximumValue() const311     double maximumValue() const override {
312         return fScalarType.maximumValue();
313     }
314 
isScalar() const315     bool isScalar() const override {
316         return true;
317     }
318 
isLiteral() const319     bool isLiteral() const override {
320         return true;
321     }
322 
isOrContainsBool() const323     bool isOrContainsBool() const override {
324         return fScalarType.isBoolean();
325     }
326 
slotCount() const327     size_t slotCount() const override {
328         return 1;
329     }
330 
slotType(size_t n) const331     const Type& slotType(size_t n) const override {
332         SkASSERT(n == 0);
333         return fScalarType;
334     }
335 
336 private:
337     using INHERITED = Type;
338 
339     const Type& fScalarType;
340     int8_t fPriority;
341 };
342 
343 
344 class ScalarType final : public Type {
345 public:
346     inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
347 
ScalarType(std::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)348     ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
349                int8_t bitWidth)
350             : INHERITED(name, abbrev, kTypeKind)
351             , fNumberKind(numberKind)
352             , fPriority(priority)
353             , fBitWidth(bitWidth) {}
354 
numberKind() const355     NumberKind numberKind() const override {
356         return fNumberKind;
357     }
358 
priority() const359     int priority() const override {
360         return fPriority;
361     }
362 
bitWidth() const363     int bitWidth() const override {
364         return fBitWidth;
365     }
366 
columns() const367     int columns() const override {
368         return 1;
369     }
370 
rows() const371     int rows() const override {
372         return 1;
373     }
374 
isScalar() const375     bool isScalar() const override {
376         return true;
377     }
378 
isAllowedInES2() const379     bool isAllowedInES2() const override {
380         return fNumberKind != NumberKind::kUnsigned;
381     }
382 
isAllowedInUniform(Position *) const383     bool isAllowedInUniform(Position*) const override {
384         return fNumberKind != NumberKind::kBoolean;
385     }
386 
isOrContainsBool() const387     bool isOrContainsBool() const override {
388         return fNumberKind == NumberKind::kBoolean;
389     }
390 
slotCount() const391     size_t slotCount() const override {
392         return 1;
393     }
394 
slotType(size_t n) const395     const Type& slotType(size_t n) const override {
396         SkASSERT(n == 0);
397         return *this;
398     }
399 
400     using int_limits = std::numeric_limits<int32_t>;
401     using short_limits = std::numeric_limits<int16_t>;
402     using uint_limits = std::numeric_limits<uint32_t>;
403     using ushort_limits = std::numeric_limits<uint16_t>;
404     using float_limits = std::numeric_limits<float>;
405 
406     /** Returns the maximum value that can fit in the type. */
minimumValue() const407     double minimumValue() const override {
408         switch (this->numberKind()) {
409             case NumberKind::kSigned:
410                 return this->highPrecision() ? int_limits::lowest()
411                                              : short_limits::lowest();
412 
413             case NumberKind::kUnsigned:
414                 return 0;
415 
416             case NumberKind::kFloat:
417             default:
418                 return float_limits::lowest();
419         }
420     }
421 
422     /** Returns the maximum value that can fit in the type. */
maximumValue() const423     double maximumValue() const override {
424         switch (this->numberKind()) {
425             case NumberKind::kSigned:
426                 return this->highPrecision() ? int_limits::max()
427                                              : short_limits::max();
428 
429             case NumberKind::kUnsigned:
430                 return this->highPrecision() ? uint_limits::max()
431                                              : ushort_limits::max();
432 
433             case NumberKind::kFloat:
434             default:
435                 return float_limits::max();
436         }
437     }
438 
439 private:
440     using INHERITED = Type;
441 
442     NumberKind fNumberKind;
443     int8_t fPriority;
444     int8_t fBitWidth;
445 };
446 
447 class AtomicType final : public Type {
448 public:
449     inline static constexpr TypeKind kTypeKind = TypeKind::kAtomic;
450 
AtomicType(std::string_view name,const char * abbrev)451     AtomicType(std::string_view name, const char* abbrev) : INHERITED(name, abbrev, kTypeKind) {}
452 
isAllowedInES2() const453     bool isAllowedInES2() const override { return false; }
454 
isAllowedInUniform(Position *) const455     bool isAllowedInUniform(Position*) const override { return false; }
456 
isOrContainsAtomic() const457     bool isOrContainsAtomic() const override { return true; }
458 
slotType(size_t n) const459     const Type& slotType(size_t n) const override {
460         SkASSERT(n == 0);
461         return *this;
462     }
463 
464 private:
465     using INHERITED = Type;
466 };
467 
468 class MatrixType final : public Type {
469 public:
470     inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
471 
MatrixType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)472     MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
473                int8_t columns, int8_t rows)
474             : INHERITED(name, abbrev, kTypeKind)
475             , fComponentType(componentType.as<ScalarType>())
476             , fColumns(columns)
477             , fRows(rows) {
478         SkASSERT(columns >= 2 && columns <= 4);
479         SkASSERT(rows >= 2 && rows <= 4);
480     }
481 
componentType() const482     const ScalarType& componentType() const override {
483         return fComponentType;
484     }
485 
columns() const486     int columns() const override {
487         return fColumns;
488     }
489 
rows() const490     int rows() const override {
491         return fRows;
492     }
493 
bitWidth() const494     int bitWidth() const override {
495         return this->componentType().bitWidth();
496     }
497 
isMatrix() const498     bool isMatrix() const override {
499         return true;
500     }
501 
isAllowedInES2() const502     bool isAllowedInES2() const override {
503         return fColumns == fRows;
504     }
505 
slotCount() const506     size_t slotCount() const override {
507         return fColumns * fRows;
508     }
509 
slotType(size_t n) const510     const Type& slotType(size_t n) const override {
511         SkASSERT(n < this->slotCount());
512         return fComponentType;
513     }
514 
515 private:
516     using INHERITED = Type;
517 
518     const ScalarType& fComponentType;
519     int8_t fColumns;
520     int8_t fRows;
521 };
522 
523 class TextureType final : public Type {
524 public:
525     inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
526 
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,TextureAccess textureAccess)527     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
528                 bool isMultisampled, TextureAccess textureAccess)
529             : INHERITED(name, "T", kTypeKind)
530             , fDimensions(dimensions)
531             , fIsDepth(isDepth)
532             , fIsArrayed(isArrayed)
533             , fIsMultisampled(isMultisampled)
534             , fTextureAccess(textureAccess) {}
535 
dimensions() const536     SpvDim_ dimensions() const override {
537         return fDimensions;
538     }
539 
isDepth() const540     bool isDepth() const override {
541         return fIsDepth;
542     }
543 
isArrayedTexture() const544     bool isArrayedTexture() const override {
545         return fIsArrayed;
546     }
547 
isMultisampled() const548     bool isMultisampled() const override {
549         return fIsMultisampled;
550     }
551 
textureAccess() const552     TextureAccess textureAccess() const override {
553         return fTextureAccess;
554     }
555 
slotType(size_t n) const556     const Type& slotType(size_t n) const override {
557         SkASSERT(n == 0);
558         return *this;
559     }
560 
561 private:
562     using INHERITED = Type;
563 
564     SpvDim_ fDimensions;
565     bool fIsDepth;
566     bool fIsArrayed;
567     bool fIsMultisampled;
568     TextureAccess fTextureAccess;
569 };
570 
571 class SamplerType final : public Type {
572 public:
573     inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
574 
SamplerType(const char * name,const Type & textureType)575     SamplerType(const char* name, const Type& textureType)
576             : INHERITED(name, "Z", kTypeKind)
577             , fTextureType(textureType.as<TextureType>()) {
578         // Samplers require sampled texture access.
579         SkASSERT(this->textureAccess() == TextureAccess::kSample);
580         // Subpass inputs cannot be sampled.
581         SkASSERT(this->dimensions() != SpvDimSubpassData);
582     }
583 
textureType() const584     const TextureType& textureType() const override {
585         return fTextureType;
586     }
587 
dimensions() const588     SpvDim_ dimensions() const override {
589         return fTextureType.dimensions();
590     }
591 
isDepth() const592     bool isDepth() const override {
593         return fTextureType.isDepth();
594     }
595 
isArrayedTexture() const596     bool isArrayedTexture() const override {
597         return fTextureType.isArrayedTexture();
598     }
599 
isMultisampled() const600     bool isMultisampled() const override {
601         return fTextureType.isMultisampled();
602     }
603 
textureAccess() const604     TextureAccess textureAccess() const override {
605         return fTextureType.textureAccess();
606     }
607 
slotType(size_t n) const608     const Type& slotType(size_t n) const override {
609         SkASSERT(n == 0);
610         return *this;
611     }
612 
613 private:
614     using INHERITED = Type;
615 
616     const TextureType& fTextureType;
617 };
618 
619 class StructType final : public Type {
620 public:
621     inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
622 
StructType(Position pos,std::string_view name,TArray<Field> fields,int nestingDepth,bool interfaceBlock,bool isBuiltin)623     StructType(Position pos, std::string_view name, TArray<Field> fields, int nestingDepth,
624                bool interfaceBlock, bool isBuiltin)
625             : INHERITED(std::move(name), "S", kTypeKind, pos)
626             , fFields(std::move(fields))
627             , fNestingDepth(nestingDepth)
628             , fInterfaceBlock(interfaceBlock)
629             , fIsBuiltin(isBuiltin) {
630         for (const Field& f : fFields) {
631             fContainsArray        = fContainsArray        || f.fType->isOrContainsArray();
632             fContainsUnsizedArray = fContainsUnsizedArray || f.fType->isOrContainsUnsizedArray();
633             fContainsAtomic       = fContainsAtomic       || f.fType->isOrContainsAtomic();
634             fContainsBool         = fContainsBool         || f.fType->isOrContainsBool();
635             fIsAllowedInES2       = fIsAllowedInES2       && f.fType->isAllowedInES2();
636         }
637         for (const Field& f : fFields) {
638             Position errorPosition = f.fPosition;
639             if (!f.fType->isAllowedInUniform(&errorPosition)) {
640                 fUniformErrorPosition = errorPosition;
641                 break;
642             }
643         }
644         if (!fContainsUnsizedArray) {
645             for (const Field& f : fFields) {
646                 fSlotCount += f.fType->slotCount();
647             }
648         }
649     }
650 
fields() const651     SkSpan<const Field> fields() const override {
652         return fFields;
653     }
654 
isStruct() const655     bool isStruct() const override {
656         return true;
657     }
658 
isInterfaceBlock() const659     bool isInterfaceBlock() const override {
660         return fInterfaceBlock;
661     }
662 
isBuiltin() const663     bool isBuiltin() const override {
664         return fIsBuiltin;
665     }
666 
isAllowedInES2() const667     bool isAllowedInES2() const override {
668         return fIsAllowedInES2;
669     }
670 
isAllowedInUniform(Position * errorPosition) const671     bool isAllowedInUniform(Position* errorPosition) const override {
672         if (errorPosition != nullptr) {
673             *errorPosition = fUniformErrorPosition;
674         }
675         return !fUniformErrorPosition.valid();
676     }
677 
isOrContainsArray() const678     bool isOrContainsArray() const override {
679         return fContainsArray;
680     }
681 
isOrContainsUnsizedArray() const682     bool isOrContainsUnsizedArray() const override {
683         return fContainsUnsizedArray;
684     }
685 
isOrContainsAtomic() const686     bool isOrContainsAtomic() const override {
687         return fContainsAtomic;
688     }
689 
isOrContainsBool() const690     bool isOrContainsBool() const override {
691         return fContainsBool;
692     }
693 
slotCount() const694     size_t slotCount() const override {
695         SkASSERT(!fContainsUnsizedArray);
696         return fSlotCount;
697     }
698 
structNestingDepth() const699     int structNestingDepth() const override {
700         return fNestingDepth;
701     }
702 
slotType(size_t n) const703     const Type& slotType(size_t n) const override {
704         for (const Field& field : fFields) {
705             size_t fieldSlots = field.fType->slotCount();
706             if (n < fieldSlots) {
707                 return field.fType->slotType(n);
708             } else {
709                 n -= fieldSlots;
710             }
711         }
712         SkDEBUGFAIL("slot index out of range");
713         return *this;
714     }
715 
716 private:
717     using INHERITED = Type;
718 
719     TArray<Field> fFields;
720     size_t fSlotCount = 0;
721     int fNestingDepth = 0;
722     Position fUniformErrorPosition = {};
723     bool fInterfaceBlock = false;
724     bool fContainsArray = false;
725     bool fContainsUnsizedArray = false;
726     bool fContainsAtomic = false;
727     bool fContainsBool = false;
728     bool fIsBuiltin = false;
729     bool fIsAllowedInES2 = true;
730 };
731 
732 class VectorType final : public Type {
733 public:
734     inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
735 
VectorType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns)736     VectorType(std::string_view name, const char* abbrev, const Type& componentType,
737                int8_t columns)
738             : INHERITED(name, abbrev, kTypeKind)
739             , fComponentType(componentType.as<ScalarType>())
740             , fColumns(columns) {
741         SkASSERT(columns >= 2 && columns <= 4);
742     }
743 
componentType() const744     const ScalarType& componentType() const override {
745         return fComponentType;
746     }
747 
columns() const748     int columns() const override {
749         return fColumns;
750     }
751 
rows() const752     int rows() const override {
753         return 1;
754     }
755 
bitWidth() const756     int bitWidth() const override {
757         return this->componentType().bitWidth();
758     }
759 
isVector() const760     bool isVector() const override {
761         return true;
762     }
763 
isAllowedInES2() const764     bool isAllowedInES2() const override {
765         return fComponentType.isAllowedInES2();
766     }
767 
isAllowedInUniform(Position * errorPosition) const768     bool isAllowedInUniform(Position* errorPosition) const override {
769         return fComponentType.isAllowedInUniform(errorPosition);
770     }
771 
isOrContainsBool() const772     bool isOrContainsBool() const override {
773         return fComponentType.isOrContainsBool();
774     }
775 
slotCount() const776     size_t slotCount() const override {
777         return fColumns;
778     }
779 
slotType(size_t n) const780     const Type& slotType(size_t n) const override {
781         SkASSERT(n < SkToSizeT(fColumns));
782         return fComponentType;
783     }
784 
785 private:
786     using INHERITED = Type;
787 
788     const ScalarType& fComponentType;
789     int8_t fColumns;
790 };
791 
getArrayName(int arraySize) const792 std::string Type::getArrayName(int arraySize) const {
793     std::string_view name = this->name();
794     if (arraySize == kUnsizedArray) {
795         return String::printf("%.*s[]", (int)name.size(), name.data());
796     }
797     return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
798 }
799 
MakeAliasType(std::string_view name,const Type & targetType)800 std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
801     return std::make_unique<AliasType>(std::move(name), targetType);
802 }
803 
MakeArrayType(const Context & context,std::string_view name,const Type & componentType,int columns)804 std::unique_ptr<Type> Type::MakeArrayType(const Context& context,
805                                           std::string_view name,
806                                           const Type& componentType,
807                                           int columns) {
808     return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
809                                        componentType, columns, context.fConfig->isBuiltinCode());
810 }
811 
MakeGenericType(const char * name,SkSpan<const Type * const> types,const Type * slotType)812 std::unique_ptr<Type> Type::MakeGenericType(const char* name,
813                                             SkSpan<const Type* const> types,
814                                             const Type* slotType) {
815     return std::make_unique<GenericType>(name, types, slotType);
816 }
817 
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)818 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
819                                             int8_t priority) {
820     return std::make_unique<LiteralType>(name, scalarType, priority);
821 }
822 
MakeMatrixType(std::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)823 std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
824                                            const Type& componentType, int columns, int8_t rows) {
825     return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
826 }
827 
MakeSamplerType(const char * name,const Type & textureType)828 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
829     return std::make_unique<SamplerType>(name, textureType);
830 }
831 
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)832 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
833                                             Type::TypeKind typeKind) {
834     return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
835 }
836 
MakeScalarType(std::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)837 std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
838                                            Type::NumberKind numberKind, int8_t priority,
839                                            int8_t bitWidth) {
840     return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
841 }
842 
MakeAtomicType(std::string_view name,const char * abbrev)843 std::unique_ptr<Type> Type::MakeAtomicType(std::string_view name, const char* abbrev) {
844     return std::make_unique<AtomicType>(name, abbrev);
845 }
846 
MakeStructType(const Context & context,Position pos,std::string_view name,TArray<Field> fields,bool interfaceBlock)847 std::unique_ptr<Type> Type::MakeStructType(const Context& context,
848                                            Position pos,
849                                            std::string_view name,
850                                            TArray<Field> fields,
851                                            bool interfaceBlock) {
852     const char* const structOrIB  = interfaceBlock ? "interface block" : "struct";
853     const char* const aStructOrIB = interfaceBlock ? "an interface block" : "a struct";
854 
855     if (fields.empty()) {
856         context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
857                                     "' must contain at least one field");
858     }
859     size_t slots = 0;
860 
861     THashSet<std::string_view> fieldNames;
862     for (const Field& field : fields) {
863         // Add this field name to our set; if the set doesn't grow, we found a duplicate.
864         int numFieldNames = fieldNames.count();
865         fieldNames.add(field.fName);
866         if (fieldNames.count() == numFieldNames) {
867             context.fErrors->error(field.fPosition, "field '" + std::string(field.fName) +
868                                                     "' was already defined in the same " +
869                                                     std::string(structOrIB) + " ('" +
870                                                     std::string(name) + "')");
871         }
872         if (field.fModifierFlags != ModifierFlag::kNone) {
873             std::string desc = field.fModifierFlags.description();
874             context.fErrors->error(field.fPosition, "modifier '" + desc + "' is not permitted on " +
875                                                     std::string(aStructOrIB) + " field");
876         }
877         if (field.fLayout.fFlags & LayoutFlag::kBinding) {
878             context.fErrors->error(field.fPosition, "layout qualifier 'binding' is not permitted "
879                                                     "on " + std::string(aStructOrIB) + " field");
880         }
881         if (field.fLayout.fFlags & LayoutFlag::kSet) {
882             context.fErrors->error(field.fPosition, "layout qualifier 'set' is not permitted on " +
883                                                     std::string(aStructOrIB) + " field");
884         }
885 
886         if (field.fType->isVoid()) {
887             context.fErrors->error(field.fPosition, "type 'void' is not permitted in " +
888                                                     std::string(aStructOrIB));
889         }
890         if (field.fType->isOpaque() && !field.fType->isAtomic()) {
891             context.fErrors->error(field.fPosition, "opaque type '" + field.fType->displayName() +
892                                                     "' is not permitted in " +
893                                                     std::string(aStructOrIB));
894         }
895         if (interfaceBlock && field.fType->isOrContainsBool()) {
896             // Reject booleans anywhere in an interface block.
897             context.fErrors->error(field.fPosition, "type 'bool' is not permitted in an "
898                                                     "interface block");
899         }
900         if (field.fType->isOrContainsUnsizedArray()) {
901             if (!interfaceBlock) {
902                 // Reject unsized arrays anywhere in structs.
903                 context.fErrors->error(field.fPosition, "unsized arrays are not permitted here");
904             }
905         } else {
906             // If we haven't already exceeded the struct size limit...
907             if (slots < kVariableSlotLimit) {
908                 // ... see if this field causes us to exceed the size limit.
909                 slots = SkSafeMath::Add(slots, field.fType->slotCount());
910                 if (slots >= kVariableSlotLimit) {
911                     context.fErrors->error(pos, std::string(structOrIB) + " is too large");
912                 }
913             }
914         }
915     }
916     int nestingDepth = 0;
917     for (const Field& field : fields) {
918         nestingDepth = std::max(nestingDepth, field.fType->structNestingDepth());
919     }
920     if (nestingDepth >= kMaxStructDepth) {
921         context.fErrors->error(pos, std::string(structOrIB) + " '" + std::string(name) +
922                                     "' is too deeply nested");
923     }
924     return std::make_unique<StructType>(pos, name, std::move(fields), nestingDepth + 1,
925                                         interfaceBlock, context.fConfig->isBuiltinCode());
926 }
927 
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,TextureAccess textureAccess)928 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
929                                             bool isArrayedTexture, bool isMultisampled,
930                                             TextureAccess textureAccess) {
931     return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
932                                          isMultisampled, textureAccess);
933 }
934 
MakeVectorType(std::string_view name,const char * abbrev,const Type & componentType,int columns)935 std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
936                                            const Type& componentType, int columns) {
937     return std::make_unique<VectorType>(name, abbrev, componentType, columns);
938 }
939 
coercionCost(const Type & other) const940 CoercionCost Type::coercionCost(const Type& other) const {
941     if (this->matches(other)) {
942         return CoercionCost::Free();
943     }
944     if (this->typeKind() == other.typeKind() &&
945         (this->isVector() || this->isMatrix() || this->isArray())) {
946         // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
947         if (this->isMatrix() && (this->rows() != other.rows())) {
948             return CoercionCost::Impossible();
949         }
950         if (this->columns() != other.columns()) {
951             return CoercionCost::Impossible();
952         }
953         return this->componentType().coercionCost(other.componentType());
954     }
955     if (this->isNumber() && other.isNumber()) {
956         if (this->isLiteral() && this->isInteger()) {
957             return CoercionCost::Free();
958         } else if (this->numberKind() != other.numberKind()) {
959             return CoercionCost::Impossible();
960         } else if (other.priority() >= this->priority()) {
961             return CoercionCost::Normal(other.priority() - this->priority());
962         } else {
963             return CoercionCost::Narrowing(this->priority() - other.priority());
964         }
965     }
966     if (fTypeKind == TypeKind::kGeneric) {
967         SkSpan<const Type* const> types = this->coercibleTypes();
968         for (size_t i = 0; i < types.size(); i++) {
969             if (types[i]->matches(other)) {
970                 return CoercionCost::Normal((int) i + 1);
971             }
972         }
973     }
974     return CoercionCost::Impossible();
975 }
976 
applyQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const977 const Type* Type::applyQualifiers(const Context& context,
978                                   ModifierFlags* modifierFlags,
979                                   Position pos) const {
980     const Type* type;
981     type = this->applyPrecisionQualifiers(context, modifierFlags, pos);
982     type = type->applyAccessQualifiers(context, modifierFlags, pos);
983     return type;
984 }
985 
applyPrecisionQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const986 const Type* Type::applyPrecisionQualifiers(const Context& context,
987                                            ModifierFlags* modifierFlags,
988                                            Position pos) const {
989     ModifierFlags precisionQualifiers = *modifierFlags & (ModifierFlag::kHighp |
990                                                           ModifierFlag::kMediump |
991                                                           ModifierFlag::kLowp);
992     if (precisionQualifiers == ModifierFlag::kNone) {
993         // No precision qualifiers here. Return the type as-is.
994         return this;
995     }
996 
997     if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
998         // We want to discourage precision modifiers internally. Instead, use the type that
999         // corresponds to the precision you need. (e.g. half vs float, short vs int)
1000         context.fErrors->error(pos, "precision qualifiers are not allowed");
1001         return context.fTypes.fPoison.get();
1002     }
1003 
1004     if (SkPopCount(precisionQualifiers.value()) > 1) {
1005         context.fErrors->error(pos, "only one precision qualifier can be used");
1006         return context.fTypes.fPoison.get();
1007     }
1008 
1009     // We're going to return a whole new type, so the modifier bits can be cleared out.
1010     *modifierFlags &= ~(ModifierFlag::kHighp |
1011                         ModifierFlag::kMediump |
1012                         ModifierFlag::kLowp);
1013 
1014     const Type& component = this->componentType();
1015     if (component.highPrecision()) {
1016         if (precisionQualifiers & ModifierFlag::kHighp) {
1017             // Type is already high precision, and we are requesting high precision. Return as-is.
1018             return this;
1019         }
1020 
1021         // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
1022         // Ascertain the mediump equivalent type for this type, if any.
1023         const Type* mediumpType;
1024         switch (component.numberKind()) {
1025             case Type::NumberKind::kFloat:
1026                 mediumpType = context.fTypes.fHalf.get();
1027                 break;
1028 
1029             case Type::NumberKind::kSigned:
1030                 mediumpType = context.fTypes.fShort.get();
1031                 break;
1032 
1033             case Type::NumberKind::kUnsigned:
1034                 mediumpType = context.fTypes.fUShort.get();
1035                 break;
1036 
1037             default:
1038                 mediumpType = context.fTypes.fPoison.get();
1039                 break;
1040         }
1041 
1042         if (mediumpType) {
1043             // Convert the mediump component type into the final vector/matrix/array type as needed.
1044             return this->isArray()
1045                     ? context.fSymbolTable->addArrayDimension(context, mediumpType, this->columns())
1046                     : &mediumpType->toCompound(context, this->columns(), this->rows());
1047         }
1048     }
1049 
1050     context.fErrors->error(pos, "type '" + this->displayName() +
1051                                 "' does not support precision qualifiers");
1052     return context.fTypes.fPoison.get();
1053 }
1054 
applyAccessQualifiers(const Context & context,ModifierFlags * modifierFlags,Position pos) const1055 const Type* Type::applyAccessQualifiers(const Context& context,
1056                                         ModifierFlags* modifierFlags,
1057                                         Position pos) const {
1058     ModifierFlags accessQualifiers = *modifierFlags & (ModifierFlag::kReadOnly |
1059                                                        ModifierFlag::kWriteOnly);
1060 
1061     // We're going to return a whole new type, so the modifier bits must be cleared out.
1062     *modifierFlags &= ~(ModifierFlag::kReadOnly |
1063                         ModifierFlag::kWriteOnly);
1064 
1065     if (this->matches(*context.fTypes.fTexture2D)) {
1066         // We require all texture2Ds to be qualified with `readonly` or `writeonly`.
1067         // (Read-write textures are not yet supported in WGSL.)
1068         if (accessQualifiers == ModifierFlag::kReadOnly) {
1069             return context.fTypes.fReadOnlyTexture2D.get();
1070         }
1071         if (accessQualifiers == ModifierFlag::kWriteOnly) {
1072             return context.fTypes.fWriteOnlyTexture2D.get();
1073         }
1074         context.fErrors->error(
1075                 pos,
1076                 accessQualifiers
1077                         ? "'readonly' and 'writeonly' qualifiers cannot be combined"
1078                         : "'texture2D' requires a 'readonly' or 'writeonly' access qualifier");
1079         return this;
1080     }
1081 
1082     if (accessQualifiers) {
1083         context.fErrors->error(pos, "type '" + this->displayName() + "' does not support "
1084                                     "qualifier '" + accessQualifiers.description() + "'");
1085     }
1086 
1087     return this;
1088 }
1089 
toCompound(const Context & context,int columns,int rows) const1090 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
1091     SkASSERT(this->isScalar());
1092     if (columns == 1 && rows == 1) {
1093         return *this;
1094     }
1095     if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
1096         switch (rows) {
1097             case 1:
1098                 switch (columns) {
1099                     case 1: return *context.fTypes.fFloat;
1100                     case 2: return *context.fTypes.fFloat2;
1101                     case 3: return *context.fTypes.fFloat3;
1102                     case 4: return *context.fTypes.fFloat4;
1103                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1104                 }
1105             case 2:
1106                 switch (columns) {
1107                     case 2: return *context.fTypes.fFloat2x2;
1108                     case 3: return *context.fTypes.fFloat3x2;
1109                     case 4: return *context.fTypes.fFloat4x2;
1110                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1111                 }
1112             case 3:
1113                 switch (columns) {
1114                     case 2: return *context.fTypes.fFloat2x3;
1115                     case 3: return *context.fTypes.fFloat3x3;
1116                     case 4: return *context.fTypes.fFloat4x3;
1117                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1118                 }
1119             case 4:
1120                 switch (columns) {
1121                     case 2: return *context.fTypes.fFloat2x4;
1122                     case 3: return *context.fTypes.fFloat3x4;
1123                     case 4: return *context.fTypes.fFloat4x4;
1124                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1125                 }
1126             default: SK_ABORT("unsupported row count (%d)", rows);
1127         }
1128     } else if (this->matches(*context.fTypes.fHalf)) {
1129         switch (rows) {
1130             case 1:
1131                 switch (columns) {
1132                     case 1: return *context.fTypes.fHalf;
1133                     case 2: return *context.fTypes.fHalf2;
1134                     case 3: return *context.fTypes.fHalf3;
1135                     case 4: return *context.fTypes.fHalf4;
1136                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1137                 }
1138             case 2:
1139                 switch (columns) {
1140                     case 2: return *context.fTypes.fHalf2x2;
1141                     case 3: return *context.fTypes.fHalf3x2;
1142                     case 4: return *context.fTypes.fHalf4x2;
1143                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1144                 }
1145             case 3:
1146                 switch (columns) {
1147                     case 2: return *context.fTypes.fHalf2x3;
1148                     case 3: return *context.fTypes.fHalf3x3;
1149                     case 4: return *context.fTypes.fHalf4x3;
1150                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1151                 }
1152             case 4:
1153                 switch (columns) {
1154                     case 2: return *context.fTypes.fHalf2x4;
1155                     case 3: return *context.fTypes.fHalf3x4;
1156                     case 4: return *context.fTypes.fHalf4x4;
1157                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
1158                 }
1159             default: SK_ABORT("unsupported row count (%d)", rows);
1160         }
1161     } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
1162         switch (rows) {
1163             case 1:
1164                 switch (columns) {
1165                     case 1: return *context.fTypes.fInt;
1166                     case 2: return *context.fTypes.fInt2;
1167                     case 3: return *context.fTypes.fInt3;
1168                     case 4: return *context.fTypes.fInt4;
1169                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1170                 }
1171             default: SK_ABORT("unsupported row count (%d)", rows);
1172         }
1173     } else if (this->matches(*context.fTypes.fShort)) {
1174         switch (rows) {
1175             case 1:
1176                 switch (columns) {
1177                     case 1: return *context.fTypes.fShort;
1178                     case 2: return *context.fTypes.fShort2;
1179                     case 3: return *context.fTypes.fShort3;
1180                     case 4: return *context.fTypes.fShort4;
1181                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1182                 }
1183             default: SK_ABORT("unsupported row count (%d)", rows);
1184         }
1185     } else if (this->matches(*context.fTypes.fUInt)) {
1186         switch (rows) {
1187             case 1:
1188                 switch (columns) {
1189                     case 1: return *context.fTypes.fUInt;
1190                     case 2: return *context.fTypes.fUInt2;
1191                     case 3: return *context.fTypes.fUInt3;
1192                     case 4: return *context.fTypes.fUInt4;
1193                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1194                 }
1195             default: SK_ABORT("unsupported row count (%d)", rows);
1196         }
1197     } else if (this->matches(*context.fTypes.fUShort)) {
1198         switch (rows) {
1199             case 1:
1200                 switch (columns) {
1201                     case 1: return *context.fTypes.fUShort;
1202                     case 2: return *context.fTypes.fUShort2;
1203                     case 3: return *context.fTypes.fUShort3;
1204                     case 4: return *context.fTypes.fUShort4;
1205                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1206                 }
1207             default: SK_ABORT("unsupported row count (%d)", rows);
1208         }
1209     } else if (this->matches(*context.fTypes.fBool)) {
1210         switch (rows) {
1211             case 1:
1212                 switch (columns) {
1213                     case 1: return *context.fTypes.fBool;
1214                     case 2: return *context.fTypes.fBool2;
1215                     case 3: return *context.fTypes.fBool3;
1216                     case 4: return *context.fTypes.fBool4;
1217                     default: SK_ABORT("unsupported vector column count (%d)", columns);
1218                 }
1219             default: SK_ABORT("unsupported row count (%d)", rows);
1220         }
1221     }
1222     SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
1223     return *context.fTypes.fVoid;
1224 }
1225 
clone(const Context & context,SymbolTable * symbolTable) const1226 const Type* Type::clone(const Context& context, SymbolTable* symbolTable) const {
1227     // Many types are built-ins, and exist in every SymbolTable by default.
1228     if (this->isInRootSymbolTable()) {
1229         return this;
1230     }
1231     // If we are compiling a program, and the type comes from the program's module, it is safe to
1232     // assume that the type is in-scope anywhere in the program without actually recursing through
1233     // the SymbolTable hierarchy to prove it.
1234     if (!context.fConfig->isBuiltinCode() && this->isBuiltin()) {
1235         return this;
1236     }
1237     // Even if the type isn't a built-in, it might already exist in the SymbolTable. Search by name.
1238     const Symbol* existingSymbol = symbolTable->find(this->name());
1239     if (existingSymbol != nullptr) {
1240         const Type* existingType = &existingSymbol->as<Type>();
1241         SkASSERT(existingType->typeKind() == this->typeKind());
1242         return existingType;
1243     }
1244     // This type actually needs to be cloned into the destination SymbolTable.
1245     switch (this->typeKind()) {
1246         case TypeKind::kArray: {
1247             return symbolTable->addArrayDimension(context, &this->componentType(), this->columns());
1248         }
1249         case TypeKind::kStruct: {
1250             // We are cloning an existing struct, so there's no need to call MakeStructType and
1251             // fully error-check it again.
1252             const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
1253             SkSpan<const Field> fieldSpan = this->fields();
1254             return symbolTable->add(
1255                     context,
1256                     std::make_unique<StructType>(this->fPosition,
1257                                                  *name,
1258                                                  TArray<Field>(fieldSpan.data(), fieldSpan.size()),
1259                                                  this->structNestingDepth(),
1260                                                  /*interfaceBlock=*/this->isInterfaceBlock(),
1261                                                  /*isBuiltin=*/context.fConfig->isBuiltinCode()));
1262         }
1263         default:
1264             SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
1265             return nullptr;
1266     }
1267 }
1268 
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const1269 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
1270                                                    const Context& context) const {
1271     if (!expr || expr->isIncomplete(context)) {
1272         return nullptr;
1273     }
1274     if (expr->type().matches(*this)) {
1275         return expr;
1276     }
1277 
1278     const Position pos = expr->fPosition;
1279     const ProgramSettings& settings = context.fConfig->fSettings;
1280     if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
1281         context.fErrors->error(pos, "expected '" + this->displayName() + "', but found '" +
1282                                     expr->type().displayName() + "'");
1283         return nullptr;
1284     }
1285 
1286     if (this->isScalar()) {
1287         return ConstructorScalarCast::Make(context, pos, *this, std::move(expr));
1288     }
1289     if (this->isVector() || this->isMatrix()) {
1290         return ConstructorCompoundCast::Make(context, pos, *this, std::move(expr));
1291     }
1292     if (this->isArray()) {
1293         return ConstructorArrayCast::Make(context, pos, *this, std::move(expr));
1294     }
1295     context.fErrors->error(pos, "cannot construct '" + this->displayName() + "'");
1296     return nullptr;
1297 }
1298 
isAllowedInES2(const Context & context) const1299 bool Type::isAllowedInES2(const Context& context) const {
1300     return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
1301 }
1302 
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const1303 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
1304     bool foundError = false;
1305     const Type& baseType = this->componentType();
1306     if (baseType.isNumber()) {
1307         // Replace constant expressions with their corresponding values.
1308         const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
1309         if (valueExpr->supportsConstantValues()) {
1310             // Iterate over every constant subexpression in the value.
1311             int numSlots = valueExpr->type().slotCount();
1312             for (int slot = 0; slot < numSlots; ++slot) {
1313                 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
1314                 // Check for Literal values that are out of range for the base type.
1315                 if (slotVal.has_value() &&
1316                     baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fPosition)) {
1317                     foundError = true;
1318                 }
1319             }
1320         }
1321     }
1322 
1323     // We don't need range checks for floats or booleans; any matched-type value is acceptable.
1324     return foundError;
1325 }
1326 
checkForOutOfRangeLiteral(const Context & context,double value,Position pos) const1327 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const {
1328     SkASSERT(this->isScalar());
1329     if (!this->isNumber()) {
1330        return false;
1331     }
1332     if (value >= this->minimumValue() && value <= this->maximumValue()) {
1333         return false;
1334     }
1335     // We found a value that can't fit in our type. Flag it as an error.
1336     context.fErrors->error(pos, SkSL::String::printf("value is out of range for type '%s': %.0f",
1337                                                      this->displayName().c_str(),
1338                                                      value));
1339     return true;
1340 }
1341 
checkIfUsableInArray(const Context & context,Position arrayPos) const1342 bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
1343     if (this->isArray()) {
1344         context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
1345         return false;
1346     }
1347     if (this->isVoid()) {
1348         context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
1349         return false;
1350     }
1351     if (this->isOpaque() && !this->isAtomic()) {
1352         context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
1353                                          "' may not be used in an array");
1354         return false;
1355     }
1356     return true;
1357 }
1358 
convertArraySize(const Context & context,Position arrayPos,std::unique_ptr<Expression> size) const1359 SKSL_INT Type::convertArraySize(const Context& context,
1360                                 Position arrayPos,
1361                                 std::unique_ptr<Expression> size) const {
1362     size = context.fTypes.fInt->coerceExpression(std::move(size), context);
1363     if (!size) {
1364         return 0;
1365     }
1366     SKSL_INT count;
1367     if (!ConstantFolder::GetConstantInt(*size, &count)) {
1368         context.fErrors->error(size->fPosition, "array size must be an integer");
1369         return 0;
1370     }
1371     return this->convertArraySize(context, arrayPos, size->fPosition, count);
1372 }
1373 
convertArraySize(const Context & context,Position arrayPos,Position sizePos,SKSL_INT size) const1374 SKSL_INT Type::convertArraySize(const Context& context,
1375                                 Position arrayPos,
1376                                 Position sizePos,
1377                                 SKSL_INT size) const {
1378     if (!this->checkIfUsableInArray(context, arrayPos)) {
1379         // `checkIfUsableInArray` will generate an error for us.
1380         return 0;
1381     }
1382     if (size <= 0) {
1383         context.fErrors->error(sizePos, "array size must be positive");
1384         return 0;
1385     }
1386     // We can't get a meaningful slot count if the interior type contains an unsized array; we'll
1387     // assert if we try. Unsized arrays should only occur in a handful of limited cases (e.g. an
1388     // interface block with a trailing buffer), and will never be valid in a runtime effect.
1389     if (!this->isOrContainsUnsizedArray()) {
1390         if (SkSafeMath::Mul(this->slotCount(), size) > kVariableSlotLimit) {
1391             context.fErrors->error(sizePos, "array size is too large");
1392             return 0;
1393         }
1394     }
1395     return size;
1396 }
1397 
description() const1398 std::string Field::description() const {
1399     return fLayout.paddedDescription() + fModifierFlags.paddedDescription() + fType->displayName() +
1400            ' ' + std::string(fName) + ';';
1401 }
1402 
1403 }  // namespace SkSL
1404