• 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         // Only allow explicitly-sized arrays.
34         SkASSERT(count > 0);
35         // Disallow multi-dimensional arrays.
36         SkASSERT(!componentType.is<ArrayType>());
37     }
38 
isArray() const39     bool isArray() const override {
40         return true;
41     }
42 
componentType() const43     const Type& componentType() const override {
44         return fComponentType;
45     }
46 
columns() const47     int columns() const override {
48         return fCount;
49     }
50 
bitWidth() const51     int bitWidth() const override {
52         return this->componentType().bitWidth();
53     }
54 
isPrivate() const55     bool isPrivate() const override {
56         return fComponentType.isPrivate();
57     }
58 
isAllowedInES2() const59     bool isAllowedInES2() const override {
60         return fComponentType.isAllowedInES2();
61     }
62 
slotCount() const63     size_t slotCount() const override {
64         SkASSERT(fCount > 0);
65         return fCount * fComponentType.slotCount();
66     }
67 
68 private:
69     using INHERITED = Type;
70 
71     const Type& fComponentType;
72     int fCount;
73 };
74 
75 class GenericType final : public Type {
76 public:
77     inline static constexpr TypeKind kTypeKind = TypeKind::kGeneric;
78 
GenericType(const char * name,std::vector<const Type * > coercibleTypes)79     GenericType(const char* name, std::vector<const Type*> coercibleTypes)
80         : INHERITED(name, "G", kTypeKind)
81         , fCoercibleTypes(std::move(coercibleTypes)) {}
82 
coercibleTypes() const83     const std::vector<const Type*>& coercibleTypes() const override {
84         return fCoercibleTypes;
85     }
86 
87 private:
88     using INHERITED = Type;
89 
90     std::vector<const Type*> fCoercibleTypes;
91 };
92 
93 class LiteralType : public Type {
94 public:
95     inline static constexpr TypeKind kTypeKind = TypeKind::kLiteral;
96 
LiteralType(const char * name,const Type & scalarType,int8_t priority)97     LiteralType(const char* name, const Type& scalarType, int8_t priority)
98         : INHERITED(name, "L", kTypeKind)
99         , fScalarType(scalarType)
100         , fPriority(priority) {}
101 
scalarTypeForLiteral() const102     const Type& scalarTypeForLiteral() const override {
103         return fScalarType;
104     }
105 
priority() const106     int priority() const override {
107         return fPriority;
108     }
109 
columns() const110     int columns() const override {
111         return 1;
112     }
113 
rows() const114     int rows() const override {
115         return 1;
116     }
117 
numberKind() const118     NumberKind numberKind() const override {
119         return fScalarType.numberKind();
120     }
121 
bitWidth() const122     int bitWidth() const override {
123         return fScalarType.bitWidth();
124     }
125 
isScalar() const126     bool isScalar() const override {
127         return true;
128     }
129 
isLiteral() const130     bool isLiteral() const override {
131         return true;
132     }
133 
slotCount() const134     size_t slotCount() const override {
135         return 1;
136     }
137 
138 private:
139     using INHERITED = Type;
140 
141     const Type& fScalarType;
142     int8_t fPriority;
143 };
144 
145 
146 class ScalarType final : public Type {
147 public:
148     inline static constexpr TypeKind kTypeKind = TypeKind::kScalar;
149 
ScalarType(skstd::string_view name,const char * abbrev,NumberKind numberKind,int8_t priority,int8_t bitWidth)150     ScalarType(skstd::string_view name, const char* abbrev, NumberKind numberKind, int8_t priority,
151                int8_t bitWidth)
152         : INHERITED(name, abbrev, kTypeKind)
153         , fNumberKind(numberKind)
154         , fPriority(priority)
155         , fBitWidth(bitWidth) {}
156 
numberKind() const157     NumberKind numberKind() const override {
158         return fNumberKind;
159     }
160 
priority() const161     int priority() const override {
162         return fPriority;
163     }
164 
bitWidth() const165     int bitWidth() const override {
166         return fBitWidth;
167     }
168 
columns() const169     int columns() const override {
170         return 1;
171     }
172 
rows() const173     int rows() const override {
174         return 1;
175     }
176 
isScalar() const177     bool isScalar() const override {
178         return true;
179     }
180 
isAllowedInES2() const181     bool isAllowedInES2() const override {
182         return fNumberKind != NumberKind::kUnsigned;
183     }
184 
slotCount() const185     size_t slotCount() const override {
186         return 1;
187     }
188 
189 private:
190     using INHERITED = Type;
191 
192     NumberKind fNumberKind;
193     int8_t fPriority;
194     int8_t fBitWidth;
195 };
196 
197 class MatrixType final : public Type {
198 public:
199     inline static constexpr TypeKind kTypeKind = TypeKind::kMatrix;
200 
MatrixType(skstd::string_view name,const char * abbrev,const Type & componentType,int8_t columns,int8_t rows)201     MatrixType(skstd::string_view name, const char* abbrev, const Type& componentType,
202                int8_t columns, int8_t rows)
203         : INHERITED(name, abbrev, kTypeKind)
204         , fComponentType(componentType.as<ScalarType>())
205         , fColumns(columns)
206         , fRows(rows) {
207         SkASSERT(columns >= 2 && columns <= 4);
208         SkASSERT(rows >= 2 && rows <= 4);
209     }
210 
componentType() const211     const ScalarType& componentType() const override {
212         return fComponentType;
213     }
214 
columns() const215     int columns() const override {
216         return fColumns;
217     }
218 
rows() const219     int rows() const override {
220         return fRows;
221     }
222 
bitWidth() const223     int bitWidth() const override {
224         return this->componentType().bitWidth();
225     }
226 
isMatrix() const227     bool isMatrix() const override {
228         return true;
229     }
230 
isAllowedInES2() const231     bool isAllowedInES2() const override {
232         return fColumns == fRows;
233     }
234 
slotCount() const235     size_t slotCount() const override {
236         return fColumns * fRows;
237     }
238 
239 private:
240     using INHERITED = Type;
241 
242     const ScalarType& fComponentType;
243     int8_t fColumns;
244     int8_t fRows;
245 };
246 
247 class TextureType final : public Type {
248 public:
249     inline static constexpr TypeKind kTypeKind = TypeKind::kTexture;
250 
TextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayed,bool isMultisampled,bool isSampled)251     TextureType(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed,
252                 bool isMultisampled, bool isSampled)
253         : INHERITED(name, "T", kTypeKind)
254         , fDimensions(dimensions)
255         , fIsDepth(isDepth)
256         , fIsArrayed(isArrayed)
257         , fIsMultisampled(isMultisampled)
258         , fIsSampled(isSampled) {}
259 
dimensions() const260     SpvDim_ dimensions() const override {
261         return fDimensions;
262     }
263 
isDepth() const264     bool isDepth() const override {
265         return fIsDepth;
266     }
267 
isArrayedTexture() const268     bool isArrayedTexture() const override {
269         return fIsArrayed;
270     }
271 
isMultisampled() const272     bool isMultisampled() const override {
273         return fIsMultisampled;
274     }
275 
isSampled() const276     bool isSampled() const override {
277         return fIsSampled;
278     }
279 
280 private:
281     using INHERITED = Type;
282 
283     SpvDim_ fDimensions;
284     bool fIsDepth;
285     bool fIsArrayed;
286     bool fIsMultisampled;
287     bool fIsSampled;
288 };
289 
290 class SamplerType final : public Type {
291 public:
292     inline static constexpr TypeKind kTypeKind = TypeKind::kSampler;
293 
SamplerType(const char * name,const Type & textureType)294     SamplerType(const char* name, const Type& textureType)
295         : INHERITED(name, "Z", kTypeKind)
296         , fTextureType(textureType.as<TextureType>()) {}
297 
textureType() const298     const TextureType& textureType() const override {
299         return fTextureType;
300     }
301 
dimensions() const302     SpvDim_ dimensions() const override {
303         return fTextureType.dimensions();
304     }
305 
isDepth() const306     bool isDepth() const override {
307         return fTextureType.isDepth();
308     }
309 
isArrayedTexture() const310     bool isArrayedTexture() const override {
311         return fTextureType.isArrayedTexture();
312     }
313 
isMultisampled() const314     bool isMultisampled() const override {
315         return fTextureType.isMultisampled();
316     }
317 
isSampled() const318     bool isSampled() const override {
319         return fTextureType.isSampled();
320     }
321 
322 private:
323     using INHERITED = Type;
324 
325     const TextureType& fTextureType;
326 };
327 
328 class StructType final : public Type {
329 public:
330     inline static constexpr TypeKind kTypeKind = TypeKind::kStruct;
331 
StructType(int line,skstd::string_view name,std::vector<Field> fields)332     StructType(int line, skstd::string_view name, std::vector<Field> fields)
333         : INHERITED(std::move(name), "S", kTypeKind, line)
334         , fFields(std::move(fields)) {}
335 
fields() const336     const std::vector<Field>& fields() const override {
337         return fFields;
338     }
339 
isStruct() const340     bool isStruct() const override {
341         return true;
342     }
343 
isPrivate() const344     bool isPrivate() const override {
345         return std::any_of(fFields.begin(), fFields.end(), [](const Field& f) {
346             return f.fType->isPrivate();
347         });
348     }
349 
isAllowedInES2() const350     bool isAllowedInES2() const override {
351         return std::all_of(fFields.begin(), fFields.end(), [](const Field& f) {
352             return f.fType->isAllowedInES2();
353         });
354     }
355 
slotCount() const356     size_t slotCount() const override {
357         size_t slots = 0;
358         for (const Field& field : fFields) {
359             slots += field.fType->slotCount();
360         }
361         return slots;
362     }
363 
364 private:
365     using INHERITED = Type;
366 
367     std::vector<Field> fFields;
368 };
369 
370 class VectorType final : public Type {
371 public:
372     inline static constexpr TypeKind kTypeKind = TypeKind::kVector;
373 
VectorType(skstd::string_view name,const char * abbrev,const Type & componentType,int8_t columns)374     VectorType(skstd::string_view name, const char* abbrev, const Type& componentType,
375                int8_t columns)
376         : INHERITED(name, abbrev, kTypeKind)
377         , fComponentType(componentType.as<ScalarType>())
378         , fColumns(columns) {
379         SkASSERT(columns >= 2 && columns <= 4);
380     }
381 
componentType() const382     const ScalarType& componentType() const override {
383         return fComponentType;
384     }
385 
columns() const386     int columns() const override {
387         return fColumns;
388     }
389 
rows() const390     int rows() const override {
391         return 1;
392     }
393 
bitWidth() const394     int bitWidth() const override {
395         return this->componentType().bitWidth();
396     }
397 
isVector() const398     bool isVector() const override {
399         return true;
400     }
401 
isAllowedInES2() const402     bool isAllowedInES2() const override {
403         return fComponentType.isAllowedInES2();
404     }
405 
slotCount() const406     size_t slotCount() const override {
407         return fColumns;
408     }
409 
410 private:
411     using INHERITED = Type;
412 
413     const ScalarType& fComponentType;
414     int8_t fColumns;
415 };
416 
getArrayName(int arraySize) const417 String Type::getArrayName(int arraySize) const {
418     skstd::string_view name = this->name();
419     return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
420 }
421 
MakeArrayType(skstd::string_view name,const Type & componentType,int columns)422 std::unique_ptr<Type> Type::MakeArrayType(skstd::string_view name, const Type& componentType,
423                                           int columns) {
424     return std::make_unique<ArrayType>(std::move(name), componentType.abbreviatedName(),
425                                        componentType, columns);
426 }
427 
MakeGenericType(const char * name,std::vector<const Type * > types)428 std::unique_ptr<Type> Type::MakeGenericType(const char* name, std::vector<const Type*> types) {
429     return std::make_unique<GenericType>(name, std::move(types));
430 }
431 
MakeLiteralType(const char * name,const Type & scalarType,int8_t priority)432 std::unique_ptr<Type> Type::MakeLiteralType(const char* name, const Type& scalarType,
433                                             int8_t priority) {
434     return std::make_unique<LiteralType>(name, scalarType, priority);
435 }
436 
MakeMatrixType(skstd::string_view name,const char * abbrev,const Type & componentType,int columns,int8_t rows)437 std::unique_ptr<Type> Type::MakeMatrixType(skstd::string_view name, const char* abbrev,
438                                            const Type& componentType, int columns, int8_t rows) {
439     return std::make_unique<MatrixType>(name, abbrev, componentType, columns, rows);
440 }
441 
MakeSamplerType(const char * name,const Type & textureType)442 std::unique_ptr<Type> Type::MakeSamplerType(const char* name, const Type& textureType) {
443     return std::make_unique<SamplerType>(name, textureType);
444 }
445 
MakeSpecialType(const char * name,const char * abbrev,Type::TypeKind typeKind)446 std::unique_ptr<Type> Type::MakeSpecialType(const char* name, const char* abbrev,
447                                             Type::TypeKind typeKind) {
448     return std::unique_ptr<Type>(new Type(name, abbrev, typeKind));
449 }
450 
MakeScalarType(skstd::string_view name,const char * abbrev,Type::NumberKind numberKind,int8_t priority,int8_t bitWidth)451 std::unique_ptr<Type> Type::MakeScalarType(skstd::string_view name, const char* abbrev,
452                                            Type::NumberKind numberKind, int8_t priority,
453                                            int8_t bitWidth) {
454     return std::make_unique<ScalarType>(name, abbrev, numberKind, priority, bitWidth);
455 
456 }
457 
MakeStructType(int line,skstd::string_view name,std::vector<Field> fields)458 std::unique_ptr<Type> Type::MakeStructType(int line, skstd::string_view name,
459                                            std::vector<Field> fields) {
460     return std::make_unique<StructType>(line, name, std::move(fields));
461 }
462 
MakeTextureType(const char * name,SpvDim_ dimensions,bool isDepth,bool isArrayedTexture,bool isMultisampled,bool isSampled)463 std::unique_ptr<Type> Type::MakeTextureType(const char* name, SpvDim_ dimensions, bool isDepth,
464                                             bool isArrayedTexture, bool isMultisampled,
465                                             bool isSampled) {
466     return std::make_unique<TextureType>(name, dimensions, isDepth, isArrayedTexture,
467                                          isMultisampled, isSampled);
468 }
469 
MakeVectorType(skstd::string_view name,const char * abbrev,const Type & componentType,int columns)470 std::unique_ptr<Type> Type::MakeVectorType(skstd::string_view name, const char* abbrev,
471                                            const Type& componentType, int columns) {
472     return std::make_unique<VectorType>(name, abbrev, componentType, columns);
473 }
474 
coercionCost(const Type & other) const475 CoercionCost Type::coercionCost(const Type& other) const {
476     if (*this == other) {
477         return CoercionCost::Free();
478     }
479     if (this->typeKind() == other.typeKind() &&
480         (this->isVector() || this->isMatrix() || this->isArray())) {
481         // Vectors/matrices/arrays of the same size can be coerced if their component type can be.
482         if (this->isMatrix() && (this->rows() != other.rows())) {
483             return CoercionCost::Impossible();
484         }
485         if (this->columns() != other.columns()) {
486             return CoercionCost::Impossible();
487         }
488         return this->componentType().coercionCost(other.componentType());
489     }
490     if (this->isNumber() && other.isNumber()) {
491         if (this->isLiteral() && this->isInteger()) {
492             return CoercionCost::Free();
493         } else if (this->numberKind() != other.numberKind()) {
494             return CoercionCost::Impossible();
495         } else if (other.priority() >= this->priority()) {
496             return CoercionCost::Normal(other.priority() - this->priority());
497         } else {
498             return CoercionCost::Narrowing(this->priority() - other.priority());
499         }
500     }
501     if (fTypeKind == TypeKind::kGeneric) {
502         const std::vector<const Type*>& types = this->coercibleTypes();
503         for (size_t i = 0; i < types.size(); i++) {
504             if (*types[i] == other) {
505                 return CoercionCost::Normal((int) i + 1);
506             }
507         }
508     }
509     return CoercionCost::Impossible();
510 }
511 
applyPrecisionQualifiers(const Context & context,Modifiers * modifiers,SymbolTable * symbols,int line) const512 const Type* Type::applyPrecisionQualifiers(const Context& context,
513                                            Modifiers* modifiers,
514                                            SymbolTable* symbols,
515                                            int line) const {
516     // SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
517     bool highp   = modifiers->fFlags & Modifiers::kHighp_Flag;
518     bool mediump = modifiers->fFlags & Modifiers::kMediump_Flag;
519     bool lowp    = modifiers->fFlags & Modifiers::kLowp_Flag;
520 
521     if (!lowp && !mediump && !highp) {
522         // No precision qualifiers here. Return the type as-is.
523         return this;
524     }
525 
526     if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
527         // We want to discourage precision modifiers internally. Instead, use the type that
528         // corresponds to the precision you need. (e.g. half vs float, short vs int)
529         context.fErrors->error(line, "precision qualifiers are not allowed");
530         return nullptr;
531     }
532 
533     if ((int(lowp) + int(mediump) + int(highp)) != 1) {
534         context.fErrors->error(line, "only one precision qualifier can be used");
535         return nullptr;
536     }
537 
538     // We're going to return a whole new type, so the modifier bits can be cleared out.
539     modifiers->fFlags &= ~(Modifiers::kHighp_Flag |
540                            Modifiers::kMediump_Flag |
541                            Modifiers::kLowp_Flag);
542 
543     const Type& component = this->componentType();
544     if (component.highPrecision()) {
545         if (highp) {
546             // Type is already high precision, and we are requesting high precision. Return as-is.
547             return this;
548         }
549 
550         // Ascertain the mediump equivalent type for this type, if any.
551         const Type* mediumpType;
552         switch (component.numberKind()) {
553             case Type::NumberKind::kFloat:
554                 mediumpType = context.fTypes.fHalf.get();
555                 break;
556 
557             case Type::NumberKind::kSigned:
558                 mediumpType = context.fTypes.fShort.get();
559                 break;
560 
561             case Type::NumberKind::kUnsigned:
562                 mediumpType = context.fTypes.fUShort.get();
563                 break;
564 
565             default:
566                 mediumpType = nullptr;
567                 break;
568         }
569 
570         if (mediumpType) {
571             // Convert the mediump component type into the final vector/matrix/array type as needed.
572             return this->isArray()
573                            ? symbols->addArrayDimension(mediumpType, this->columns())
574                            : &mediumpType->toCompound(context, this->columns(), this->rows());
575         }
576     }
577 
578     context.fErrors->error(line, "type '" + this->displayName() +
579                                  "' does not support precision qualifiers");
580     return nullptr;
581 }
582 
toCompound(const Context & context,int columns,int rows) const583 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
584     SkASSERT(this->isScalar());
585     if (columns == 1 && rows == 1) {
586         return *this;
587     }
588     if (*this == *context.fTypes.fFloat || *this == *context.fTypes.fFloatLiteral) {
589         switch (rows) {
590             case 1:
591                 switch (columns) {
592                     case 1: return *context.fTypes.fFloat;
593                     case 2: return *context.fTypes.fFloat2;
594                     case 3: return *context.fTypes.fFloat3;
595                     case 4: return *context.fTypes.fFloat4;
596                     default: SK_ABORT("unsupported vector column count (%d)", columns);
597                 }
598             case 2:
599                 switch (columns) {
600                     case 2: return *context.fTypes.fFloat2x2;
601                     case 3: return *context.fTypes.fFloat3x2;
602                     case 4: return *context.fTypes.fFloat4x2;
603                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
604                 }
605             case 3:
606                 switch (columns) {
607                     case 2: return *context.fTypes.fFloat2x3;
608                     case 3: return *context.fTypes.fFloat3x3;
609                     case 4: return *context.fTypes.fFloat4x3;
610                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
611                 }
612             case 4:
613                 switch (columns) {
614                     case 2: return *context.fTypes.fFloat2x4;
615                     case 3: return *context.fTypes.fFloat3x4;
616                     case 4: return *context.fTypes.fFloat4x4;
617                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
618                 }
619             default: SK_ABORT("unsupported row count (%d)", rows);
620         }
621     } else if (*this == *context.fTypes.fHalf) {
622         switch (rows) {
623             case 1:
624                 switch (columns) {
625                     case 1: return *context.fTypes.fHalf;
626                     case 2: return *context.fTypes.fHalf2;
627                     case 3: return *context.fTypes.fHalf3;
628                     case 4: return *context.fTypes.fHalf4;
629                     default: SK_ABORT("unsupported vector column count (%d)", columns);
630                 }
631             case 2:
632                 switch (columns) {
633                     case 2: return *context.fTypes.fHalf2x2;
634                     case 3: return *context.fTypes.fHalf3x2;
635                     case 4: return *context.fTypes.fHalf4x2;
636                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
637                 }
638             case 3:
639                 switch (columns) {
640                     case 2: return *context.fTypes.fHalf2x3;
641                     case 3: return *context.fTypes.fHalf3x3;
642                     case 4: return *context.fTypes.fHalf4x3;
643                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
644                 }
645             case 4:
646                 switch (columns) {
647                     case 2: return *context.fTypes.fHalf2x4;
648                     case 3: return *context.fTypes.fHalf3x4;
649                     case 4: return *context.fTypes.fHalf4x4;
650                     default: SK_ABORT("unsupported matrix column count (%d)", columns);
651                 }
652             default: SK_ABORT("unsupported row count (%d)", rows);
653         }
654     } else if (*this == *context.fTypes.fInt || *this == *context.fTypes.fIntLiteral) {
655         switch (rows) {
656             case 1:
657                 switch (columns) {
658                     case 1: return *context.fTypes.fInt;
659                     case 2: return *context.fTypes.fInt2;
660                     case 3: return *context.fTypes.fInt3;
661                     case 4: return *context.fTypes.fInt4;
662                     default: SK_ABORT("unsupported vector column count (%d)", columns);
663                 }
664             default: SK_ABORT("unsupported row count (%d)", rows);
665         }
666     } else if (*this == *context.fTypes.fShort) {
667         switch (rows) {
668             case 1:
669                 switch (columns) {
670                     case 1: return *context.fTypes.fShort;
671                     case 2: return *context.fTypes.fShort2;
672                     case 3: return *context.fTypes.fShort3;
673                     case 4: return *context.fTypes.fShort4;
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.fUInt) {
679         switch (rows) {
680             case 1:
681                 switch (columns) {
682                     case 1: return *context.fTypes.fUInt;
683                     case 2: return *context.fTypes.fUInt2;
684                     case 3: return *context.fTypes.fUInt3;
685                     case 4: return *context.fTypes.fUInt4;
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.fUShort) {
691         switch (rows) {
692             case 1:
693                 switch (columns) {
694                     case 1: return *context.fTypes.fUShort;
695                     case 2: return *context.fTypes.fUShort2;
696                     case 3: return *context.fTypes.fUShort3;
697                     case 4: return *context.fTypes.fUShort4;
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.fBool) {
703         switch (rows) {
704             case 1:
705                 switch (columns) {
706                     case 1: return *context.fTypes.fBool;
707                     case 2: return *context.fTypes.fBool2;
708                     case 3: return *context.fTypes.fBool3;
709                     case 4: return *context.fTypes.fBool4;
710                     default: SK_ABORT("unsupported vector column count (%d)", columns);
711                 }
712             default: SK_ABORT("unsupported row count (%d)", rows);
713         }
714     }
715     SkDEBUGFAILF("unsupported toCompound type %s", this->description().c_str());
716     return *context.fTypes.fVoid;
717 }
718 
clone(SymbolTable * symbolTable) const719 const Type* Type::clone(SymbolTable* symbolTable) const {
720     // Many types are built-ins, and exist in every SymbolTable by default.
721     if (this->isInBuiltinTypes()) {
722         return this;
723     }
724     // Even if the type isn't a built-in, it might already exist in the SymbolTable.
725     const Symbol* clonedSymbol = (*symbolTable)[this->name()];
726     if (clonedSymbol != nullptr) {
727         const Type& clonedType = clonedSymbol->as<Type>();
728         SkASSERT(clonedType.typeKind() == this->typeKind());
729         return &clonedType;
730     }
731     // This type actually needs to be cloned into the destination SymbolTable.
732     switch (this->typeKind()) {
733         case TypeKind::kArray: {
734             return symbolTable->addArrayDimension(&this->componentType(), this->columns());
735         }
736         case TypeKind::kStruct: {
737             const String* name = symbolTable->takeOwnershipOfString(String(this->name()));
738             return symbolTable->add(Type::MakeStructType(this->fLine, *name, this->fields()));
739         }
740         default:
741             SkDEBUGFAILF("don't know how to clone type '%s'", this->description().c_str());
742             return nullptr;
743     }
744 }
745 
coerceExpression(std::unique_ptr<Expression> expr,const Context & context) const746 std::unique_ptr<Expression> Type::coerceExpression(std::unique_ptr<Expression> expr,
747                                                    const Context& context) const {
748     if (!expr || expr->isIncomplete(context)) {
749         return nullptr;
750     }
751     if (expr->type() == *this) {
752         return expr;
753     }
754 
755     const int line = expr->fLine;
756     const Program::Settings& settings = context.fConfig->fSettings;
757     if (!expr->coercionCost(*this).isPossible(settings.fAllowNarrowingConversions)) {
758         context.fErrors->error(line, "expected '" + this->displayName() + "', but found '" +
759                                      expr->type().displayName() + "'");
760         return nullptr;
761     }
762 
763     if (this->isScalar()) {
764         return ConstructorScalarCast::Make(context, line, *this, std::move(expr));
765     }
766     if (this->isVector() || this->isMatrix()) {
767         return ConstructorCompoundCast::Make(context, line, *this, std::move(expr));
768     }
769     if (this->isArray()) {
770         return ConstructorArrayCast::Make(context, line, *this, std::move(expr));
771     }
772     context.fErrors->error(line, "cannot construct '" + this->displayName() + "'");
773     return nullptr;
774 }
775 
isOrContainsArray() const776 bool Type::isOrContainsArray() const {
777     if (this->isStruct()) {
778         for (const Field& f : this->fields()) {
779             if (f.fType->isOrContainsArray()) {
780                 return true;
781             }
782         }
783         return false;
784     }
785 
786     return this->isArray();
787 }
788 
isTooDeeplyNested(int limit) const789 bool Type::isTooDeeplyNested(int limit) const {
790     if (limit < 0) {
791         return true;
792     }
793 
794     if (this->isStruct()) {
795         for (const Type::Field& f : this->fields()) {
796             if (f.fType->isTooDeeplyNested(limit - 1)) {
797                 return true;
798             }
799         }
800     }
801 
802     return false;
803 }
804 
isTooDeeplyNested() const805 bool Type::isTooDeeplyNested() const {
806     return this->isTooDeeplyNested(kMaxStructDepth);
807 }
808 
isAllowedInES2(const Context & context) const809 bool Type::isAllowedInES2(const Context& context) const {
810     return !context.fConfig->strictES2Mode() || this->isAllowedInES2();
811 }
812 
checkForOutOfRangeLiteral(const Context & context,const Expression & expr) const813 bool Type::checkForOutOfRangeLiteral(const Context& context, const Expression& expr) const {
814     bool foundError = false;
815     const Type& baseType = this->componentType();
816     if (baseType.isInteger()) {
817         // Replace constant expressions with their corresponding values.
818         const Expression* valueExpr = ConstantFolder::GetConstantValueForVariable(expr);
819         if (valueExpr->supportsConstantValues()) {
820             // Iterate over every constant subexpression in the value.
821             int numSlots = valueExpr->type().slotCount();
822             for (int slot = 0; slot < numSlots; ++slot) {
823                 skstd::optional<double> slotVal = valueExpr->getConstantValue(slot);
824                 // Check for Literal values that are out of range for the base type.
825                 if (slotVal.has_value() &&
826                     baseType.checkForOutOfRangeLiteral(context, *slotVal, valueExpr->fLine)) {
827                     foundError = true;
828                 }
829             }
830         }
831     }
832 
833     // We don't need range checks for floats or booleans; any matched-type value is acceptable.
834     return foundError;
835 }
836 
checkForOutOfRangeLiteral(const Context & context,double value,int line) const837 bool Type::checkForOutOfRangeLiteral(const Context& context, double value, int line) const {
838     SkASSERT(this->isScalar());
839     if (this->isInteger()) {
840         if (value < this->minimumValue() || value > this->maximumValue()) {
841             // We found a value that can't fit in the type. Flag it as an error.
842             context.fErrors->error(line, String("integer is out of range for type '") +
843                                          this->displayName().c_str() +
844                                          "': " + to_string((SKSL_INT)value));
845             return true;
846         }
847     }
848     return false;
849 }
850 
convertArraySize(const Context & context,std::unique_ptr<Expression> size) const851 SKSL_INT Type::convertArraySize(const Context& context, std::unique_ptr<Expression> size) const {
852     size = context.fTypes.fInt->coerceExpression(std::move(size), context);
853     if (!size) {
854         return 0;
855     }
856     if (this->isArray()) {
857         context.fErrors->error(size->fLine, "multi-dimensional arrays are not supported");
858         return 0;
859     }
860     if (this->isVoid()) {
861         context.fErrors->error(size->fLine, "type 'void' may not be used in an array");
862         return 0;
863     }
864     if (this->isOpaque()) {
865         context.fErrors->error(size->fLine, "opaque type '" + this->name() +
866                                             "' may not be used in an array");
867         return 0;
868     }
869     SKSL_INT count;
870     if (!ConstantFolder::GetConstantInt(*size, &count)) {
871         context.fErrors->error(size->fLine, "array size must be an integer");
872         return 0;
873     }
874     if (count <= 0) {
875         context.fErrors->error(size->fLine, "array size must be positive");
876         return 0;
877     }
878     if (!SkTFitsIn<int32_t>(count)) {
879         context.fErrors->error(size->fLine, "array size is too large");
880         return 0;
881     }
882     return static_cast<int>(count);
883 }
884 
885 }  // namespace SkSL
886