1 // Copyright 2019 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_TORQUE_TYPE_INFERENCE_H_ 6 #define V8_TORQUE_TYPE_INFERENCE_H_ 7 8 #include <string> 9 #include <unordered_map> 10 11 #include "src/base/optional.h" 12 #include "src/torque/ast.h" 13 #include "src/torque/declarations.h" 14 #include "src/torque/types.h" 15 16 namespace v8 { 17 namespace internal { 18 namespace torque { 19 20 // Type argument inference computes a potential instantiation of a generic 21 // callable given some concrete argument types. As an example, consider the 22 // generic macro 23 // 24 // macro Pick<T: type>(x: T, y: T): T 25 // 26 // along with a given call site, such as 27 // 28 // Pick(1, 2); 29 // 30 // The inference proceeds by matching the term argument types (`constexpr 31 // int31`, in case of `1` and `2`) against the formal parameter types (`T` in 32 // both cases). During this matching we discover that `T` must equal `constexpr 33 // int31`. 34 // 35 // The inference will not perform any comprehensive type checking of its own, 36 // but *does* fail if type parameters cannot be soundly instantiated given the 37 // call site. For instance, for the following call site 38 // 39 // const aSmi: Smi = ...; 40 // Pick(1, aSmi); // inference fails 41 // 42 // inference would fail, since `constexpr int31` is distinct from `Smi`. To 43 // allow for implicit conversions to be tried in a separate step after type 44 // argument inference, a number of type arguments may be given explicitly: 45 // 46 // Pick<Smi>(1, aSmi); // inference succeeds (doing nothing) 47 // 48 // In the above case the inference simply ignores inconsistent constraints on 49 // `T`. Similarly, we ignore all constraints arising from formal parameters 50 // that are function- or union-typed. 51 // 52 // Finally, note that term parameters are passed as type expressions, since 53 // we have no way of expressing a reference to type parameter as a Type. These 54 // type expressions are resolved during matching, so TypeArgumentInference 55 // should be instantiated in the appropriate scope. 56 class TypeArgumentInference { 57 public: 58 TypeArgumentInference( 59 const GenericParameters& type_parameters, 60 const TypeVector& explicit_type_arguments, 61 const std::vector<TypeExpression*>& term_parameters, 62 const std::vector<base::Optional<const Type*>>& term_argument_types); 63 HasFailed()64 bool HasFailed() const { return failure_reason_.has_value(); } GetFailureReason()65 const std::string& GetFailureReason() { return *failure_reason_; } 66 TypeVector GetResult() const; Fail(std::string reason)67 void Fail(std::string reason) { failure_reason_ = {reason}; } 68 69 private: 70 void Match(TypeExpression* parameter, const Type* argument_type); 71 void MatchGeneric(BasicTypeExpression* parameter, const Type* argument_type); 72 73 size_t num_explicit_; 74 std::unordered_map<std::string, size_t> type_parameter_from_name_; 75 std::vector<base::Optional<const Type*>> inferred_; 76 base::Optional<std::string> failure_reason_; 77 }; 78 79 } // namespace torque 80 } // namespace internal 81 } // namespace v8 82 83 #endif // V8_TORQUE_TYPE_INFERENCE_H_ 84