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