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