1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionDeclaration.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h"
11cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLUnresolvedFunction.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_cinamespace SkSL {
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cistatic IntrinsicKind identify_intrinsic(skstd::string_view functionName) {
16cb93a386Sopenharmony_ci    #define SKSL_INTRINSIC(name) {#name, k_##name##_IntrinsicKind},
17cb93a386Sopenharmony_ci    static const auto* kAllIntrinsics = new std::unordered_map<skstd::string_view, IntrinsicKind>{
18cb93a386Sopenharmony_ci        SKSL_INTRINSIC_LIST
19cb93a386Sopenharmony_ci    };
20cb93a386Sopenharmony_ci    #undef SKSL_INTRINSIC
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci    if (functionName.starts_with('$')) {
23cb93a386Sopenharmony_ci        functionName.remove_prefix(1);
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    auto iter = kAllIntrinsics->find(functionName);
27cb93a386Sopenharmony_ci    if (iter != kAllIntrinsics->end()) {
28cb93a386Sopenharmony_ci        return iter->second;
29cb93a386Sopenharmony_ci    }
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci    return kNotIntrinsic;
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cistatic bool check_modifiers(const Context& context,
35cb93a386Sopenharmony_ci                            int line,
36cb93a386Sopenharmony_ci                            const Modifiers& modifiers) {
37cb93a386Sopenharmony_ci    const int permitted = Modifiers::kHasSideEffects_Flag |
38cb93a386Sopenharmony_ci                          Modifiers::kInline_Flag |
39cb93a386Sopenharmony_ci                          Modifiers::kNoInline_Flag |
40cb93a386Sopenharmony_ci                          (context.fConfig->fIsBuiltinCode ? Modifiers::kES3_Flag : 0);
41cb93a386Sopenharmony_ci    modifiers.checkPermitted(context, line, permitted, /*permittedLayoutFlags=*/0);
42cb93a386Sopenharmony_ci    if ((modifiers.fFlags & Modifiers::kInline_Flag) &&
43cb93a386Sopenharmony_ci        (modifiers.fFlags & Modifiers::kNoInline_Flag)) {
44cb93a386Sopenharmony_ci        context.fErrors->error(line, "functions cannot be both 'inline' and 'noinline'");
45cb93a386Sopenharmony_ci        return false;
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci    return true;
48cb93a386Sopenharmony_ci}
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_cistatic bool check_return_type(const Context& context, int line, const Type& returnType) {
51cb93a386Sopenharmony_ci    ErrorReporter& errors = *context.fErrors;
52cb93a386Sopenharmony_ci    if (returnType.isArray()) {
53cb93a386Sopenharmony_ci        errors.error(line, "functions may not return type '" + returnType.displayName() + "'");
54cb93a386Sopenharmony_ci        return false;
55cb93a386Sopenharmony_ci    }
56cb93a386Sopenharmony_ci    if (context.fConfig->strictES2Mode() && returnType.isOrContainsArray()) {
57cb93a386Sopenharmony_ci        errors.error(line, "functions may not return structs containing arrays");
58cb93a386Sopenharmony_ci        return false;
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci    if (!context.fConfig->fIsBuiltinCode && !returnType.isVoid() &&
61cb93a386Sopenharmony_ci        returnType.componentType().isOpaque()) {
62cb93a386Sopenharmony_ci        errors.error(line, "functions may not return opaque type '" + returnType.displayName() +
63cb93a386Sopenharmony_ci                           "'");
64cb93a386Sopenharmony_ci        return false;
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    return true;
67cb93a386Sopenharmony_ci}
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_cistatic bool check_parameters(const Context& context,
70cb93a386Sopenharmony_ci                             std::vector<std::unique_ptr<Variable>>& parameters,
71cb93a386Sopenharmony_ci                             bool isMain) {
72cb93a386Sopenharmony_ci    auto typeIsValidForColor = [&](const Type& type) {
73cb93a386Sopenharmony_ci        return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
74cb93a386Sopenharmony_ci    };
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    // The first color parameter passed to main() is the input color; the second is the dest color.
77cb93a386Sopenharmony_ci    static constexpr int kBuiltinColorIDs[] = {SK_INPUT_COLOR_BUILTIN, SK_DEST_COLOR_BUILTIN};
78cb93a386Sopenharmony_ci    unsigned int builtinColorIndex = 0;
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci    // Check modifiers on each function parameter.
81cb93a386Sopenharmony_ci    for (auto& param : parameters) {
82cb93a386Sopenharmony_ci        param->modifiers().checkPermitted(context, param->fLine,
83cb93a386Sopenharmony_ci                Modifiers::kConst_Flag | Modifiers::kIn_Flag | Modifiers::kOut_Flag,
84cb93a386Sopenharmony_ci                /*permittedLayoutFlags=*/0);
85cb93a386Sopenharmony_ci        const Type& type = param->type();
86cb93a386Sopenharmony_ci        // Only the (builtin) declarations of 'sample' are allowed to have shader/colorFilter or FP
87cb93a386Sopenharmony_ci        // parameters. You can pass other opaque types to functions safely; this restriction is
88cb93a386Sopenharmony_ci        // specific to "child" objects.
89cb93a386Sopenharmony_ci        if (type.isEffectChild() && !context.fConfig->fIsBuiltinCode) {
90cb93a386Sopenharmony_ci            context.fErrors->error(param->fLine, "parameters of type '" + type.displayName() +
91cb93a386Sopenharmony_ci                                                 "' not allowed");
92cb93a386Sopenharmony_ci            return false;
93cb93a386Sopenharmony_ci        }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci        Modifiers m = param->modifiers();
96cb93a386Sopenharmony_ci        bool modifiersChanged = false;
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci        // The `in` modifier on function parameters is implicit, so we can replace `in float x` with
99cb93a386Sopenharmony_ci        // `float x`. This prevents any ambiguity when matching a function by its param types.
100cb93a386Sopenharmony_ci        if (Modifiers::kIn_Flag == (m.fFlags & (Modifiers::kOut_Flag | Modifiers::kIn_Flag))) {
101cb93a386Sopenharmony_ci            m.fFlags &= ~(Modifiers::kOut_Flag | Modifiers::kIn_Flag);
102cb93a386Sopenharmony_ci            modifiersChanged = true;
103cb93a386Sopenharmony_ci        }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci        if (isMain) {
106cb93a386Sopenharmony_ci            if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
107cb93a386Sopenharmony_ci                // We verify that the signature is fully correct later. For now, if this is a
108cb93a386Sopenharmony_ci                // runtime effect of any flavor, a float2 param is supposed to be the coords, and a
109cb93a386Sopenharmony_ci                // half4/float parameter is supposed to be the input or destination color:
110cb93a386Sopenharmony_ci                if (type == *context.fTypes.fFloat2) {
111cb93a386Sopenharmony_ci                    m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
112cb93a386Sopenharmony_ci                    modifiersChanged = true;
113cb93a386Sopenharmony_ci                } else if (typeIsValidForColor(type) &&
114cb93a386Sopenharmony_ci                           builtinColorIndex < SK_ARRAY_COUNT(kBuiltinColorIDs)) {
115cb93a386Sopenharmony_ci                    m.fLayout.fBuiltin = kBuiltinColorIDs[builtinColorIndex++];
116cb93a386Sopenharmony_ci                    modifiersChanged = true;
117cb93a386Sopenharmony_ci                }
118cb93a386Sopenharmony_ci            } else if (context.fConfig->fKind == ProgramKind::kFragment) {
119cb93a386Sopenharmony_ci                // For testing purposes, we have .sksl inputs that are treated as both runtime
120cb93a386Sopenharmony_ci                // effects and fragment shaders. To make that work, fragment shaders are allowed to
121cb93a386Sopenharmony_ci                // have a coords parameter.
122cb93a386Sopenharmony_ci                if (type == *context.fTypes.fFloat2) {
123cb93a386Sopenharmony_ci                    m.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
124cb93a386Sopenharmony_ci                    modifiersChanged = true;
125cb93a386Sopenharmony_ci                }
126cb93a386Sopenharmony_ci            }
127cb93a386Sopenharmony_ci        }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci        if (modifiersChanged) {
130cb93a386Sopenharmony_ci            param->setModifiers(context.fModifiersPool->add(m));
131cb93a386Sopenharmony_ci        }
132cb93a386Sopenharmony_ci    }
133cb93a386Sopenharmony_ci    return true;
134cb93a386Sopenharmony_ci}
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_cistatic bool check_main_signature(const Context& context, int line, const Type& returnType,
137cb93a386Sopenharmony_ci                                 std::vector<std::unique_ptr<Variable>>& parameters) {
138cb93a386Sopenharmony_ci    ErrorReporter& errors = *context.fErrors;
139cb93a386Sopenharmony_ci    ProgramKind kind = context.fConfig->fKind;
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    auto typeIsValidForColor = [&](const Type& type) {
142cb93a386Sopenharmony_ci        return type == *context.fTypes.fHalf4 || type == *context.fTypes.fFloat4;
143cb93a386Sopenharmony_ci    };
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    auto paramIsCoords = [&](int idx) {
146cb93a386Sopenharmony_ci        const Variable& p = *parameters[idx];
147cb93a386Sopenharmony_ci        return p.type() == *context.fTypes.fFloat2 &&
148cb93a386Sopenharmony_ci               p.modifiers().fFlags == 0 &&
149cb93a386Sopenharmony_ci               p.modifiers().fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN;
150cb93a386Sopenharmony_ci    };
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci    auto paramIsBuiltinColor = [&](int idx, int builtinID) {
153cb93a386Sopenharmony_ci        const Variable& p = *parameters[idx];
154cb93a386Sopenharmony_ci        return typeIsValidForColor(p.type()) &&
155cb93a386Sopenharmony_ci               p.modifiers().fFlags == 0 &&
156cb93a386Sopenharmony_ci               p.modifiers().fLayout.fBuiltin == builtinID;
157cb93a386Sopenharmony_ci    };
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    auto paramIsInputColor = [&](int n) { return paramIsBuiltinColor(n, SK_INPUT_COLOR_BUILTIN); };
160cb93a386Sopenharmony_ci    auto paramIsDestColor  = [&](int n) { return paramIsBuiltinColor(n, SK_DEST_COLOR_BUILTIN); };
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci    switch (kind) {
163cb93a386Sopenharmony_ci        case ProgramKind::kRuntimeColorFilter: {
164cb93a386Sopenharmony_ci            // (half4|float4) main(half4|float4)
165cb93a386Sopenharmony_ci            if (!typeIsValidForColor(returnType)) {
166cb93a386Sopenharmony_ci                errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
167cb93a386Sopenharmony_ci                return false;
168cb93a386Sopenharmony_ci            }
169cb93a386Sopenharmony_ci            bool validParams = (parameters.size() == 1 && paramIsInputColor(0));
170cb93a386Sopenharmony_ci            if (!validParams) {
171cb93a386Sopenharmony_ci                errors.error(line, "'main' parameter must be 'vec4', 'float4', or 'half4'");
172cb93a386Sopenharmony_ci                return false;
173cb93a386Sopenharmony_ci            }
174cb93a386Sopenharmony_ci            break;
175cb93a386Sopenharmony_ci        }
176cb93a386Sopenharmony_ci        case ProgramKind::kRuntimeShader: {
177cb93a386Sopenharmony_ci            // (half4|float4) main(float2)  -or-  (half4|float4) main(float2, half4|float4)
178cb93a386Sopenharmony_ci            if (!typeIsValidForColor(returnType)) {
179cb93a386Sopenharmony_ci                errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
180cb93a386Sopenharmony_ci                return false;
181cb93a386Sopenharmony_ci            }
182cb93a386Sopenharmony_ci            bool validParams =
183cb93a386Sopenharmony_ci                    (parameters.size() == 1 && paramIsCoords(0)) ||
184cb93a386Sopenharmony_ci                    (parameters.size() == 2 && paramIsCoords(0) && paramIsInputColor(1));
185cb93a386Sopenharmony_ci            if (!validParams) {
186cb93a386Sopenharmony_ci                errors.error(line, "'main' parameters must be (float2, (vec4|float4|half4)?)");
187cb93a386Sopenharmony_ci                return false;
188cb93a386Sopenharmony_ci            }
189cb93a386Sopenharmony_ci            break;
190cb93a386Sopenharmony_ci        }
191cb93a386Sopenharmony_ci        case ProgramKind::kRuntimeBlender: {
192cb93a386Sopenharmony_ci            // (half4|float4) main(half4|float4, half4|float4)
193cb93a386Sopenharmony_ci            if (!typeIsValidForColor(returnType)) {
194cb93a386Sopenharmony_ci                errors.error(line, "'main' must return: 'vec4', 'float4', or 'half4'");
195cb93a386Sopenharmony_ci                return false;
196cb93a386Sopenharmony_ci            }
197cb93a386Sopenharmony_ci            if (!(parameters.size() == 2 &&
198cb93a386Sopenharmony_ci                  paramIsInputColor(0) &&
199cb93a386Sopenharmony_ci                  paramIsDestColor(1))) {
200cb93a386Sopenharmony_ci                errors.error(line, "'main' parameters must be (vec4|float4|half4, "
201cb93a386Sopenharmony_ci                                                                "vec4|float4|half4)");
202cb93a386Sopenharmony_ci                return false;
203cb93a386Sopenharmony_ci            }
204cb93a386Sopenharmony_ci            break;
205cb93a386Sopenharmony_ci        }
206cb93a386Sopenharmony_ci        case ProgramKind::kGeneric:
207cb93a386Sopenharmony_ci            // No rules apply here
208cb93a386Sopenharmony_ci            break;
209cb93a386Sopenharmony_ci        case ProgramKind::kFragment: {
210cb93a386Sopenharmony_ci            bool validParams = (parameters.size() == 0) ||
211cb93a386Sopenharmony_ci                               (parameters.size() == 1 && paramIsCoords(0));
212cb93a386Sopenharmony_ci            if (!validParams) {
213cb93a386Sopenharmony_ci                errors.error(line, "shader 'main' must be main() or main(float2)");
214cb93a386Sopenharmony_ci                return false;
215cb93a386Sopenharmony_ci            }
216cb93a386Sopenharmony_ci            break;
217cb93a386Sopenharmony_ci        }
218cb93a386Sopenharmony_ci        case ProgramKind::kVertex:
219cb93a386Sopenharmony_ci            if (parameters.size()) {
220cb93a386Sopenharmony_ci                errors.error(line, "shader 'main' must have zero parameters");
221cb93a386Sopenharmony_ci                return false;
222cb93a386Sopenharmony_ci            }
223cb93a386Sopenharmony_ci            break;
224cb93a386Sopenharmony_ci    }
225cb93a386Sopenharmony_ci    return true;
226cb93a386Sopenharmony_ci}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci/**
229cb93a386Sopenharmony_ci * Checks for a previously existing declaration of this function, reporting errors if there is an
230cb93a386Sopenharmony_ci * incompatible symbol. Returns true and sets outExistingDecl to point to the existing declaration
231cb93a386Sopenharmony_ci * (or null if none) on success, returns false on error.
232cb93a386Sopenharmony_ci */
233cb93a386Sopenharmony_cistatic bool find_existing_declaration(const Context& context,
234cb93a386Sopenharmony_ci                                      SymbolTable& symbols,
235cb93a386Sopenharmony_ci                                      int line,
236cb93a386Sopenharmony_ci                                      skstd::string_view name,
237cb93a386Sopenharmony_ci                                      std::vector<std::unique_ptr<Variable>>& parameters,
238cb93a386Sopenharmony_ci                                      const Type* returnType,
239cb93a386Sopenharmony_ci                                      const FunctionDeclaration** outExistingDecl) {
240cb93a386Sopenharmony_ci    ErrorReporter& errors = *context.fErrors;
241cb93a386Sopenharmony_ci    const Symbol* entry = symbols[name];
242cb93a386Sopenharmony_ci    *outExistingDecl = nullptr;
243cb93a386Sopenharmony_ci    if (entry) {
244cb93a386Sopenharmony_ci        std::vector<const FunctionDeclaration*> functions;
245cb93a386Sopenharmony_ci        switch (entry->kind()) {
246cb93a386Sopenharmony_ci            case Symbol::Kind::kUnresolvedFunction:
247cb93a386Sopenharmony_ci                functions = entry->as<UnresolvedFunction>().functions();
248cb93a386Sopenharmony_ci                break;
249cb93a386Sopenharmony_ci            case Symbol::Kind::kFunctionDeclaration:
250cb93a386Sopenharmony_ci                functions.push_back(&entry->as<FunctionDeclaration>());
251cb93a386Sopenharmony_ci                break;
252cb93a386Sopenharmony_ci            default:
253cb93a386Sopenharmony_ci                errors.error(line, "symbol '" + name + "' was already defined");
254cb93a386Sopenharmony_ci                return false;
255cb93a386Sopenharmony_ci        }
256cb93a386Sopenharmony_ci        for (const FunctionDeclaration* other : functions) {
257cb93a386Sopenharmony_ci            SkASSERT(name == other->name());
258cb93a386Sopenharmony_ci            if (parameters.size() != other->parameters().size()) {
259cb93a386Sopenharmony_ci                continue;
260cb93a386Sopenharmony_ci            }
261cb93a386Sopenharmony_ci            bool match = true;
262cb93a386Sopenharmony_ci            for (size_t i = 0; i < parameters.size(); i++) {
263cb93a386Sopenharmony_ci                if (parameters[i]->type() != other->parameters()[i]->type()) {
264cb93a386Sopenharmony_ci                    match = false;
265cb93a386Sopenharmony_ci                    break;
266cb93a386Sopenharmony_ci                }
267cb93a386Sopenharmony_ci            }
268cb93a386Sopenharmony_ci            if (!match) {
269cb93a386Sopenharmony_ci                continue;
270cb93a386Sopenharmony_ci            }
271cb93a386Sopenharmony_ci            if (*returnType != other->returnType()) {
272cb93a386Sopenharmony_ci                std::vector<const Variable*> paramPtrs;
273cb93a386Sopenharmony_ci                paramPtrs.reserve(parameters.size());
274cb93a386Sopenharmony_ci                for (std::unique_ptr<Variable>& param : parameters) {
275cb93a386Sopenharmony_ci                    paramPtrs.push_back(param.get());
276cb93a386Sopenharmony_ci                }
277cb93a386Sopenharmony_ci                FunctionDeclaration invalidDecl(line,
278cb93a386Sopenharmony_ci                                                &other->modifiers(),
279cb93a386Sopenharmony_ci                                                name,
280cb93a386Sopenharmony_ci                                                std::move(paramPtrs),
281cb93a386Sopenharmony_ci                                                returnType,
282cb93a386Sopenharmony_ci                                                context.fConfig->fIsBuiltinCode);
283cb93a386Sopenharmony_ci                errors.error(line,
284cb93a386Sopenharmony_ci                             "functions '" + invalidDecl.description() + "' and '" +
285cb93a386Sopenharmony_ci                             other->description() + "' differ only in return type");
286cb93a386Sopenharmony_ci                return false;
287cb93a386Sopenharmony_ci            }
288cb93a386Sopenharmony_ci            for (size_t i = 0; i < parameters.size(); i++) {
289cb93a386Sopenharmony_ci                if (parameters[i]->modifiers() != other->parameters()[i]->modifiers()) {
290cb93a386Sopenharmony_ci                    errors.error(line,
291cb93a386Sopenharmony_ci                                 "modifiers on parameter " + to_string((uint64_t)i + 1) +
292cb93a386Sopenharmony_ci                                 " differ between declaration and definition");
293cb93a386Sopenharmony_ci                    return false;
294cb93a386Sopenharmony_ci                }
295cb93a386Sopenharmony_ci            }
296cb93a386Sopenharmony_ci            if (other->definition() && !other->isBuiltin()) {
297cb93a386Sopenharmony_ci                errors.error(line, "duplicate definition of " + other->description());
298cb93a386Sopenharmony_ci                return false;
299cb93a386Sopenharmony_ci            }
300cb93a386Sopenharmony_ci            *outExistingDecl = other;
301cb93a386Sopenharmony_ci            break;
302cb93a386Sopenharmony_ci        }
303cb93a386Sopenharmony_ci    }
304cb93a386Sopenharmony_ci    return true;
305cb93a386Sopenharmony_ci}
306cb93a386Sopenharmony_ci
307cb93a386Sopenharmony_ciFunctionDeclaration::FunctionDeclaration(int line,
308cb93a386Sopenharmony_ci                                         const Modifiers* modifiers,
309cb93a386Sopenharmony_ci                                         skstd::string_view name,
310cb93a386Sopenharmony_ci                                         std::vector<const Variable*> parameters,
311cb93a386Sopenharmony_ci                                         const Type* returnType,
312cb93a386Sopenharmony_ci                                         bool builtin)
313cb93a386Sopenharmony_ci        : INHERITED(line, kSymbolKind, name, /*type=*/nullptr)
314cb93a386Sopenharmony_ci        , fDefinition(nullptr)
315cb93a386Sopenharmony_ci        , fModifiers(modifiers)
316cb93a386Sopenharmony_ci        , fParameters(std::move(parameters))
317cb93a386Sopenharmony_ci        , fReturnType(returnType)
318cb93a386Sopenharmony_ci        , fBuiltin(builtin)
319cb93a386Sopenharmony_ci        , fIsMain(name == "main")
320cb93a386Sopenharmony_ci        , fIntrinsicKind(builtin ? identify_intrinsic(name) : kNotIntrinsic) {}
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ciconst FunctionDeclaration* FunctionDeclaration::Convert(
323cb93a386Sopenharmony_ci        const Context& context,
324cb93a386Sopenharmony_ci        SymbolTable& symbols,
325cb93a386Sopenharmony_ci        int line,
326cb93a386Sopenharmony_ci        const Modifiers* modifiers,
327cb93a386Sopenharmony_ci        skstd::string_view name,
328cb93a386Sopenharmony_ci        std::vector<std::unique_ptr<Variable>> parameters,
329cb93a386Sopenharmony_ci        const Type* returnType) {
330cb93a386Sopenharmony_ci    bool isMain = (name == "main");
331cb93a386Sopenharmony_ci
332cb93a386Sopenharmony_ci    const FunctionDeclaration* decl = nullptr;
333cb93a386Sopenharmony_ci    if (!check_modifiers(context, line, *modifiers) ||
334cb93a386Sopenharmony_ci        !check_return_type(context, line, *returnType) ||
335cb93a386Sopenharmony_ci        !check_parameters(context, parameters, isMain) ||
336cb93a386Sopenharmony_ci        (isMain && !check_main_signature(context, line, *returnType, parameters)) ||
337cb93a386Sopenharmony_ci        !find_existing_declaration(context, symbols, line, name, parameters, returnType, &decl)) {
338cb93a386Sopenharmony_ci        return nullptr;
339cb93a386Sopenharmony_ci    }
340cb93a386Sopenharmony_ci    std::vector<const Variable*> finalParameters;
341cb93a386Sopenharmony_ci    finalParameters.reserve(parameters.size());
342cb93a386Sopenharmony_ci    for (std::unique_ptr<Variable>& param : parameters) {
343cb93a386Sopenharmony_ci        finalParameters.push_back(symbols.takeOwnershipOfSymbol(std::move(param)));
344cb93a386Sopenharmony_ci    }
345cb93a386Sopenharmony_ci    if (decl) {
346cb93a386Sopenharmony_ci        return decl;
347cb93a386Sopenharmony_ci    }
348cb93a386Sopenharmony_ci    auto result = std::make_unique<FunctionDeclaration>(line, modifiers, name,
349cb93a386Sopenharmony_ci                                                        std::move(finalParameters), returnType,
350cb93a386Sopenharmony_ci                                                        context.fConfig->fIsBuiltinCode);
351cb93a386Sopenharmony_ci    return symbols.add(std::move(result));
352cb93a386Sopenharmony_ci}
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ciString FunctionDeclaration::mangledName() const {
355cb93a386Sopenharmony_ci    if ((this->isBuiltin() && !this->definition()) || this->isMain()) {
356cb93a386Sopenharmony_ci        // Builtins without a definition (like `sin` or `sqrt`) must use their real names.
357cb93a386Sopenharmony_ci        return String(this->name());
358cb93a386Sopenharmony_ci    }
359cb93a386Sopenharmony_ci    // GLSL forbids two underscores in a row; add an extra character if necessary to avoid this.
360cb93a386Sopenharmony_ci    const char* splitter = this->name().ends_with("_") ? "x_" : "_";
361cb93a386Sopenharmony_ci    // Rename function to `funcname_returntypeparamtypes`.
362cb93a386Sopenharmony_ci    String result = this->name() + splitter + this->returnType().abbreviatedName();
363cb93a386Sopenharmony_ci    for (const Variable* p : this->parameters()) {
364cb93a386Sopenharmony_ci        result += p->type().abbreviatedName();
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci    return result;
367cb93a386Sopenharmony_ci}
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ciString FunctionDeclaration::description() const {
370cb93a386Sopenharmony_ci    String result = this->returnType().displayName() + " " + this->name() + "(";
371cb93a386Sopenharmony_ci    String separator;
372cb93a386Sopenharmony_ci    for (const Variable* p : this->parameters()) {
373cb93a386Sopenharmony_ci        result += separator;
374cb93a386Sopenharmony_ci        separator = ", ";
375cb93a386Sopenharmony_ci        result += p->type().displayName();
376cb93a386Sopenharmony_ci        result += " ";
377cb93a386Sopenharmony_ci        result += p->name();
378cb93a386Sopenharmony_ci    }
379cb93a386Sopenharmony_ci    result += ")";
380cb93a386Sopenharmony_ci    return result;
381cb93a386Sopenharmony_ci}
382cb93a386Sopenharmony_ci
383cb93a386Sopenharmony_cibool FunctionDeclaration::matches(const FunctionDeclaration& f) const {
384cb93a386Sopenharmony_ci    if (this->name() != f.name()) {
385cb93a386Sopenharmony_ci        return false;
386cb93a386Sopenharmony_ci    }
387cb93a386Sopenharmony_ci    const std::vector<const Variable*>& parameters = this->parameters();
388cb93a386Sopenharmony_ci    const std::vector<const Variable*>& otherParameters = f.parameters();
389cb93a386Sopenharmony_ci    if (parameters.size() != otherParameters.size()) {
390cb93a386Sopenharmony_ci        return false;
391cb93a386Sopenharmony_ci    }
392cb93a386Sopenharmony_ci    for (size_t i = 0; i < parameters.size(); i++) {
393cb93a386Sopenharmony_ci        if (parameters[i]->type() != otherParameters[i]->type()) {
394cb93a386Sopenharmony_ci            return false;
395cb93a386Sopenharmony_ci        }
396cb93a386Sopenharmony_ci    }
397cb93a386Sopenharmony_ci    return true;
398cb93a386Sopenharmony_ci}
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_cibool FunctionDeclaration::determineFinalTypes(const ExpressionArray& arguments,
401cb93a386Sopenharmony_ci                                              ParamTypes* outParameterTypes,
402cb93a386Sopenharmony_ci                                              const Type** outReturnType) const {
403cb93a386Sopenharmony_ci    const std::vector<const Variable*>& parameters = this->parameters();
404cb93a386Sopenharmony_ci    SkASSERT(arguments.size() == parameters.size());
405cb93a386Sopenharmony_ci
406cb93a386Sopenharmony_ci    outParameterTypes->reserve_back(arguments.size());
407cb93a386Sopenharmony_ci    int genericIndex = -1;
408cb93a386Sopenharmony_ci    for (size_t i = 0; i < arguments.size(); i++) {
409cb93a386Sopenharmony_ci        // Non-generic parameters are final as-is.
410cb93a386Sopenharmony_ci        const Type& parameterType = parameters[i]->type();
411cb93a386Sopenharmony_ci        if (parameterType.typeKind() != Type::TypeKind::kGeneric) {
412cb93a386Sopenharmony_ci            outParameterTypes->push_back(&parameterType);
413cb93a386Sopenharmony_ci            continue;
414cb93a386Sopenharmony_ci        }
415cb93a386Sopenharmony_ci        // We use the first generic parameter we find to lock in the generic index;
416cb93a386Sopenharmony_ci        // e.g. if we find `float3` here, all `$genType`s will be assumed to be `float3`.
417cb93a386Sopenharmony_ci        const std::vector<const Type*>& types = parameterType.coercibleTypes();
418cb93a386Sopenharmony_ci        if (genericIndex == -1) {
419cb93a386Sopenharmony_ci            for (size_t j = 0; j < types.size(); j++) {
420cb93a386Sopenharmony_ci                if (arguments[i]->type().canCoerceTo(*types[j], /*allowNarrowing=*/true)) {
421cb93a386Sopenharmony_ci                    genericIndex = j;
422cb93a386Sopenharmony_ci                    break;
423cb93a386Sopenharmony_ci                }
424cb93a386Sopenharmony_ci            }
425cb93a386Sopenharmony_ci            if (genericIndex == -1) {
426cb93a386Sopenharmony_ci                // The passed-in type wasn't a match for ANY of the generic possibilities.
427cb93a386Sopenharmony_ci                // This function isn't a match at all.
428cb93a386Sopenharmony_ci                return false;
429cb93a386Sopenharmony_ci            }
430cb93a386Sopenharmony_ci        }
431cb93a386Sopenharmony_ci        outParameterTypes->push_back(types[genericIndex]);
432cb93a386Sopenharmony_ci    }
433cb93a386Sopenharmony_ci    // Apply the generic index to our return type.
434cb93a386Sopenharmony_ci    const Type& returnType = this->returnType();
435cb93a386Sopenharmony_ci    if (returnType.typeKind() == Type::TypeKind::kGeneric) {
436cb93a386Sopenharmony_ci        if (genericIndex == -1) {
437cb93a386Sopenharmony_ci            // We don't support functions with a generic return type and no other generics.
438cb93a386Sopenharmony_ci            return false;
439cb93a386Sopenharmony_ci        }
440cb93a386Sopenharmony_ci        *outReturnType = returnType.coercibleTypes()[genericIndex];
441cb93a386Sopenharmony_ci    } else {
442cb93a386Sopenharmony_ci        *outReturnType = &returnType;
443cb93a386Sopenharmony_ci    }
444cb93a386Sopenharmony_ci    return true;
445cb93a386Sopenharmony_ci}
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ci}  // namespace SkSL
448