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 #include "src/torque/type-inference.h"
6
7 namespace v8 {
8 namespace internal {
9 namespace torque {
10
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)11 TypeArgumentInference::TypeArgumentInference(
12 const GenericParameters& type_parameters,
13 const TypeVector& explicit_type_arguments,
14 const std::vector<TypeExpression*>& term_parameters,
15 const std::vector<base::Optional<const Type*>>& term_argument_types)
16 : num_explicit_(explicit_type_arguments.size()),
17 type_parameter_from_name_(type_parameters.size()),
18 inferred_(type_parameters.size()) {
19 if (num_explicit_ > type_parameters.size()) {
20 Fail("more explicit type arguments than expected");
21 return;
22 }
23 if (term_argument_types.size() > term_parameters.size()) {
24 Fail("more arguments than expected");
25 return;
26 }
27
28 for (size_t i = 0; i < type_parameters.size(); i++) {
29 type_parameter_from_name_[type_parameters[i].name->value] = i;
30 }
31 for (size_t i = 0; i < num_explicit_; i++) {
32 inferred_[i] = {explicit_type_arguments[i]};
33 }
34
35 for (size_t i = 0; i < term_argument_types.size(); i++) {
36 if (term_argument_types[i])
37 Match(term_parameters[i], *term_argument_types[i]);
38 if (HasFailed()) return;
39 }
40
41 for (size_t i = 0; i < type_parameters.size(); i++) {
42 if (!inferred_[i]) {
43 Fail("failed to infer arguments for all type parameters");
44 return;
45 }
46 }
47 }
48
GetResult() const49 TypeVector TypeArgumentInference::GetResult() const {
50 CHECK(!HasFailed());
51 TypeVector result(inferred_.size());
52 std::transform(
53 inferred_.begin(), inferred_.end(), result.begin(),
54 [](base::Optional<const Type*> maybe_type) { return *maybe_type; });
55 return result;
56 }
57
Match(TypeExpression * parameter,const Type * argument_type)58 void TypeArgumentInference::Match(TypeExpression* parameter,
59 const Type* argument_type) {
60 if (BasicTypeExpression* basic =
61 BasicTypeExpression::DynamicCast(parameter)) {
62 // If the parameter is referring to one of the type parameters, substitute
63 if (basic->namespace_qualification.empty() && !basic->is_constexpr) {
64 auto result = type_parameter_from_name_.find(basic->name->value);
65 if (result != type_parameter_from_name_.end()) {
66 size_t type_parameter_index = result->second;
67 if (type_parameter_index < num_explicit_) {
68 return;
69 }
70 base::Optional<const Type*>& maybe_inferred =
71 inferred_[type_parameter_index];
72 if (maybe_inferred && *maybe_inferred != argument_type) {
73 Fail("found conflicting types for generic parameter");
74 } else {
75 inferred_[type_parameter_index] = {argument_type};
76 }
77 return;
78 }
79 }
80 // Try to recurse in case of generic types
81 if (!basic->generic_arguments.empty()) {
82 MatchGeneric(basic, argument_type);
83 }
84 // NOTE: We could also check whether ground parameter types match the
85 // argument types, but we are only interested in inferring type arguments
86 // here
87 } else {
88 // TODO(gsps): Perform inference on function and union types
89 }
90 }
91
MatchGeneric(BasicTypeExpression * parameter,const Type * argument_type)92 void TypeArgumentInference::MatchGeneric(BasicTypeExpression* parameter,
93 const Type* argument_type) {
94 QualifiedName qualified_name{parameter->namespace_qualification,
95 parameter->name->value};
96 GenericType* generic_type =
97 Declarations::LookupUniqueGenericType(qualified_name);
98 auto& specialized_from = argument_type->GetSpecializedFrom();
99 if (!specialized_from || specialized_from->generic != generic_type) {
100 return Fail("found conflicting generic type constructors");
101 }
102 auto& parameters = parameter->generic_arguments;
103 auto& argument_types = specialized_from->specialized_types;
104 if (parameters.size() != argument_types.size()) {
105 Error(
106 "cannot infer types from generic-struct-typed parameter with "
107 "incompatible number of arguments")
108 .Position(parameter->pos)
109 .Throw();
110 }
111 for (size_t i = 0; i < parameters.size(); i++) {
112 Match(parameters[i], argument_types[i]);
113 if (HasFailed()) return;
114 }
115 }
116
117 } // namespace torque
118 } // namespace internal
119 } // namespace v8
120