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