• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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