1 /*
2 * Copyright 2021 Google LLC
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 "include/sksl/SkSLErrorReporter.h"
9 #include "src/sksl/SkSLProgramSettings.h"
10 #include "src/sksl/ir/SkSLConstructorArray.h"
11 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
12
13 namespace SkSL {
14
Convert(const Context & context,int line,const Type & type,ExpressionArray args)15 std::unique_ptr<Expression> ConstructorArray::Convert(const Context& context,
16 int line,
17 const Type& type,
18 ExpressionArray args) {
19 SkASSERTF(type.isArray() && type.columns() > 0, "%s", type.description().c_str());
20
21 // ES2 doesn't support first-class array types.
22 if (context.fConfig->strictES2Mode()) {
23 context.fErrors->error(line, "construction of array type '" + type.displayName() +
24 "' is not supported");
25 return nullptr;
26 }
27
28 // If there is a single argument containing an array of matching size and the types are
29 // coercible, this is actually a cast. i.e., `half[10](myFloat10Array)`. This isn't a GLSL
30 // feature, but the Pipeline stage code generator needs this functionality so that code which
31 // was originally compiled with "allow narrowing conversions" enabled can be later recompiled
32 // without narrowing conversions (we patch over these conversions with an explicit cast).
33 if (args.size() == 1) {
34 const Expression& expr = *args.front();
35 const Type& exprType = expr.type();
36
37 if (exprType.isArray() && exprType.canCoerceTo(type, /*allowNarrowing=*/true)) {
38 return ConstructorArrayCast::Make(context, line, type, std::move(args.front()));
39 }
40 }
41
42 // Check that the number of constructor arguments matches the array size.
43 if (type.columns() != args.count()) {
44 context.fErrors->error(line, String::printf("invalid arguments to '%s' constructor "
45 "(expected %d elements, but found %d)",
46 type.displayName().c_str(), type.columns(),
47 args.count()));
48 return nullptr;
49 }
50
51 // Convert each constructor argument to the array's component type.
52 const Type& baseType = type.componentType();
53 for (std::unique_ptr<Expression>& argument : args) {
54 argument = baseType.coerceExpression(std::move(argument), context);
55 if (!argument) {
56 return nullptr;
57 }
58 }
59
60 return ConstructorArray::Make(context, line, type, std::move(args));
61 }
62
Make(const Context & context,int line,const Type & type,ExpressionArray args)63 std::unique_ptr<Expression> ConstructorArray::Make(const Context& context,
64 int line,
65 const Type& type,
66 ExpressionArray args) {
67 SkASSERT(!context.fConfig->strictES2Mode());
68 SkASSERT(type.isAllowedInES2(context));
69 SkASSERT(type.columns() == args.count());
70 SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) {
71 return type.componentType() == arg->type();
72 }));
73
74 return std::make_unique<ConstructorArray>(line, type, std::move(args));
75 }
76
77 } // namespace SkSL
78