blob: 8436460c24b2cd9cb2a0e69e94e3f8c252238dd4 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKSL_FUNCTIONDECLARATION
#define SKSL_FUNCTIONDECLARATION
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLModifiers.h"
#include "src/sksl/ir/SkSLSymbol.h"
#include "src/sksl/ir/SkSLSymbolTable.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVariable.h"
#include <atomic>
namespace SkSL {
struct FunctionDefinition;
/**
* A function declaration (not a definition -- does not contain a body).
*/
struct FunctionDeclaration : public Symbol {
FunctionDeclaration(int offset, Modifiers modifiers, StringFragment name,
std::vector<const Variable*> parameters, const Type& returnType)
: INHERITED(offset, kFunctionDeclaration_Kind, std::move(name))
, fDefinition(nullptr)
, fBuiltin(false)
, fModifiers(modifiers)
, fParameters(std::move(parameters))
, fReturnType(returnType) {}
String declaration() const {
String result = fReturnType.displayName() + " " + fName + "(";
String separator;
for (auto p : fParameters) {
result += separator;
separator = ", ";
result += p->fType.displayName();
}
result += ")";
return result;
}
String description() const override {
return this->declaration();
}
bool matches(const FunctionDeclaration& f) const {
if (fName != f.fName) {
return false;
}
if (fParameters.size() != f.fParameters.size()) {
return false;
}
for (size_t i = 0; i < fParameters.size(); i++) {
if (fParameters[i]->fType != f.fParameters[i]->fType) {
return false;
}
}
return true;
}
/**
* Determine the effective types of this function's parameters and return value when called with
* the given arguments. This is relevant for functions with generic parameter types, where this
* will collapse the generic types down into specific concrete types.
*
* Returns true if it was able to select a concrete set of types for the generic function, false
* if there is no possible way this can match the argument types. Note that even a true return
* does not guarantee that the function can be successfully called with those arguments, merely
* indicates that an attempt should be made. If false is returned, the state of
* outParameterTypes and outReturnType are undefined.
*/
bool determineFinalTypes(const std::vector<std::unique_ptr<Expression>>& arguments,
std::vector<const Type*>* outParameterTypes,
const Type** outReturnType) const {
SkASSERT(arguments.size() == fParameters.size());
int genericIndex = -1;
for (size_t i = 0; i < arguments.size(); i++) {
if (fParameters[i]->fType.kind() == Type::kGeneric_Kind) {
std::vector<const Type*> types = fParameters[i]->fType.coercibleTypes();
if (genericIndex == -1) {
for (size_t j = 0; j < types.size(); j++) {
if (arguments[i]->fType.canCoerceTo(*types[j])) {
genericIndex = j;
break;
}
}
if (genericIndex == -1) {
return false;
}
}
outParameterTypes->push_back(types[genericIndex]);
} else {
outParameterTypes->push_back(&fParameters[i]->fType);
}
}
if (fReturnType.kind() == Type::kGeneric_Kind) {
if (genericIndex == -1) {
return false;
}
*outReturnType = fReturnType.coercibleTypes()[genericIndex];
} else {
*outReturnType = &fReturnType;
}
return true;
}
mutable FunctionDefinition* fDefinition;
bool fBuiltin;
Modifiers fModifiers;
const std::vector<const Variable*> fParameters;
const Type& fReturnType;
mutable std::atomic<int> fCallCount = 0;
typedef Symbol INHERITED;
};
} // namespace
#endif