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