• 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 "src/sksl/SkSLConstantFolder.h"
11 #include "src/sksl/SkSLContext.h"
12 #include "src/sksl/SkSLProgramSettings.h"
13 #include "src/sksl/ir/SkSLConstructor.h"
14 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
15 #include "src/sksl/ir/SkSLConstructorCompoundCast.h"
16 #include "src/sksl/ir/SkSLConstructorScalarCast.h"
17 #include "src/sksl/ir/SkSLProgram.h"
18 #include "src/sksl/ir/SkSLSymbolTable.h"
19 #include "src/sksl/ir/SkSLType.h"
20 
21 namespace SkSL {
22 
23 static constexpr int kMaxStructDepth = 8;
24 
25 class ArrayType final : public Type {
26 public:
27     inline static constexpr TypeKind kTypeKind = TypeKind::kArray;
28 
ArrayType(skstd::string_view name,const char * abbrev,const Type & componentType,int count)29     ArrayType(skstd::string_view name, const char* abbrev, const Type& componentType, int count)
30         : INHERITED(name, abbrev, kTypeKind)
31         , fComponentType(componentType)
32         , fCount(count) {
33 #ifdef SKSL_EXT
34         SkASSERT(count > 0 || count == kUnsizedArray);
35 #else
36         // Only allow explicitly-sized arrays.
37         SkASSERT(count > 0);
38 #endif
39         // Disallow multi-dimensional arrays.
40         SkASSERT(!componentType.is<ArrayType>());
41     }
42 
isArray() const43     bool isArray() const override {
44         return true;
45     }
46 
47 #ifdef SKSL_EXT
isUnsizedArray() const48     bool isUnsizedArray() const override {
49         return fCount == kUnsizedArray;
50     }
51 #endif
52 
componentType() const53     const Type& componentType() const override {
54         return fComponentType;
55     }
56 
columns() const57     int columns() const override {
58         return fCount;
59     }
60 
bitWidth() const61     int bitWidth() const override {
62         return this->componentType().bitWidth();
63     }
64 
isPrivate() const65     bool isPrivate() const override {
66         return fComponentType.isPrivate();
67     }
68 
isAllowedInES2() const69     bool isAllowedInES2() const override {
70         return fComponentType.isAllowedInES2();
71     }
72 
slotCount() const73     size_t slotCount() const override {
74         SkASSERT(fCount > 0);
75         return fCount * fComponentType.slotCount();
76     }
77 
78 private:
79     using INHERITED = Type;
80 
81     const Type& fComponentType;
82     int fCount;
83 };
84 
85 class GenericType final : public Type {
86 public:
87     inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
88 
GenericType(const char * name,std::vector<const Type * > coercibleTypes)89     GenericType(const char* name, std::vector<const Type*> coercibleTypes)
90         : INHERITED(name, "G", kTypeKind)
91         , fCoercibleTypes(std::move(coercibleTypes)) {}
92 
coercibleTypes() const93     const std::vector<const Type*>& coercibleTypes() const override {
94         return fCoercibleTypes;
95     }
96 
97 private:
98     using INHERITED = Type;
99 
100     std::vector<const Type*> fCoercibleTypes;
101 };
102 
103 class LiteralType : public Type {
104 public:
105     inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
106 
LiteralType(const char * name,const Type & scalarType,int8_t priority)107     LiteralType(const char* name, const Type& scalarType, int8_t priority)
108         : INHERITED(name, "L", kTypeKind)
109         , fScalarType(scalarType)
110         , fPriority(priority) {}
111 
scalarTypeForLiteral() const112     const Type& scalarTypeForLiteral() const override {
113         return fScalarType;
114     }
115 
priority() const116     int priority() const override {
117         return fPriority;
118     }
119 
columns() const120     int columns() const override {
121         return 1;
122     }
123 
rows() const124     int rows() const override {
125         return 1;
126     }
127 
numberKind() const128     NumberKind numberKind() const override {
129         return fScalarType.numberKind();
130     }
131 
bitWidth() const132     int bitWidth() const override {
133         return fScalarType.bitWidth();
134     }
135 
isScalar() const136     bool isScalar() const override {
137         return true;
138     }
139 
isLiteral() const140     bool isLiteral() const override {
141         return true;
142     }
143 
slotCount() const144     size_t slotCount() const override {
145         return 1;
146     }
147 
148 private:
149     using INHERITED = Type;
150 
151     const Type& fScalarType;
152     int8_t fPriority;
153 };
154 
155 
156 class ScalarType final : public Type {
157 public:
158     inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
159 
ScalarType(skstd::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)160     ScalarType(skstd::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
161                int8_t bitWidth)
162         : INHERITED(name, abbrev, kTypeKind)
163         , fNumberKind(numberKind)
164         , fPriority(priority)
165         , fBitWidth(bitWidth) {}
166 
numberKind() const167     NumberKind numberKind() const override {
168         return fNumberKind;
169     }
170 
priority() const171     int priority() const override {
172         return fPriority;
173     }
174 
bitWidth() const175     int bitWidth() const override {
176         return fBitWidth;
177     }
178 
columns() const179     int columns() const override {
180         return 1;
181     }
182 
rows() const183     int rows() const override {
184         return 1;
185     }
186 
isScalar() const187     bool isScalar() const override {
188         return true;
189     }
190 
isAllowedInES2() const191     bool isAllowedInES2() const override {
192         return fNumberKind != NumberKind::kUnsigned;
193     }
194 
slotCount() const195     size_t slotCount() const override {
196         return 1;
197     }
198 
199 private:
200     using INHERITED = Type;
201 
202     NumberKind fNumberKind;
203     int8_t fPriority;
204     int8_t fBitWidth;
205 };
206 
207 class MatrixType final : public Type {
208 public:
209     inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
210 
MatrixType(skstd::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)211     MatrixType(skstd::string_view name, const char* abbrev, const Type& componentType,
212                int8_t columns, int8_t rows)
213         : INHERITED(name, abbrev, kTypeKind)
214         , fComponentType(componentType.as<ScalarType>())
215         , fColumns(columns)
216         , fRows(rows) {
217         SkASSERT(columns >= 2 && columns <= 4);
218         SkASSERT(rows >= 2 && rows <= 4);
219     }
220 
componentType() const221     const ScalarType& componentType() const override {
222         return fComponentType;
223     }
224 
columns() const225     int columns() const override {
226         return fColumns;
227     }
228 
rows() const229     int rows() const override {
230         return fRows;
231     }
232 
bitWidth() const233     int bitWidth() const override {
234         return this->componentType().bitWidth();
235     }
236 
isMatrix() const237     bool isMatrix() const override {
238         return true;
239     }
240 
isAllowedInES2() const241     bool isAllowedInES2() const override {
242         return fColumns == fRows;
243     }
244 
slotCount() const245     size_t slotCount() const override {
246         return fColumns * fRows;
247     }
248 
249 private:
250     using INHERITED = Type;
251 
252     const ScalarType& fComponentType;
253     int8_t fColumns;
254     int8_t fRows;
255 };
256 
257 class TextureType final : public Type {
258 public:
259     inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
260 
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,bool isSampled)261     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
262                 bool isMultisampled, bool isSampled)
263         : INHERITED(name, "T", kTypeKind)
264         , fDimensions(dimensions)
265         , fIsDepth(isDepth)
266         , fIsArrayed(isArrayed)
267         , fIsMultisampled(isMultisampled)
268         , fIsSampled(isSampled) {}
269 
dimensions() const270     SpvDim_ dimensions() const override {
271         return fDimensions;
272     }
273 
isDepth() const274     bool isDepth() const override {
275         return fIsDepth;
276     }
277 
isArrayedTexture() const278     bool isArrayedTexture() const override {
279         return fIsArrayed;
280     }
281 
isMultisampled() const282     bool isMultisampled() const override {
283         return fIsMultisampled;
284     }
285 
isSampled() const286     bool isSampled() const override {
287         return fIsSampled;
288     }
289 
290 private:
291     using INHERITED = Type;
292 
293     SpvDim_ fDimensions;
294     bool fIsDepth;
295     bool fIsArrayed;
296     bool fIsMultisampled;
297     bool fIsSampled;
298 };
299 
300 class SamplerType final : public Type {
301 public:
302     inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
303 
SamplerType(const char * name,const Type & textureType)304     SamplerType(const char* name, const Type& textureType)
305         : INHERITED(name, "Z", kTypeKind)
306         , fTextureType(textureType.as<TextureType>()) {}
307 
textureType() const308     const TextureType& textureType() const override {
309         return fTextureType;
310     }
311 
dimensions() const312     SpvDim_ dimensions() const override {
313         return fTextureType.dimensions();
314     }
315 
isDepth() const316     bool isDepth() const override {
317         return fTextureType.isDepth();
318     }
319 
isArrayedTexture() const320     bool isArrayedTexture() const override {
321         return fTextureType.isArrayedTexture();
322     }
323 
isMultisampled() const324     bool isMultisampled() const override {
325         return fTextureType.isMultisampled();
326     }
327 
isSampled() const328     bool isSampled() const override {
329         return fTextureType.isSampled();
330     }
331 
332 private:
333     using INHERITED = Type;
334 
335     const TextureType& fTextureType;
336 };
337 
338 class StructType final : public Type {
339 public:
340     inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
341 
StructType(int line,skstd::string_view name,std::vector<Field> fields)342     StructType(int line, skstd::string_view name, std::vector<Field> fields)
343         : INHERITED(std::move(name), "S", kTypeKind, line)
344         , fFields(std::move(fields)) {}
345 
fields() const346     const std::vector<Field>& fields() const override {
347         return fFields;
348     }
349 
isStruct() const350     bool isStruct() const override {
351         return true;
352     }
353 
isPrivate() const354     bool isPrivate() const override {
355         return std::any_of(fFields.begin(), fFields.end(), [](const Field& f) {
356             return f.fType->isPrivate();
357         });
358     }
359 
isAllowedInES2() const360     bool isAllowedInES2() const override {
361         return std::all_of(fFields.begin(), fFields.end(), [](const Field& f) {
362             return f.fType->isAllowedInES2();
363         });
364     }
365 
slotCount() const366     size_t slotCount() const override {
367         size_t slots = 0;
368         for (const Field& field : fFields) {
369             slots += field.fType->slotCount();
370         }
371         return slots;
372     }
373 
374 private:
375     using INHERITED = Type;
376 
377     std::vector<Field> fFields;
378 };
379 
380 class VectorType final : public Type {
381 public:
382     inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
383 
VectorType(skstd::string_view name,const char * abbrev,const Type & componentType,int8_t columns)384     VectorType(skstd::string_view name, const char* abbrev, const Type& componentType,
385                int8_t columns)
386         : INHERITED(name, abbrev, kTypeKind)
387         , fComponentType(componentType.as<ScalarType>())
388         , fColumns(columns) {
389         SkASSERT(columns >= 2 && columns <= 4);
390     }
391 
componentType() const392     const ScalarType& componentType() const override {
393         return fComponentType;
394     }
395 
columns() const396     int columns() const override {
397         return fColumns;
398     }
399 
rows() const400     int rows() const override {
401         return 1;
402     }
403 
bitWidth() const404     int bitWidth() const override {
405         return this->componentType().bitWidth();
406     }
407 
isVector() const408     bool isVector() const override {
409         return true;
410     }
411 
isAllowedInES2() const412     bool isAllowedInES2() const override {
413         return fComponentType.isAllowedInES2();
414     }
415 
slotCount() const416     size_t slotCount() const override {
417         return fColumns;
418     }
419 
420 private:
421     using INHERITED = Type;
422 
423     const ScalarType& fComponentType;
424     int8_t fColumns;
425 };
426 
getArrayName(int arraySize) const427 String Type::getArrayName(int arraySize) const {
428     skstd::string_view name = this->name();
429     return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
430 }
431 
MakeArrayType(skstd::string_view name,const Type & componentType,int columns)432 std::unique_ptr<Type> Type::MakeArrayType(skstd::string_view name, const Type& componentType,
433                                           int columns) {
434     return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
435                                        componentType, columns);
436 }
437 
MakeGenericType(const char * name,std::vector<const Type * > types)438 std::unique_ptr<Type> Type::MakeGenericType(const char* name, std::vector<const Type*> types) {
439     return std::make_unique<GenericType>(name, std::move(types));
440 }
441 
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)442 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
443                                             int8_t priority) {
444     return std::make_unique<LiteralType>(name, scalarType, priority);
445 }
446 
MakeMatrixType(skstd::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)447 std::unique_ptr<Type> Type::MakeMatrixType(skstd::string_view name, const char* abbrev,
448                                            const Type& componentType, int columns, int8_t rows) {
449     return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
450 }
451 
MakeSamplerType(const char * name,const Type & textureType)452 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
453     return std::make_unique<SamplerType>(name, textureType);
454 }
455 
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)456 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
457                                             Type::TypeKind typeKind) {
458     return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
459 }
460 
MakeScalarType(skstd::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)461 std::unique_ptr<Type> Type::MakeScalarType(skstd::string_view name, const char* abbrev,
462                                            Type::NumberKind numberKind, int8_t priority,
463                                            int8_t bitWidth) {
464     return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
465 
466 }
467 
MakeStructType(int line,skstd::string_view name,std::vector<Field> fields)468 std::unique_ptr<Type> Type::MakeStructType(int line, skstd::string_view name,
469                                            std::vector<Field> fields) {
470     return std::make_unique<StructType>(line, name, std::move(fields));
471 }
472 
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,bool isSampled)473 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
474                                             bool isArrayedTexture, bool isMultisampled,
475                                             bool isSampled) {
476     return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
477                                          isMultisampled, isSampled);
478 }
479 
MakeVectorType(skstd::string_view name,const char * abbrev,const Type & componentType,int columns)480 std::unique_ptr<Type> Type::MakeVectorType(skstd::string_view name, const char* abbrev,
481                                            const Type& componentType, int columns) {
482     return std::make_unique<VectorType>(name, abbrev, componentType, columns);
483 }
484 
coercionCost(const Type & other) const485 CoercionCost Type::coercionCost(const Type& other) const {
486     if (*this == other) {
487         return CoercionCost::Free();
488     }
489     if (this->typeKind() == other.typeKind() &&
490         (this->isVector() || this->isMatrix() || this->isArray())) {
491         // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
492         if (this->isMatrix() && (this->rows() != other.rows())) {
493             return CoercionCost::Impossible();
494         }
495         if (this->columns() != other.columns()) {
496             return CoercionCost::Impossible();
497         }
498         return this->componentType().coercionCost(other.componentType());
499     }
500     if (this->isNumber() && other.isNumber()) {
501         if (this->isLiteral() && this->isInteger()) {
502             return CoercionCost::Free();
503 #ifndef SKSL_EXT
504         } else if (this->numberKind() != other.numberKind()) {
505             return CoercionCost::Impossible();
506 #endif
507         } else if (other.priority() >= this->priority()) {
508             return CoercionCost::Normal(other.priority() - this->priority());
509         } else {
510             return CoercionCost::Narrowing(this->priority() - other.priority());
511         }
512     }
513     if (fTypeKind == TypeKind::kGeneric) {
514         const std::vector<const Type*>& types = this->coercibleTypes();
515         for (size_t i = 0; i < types.size(); i++) {
516             if (*types[i] == other) {
517                 return CoercionCost::Normal((int) i + 1);
518             }
519         }
520     }
521     return CoercionCost::Impossible();
522 }
523 
applyPrecisionQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,int line) const524 const Type* Type::applyPrecisionQualifiers(const Context& context,
525                                            Modifiers* modifiers,
526                                            SymbolTable* symbols,
527                                            int line) const {
528     // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
529     bool highp   = modifiers->fFlags & Modifiers::kHighp_Flag;
530     bool mediump = modifiers->fFlags & Modifiers::kMediump_Flag;
531     bool lowp    = modifiers->fFlags & Modifiers::kLowp_Flag;
532 
533     if (!lowp && !mediump && !highp) {
534         // No precision qualifiers here. Return the type as-is.
535         return this;
536     }
537 
538     if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
539         // We want to discourage precision modifiers internally. Instead, use the type that
540         // corresponds to the precision you need. (e.g. half vs float, short vs int)
541         context.fErrors->error(line, "precision qualifiers are not allowed");
542         return nullptr;
543     }
544 
545     if ((int(lowp) + int(mediump) + int(highp)) != 1) {
546         context.fErrors->error(line, "only one precision qualifier can be used");
547         return nullptr;
548     }
549 
550     // We're going to return a whole new type, so the modifier bits can be cleared out.
551     modifiers->fFlags &= ~(Modifiers::kHighp_Flag |
552                            Modifiers::kMediump_Flag |
553                            Modifiers::kLowp_Flag);
554 
555     const Type& component = this->componentType();
556     if (component.highPrecision()) {
557         if (highp) {
558             // Type is already high precision, and we are requesting high precision. Return as-is.
559             return this;
560         }
561 
562         // Ascertain the mediump equivalent type for this type, if any.
563         const Type* mediumpType;
564         switch (component.numberKind()) {
565             case Type::NumberKind::kFloat:
566                 mediumpType = context.fTypes.fHalf.get();
567                 break;
568 
569             case Type::NumberKind::kSigned:
570                 mediumpType = context.fTypes.fShort.get();
571                 break;
572 
573             case Type::NumberKind::kUnsigned:
574                 mediumpType = context.fTypes.fUShort.get();
575                 break;
576 
577             default:
578                 mediumpType = nullptr;
579                 break;
580         }
581 
582         if (mediumpType) {
583             // Convert the mediump component type into the final vector/matrix/array type as needed.
584             return this->isArray()
585                            ? symbols->addArrayDimension(mediumpType, this->columns())
586                            : &mediumpType->toCompound(context, this->columns(), this->rows());
587         }
588     }
589 
590     context.fErrors->error(line, "type '" + this->displayName() +
591                                  "' does not support precision qualifiers");
592     return nullptr;
593 }
594 
toCompound(const Context & context,int columns,int rows) const595 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
596     SkASSERT(this->isScalar());
597     if (columns == 1 && rows == 1) {
598         return *this;
599     }
600     if (*this == *context.fTypes.fFloat || *this == *context.fTypes.fFloatLiteral) {
601         switch (rows) {
602             case 1:
603                 switch (columns) {
604                     case 1: return *context.fTypes.fFloat;
605                     case 2: return *context.fTypes.fFloat2;
606                     case 3: return *context.fTypes.fFloat3;
607                     case 4: return *context.fTypes.fFloat4;
608                     default: SK_ABORT("unsupported vector column count (%d)", columns);
609                 }
610             case 2:
611                 switch (columns) {
612                     case 2: return *context.fTypes.fFloat2x2;
613                     case 3: return *context.fTypes.fFloat3x2;
614                     case 4: return *context.fTypes.fFloat4x2;
615                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
616                 }
617             case 3:
618                 switch (columns) {
619                     case 2: return *context.fTypes.fFloat2x3;
620                     case 3: return *context.fTypes.fFloat3x3;
621                     case 4: return *context.fTypes.fFloat4x3;
622                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
623                 }
624             case 4:
625                 switch (columns) {
626                     case 2: return *context.fTypes.fFloat2x4;
627                     case 3: return *context.fTypes.fFloat3x4;
628                     case 4: return *context.fTypes.fFloat4x4;
629                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
630                 }
631             default: SK_ABORT("unsupported row count (%d)", rows);
632         }
633     } else if (*this == *context.fTypes.fHalf) {
634         switch (rows) {
635             case 1:
636                 switch (columns) {
637                     case 1: return *context.fTypes.fHalf;
638                     case 2: return *context.fTypes.fHalf2;
639                     case 3: return *context.fTypes.fHalf3;
640                     case 4: return *context.fTypes.fHalf4;
641                     default: SK_ABORT("unsupported vector column count (%d)", columns);
642                 }
643             case 2:
644                 switch (columns) {
645                     case 2: return *context.fTypes.fHalf2x2;
646                     case 3: return *context.fTypes.fHalf3x2;
647                     case 4: return *context.fTypes.fHalf4x2;
648                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
649                 }
650             case 3:
651                 switch (columns) {
652                     case 2: return *context.fTypes.fHalf2x3;
653                     case 3: return *context.fTypes.fHalf3x3;
654                     case 4: return *context.fTypes.fHalf4x3;
655                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
656                 }
657             case 4:
658                 switch (columns) {
659                     case 2: return *context.fTypes.fHalf2x4;
660                     case 3: return *context.fTypes.fHalf3x4;
661                     case 4: return *context.fTypes.fHalf4x4;
662                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
663                 }
664             default: SK_ABORT("unsupported row count (%d)", rows);
665         }
666     } else if (*this == *context.fTypes.fInt || *this == *context.fTypes.fIntLiteral) {
667         switch (rows) {
668             case 1:
669                 switch (columns) {
670                     case 1: return *context.fTypes.fInt;
671                     case 2: return *context.fTypes.fInt2;
672                     case 3: return *context.fTypes.fInt3;
673                     case 4: return *context.fTypes.fInt4;
674                     default: SK_ABORT("unsupported vector column count (%d)", columns);
675                 }
676             default: SK_ABORT("unsupported row count (%d)", rows);
677         }
678     } else if (*this == *context.fTypes.fShort) {
679         switch (rows) {
680             case 1:
681                 switch (columns) {
682                     case 1: return *context.fTypes.fShort;
683                     case 2: return *context.fTypes.fShort2;
684                     case 3: return *context.fTypes.fShort3;
685                     case 4: return *context.fTypes.fShort4;
686                     default: SK_ABORT("unsupported vector column count (%d)", columns);
687                 }
688             default: SK_ABORT("unsupported row count (%d)", rows);
689         }
690     } else if (*this == *context.fTypes.fUInt) {
691         switch (rows) {
692             case 1:
693                 switch (columns) {
694                     case 1: return *context.fTypes.fUInt;
695                     case 2: return *context.fTypes.fUInt2;
696                     case 3: return *context.fTypes.fUInt3;
697                     case 4: return *context.fTypes.fUInt4;
698                     default: SK_ABORT("unsupported vector column count (%d)", columns);
699                 }
700             default: SK_ABORT("unsupported row count (%d)", rows);
701         }
702     } else if (*this == *context.fTypes.fUShort) {
703         switch (rows) {
704             case 1:
705                 switch (columns) {
706                     case 1: return *context.fTypes.fUShort;
707                     case 2: return *context.fTypes.fUShort2;
708                     case 3: return *context.fTypes.fUShort3;
709                     case 4: return *context.fTypes.fUShort4;
710                     default: SK_ABORT("unsupported vector column count (%d)", columns);
711                 }
712             default: SK_ABORT("unsupported row count (%d)", rows);
713         }
714     } else if (*this == *context.fTypes.fBool) {
715         switch (rows) {
716             case 1:
717                 switch (columns) {
718                     case 1: return *context.fTypes.fBool;
719                     case 2: return *context.fTypes.fBool2;
720                     case 3: return *context.fTypes.fBool3;
721                     case 4: return *context.fTypes.fBool4;
722                     default: SK_ABORT("unsupported vector column count (%d)", columns);
723                 }
724             default: SK_ABORT("unsupported row count (%d)", rows);
725         }
726     }
727     SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
728     return *context.fTypes.fVoid;
729 }
730 
clone(SymbolTable * symbolTable) const731 const Type* Type::clone(SymbolTable* symbolTable) const {
732     // Many types are built-ins, and exist in every SymbolTable by default.
733     if (this->isInBuiltinTypes()) {
734         return this;
735     }
736     // Even if the type isn't a built-in, it might already exist in the SymbolTable.
737     const Symbol* clonedSymbol = (*symbolTable)[this->name()];
738     if (clonedSymbol != nullptr) {
739         const Type& clonedType = clonedSymbol->as<Type>();
740         SkASSERT(clonedType.typeKind() == this->typeKind());
741         return &clonedType;
742     }
743     // This type actually needs to be cloned into the destination SymbolTable.
744     switch (this->typeKind()) {
745         case TypeKind::kArray: {
746             return symbolTable->addArrayDimension(&this->componentType(), this->columns());
747         }
748         case TypeKind::kStruct: {
749             const String* name = symbolTable->takeOwnershipOfString(String(this->name()));
750             return symbolTable->add(Type::MakeStructType(this->fLine, *name, this->fields()));
751         }
752         default:
753             SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
754             return nullptr;
755     }
756 }
757 
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const758 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
759                                                    const Context& context) const {
760     if (!expr || expr->isIncomplete(context)) {
761         return nullptr;
762     }
763     if (expr->type() == *this) {
764         return expr;
765     }
766 
767     const int line = expr->fLine;
768     const Program::Settings& settings = context.fConfig->fSettings;
769     if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
770         context.fErrors->error(line, "expected '" + this->displayName() + "', but found '" +
771                                      expr->type().displayName() + "'");
772         return nullptr;
773     }
774 
775     if (this->isScalar()) {
776         return ConstructorScalarCast::Make(context, line, *this, std::move(expr));
777     }
778     if (this->isVector() || this->isMatrix()) {
779         return ConstructorCompoundCast::Make(context, line, *this, std::move(expr));
780     }
781     if (this->isArray()) {
782         return ConstructorArrayCast::Make(context, line, *this, std::move(expr));
783     }
784     context.fErrors->error(line, "cannot construct '" + this->displayName() + "'");
785     return nullptr;
786 }
787 
isOrContainsArray() const788 bool Type::isOrContainsArray() const {
789     if (this->isStruct()) {
790         for (const Field& f : this->fields()) {
791             if (f.fType->isOrContainsArray()) {
792                 return true;
793             }
794         }
795         return false;
796     }
797 
798     return this->isArray();
799 }
800 
isTooDeeplyNested(int limit) const801 bool Type::isTooDeeplyNested(int limit) const {
802     if (limit < 0) {
803         return true;
804     }
805 
806     if (this->isStruct()) {
807         for (const Type::Field& f : this->fields()) {
808             if (f.fType->isTooDeeplyNested(limit - 1)) {
809                 return true;
810             }
811         }
812     }
813 
814     return false;
815 }
816 
isTooDeeplyNested() const817 bool Type::isTooDeeplyNested() const {
818     return this->isTooDeeplyNested(kMaxStructDepth);
819 }
820 
isAllowedInES2(const Context & context) const821 bool Type::isAllowedInES2(const Context& context) const {
822     return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
823 }
824 
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const825 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
826     bool foundError = false;
827     const Type& baseType = this->componentType();
828     if (baseType.isInteger()) {
829         // Replace constant expressions with their corresponding values.
830         const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
831         if (valueExpr->supportsConstantValues()) {
832             // Iterate over every constant subexpression in the value.
833             int numSlots = valueExpr->type().slotCount();
834             for (int slot = 0; slot < numSlots; ++slot) {
835                 skstd::optional<double> slotVal = valueExpr->getConstantValue(slot);
836                 // Check for Literal values that are out of range for the base type.
837                 if (slotVal.has_value() &&
838                     baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fLine)) {
839                     foundError = true;
840                 }
841             }
842         }
843     }
844 
845     // We don't need range checks for floats or booleans; any matched-type value is acceptable.
846     return foundError;
847 }
848 
checkForOutOfRangeLiteral(const Context & context,double value,int line) const849 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, int line) const {
850     SkASSERT(this->isScalar());
851     if (this->isInteger()) {
852         if (value < this->minimumValue() || value > this->maximumValue()) {
853             // We found a value that can't fit in the type. Flag it as an error.
854             context.fErrors->error(line, String("integer is out of range for type '") +
855                                          this->displayName().c_str() +
856                                          "': " + to_string((SKSL_INT)value));
857             return true;
858         }
859     }
860     return false;
861 }
862 
convertArraySize(const Context & context,std::unique_ptr<Expression> size) const863 SKSL_INT Type::convertArraySize(const Context& context, std::unique_ptr<Expression> size) const {
864     size = context.fTypes.fInt->coerceExpression(std::move(size), context);
865     if (!size) {
866         return 0;
867     }
868     if (this->isArray()) {
869         context.fErrors->error(size->fLine, "multi-dimensional arrays are not supported");
870         return 0;
871     }
872     if (this->isVoid()) {
873         context.fErrors->error(size->fLine, "type 'void' may not be used in an array");
874         return 0;
875     }
876 #ifdef SKSL_EXT
877     if (this->isOpaque() && this->name() != "sampler2D") {
878 #else
879     if (this->isOpaque()) {
880 #endif
881         context.fErrors->error(size->fLine, "opaque type '" + this->name() +
882                                             "' may not be used in an array");
883         return 0;
884     }
885     SKSL_INT count;
886     if (!ConstantFolder::GetConstantInt(*size, &count)) {
887         context.fErrors->error(size->fLine, "array size must be an integer");
888         return 0;
889     }
890     if (count <= 0) {
891         context.fErrors->error(size->fLine, "array size must be positive");
892         return 0;
893     }
894     if (!SkTFitsIn<int32_t>(count)) {
895         context.fErrors->error(size->fLine, "array size is too large");
896         return 0;
897     }
898     return static_cast<int>(count);
899 }
900 
901 }  // namespace SkSL
902