blob: 8d531d81ec44775e38fd6411cf62b946683e816b [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TORQUE_TYPE_INFERENCE_H_
#define V8_TORQUE_TYPE_INFERENCE_H_
#include <string>
#include <unordered_map>
#include "src/base/optional.h"
#include "src/torque/ast.h"
#include "src/torque/declarations.h"
#include "src/torque/types.h"
namespace v8 {
namespace internal {
namespace torque {
// Type argument inference computes a potential instantiation of a generic
// callable given some concrete argument types. As an example, consider the
// generic macro
//
// macro Pick<T: type>(x: T, y: T): T
//
// along with a given call site, such as
//
// Pick(1, 2);
//
// The inference proceeds by matching the term argument types (`constexpr
// int31`, in case of `1` and `2`) against the formal parameter types (`T` in
// both cases). During this matching we discover that `T` must equal `constexpr
// int31`.
//
// The inference will not perform any comprehensive type checking of its own,
// but *does* fail if type parameters cannot be soundly instantiated given the
// call site. For instance, for the following call site
//
// const aSmi: Smi = ...;
// Pick(1, aSmi); // inference fails
//
// inference would fail, since `constexpr int31` is distinct from `Smi`. To
// allow for implicit conversions to be tried in a separate step after type
// argument inference, a number of type arguments may be given explicitly:
//
// Pick<Smi>(1, aSmi); // inference succeeds (doing nothing)
//
// In the above case the inference simply ignores inconsistent constraints on
// `T`. Similarly, we ignore all constraints arising from formal parameters
// that are function- or union-typed.
//
// Finally, note that term parameters are passed as type expressions, since
// we have no way of expressing a reference to type parameter as a Type. These
// type expressions are resolved during matching, so TypeArgumentInference
// should be instantiated in the appropriate scope.
class TypeArgumentInference {
public:
TypeArgumentInference(
const GenericParameters& type_parameters,
const TypeVector& explicit_type_arguments,
const std::vector<TypeExpression*>& term_parameters,
const std::vector<base::Optional<const Type*>>& term_argument_types);
bool HasFailed() const { return failure_reason_.has_value(); }
const std::string& GetFailureReason() { return *failure_reason_; }
TypeVector GetResult() const;
void Fail(std::string reason) { failure_reason_ = {reason}; }
private:
void Match(TypeExpression* parameter, const Type* argument_type);
void MatchGeneric(BasicTypeExpression* parameter, const Type* argument_type);
size_t num_explicit_;
std::unordered_map<std::string, size_t> type_parameter_from_name_;
std::vector<base::Optional<const Type*>> inferred_;
base::Optional<std::string> failure_reason_;
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_TYPE_INFERENCE_H_