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 "src/sksl/ir/SkSLConstructorStruct.h"
9
10 #include "include/core/SkSpan.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/base/SkTArray.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/sksl/SkSLContext.h"
15 #include "src/sksl/SkSLErrorReporter.h"
16 #include "src/sksl/SkSLString.h"
17 #include "src/sksl/ir/SkSLType.h"
18
19 #include <string>
20
21 namespace SkSL {
22
Convert(const Context & context,Position pos,const Type & type,ExpressionArray args)23 std::unique_ptr<Expression> ConstructorStruct::Convert(const Context& context,
24 Position pos,
25 const Type& type,
26 ExpressionArray args) {
27 SkASSERTF(type.isStruct() && type.fields().size() > 0, "%s", type.description().c_str());
28
29 // Check that the number of constructor arguments matches the array size.
30 if (type.fields().size() != SkToSizeT(args.size())) {
31 context.fErrors->error(pos,
32 String::printf("invalid arguments to '%s' constructor "
33 "(expected %zu elements, but found %d)",
34 type.displayName().c_str(), type.fields().size(),
35 args.size()));
36 return nullptr;
37 }
38
39 // A struct with atomic members cannot be constructed.
40 if (type.isOrContainsAtomic()) {
41 context.fErrors->error(
42 pos,
43 String::printf("construction of struct type '%s' with atomic member is not allowed",
44 type.displayName().c_str()));
45 return nullptr;
46 }
47
48 // Convert each constructor argument to the struct's field type.
49 for (int index=0; index<args.size(); ++index) {
50 std::unique_ptr<Expression>& argument = args[index];
51 const Field& field = type.fields()[index];
52
53 argument = field.fType->coerceExpression(std::move(argument), context);
54 if (!argument) {
55 return nullptr;
56 }
57 }
58
59 return ConstructorStruct::Make(context, pos, type, std::move(args));
60 }
61
arguments_match_field_types(const ExpressionArray & args,const Type & type)62 [[maybe_unused]] static bool arguments_match_field_types(const ExpressionArray& args,
63 const Type& type) {
64 SkASSERT(type.fields().size() == SkToSizeT(args.size()));
65
66 for (int index = 0; index < args.size(); ++index) {
67 const std::unique_ptr<Expression>& argument = args[index];
68 const Field& field = type.fields()[index];
69 if (!argument->type().matches(*field.fType)) {
70 return false;
71 }
72 }
73
74 return true;
75 }
76
Make(const Context & context,Position pos,const Type & type,ExpressionArray args)77 std::unique_ptr<Expression> ConstructorStruct::Make(const Context& context,
78 Position pos,
79 const Type& type,
80 ExpressionArray args) {
81 SkASSERT(type.isAllowedInES2(context));
82 SkASSERT(arguments_match_field_types(args, type));
83 SkASSERT(!type.isOrContainsAtomic());
84 return std::make_unique<ConstructorStruct>(pos, type, std::move(args));
85 }
86
87 } // namespace SkSL
88