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