1 // Copyright 2017 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_DECLARABLE_H_
6 #define V8_TORQUE_DECLARABLE_H_
7
8 #include <cassert>
9 #include <string>
10 #include <unordered_map>
11
12 #include "src/base/functional.h"
13 #include "src/base/logging.h"
14 #include "src/torque/ast.h"
15 #include "src/torque/types.h"
16 #include "src/torque/utils.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace torque {
21
22 class Scope;
23 class Namespace;
24 class TypeArgumentInference;
25
26 DECLARE_CONTEXTUAL_VARIABLE(CurrentScope, Scope*);
27
28 struct QualifiedName {
29 std::vector<std::string> namespace_qualification;
30 std::string name;
31
QualifiedNameQualifiedName32 QualifiedName(std::vector<std::string> namespace_qualification,
33 std::string name)
34 : namespace_qualification(std::move(namespace_qualification)),
35 name(std::move(name)) {}
QualifiedNameQualifiedName36 explicit QualifiedName(std::string name)
37 : QualifiedName({}, std::move(name)) {}
38
39 static QualifiedName Parse(std::string qualified_name);
40
HasNamespaceQualificationQualifiedName41 bool HasNamespaceQualification() const {
42 return !namespace_qualification.empty();
43 }
44
DropFirstNamespaceQualificationQualifiedName45 QualifiedName DropFirstNamespaceQualification() const {
46 return QualifiedName{
47 std::vector<std::string>(namespace_qualification.begin() + 1,
48 namespace_qualification.end()),
49 name};
50 }
51
52 friend std::ostream& operator<<(std::ostream& os, const QualifiedName& name);
53 };
54
55 class Declarable {
56 public:
57 virtual ~Declarable() = default;
58 enum Kind {
59 kNamespace,
60 kTorqueMacro,
61 kExternMacro,
62 kMethod,
63 kBuiltin,
64 kRuntimeFunction,
65 kIntrinsic,
66 kGenericCallable,
67 kGenericType,
68 kTypeAlias,
69 kExternConstant,
70 kNamespaceConstant
71 };
kind()72 Kind kind() const { return kind_; }
IsNamespace()73 bool IsNamespace() const { return kind() == kNamespace; }
IsMacro()74 bool IsMacro() const { return IsTorqueMacro() || IsExternMacro(); }
IsTorqueMacro()75 bool IsTorqueMacro() const { return kind() == kTorqueMacro || IsMethod(); }
IsMethod()76 bool IsMethod() const { return kind() == kMethod; }
IsExternMacro()77 bool IsExternMacro() const { return kind() == kExternMacro; }
IsIntrinsic()78 bool IsIntrinsic() const { return kind() == kIntrinsic; }
IsBuiltin()79 bool IsBuiltin() const { return kind() == kBuiltin; }
IsRuntimeFunction()80 bool IsRuntimeFunction() const { return kind() == kRuntimeFunction; }
IsGenericCallable()81 bool IsGenericCallable() const { return kind() == kGenericCallable; }
IsGenericType()82 bool IsGenericType() const { return kind() == kGenericType; }
IsTypeAlias()83 bool IsTypeAlias() const { return kind() == kTypeAlias; }
IsExternConstant()84 bool IsExternConstant() const { return kind() == kExternConstant; }
IsNamespaceConstant()85 bool IsNamespaceConstant() const { return kind() == kNamespaceConstant; }
IsValue()86 bool IsValue() const { return IsExternConstant() || IsNamespaceConstant(); }
IsScope()87 bool IsScope() const { return IsNamespace() || IsCallable(); }
IsCallable()88 bool IsCallable() const {
89 return IsMacro() || IsBuiltin() || IsRuntimeFunction() || IsIntrinsic() ||
90 IsMethod();
91 }
type_name()92 virtual const char* type_name() const { return "<<unknown>>"; }
ParentScope()93 Scope* ParentScope() const { return parent_scope_; }
94
95 // The SourcePosition of the whole declarable. For example, for a macro
96 // this will encompass not only the signature, but also the body.
Position()97 SourcePosition Position() const { return position_; }
SetPosition(const SourcePosition & position)98 void SetPosition(const SourcePosition& position) { position_ = position; }
99
100 // The SourcePosition of the identifying name of the declarable. For example,
101 // for a macro this will be the SourcePosition of the name.
102 // Note that this SourcePosition might not make sense for all kinds of
103 // declarables, in that case, the default SourcePosition is returned.
IdentifierPosition()104 SourcePosition IdentifierPosition() const {
105 return identifier_position_.source.IsValid() ? identifier_position_
106 : position_;
107 }
SetIdentifierPosition(const SourcePosition & position)108 void SetIdentifierPosition(const SourcePosition& position) {
109 identifier_position_ = position;
110 }
111
IsUserDefined()112 bool IsUserDefined() const { return is_user_defined_; }
SetIsUserDefined(bool is_user_defined)113 void SetIsUserDefined(bool is_user_defined) {
114 is_user_defined_ = is_user_defined;
115 }
116
117 protected:
Declarable(Kind kind)118 explicit Declarable(Kind kind) : kind_(kind) {}
119
120 private:
121 const Kind kind_;
122 Scope* const parent_scope_ = CurrentScope::Get();
123 SourcePosition position_ = CurrentSourcePosition::Get();
124 SourcePosition identifier_position_ = SourcePosition::Invalid();
125 bool is_user_defined_ = true;
126 };
127
128 #define DECLARE_DECLARABLE_BOILERPLATE(x, y) \
129 static x* cast(Declarable* declarable) { \
130 DCHECK(declarable->Is##x()); \
131 return static_cast<x*>(declarable); \
132 } \
133 static const x* cast(const Declarable* declarable) { \
134 DCHECK(declarable->Is##x()); \
135 return static_cast<const x*>(declarable); \
136 } \
137 const char* type_name() const override { return #y; } \
138 static x* DynamicCast(Declarable* declarable) { \
139 if (!declarable) return nullptr; \
140 if (!declarable->Is##x()) return nullptr; \
141 return static_cast<x*>(declarable); \
142 } \
143 static const x* DynamicCast(const Declarable* declarable) { \
144 if (!declarable) return nullptr; \
145 if (!declarable->Is##x()) return nullptr; \
146 return static_cast<const x*>(declarable); \
147 }
148
149 // Information about what code caused a specialization to exist. This is used
150 // for error reporting.
151 struct SpecializationRequester {
152 // The position of the expression that caused this specialization.
153 SourcePosition position;
154 // The Scope which contains the expression that caused this specialization.
155 // It may in turn also be within a specialization, which allows us to print
156 // the stack of requesters when an error occurs.
157 Scope* scope;
158 // The name of the specialization.
159 std::string name;
160
NoneSpecializationRequester161 static SpecializationRequester None() {
162 return {SourcePosition::Invalid(), nullptr, ""};
163 }
164
IsNoneSpecializationRequester165 bool IsNone() const {
166 return position == SourcePosition::Invalid() && scope == nullptr &&
167 name == "";
168 }
169 SpecializationRequester(SourcePosition position, Scope* scope,
170 std::string name);
171 };
172
173 class Scope : public Declarable {
174 public:
DECLARE_DECLARABLE_BOILERPLATE(Scope,scope)175 DECLARE_DECLARABLE_BOILERPLATE(Scope, scope)
176 explicit Scope(Declarable::Kind kind) : Declarable(kind) {}
177
LookupShallow(const QualifiedName & name)178 std::vector<Declarable*> LookupShallow(const QualifiedName& name) {
179 if (!name.HasNamespaceQualification()) return declarations_[name.name];
180 Scope* child = nullptr;
181 for (Declarable* declarable :
182 declarations_[name.namespace_qualification.front()]) {
183 if (Scope* scope = Scope::DynamicCast(declarable)) {
184 if (child != nullptr) {
185 ReportError("ambiguous reference to scope ",
186 name.namespace_qualification.front());
187 }
188 child = scope;
189 }
190 }
191 if (child == nullptr) return {};
192 return child->LookupShallow(name.DropFirstNamespaceQualification());
193 }
194
195 std::vector<Declarable*> Lookup(const QualifiedName& name);
196 template <class T>
AddDeclarable(const std::string & name,T * declarable)197 T* AddDeclarable(const std::string& name, T* declarable) {
198 declarations_[name].push_back(declarable);
199 return declarable;
200 }
201
GetSpecializationRequester()202 const SpecializationRequester& GetSpecializationRequester() const {
203 return requester_;
204 }
SetSpecializationRequester(const SpecializationRequester & requester)205 void SetSpecializationRequester(const SpecializationRequester& requester) {
206 requester_ = requester;
207 }
208
209 private:
210 std::unordered_map<std::string, std::vector<Declarable*>> declarations_;
211
212 // If this Scope was created for specializing a generic type or callable,
213 // then {requester_} refers to the place that caused the specialization so we
214 // can construct useful error messages.
215 SpecializationRequester requester_ = SpecializationRequester::None();
216 };
217
218 class Namespace : public Scope {
219 public:
DECLARE_DECLARABLE_BOILERPLATE(Namespace,namespace)220 DECLARE_DECLARABLE_BOILERPLATE(Namespace, namespace)
221 explicit Namespace(const std::string& name)
222 : Scope(Declarable::kNamespace), name_(name) {}
name()223 const std::string& name() const { return name_; }
224 bool IsDefaultNamespace() const;
225 bool IsTestNamespace() const;
226
227 private:
228 std::string name_;
229 };
230
CurrentNamespace()231 inline Namespace* CurrentNamespace() {
232 Scope* scope = CurrentScope::Get();
233 while (true) {
234 if (Namespace* n = Namespace::DynamicCast(scope)) {
235 return n;
236 }
237 scope = scope->ParentScope();
238 }
239 }
240
241 class Value : public Declarable {
242 public:
DECLARE_DECLARABLE_BOILERPLATE(Value,value)243 DECLARE_DECLARABLE_BOILERPLATE(Value, value)
244 const Identifier* name() const { return name_; }
IsConst()245 virtual bool IsConst() const { return true; }
value()246 VisitResult value() const { return *value_; }
type()247 const Type* type() const { return type_; }
248
set_value(VisitResult value)249 void set_value(VisitResult value) {
250 DCHECK(!value_);
251 value_ = value;
252 }
253
254 protected:
Value(Kind kind,const Type * type,Identifier * name)255 Value(Kind kind, const Type* type, Identifier* name)
256 : Declarable(kind), type_(type), name_(name) {}
257
258 private:
259 const Type* type_;
260 Identifier* name_;
261 base::Optional<VisitResult> value_;
262 };
263
264 class NamespaceConstant : public Value {
265 public:
DECLARE_DECLARABLE_BOILERPLATE(NamespaceConstant,constant)266 DECLARE_DECLARABLE_BOILERPLATE(NamespaceConstant, constant)
267
268 const std::string& external_name() const { return external_name_; }
body()269 Expression* body() const { return body_; }
270
271 private:
272 friend class Declarations;
NamespaceConstant(Identifier * constant_name,std::string external_name,const Type * type,Expression * body)273 explicit NamespaceConstant(Identifier* constant_name,
274 std::string external_name, const Type* type,
275 Expression* body)
276 : Value(Declarable::kNamespaceConstant, type, constant_name),
277 external_name_(std::move(external_name)),
278 body_(body) {}
279
280 std::string external_name_;
281 Expression* body_;
282 };
283
284 class ExternConstant : public Value {
285 public:
DECLARE_DECLARABLE_BOILERPLATE(ExternConstant,constant)286 DECLARE_DECLARABLE_BOILERPLATE(ExternConstant, constant)
287
288 private:
289 friend class Declarations;
290 explicit ExternConstant(Identifier* name, const Type* type, std::string value)
291 : Value(Declarable::kExternConstant, type, name) {
292 set_value(VisitResult(type, std::move(value)));
293 }
294 };
295
296 enum class OutputType {
297 kCSA,
298 kCC,
299 kCCDebug,
300 };
301
302 class Callable : public Scope {
303 public:
DECLARE_DECLARABLE_BOILERPLATE(Callable,callable)304 DECLARE_DECLARABLE_BOILERPLATE(Callable, callable)
305 const std::string& ExternalName() const { return external_name_; }
ReadableName()306 const std::string& ReadableName() const { return readable_name_; }
signature()307 const Signature& signature() const { return signature_; }
IsTransitioning()308 bool IsTransitioning() const { return signature().transitioning; }
parameter_names()309 const NameVector& parameter_names() const {
310 return signature_.parameter_names;
311 }
HasReturnValue()312 bool HasReturnValue() const {
313 return !signature_.return_type->IsVoidOrNever();
314 }
IncrementReturns()315 void IncrementReturns() { ++returns_; }
HasReturns()316 bool HasReturns() const { return returns_; }
body()317 base::Optional<Statement*> body() const { return body_; }
IsExternal()318 bool IsExternal() const { return !body_.has_value(); }
ShouldBeInlined(OutputType output_type)319 virtual bool ShouldBeInlined(OutputType output_type) const {
320 // C++ output doesn't support exiting to labels, so functions with labels in
321 // the signature must be inlined.
322 return output_type == OutputType::kCC && !signature().labels.empty();
323 }
ShouldGenerateExternalCode(OutputType output_type)324 bool ShouldGenerateExternalCode(OutputType output_type) const {
325 return !ShouldBeInlined(output_type);
326 }
327
PrefixNameForCCOutput(const std::string & name)328 static std::string PrefixNameForCCOutput(const std::string& name) {
329 // If a Torque macro requires a C++ runtime function to be generated, then
330 // the generated function begins with this prefix to avoid any naming
331 // collisions with the generated CSA function for the same macro.
332 return "TqRuntime" + name;
333 }
334
PrefixNameForCCDebugOutput(const std::string & name)335 static std::string PrefixNameForCCDebugOutput(const std::string& name) {
336 // If a Torque macro requires a C++ runtime function to be generated, then
337 // the generated function begins with this prefix to avoid any naming
338 // collisions with the generated CSA function for the same macro.
339 return "TqDebug" + name;
340 }
341
342 // Name to use in runtime C++ code.
CCName()343 virtual std::string CCName() const {
344 return PrefixNameForCCOutput(ExternalName());
345 }
346
347 // Name to use in debug C++ code.
CCDebugName()348 virtual std::string CCDebugName() const {
349 return PrefixNameForCCDebugOutput(ExternalName());
350 }
351
352 protected:
Callable(Declarable::Kind kind,std::string external_name,std::string readable_name,Signature signature,base::Optional<Statement * > body)353 Callable(Declarable::Kind kind, std::string external_name,
354 std::string readable_name, Signature signature,
355 base::Optional<Statement*> body)
356 : Scope(kind),
357 external_name_(std::move(external_name)),
358
359 readable_name_(std::move(readable_name)),
360 signature_(std::move(signature)),
361 returns_(0),
362 body_(body) {
363 DCHECK(!body || *body);
364 }
365
366 private:
367 std::string external_name_;
368 std::string readable_name_;
369 Signature signature_;
370 size_t returns_;
371 base::Optional<Statement*> body_;
372 };
373
374 class Macro : public Callable {
375 public:
DECLARE_DECLARABLE_BOILERPLATE(Macro,macro)376 DECLARE_DECLARABLE_BOILERPLATE(Macro, macro)
377 bool ShouldBeInlined(OutputType output_type) const override {
378 for (const LabelDeclaration& label : signature().labels) {
379 for (const Type* type : label.types) {
380 if (type->StructSupertype()) return true;
381 }
382 }
383 // Intrinsics that are used internally in Torque and implemented as torque
384 // code should be inlined and not generate C++ definitions.
385 if (ReadableName()[0] == '%') return true;
386 return Callable::ShouldBeInlined(output_type);
387 }
388
SetUsed()389 void SetUsed() { used_ = true; }
IsUsed()390 bool IsUsed() const { return used_; }
391
392 protected:
Macro(Declarable::Kind kind,std::string external_name,std::string readable_name,const Signature & signature,base::Optional<Statement * > body)393 Macro(Declarable::Kind kind, std::string external_name,
394 std::string readable_name, const Signature& signature,
395 base::Optional<Statement*> body)
396 : Callable(kind, std::move(external_name), std::move(readable_name),
397 signature, body),
398 used_(false) {
399 if (signature.parameter_types.var_args) {
400 ReportError("Varargs are not supported for macros.");
401 }
402 }
403
404 private:
405 bool used_;
406 };
407
408 class ExternMacro : public Macro {
409 public:
DECLARE_DECLARABLE_BOILERPLATE(ExternMacro,ExternMacro)410 DECLARE_DECLARABLE_BOILERPLATE(ExternMacro, ExternMacro)
411
412 const std::string& external_assembler_name() const {
413 return external_assembler_name_;
414 }
415
CCName()416 std::string CCName() const override {
417 return "TorqueRuntimeMacroShims::" + external_assembler_name() +
418 "::" + ExternalName();
419 }
420
CCDebugName()421 std::string CCDebugName() const override {
422 return "TorqueDebugMacroShims::" + external_assembler_name() +
423 "::" + ExternalName();
424 }
425
426 private:
427 friend class Declarations;
ExternMacro(const std::string & name,std::string external_assembler_name,Signature signature)428 ExternMacro(const std::string& name, std::string external_assembler_name,
429 Signature signature)
430 : Macro(Declarable::kExternMacro, name, name, std::move(signature),
431 base::nullopt),
432 external_assembler_name_(std::move(external_assembler_name)) {}
433
434 std::string external_assembler_name_;
435 };
436
437 class TorqueMacro : public Macro {
438 public:
DECLARE_DECLARABLE_BOILERPLATE(TorqueMacro,TorqueMacro)439 DECLARE_DECLARABLE_BOILERPLATE(TorqueMacro, TorqueMacro)
440 bool IsExportedToCSA() const { return exported_to_csa_; }
CCName()441 std::string CCName() const override {
442 // Exported functions must have unique and C++-friendly readable names, so
443 // prefer those wherever possible.
444 return PrefixNameForCCOutput(IsExportedToCSA() ? ReadableName()
445 : ExternalName());
446 }
CCDebugName()447 std::string CCDebugName() const override {
448 // Exported functions must have unique and C++-friendly readable names, so
449 // prefer those wherever possible.
450 return PrefixNameForCCDebugOutput(IsExportedToCSA() ? ReadableName()
451 : ExternalName());
452 }
453
454 protected:
TorqueMacro(Declarable::Kind kind,std::string external_name,std::string readable_name,const Signature & signature,base::Optional<Statement * > body,bool is_user_defined,bool exported_to_csa)455 TorqueMacro(Declarable::Kind kind, std::string external_name,
456 std::string readable_name, const Signature& signature,
457 base::Optional<Statement*> body, bool is_user_defined,
458 bool exported_to_csa)
459 : Macro(kind, std::move(external_name), std::move(readable_name),
460 signature, body),
461 exported_to_csa_(exported_to_csa) {
462 SetIsUserDefined(is_user_defined);
463 }
464
465 private:
466 friend class Declarations;
TorqueMacro(std::string external_name,std::string readable_name,const Signature & signature,base::Optional<Statement * > body,bool is_user_defined,bool exported_to_csa)467 TorqueMacro(std::string external_name, std::string readable_name,
468 const Signature& signature, base::Optional<Statement*> body,
469 bool is_user_defined, bool exported_to_csa)
470 : TorqueMacro(Declarable::kTorqueMacro, std::move(external_name),
471 std::move(readable_name), signature, body, is_user_defined,
472 exported_to_csa) {}
473
474 bool exported_to_csa_ = false;
475 };
476
477 class Method : public TorqueMacro {
478 public:
DECLARE_DECLARABLE_BOILERPLATE(Method,Method)479 DECLARE_DECLARABLE_BOILERPLATE(Method, Method)
480 bool ShouldBeInlined(OutputType output_type) const override {
481 return Macro::ShouldBeInlined(output_type) ||
482 signature()
483 .parameter_types.types[signature().implicit_count]
484 ->IsStructType();
485 }
aggregate_type()486 AggregateType* aggregate_type() const { return aggregate_type_; }
487
488 private:
489 friend class Declarations;
Method(AggregateType * aggregate_type,std::string external_name,std::string readable_name,const Signature & signature,Statement * body)490 Method(AggregateType* aggregate_type, std::string external_name,
491 std::string readable_name, const Signature& signature, Statement* body)
492 : TorqueMacro(Declarable::kMethod, std::move(external_name),
493 std::move(readable_name), signature, body, true, false),
494 aggregate_type_(aggregate_type) {}
495 AggregateType* aggregate_type_;
496 };
497
498 class Builtin : public Callable {
499 public:
500 enum Kind { kStub, kFixedArgsJavaScript, kVarArgsJavaScript };
DECLARE_DECLARABLE_BOILERPLATE(Builtin,builtin)501 DECLARE_DECLARABLE_BOILERPLATE(Builtin, builtin)
502 Kind kind() const { return kind_; }
IsStub()503 bool IsStub() const { return kind_ == kStub; }
IsVarArgsJavaScript()504 bool IsVarArgsJavaScript() const { return kind_ == kVarArgsJavaScript; }
IsFixedArgsJavaScript()505 bool IsFixedArgsJavaScript() const { return kind_ == kFixedArgsJavaScript; }
506
507 private:
508 friend class Declarations;
Builtin(std::string external_name,std::string readable_name,Builtin::Kind kind,const Signature & signature,base::Optional<Statement * > body)509 Builtin(std::string external_name, std::string readable_name,
510 Builtin::Kind kind, const Signature& signature,
511 base::Optional<Statement*> body)
512 : Callable(Declarable::kBuiltin, std::move(external_name),
513 std::move(readable_name), signature, body),
514 kind_(kind) {}
515
516 Kind kind_;
517 };
518
519 class RuntimeFunction : public Callable {
520 public:
DECLARE_DECLARABLE_BOILERPLATE(RuntimeFunction,runtime)521 DECLARE_DECLARABLE_BOILERPLATE(RuntimeFunction, runtime)
522
523 private:
524 friend class Declarations;
525 RuntimeFunction(const std::string& name, const Signature& signature)
526 : Callable(Declarable::kRuntimeFunction, name, name, signature,
527 base::nullopt) {}
528 };
529
530 class Intrinsic : public Callable {
531 public:
DECLARE_DECLARABLE_BOILERPLATE(Intrinsic,intrinsic)532 DECLARE_DECLARABLE_BOILERPLATE(Intrinsic, intrinsic)
533
534 private:
535 friend class Declarations;
536 Intrinsic(std::string name, const Signature& signature)
537 : Callable(Declarable::kIntrinsic, name, name, signature, base::nullopt) {
538 if (signature.parameter_types.var_args) {
539 ReportError("Varargs are not supported for intrinsics.");
540 }
541 }
542 };
543
544 class TypeConstraint {
545 public:
546 base::Optional<std::string> IsViolated(const Type*) const;
547
Unconstrained()548 static TypeConstraint Unconstrained() { return {}; }
SubtypeConstraint(const Type * upper_bound)549 static TypeConstraint SubtypeConstraint(const Type* upper_bound) {
550 TypeConstraint result;
551 result.upper_bound = {upper_bound};
552 return result;
553 }
554
555 private:
556 base::Optional<const Type*> upper_bound;
557 };
558
559 base::Optional<std::string> FindConstraintViolation(
560 const std::vector<const Type*>& types,
561 const std::vector<TypeConstraint>& constraints);
562
563 std::vector<TypeConstraint> ComputeConstraints(
564 Scope* scope, const GenericParameters& parameters);
565
566 template <class SpecializationType, class DeclarationType>
567 class GenericDeclarable : public Declarable {
568 private:
569 using Map = std::unordered_map<TypeVector, SpecializationType,
570 base::hash<TypeVector>>;
571
572 public:
AddSpecialization(const TypeVector & type_arguments,SpecializationType specialization)573 void AddSpecialization(const TypeVector& type_arguments,
574 SpecializationType specialization) {
575 DCHECK_EQ(0, specializations_.count(type_arguments));
576 if (auto violation =
577 FindConstraintViolation(type_arguments, Constraints())) {
578 Error(*violation).Throw();
579 }
580 specializations_[type_arguments] = specialization;
581 }
GetSpecialization(const TypeVector & type_arguments)582 base::Optional<SpecializationType> GetSpecialization(
583 const TypeVector& type_arguments) const {
584 auto it = specializations_.find(type_arguments);
585 if (it != specializations_.end()) return it->second;
586 return base::nullopt;
587 }
588
589 using iterator = typename Map::const_iterator;
begin()590 iterator begin() const { return specializations_.begin(); }
end()591 iterator end() const { return specializations_.end(); }
592
name()593 const std::string& name() const { return name_; }
declaration()594 auto declaration() const { return generic_declaration_->declaration; }
generic_parameters()595 const GenericParameters& generic_parameters() const {
596 return generic_declaration_->generic_parameters;
597 }
598
Constraints()599 const std::vector<TypeConstraint>& Constraints() {
600 if (!constraints_)
601 constraints_ = {ComputeConstraints(ParentScope(), generic_parameters())};
602 return *constraints_;
603 }
604
605 protected:
GenericDeclarable(Declarable::Kind kind,const std::string & name,DeclarationType generic_declaration)606 GenericDeclarable(Declarable::Kind kind, const std::string& name,
607 DeclarationType generic_declaration)
608 : Declarable(kind),
609 name_(name),
610 generic_declaration_(generic_declaration) {
611 DCHECK(!generic_declaration->generic_parameters.empty());
612 }
613
614 private:
615 std::string name_;
616 DeclarationType generic_declaration_;
617 Map specializations_;
618 base::Optional<std::vector<TypeConstraint>> constraints_;
619 };
620
621 class GenericCallable
622 : public GenericDeclarable<Callable*, GenericCallableDeclaration*> {
623 public:
624 DECLARE_DECLARABLE_BOILERPLATE(GenericCallable, generic_callable)
625
626 base::Optional<Statement*> CallableBody();
627
628 TypeArgumentInference InferSpecializationTypes(
629 const TypeVector& explicit_specialization_types,
630 const std::vector<base::Optional<const Type*>>& arguments);
631
632 private:
633 friend class Declarations;
GenericCallable(const std::string & name,GenericCallableDeclaration * generic_declaration)634 GenericCallable(const std::string& name,
635 GenericCallableDeclaration* generic_declaration)
636 : GenericDeclarable<Callable*, GenericCallableDeclaration*>(
637 Declarable::kGenericCallable, name, generic_declaration) {}
638 };
639
640 class GenericType
641 : public GenericDeclarable<const Type*, GenericTypeDeclaration*> {
642 public:
DECLARE_DECLARABLE_BOILERPLATE(GenericType,generic_type)643 DECLARE_DECLARABLE_BOILERPLATE(GenericType, generic_type)
644
645 private:
646 friend class Declarations;
647 GenericType(const std::string& name,
648 GenericTypeDeclaration* generic_declaration)
649 : GenericDeclarable<const Type*, GenericTypeDeclaration*>(
650 Declarable::kGenericType, name, generic_declaration) {}
651 };
652
653 class TypeAlias : public Declarable {
654 public:
DECLARE_DECLARABLE_BOILERPLATE(TypeAlias,type_alias)655 DECLARE_DECLARABLE_BOILERPLATE(TypeAlias, type_alias)
656
657 const Type* type() const {
658 if (type_) return *type_;
659 return Resolve();
660 }
661 const Type* Resolve() const;
IsRedeclaration()662 bool IsRedeclaration() const { return redeclaration_; }
GetDeclarationPosition()663 SourcePosition GetDeclarationPosition() const {
664 return declaration_position_;
665 }
666
667 private:
668 friend class Declarations;
669 friend class TypeVisitor;
670
671 explicit TypeAlias(
672 const Type* type, bool redeclaration,
673 SourcePosition declaration_position = SourcePosition::Invalid())
Declarable(Declarable::kTypeAlias)674 : Declarable(Declarable::kTypeAlias),
675 type_(type),
676 redeclaration_(redeclaration),
677 declaration_position_(declaration_position) {}
678 explicit TypeAlias(
679 TypeDeclaration* type, bool redeclaration,
680 SourcePosition declaration_position = SourcePosition::Invalid())
Declarable(Declarable::kTypeAlias)681 : Declarable(Declarable::kTypeAlias),
682 delayed_(type),
683 redeclaration_(redeclaration),
684 declaration_position_(declaration_position) {}
685
686 mutable bool being_resolved_ = false;
687 mutable base::Optional<TypeDeclaration*> delayed_;
688 mutable base::Optional<const Type*> type_;
689 bool redeclaration_;
690 const SourcePosition declaration_position_;
691 };
692
693 std::ostream& operator<<(std::ostream& os, const Callable& m);
694 std::ostream& operator<<(std::ostream& os, const Builtin& b);
695 std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b);
696 std::ostream& operator<<(std::ostream& os, const GenericCallable& g);
697
698 #undef DECLARE_DECLARABLE_BOILERPLATE
699
700 } // namespace torque
701 } // namespace internal
702 } // namespace v8
703
704 #endif // V8_TORQUE_DECLARABLE_H_
705