xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLConstructorStruct.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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