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