• 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/SkStringView.h"
11 #include "src/sksl/SkSLConstantFolder.h"
12 #include "src/sksl/SkSLContext.h"
13 #include "src/sksl/SkSLProgramSettings.h"
14 #include "src/sksl/ir/SkSLConstructor.h"
15 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
16 #include "src/sksl/ir/SkSLConstructorCompoundCast.h"
17 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
18 #include "src/sksl/ir/SkSLProgram.h"
19 #include "src/sksl/ir/SkSLSymbolTable.h"
20 #include "src/sksl/ir/SkSLType.h"
21 
22 #include <optional>
23 #include <string_view>
24 
25 namespace SkSL {
26 
27 static constexpr int kMaxStructDepth = 8;
28 
29 class AliasType final : public Type {
30 public:
AliasType(std::string_view name,const Type & targetType)31     AliasType(std::string_view name, const Type& targetType)
32         : INHERITED(name, targetType.abbreviatedName(), targetType.typeKind())
33         , fTargetType(targetType) {}
34 
resolve() const35     const Type& resolve() const override {
36         return fTargetType;
37     }
38 
componentType() const39     const Type& componentType() const override {
40         return fTargetType.componentType();
41     }
42 
numberKind() const43     NumberKind numberKind() const override {
44         return fTargetType.numberKind();
45     }
46 
priority() const47     int priority() const override {
48         return fTargetType.priority();
49     }
50 
columns() const51     int columns() const override {
52         return fTargetType.columns();
53     }
54 
rows() const55     int rows() const override {
56         return fTargetType.rows();
57     }
58 
bitWidth() const59     int bitWidth() const override {
60         return fTargetType.bitWidth();
61     }
62 
isPrivate() const63     bool isPrivate() const override {
64         return fTargetType.isPrivate();
65     }
66 
isAllowedInES2() const67     bool isAllowedInES2() const override {
68         return fTargetType.isAllowedInES2();
69     }
70 
slotCount() const71     size_t slotCount() const override {
72         return fTargetType.slotCount();
73     }
74 
isDepth() const75     bool isDepth() const override {
76         return fTargetType.isDepth();
77     }
78 
isArrayedTexture() const79     bool isArrayedTexture() const override {
80         return fTargetType.isArrayedTexture();
81     }
82 
isScalar() const83     bool isScalar() const override {
84         return fTargetType.isScalar();
85     }
86 
isLiteral() const87     bool isLiteral() const override {
88         return fTargetType.isLiteral();
89     }
90 
isVector() const91     bool isVector() const override {
92         return fTargetType.isVector();
93     }
94 
isMatrix() const95     bool isMatrix() const override {
96         return fTargetType.isMatrix();
97     }
98 
isArray() const99     bool isArray() const override {
100         return fTargetType.isArray();
101     }
102 
isStruct() const103     bool isStruct() const override {
104         return fTargetType.isStruct();
105     }
106 
isInterfaceBlock() const107     bool isInterfaceBlock() const override {
108         return fTargetType.isInterfaceBlock();
109     }
110 
coercibleTypes() const111     const std::vector<const Type*>& coercibleTypes() const override {
112         return fTargetType.coercibleTypes();
113     }
114 
115 private:
116     using INHERITED = Type;
117 
118     const Type& fTargetType;
119 };
120 
121 class ArrayType final : public Type {
122 public:
123     inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
124 
ArrayType(std::string_view name,const char * abbrev,const Type & componentType,int count)125     ArrayType(std::string_view name, const char* abbrev, const Type& componentType, int count)
126         : INHERITED(name, abbrev, kTypeKind)
127         , fComponentType(componentType)
128         , fCount(count) {
129         // Only allow explicitly-sized arrays.
130         SkASSERT(count > 0);
131         // Disallow multi-dimensional arrays.
132         SkASSERT(!componentType.is<ArrayType>());
133     }
134 
isArray() const135     bool isArray() const override {
136         return true;
137     }
138 
componentType() const139     const Type& componentType() const override {
140         return fComponentType;
141     }
142 
columns() const143     int columns() const override {
144         return fCount;
145     }
146 
bitWidth() const147     int bitWidth() const override {
148         return this->componentType().bitWidth();
149     }
150 
isPrivate() const151     bool isPrivate() const override {
152         return fComponentType.isPrivate();
153     }
154 
isAllowedInES2() const155     bool isAllowedInES2() const override {
156         return fComponentType.isAllowedInES2();
157     }
158 
slotCount() const159     size_t slotCount() const override {
160         SkASSERT(fCount > 0);
161         return fCount * fComponentType.slotCount();
162     }
163 
164 private:
165     using INHERITED = Type;
166 
167     const Type& fComponentType;
168     int fCount;
169 };
170 
171 class GenericType final : public Type {
172 public:
173     inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
174 
GenericType(const char * name,std::vector<const Type * > coercibleTypes)175     GenericType(const char* name, std::vector<const Type*> coercibleTypes)
176         : INHERITED(name, "G", kTypeKind)
177         , fCoercibleTypes(std::move(coercibleTypes)) {}
178 
coercibleTypes() const179     const std::vector<const Type*>& coercibleTypes() const override {
180         return fCoercibleTypes;
181     }
182 
183 private:
184     using INHERITED = Type;
185 
186     std::vector<const Type*> fCoercibleTypes;
187 };
188 
189 class LiteralType : public Type {
190 public:
191     inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
192 
LiteralType(const char * name,const Type & scalarType,int8_t priority)193     LiteralType(const char* name, const Type& scalarType, int8_t priority)
194         : INHERITED(name, "L", kTypeKind)
195         , fScalarType(scalarType)
196         , fPriority(priority) {}
197 
scalarTypeForLiteral() const198     const Type& scalarTypeForLiteral() const override {
199         return fScalarType;
200     }
201 
priority() const202     int priority() const override {
203         return fPriority;
204     }
205 
columns() const206     int columns() const override {
207         return 1;
208     }
209 
rows() const210     int rows() const override {
211         return 1;
212     }
213 
numberKind() const214     NumberKind numberKind() const override {
215         return fScalarType.numberKind();
216     }
217 
bitWidth() const218     int bitWidth() const override {
219         return fScalarType.bitWidth();
220     }
221 
isScalar() const222     bool isScalar() const override {
223         return true;
224     }
225 
isLiteral() const226     bool isLiteral() const override {
227         return true;
228     }
229 
isPrivate() const230     bool isPrivate() const override {
231         return true;
232     }
233 
slotCount() const234     size_t slotCount() const override {
235         return 1;
236     }
237 
238 private:
239     using INHERITED = Type;
240 
241     const Type& fScalarType;
242     int8_t fPriority;
243 };
244 
245 
246 class ScalarType final : public Type {
247 public:
248     inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
249 
ScalarType(std::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)250     ScalarType(std::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
251                int8_t bitWidth)
252         : INHERITED(name, abbrev, kTypeKind)
253         , fNumberKind(numberKind)
254         , fPriority(priority)
255         , fBitWidth(bitWidth) {}
256 
numberKind() const257     NumberKind numberKind() const override {
258         return fNumberKind;
259     }
260 
priority() const261     int priority() const override {
262         return fPriority;
263     }
264 
bitWidth() const265     int bitWidth() const override {
266         return fBitWidth;
267     }
268 
columns() const269     int columns() const override {
270         return 1;
271     }
272 
rows() const273     int rows() const override {
274         return 1;
275     }
276 
isScalar() const277     bool isScalar() const override {
278         return true;
279     }
280 
isAllowedInES2() const281     bool isAllowedInES2() const override {
282         return fNumberKind != NumberKind::kUnsigned;
283     }
284 
slotCount() const285     size_t slotCount() const override {
286         return 1;
287     }
288 
289 private:
290     using INHERITED = Type;
291 
292     NumberKind fNumberKind;
293     int8_t fPriority;
294     int8_t fBitWidth;
295 };
296 
297 class MatrixType final : public Type {
298 public:
299     inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
300 
MatrixType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)301     MatrixType(std::string_view name, const char* abbrev, const Type& componentType,
302                int8_t columns, int8_t rows)
303         : INHERITED(name, abbrev, kTypeKind)
304         , fComponentType(componentType.as<ScalarType>())
305         , fColumns(columns)
306         , fRows(rows) {
307         SkASSERT(columns >= 2 && columns <= 4);
308         SkASSERT(rows >= 2 && rows <= 4);
309     }
310 
componentType() const311     const ScalarType& componentType() const override {
312         return fComponentType;
313     }
314 
columns() const315     int columns() const override {
316         return fColumns;
317     }
318 
rows() const319     int rows() const override {
320         return fRows;
321     }
322 
bitWidth() const323     int bitWidth() const override {
324         return this->componentType().bitWidth();
325     }
326 
isMatrix() const327     bool isMatrix() const override {
328         return true;
329     }
330 
isAllowedInES2() const331     bool isAllowedInES2() const override {
332         return fColumns == fRows;
333     }
334 
slotCount() const335     size_t slotCount() const override {
336         return fColumns * fRows;
337     }
338 
339 private:
340     using INHERITED = Type;
341 
342     const ScalarType& fComponentType;
343     int8_t fColumns;
344     int8_t fRows;
345 };
346 
347 class TextureType final : public Type {
348 public:
349     inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
350 
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,bool isSampled)351     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
352                 bool isMultisampled, bool isSampled)
353         : INHERITED(name, "T", kTypeKind)
354         , fDimensions(dimensions)
355         , fIsDepth(isDepth)
356         , fIsArrayed(isArrayed)
357         , fIsMultisampled(isMultisampled)
358         , fIsSampled(isSampled) {}
359 
dimensions() const360     SpvDim_ dimensions() const override {
361         return fDimensions;
362     }
363 
isDepth() const364     bool isDepth() const override {
365         return fIsDepth;
366     }
367 
isArrayedTexture() const368     bool isArrayedTexture() const override {
369         return fIsArrayed;
370     }
371 
isMultisampled() const372     bool isMultisampled() const override {
373         return fIsMultisampled;
374     }
375 
isSampled() const376     bool isSampled() const override {
377         return fIsSampled;
378     }
379 
380 private:
381     using INHERITED = Type;
382 
383     SpvDim_ fDimensions;
384     bool fIsDepth;
385     bool fIsArrayed;
386     bool fIsMultisampled;
387     bool fIsSampled;
388 };
389 
390 class SamplerType final : public Type {
391 public:
392     inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
393 
SamplerType(const char * name,const Type & textureType)394     SamplerType(const char* name, const Type& textureType)
395         : INHERITED(name, "Z", kTypeKind)
396         , fTextureType(textureType.as<TextureType>()) {}
397 
textureType() const398     const TextureType& textureType() const override {
399         return fTextureType;
400     }
401 
dimensions() const402     SpvDim_ dimensions() const override {
403         return fTextureType.dimensions();
404     }
405 
isDepth() const406     bool isDepth() const override {
407         return fTextureType.isDepth();
408     }
409 
isArrayedTexture() const410     bool isArrayedTexture() const override {
411         return fTextureType.isArrayedTexture();
412     }
413 
isMultisampled() const414     bool isMultisampled() const override {
415         return fTextureType.isMultisampled();
416     }
417 
isSampled() const418     bool isSampled() const override {
419         return fTextureType.isSampled();
420     }
421 
422 private:
423     using INHERITED = Type;
424 
425     const TextureType& fTextureType;
426 };
427 
428 class StructType final : public Type {
429 public:
430     inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
431 
StructType(int line,std::string_view name,std::vector<Field> fields,bool interfaceBlock)432     StructType(int line, std::string_view name, std::vector<Field> fields, bool interfaceBlock)
433         : INHERITED(std::move(name), "S", kTypeKind, line)
434         , fFields(std::move(fields))
435         , fInterfaceBlock(interfaceBlock) {}
436 
fields() const437     const std::vector<Field>& fields() const override {
438         return fFields;
439     }
440 
isStruct() const441     bool isStruct() const override {
442         return true;
443     }
444 
isInterfaceBlock() const445     bool isInterfaceBlock() const override {
446         return fInterfaceBlock;
447     }
448 
isPrivate() const449     bool isPrivate() const override {
450         return std::any_of(fFields.begin(), fFields.end(), [](const Field& f) {
451             return f.fType->isPrivate();
452         });
453     }
454 
isAllowedInES2() const455     bool isAllowedInES2() const override {
456         return std::all_of(fFields.begin(), fFields.end(), [](const Field& f) {
457             return f.fType->isAllowedInES2();
458         });
459     }
460 
slotCount() const461     size_t slotCount() const override {
462         size_t slots = 0;
463         for (const Field& field : fFields) {
464             slots += field.fType->slotCount();
465         }
466         return slots;
467     }
468 
469 private:
470     using INHERITED = Type;
471 
472     std::vector<Field> fFields;
473     bool fInterfaceBlock;
474 };
475 
476 class VectorType final : public Type {
477 public:
478     inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
479 
VectorType(std::string_view name,const char * abbrev,const Type & componentType,int8_t columns)480     VectorType(std::string_view name, const char* abbrev, const Type& componentType,
481                int8_t columns)
482         : INHERITED(name, abbrev, kTypeKind)
483         , fComponentType(componentType.as<ScalarType>())
484         , fColumns(columns) {
485         SkASSERT(columns >= 2 && columns <= 4);
486     }
487 
componentType() const488     const ScalarType& componentType() const override {
489         return fComponentType;
490     }
491 
columns() const492     int columns() const override {
493         return fColumns;
494     }
495 
rows() const496     int rows() const override {
497         return 1;
498     }
499 
bitWidth() const500     int bitWidth() const override {
501         return this->componentType().bitWidth();
502     }
503 
isVector() const504     bool isVector() const override {
505         return true;
506     }
507 
isAllowedInES2() const508     bool isAllowedInES2() const override {
509         return fComponentType.isAllowedInES2();
510     }
511 
slotCount() const512     size_t slotCount() const override {
513         return fColumns;
514     }
515 
516 private:
517     using INHERITED = Type;
518 
519     const ScalarType& fComponentType;
520     int8_t fColumns;
521 };
522 
getArrayName(int arraySize) const523 std::string Type::getArrayName(int arraySize) const {
524     std::string_view name = this->name();
525     return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
526 }
527 
MakeAliasType(std::string_view name,const Type & targetType)528 std::unique_ptr<Type> Type::MakeAliasType(std::string_view name, const Type& targetType) {
529     return std::make_unique<AliasType>(std::move(name), targetType);
530 }
531 
MakeArrayType(std::string_view name,const Type & componentType,int columns)532 std::unique_ptr<Type> Type::MakeArrayType(std::string_view name, const Type& componentType,
533                                           int columns) {
534     return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
535                                        componentType, columns);
536 }
537 
MakeGenericType(const char * name,std::vector<const Type * > types)538 std::unique_ptr<Type> Type::MakeGenericType(const char* name, std::vector<const Type*> types) {
539     return std::make_unique<GenericType>(name, std::move(types));
540 }
541 
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)542 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
543                                             int8_t priority) {
544     return std::make_unique<LiteralType>(name, scalarType, priority);
545 }
546 
MakeMatrixType(std::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)547 std::unique_ptr<Type> Type::MakeMatrixType(std::string_view name, const char* abbrev,
548                                            const Type& componentType, int columns, int8_t rows) {
549     return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
550 }
551 
MakeSamplerType(const char * name,const Type & textureType)552 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
553     return std::make_unique<SamplerType>(name, textureType);
554 }
555 
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)556 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
557                                             Type::TypeKind typeKind) {
558     return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
559 }
560 
MakeScalarType(std::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)561 std::unique_ptr<Type> Type::MakeScalarType(std::string_view name, const char* abbrev,
562                                            Type::NumberKind numberKind, int8_t priority,
563                                            int8_t bitWidth) {
564     return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
565 
566 }
567 
MakeStructType(int line,std::string_view name,std::vector<Field> fields,bool interfaceBlock)568 std::unique_ptr<Type> Type::MakeStructType(int line, std::string_view name,
569                                            std::vector<Field> fields, bool interfaceBlock) {
570     return std::make_unique<StructType>(line, name, std::move(fields), interfaceBlock);
571 }
572 
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,bool isSampled)573 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
574                                             bool isArrayedTexture, bool isMultisampled,
575                                             bool isSampled) {
576     return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
577                                          isMultisampled, isSampled);
578 }
579 
MakeVectorType(std::string_view name,const char * abbrev,const Type & componentType,int columns)580 std::unique_ptr<Type> Type::MakeVectorType(std::string_view name, const char* abbrev,
581                                            const Type& componentType, int columns) {
582     return std::make_unique<VectorType>(name, abbrev, componentType, columns);
583 }
584 
coercionCost(const Type & other) const585 CoercionCost Type::coercionCost(const Type& other) const {
586     if (this->matches(other)) {
587         return CoercionCost::Free();
588     }
589     if (this->typeKind() == other.typeKind() &&
590         (this->isVector() || this->isMatrix() || this->isArray())) {
591         // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
592         if (this->isMatrix() && (this->rows() != other.rows())) {
593             return CoercionCost::Impossible();
594         }
595         if (this->columns() != other.columns()) {
596             return CoercionCost::Impossible();
597         }
598         return this->componentType().coercionCost(other.componentType());
599     }
600     if (this->isNumber() && other.isNumber()) {
601         if (this->isLiteral() && this->isInteger()) {
602             return CoercionCost::Free();
603         } else if (this->numberKind() != other.numberKind()) {
604             return CoercionCost::Impossible();
605         } else if (other.priority() >= this->priority()) {
606             return CoercionCost::Normal(other.priority() - this->priority());
607         } else {
608             return CoercionCost::Narrowing(this->priority() - other.priority());
609         }
610     }
611     if (fTypeKind == TypeKind::kGeneric) {
612         const std::vector<const Type*>& types = this->coercibleTypes();
613         for (size_t i = 0; i < types.size(); i++) {
614             if (types[i]->matches(other)) {
615                 return CoercionCost::Normal((int) i + 1);
616             }
617         }
618     }
619     return CoercionCost::Impossible();
620 }
621 
applyPrecisionQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,int line) const622 const Type* Type::applyPrecisionQualifiers(const Context& context,
623                                            Modifiers* modifiers,
624                                            SymbolTable* symbols,
625                                            int line) const {
626     // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
627     bool highp   = modifiers->fFlags & Modifiers::kHighp_Flag;
628     bool mediump = modifiers->fFlags & Modifiers::kMediump_Flag;
629     bool lowp    = modifiers->fFlags & Modifiers::kLowp_Flag;
630 
631     if (!lowp && !mediump && !highp) {
632         // No precision qualifiers here. Return the type as-is.
633         return this;
634     }
635 
636     if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
637         // We want to discourage precision modifiers internally. Instead, use the type that
638         // corresponds to the precision you need. (e.g. half vs float, short vs int)
639         context.fErrors->error(line, "precision qualifiers are not allowed");
640         return nullptr;
641     }
642 
643     if ((int(lowp) + int(mediump) + int(highp)) != 1) {
644         context.fErrors->error(line, "only one precision qualifier can be used");
645         return nullptr;
646     }
647 
648     // We're going to return a whole new type, so the modifier bits can be cleared out.
649     modifiers->fFlags &= ~(Modifiers::kHighp_Flag |
650                            Modifiers::kMediump_Flag |
651                            Modifiers::kLowp_Flag);
652 
653     const Type& component = this->componentType();
654     if (component.highPrecision()) {
655         if (highp) {
656             // Type is already high precision, and we are requesting high precision. Return as-is.
657             return this;
658         }
659 
660         // Ascertain the mediump equivalent type for this type, if any.
661         const Type* mediumpType;
662         switch (component.numberKind()) {
663             case Type::NumberKind::kFloat:
664                 mediumpType = context.fTypes.fHalf.get();
665                 break;
666 
667             case Type::NumberKind::kSigned:
668                 mediumpType = context.fTypes.fShort.get();
669                 break;
670 
671             case Type::NumberKind::kUnsigned:
672                 mediumpType = context.fTypes.fUShort.get();
673                 break;
674 
675             default:
676                 mediumpType = nullptr;
677                 break;
678         }
679 
680         if (mediumpType) {
681             // Convert the mediump component type into the final vector/matrix/array type as needed.
682             return this->isArray()
683                            ? symbols->addArrayDimension(mediumpType, this->columns())
684                            : &mediumpType->toCompound(context, this->columns(), this->rows());
685         }
686     }
687 
688     context.fErrors->error(line, "type '" + this->displayName() +
689                                  "' does not support precision qualifiers");
690     return nullptr;
691 }
692 
toCompound(const Context & context,int columns,int rows) const693 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
694     SkASSERT(this->isScalar());
695     if (columns == 1 && rows == 1) {
696         return *this;
697     }
698     if (this->matches(*context.fTypes.fFloat) || this->matches(*context.fTypes.fFloatLiteral)) {
699         switch (rows) {
700             case 1:
701                 switch (columns) {
702                     case 1: return *context.fTypes.fFloat;
703                     case 2: return *context.fTypes.fFloat2;
704                     case 3: return *context.fTypes.fFloat3;
705                     case 4: return *context.fTypes.fFloat4;
706                     default: SK_ABORT("unsupported vector column count (%d)", columns);
707                 }
708             case 2:
709                 switch (columns) {
710                     case 2: return *context.fTypes.fFloat2x2;
711                     case 3: return *context.fTypes.fFloat3x2;
712                     case 4: return *context.fTypes.fFloat4x2;
713                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
714                 }
715             case 3:
716                 switch (columns) {
717                     case 2: return *context.fTypes.fFloat2x3;
718                     case 3: return *context.fTypes.fFloat3x3;
719                     case 4: return *context.fTypes.fFloat4x3;
720                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
721                 }
722             case 4:
723                 switch (columns) {
724                     case 2: return *context.fTypes.fFloat2x4;
725                     case 3: return *context.fTypes.fFloat3x4;
726                     case 4: return *context.fTypes.fFloat4x4;
727                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
728                 }
729             default: SK_ABORT("unsupported row count (%d)", rows);
730         }
731     } else if (this->matches(*context.fTypes.fHalf)) {
732         switch (rows) {
733             case 1:
734                 switch (columns) {
735                     case 1: return *context.fTypes.fHalf;
736                     case 2: return *context.fTypes.fHalf2;
737                     case 3: return *context.fTypes.fHalf3;
738                     case 4: return *context.fTypes.fHalf4;
739                     default: SK_ABORT("unsupported vector column count (%d)", columns);
740                 }
741             case 2:
742                 switch (columns) {
743                     case 2: return *context.fTypes.fHalf2x2;
744                     case 3: return *context.fTypes.fHalf3x2;
745                     case 4: return *context.fTypes.fHalf4x2;
746                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
747                 }
748             case 3:
749                 switch (columns) {
750                     case 2: return *context.fTypes.fHalf2x3;
751                     case 3: return *context.fTypes.fHalf3x3;
752                     case 4: return *context.fTypes.fHalf4x3;
753                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
754                 }
755             case 4:
756                 switch (columns) {
757                     case 2: return *context.fTypes.fHalf2x4;
758                     case 3: return *context.fTypes.fHalf3x4;
759                     case 4: return *context.fTypes.fHalf4x4;
760                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
761                 }
762             default: SK_ABORT("unsupported row count (%d)", rows);
763         }
764     } else if (this->matches(*context.fTypes.fInt) || this->matches(*context.fTypes.fIntLiteral)) {
765         switch (rows) {
766             case 1:
767                 switch (columns) {
768                     case 1: return *context.fTypes.fInt;
769                     case 2: return *context.fTypes.fInt2;
770                     case 3: return *context.fTypes.fInt3;
771                     case 4: return *context.fTypes.fInt4;
772                     default: SK_ABORT("unsupported vector column count (%d)", columns);
773                 }
774             default: SK_ABORT("unsupported row count (%d)", rows);
775         }
776     } else if (this->matches(*context.fTypes.fShort)) {
777         switch (rows) {
778             case 1:
779                 switch (columns) {
780                     case 1: return *context.fTypes.fShort;
781                     case 2: return *context.fTypes.fShort2;
782                     case 3: return *context.fTypes.fShort3;
783                     case 4: return *context.fTypes.fShort4;
784                     default: SK_ABORT("unsupported vector column count (%d)", columns);
785                 }
786             default: SK_ABORT("unsupported row count (%d)", rows);
787         }
788     } else if (this->matches(*context.fTypes.fUInt)) {
789         switch (rows) {
790             case 1:
791                 switch (columns) {
792                     case 1: return *context.fTypes.fUInt;
793                     case 2: return *context.fTypes.fUInt2;
794                     case 3: return *context.fTypes.fUInt3;
795                     case 4: return *context.fTypes.fUInt4;
796                     default: SK_ABORT("unsupported vector column count (%d)", columns);
797                 }
798             default: SK_ABORT("unsupported row count (%d)", rows);
799         }
800     } else if (this->matches(*context.fTypes.fUShort)) {
801         switch (rows) {
802             case 1:
803                 switch (columns) {
804                     case 1: return *context.fTypes.fUShort;
805                     case 2: return *context.fTypes.fUShort2;
806                     case 3: return *context.fTypes.fUShort3;
807                     case 4: return *context.fTypes.fUShort4;
808                     default: SK_ABORT("unsupported vector column count (%d)", columns);
809                 }
810             default: SK_ABORT("unsupported row count (%d)", rows);
811         }
812     } else if (this->matches(*context.fTypes.fBool)) {
813         switch (rows) {
814             case 1:
815                 switch (columns) {
816                     case 1: return *context.fTypes.fBool;
817                     case 2: return *context.fTypes.fBool2;
818                     case 3: return *context.fTypes.fBool3;
819                     case 4: return *context.fTypes.fBool4;
820                     default: SK_ABORT("unsupported vector column count (%d)", columns);
821                 }
822             default: SK_ABORT("unsupported row count (%d)", rows);
823         }
824     }
825     SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
826     return *context.fTypes.fVoid;
827 }
828 
clone(SymbolTable * symbolTable) const829 const Type* Type::clone(SymbolTable* symbolTable) const {
830     // Many types are built-ins, and exist in every SymbolTable by default.
831     if (this->isInBuiltinTypes()) {
832         return this;
833     }
834     // Even if the type isn't a built-in, it might already exist in the SymbolTable.
835     const Symbol* clonedSymbol = (*symbolTable)[this->name()];
836     if (clonedSymbol != nullptr) {
837         const Type& clonedType = clonedSymbol->as<Type>();
838         SkASSERT(clonedType.typeKind() == this->typeKind());
839         return &clonedType;
840     }
841     // This type actually needs to be cloned into the destination SymbolTable.
842     switch (this->typeKind()) {
843         case TypeKind::kArray: {
844             return symbolTable->addArrayDimension(&this->componentType(), this->columns());
845         }
846         case TypeKind::kStruct: {
847             const std::string* name = symbolTable->takeOwnershipOfString(std::string(this->name()));
848             return symbolTable->add(Type::MakeStructType(
849                     this->fLine, *name, this->fields(), this->isInterfaceBlock()));
850         }
851         default:
852             SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
853             return nullptr;
854     }
855 }
856 
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const857 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
858                                                    const Context& context) const {
859     if (!expr || expr->isIncomplete(context)) {
860         return nullptr;
861     }
862     if (expr->type().matches(*this)) {
863         return expr;
864     }
865 
866     const int line = expr->fLine;
867     const Program::Settings& settings = context.fConfig->fSettings;
868     if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
869         context.fErrors->error(line, "expected '" + this->displayName() + "', but found '" +
870                                      expr->type().displayName() + "'");
871         return nullptr;
872     }
873 
874     if (this->isScalar()) {
875         return ConstructorScalarCast::Make(context, line, *this, std::move(expr));
876     }
877     if (this->isVector() || this->isMatrix()) {
878         return ConstructorCompoundCast::Make(context, line, *this, std::move(expr));
879     }
880     if (this->isArray()) {
881         return ConstructorArrayCast::Make(context, line, *this, std::move(expr));
882     }
883     context.fErrors->error(line, "cannot construct '" + this->displayName() + "'");
884     return nullptr;
885 }
886 
isPrivate() const887 bool Type::isPrivate() const {
888     return skstd::starts_with(this->name(), '$');
889 }
890 
isOrContainsArray() const891 bool Type::isOrContainsArray() const {
892     if (this->isStruct()) {
893         for (const Field& f : this->fields()) {
894             if (f.fType->isOrContainsArray()) {
895                 return true;
896             }
897         }
898         return false;
899     }
900 
901     return this->isArray();
902 }
903 
isTooDeeplyNested(int limit) const904 bool Type::isTooDeeplyNested(int limit) const {
905     if (limit < 0) {
906         return true;
907     }
908 
909     if (this->isStruct()) {
910         for (const Type::Field& f : this->fields()) {
911             if (f.fType->isTooDeeplyNested(limit - 1)) {
912                 return true;
913             }
914         }
915     }
916 
917     return false;
918 }
919 
isTooDeeplyNested() const920 bool Type::isTooDeeplyNested() const {
921     return this->isTooDeeplyNested(kMaxStructDepth);
922 }
923 
isAllowedInES2(const Context & context) const924 bool Type::isAllowedInES2(const Context& context) const {
925     return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
926 }
927 
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const928 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
929     bool foundError = false;
930     const Type& baseType = this->componentType();
931     if (baseType.isInteger()) {
932         // Replace constant expressions with their corresponding values.
933         const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
934         if (valueExpr->supportsConstantValues()) {
935             // Iterate over every constant subexpression in the value.
936             int numSlots = valueExpr->type().slotCount();
937             for (int slot = 0; slot < numSlots; ++slot) {
938                 std::optional<double> slotVal = valueExpr->getConstantValue(slot);
939                 // Check for Literal values that are out of range for the base type.
940                 if (slotVal.has_value() &&
941                     baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fLine)) {
942                     foundError = true;
943                 }
944             }
945         }
946     }
947 
948     // We don't need range checks for floats or booleans; any matched-type value is acceptable.
949     return foundError;
950 }
951 
checkForOutOfRangeLiteral(const Context & context,double value,int line) const952 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, int line) const {
953     SkASSERT(this->isScalar());
954     if (this->isInteger()) {
955         if (value < this->minimumValue() || value > this->maximumValue()) {
956             // We found a value that can't fit in the type. Flag it as an error.
957             context.fErrors->error(
958                     line,
959                     SkSL::String::printf("integer is out of range for type '%s': %.0f",
960                                          this->displayName().c_str(),
961                                          std::floor(value)));
962             return true;
963         }
964     }
965     return false;
966 }
967 
convertArraySize(const Context & context,std::unique_ptr<Expression> size) const968 SKSL_INT Type::convertArraySize(const Context& context, std::unique_ptr<Expression> size) const {
969     size = context.fTypes.fInt->coerceExpression(std::move(size), context);
970     if (!size) {
971         return 0;
972     }
973     if (this->isArray()) {
974         context.fErrors->error(size->fLine, "multi-dimensional arrays are not supported");
975         return 0;
976     }
977     if (this->isVoid()) {
978         context.fErrors->error(size->fLine, "type 'void' may not be used in an array");
979         return 0;
980     }
981     if (this->isOpaque()) {
982         context.fErrors->error(size->fLine, "opaque type '" + std::string(this->name()) +
983                                             "' may not be used in an array");
984         return 0;
985     }
986     SKSL_INT count;
987     if (!ConstantFolder::GetConstantInt(*size, &count)) {
988         context.fErrors->error(size->fLine, "array size must be an integer");
989         return 0;
990     }
991     if (count <= 0) {
992         context.fErrors->error(size->fLine, "array size must be positive");
993         return 0;
994     }
995     if (!SkTFitsIn<int32_t>(count)) {
996         context.fErrors->error(size->fLine, "array size is too large");
997         return 0;
998     }
999     return static_cast<int>(count);
1000 }
1001 
1002 }  // namespace SkSL
1003