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(¶meterType); 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