Commit bf9d2893 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] add union types

This adds support for union types to Torque.

There is a new type expression
A | B
to form the union of the type expressions A and B.
This is only possible if A and B have a common supertype, to prevent
nonsensical unions of types with different representations.

Union types are normalized:
A | B == B | A
A | (B | C) == (A | B) | C
A | A == A

The subtyping rules are defined recursively:
(A | B) <: C  if  A <: C and B <: C
A <: (B | C)  if  A <: B or A <: C

This allows to define Object as a union type:

type Tagged generates 'TNode<Object>';
type Smi extends Tagged generates 'TNode<Smi>';
type HeapObject extends Tagged generates 'TNode<HeapObject>';
type Object = Smi | HeapObject;

The type {Tagged} is introduced to have a common supertype of all
tagged values, but we should not use it directly, because {Object}
contains the additional information that there is nothing but {Smi}
and {HeapObject} values.

When mapping union types to CSA types, we select the most specific
common supertype. For Number and Numeric, we already use union types
on the CSA side. Since it is not possible to map to CSA union types
in general, we special-case these two union types to map them to
the CSA union types we already use.

Bug: v8:7793
Change-Id: I7a4e466436f55d04012f29ef17acfdb957653908
Reviewed-on: https://chromium-review.googlesource.com/1076132Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53411}
parent 57cc9eae
...@@ -6,7 +6,10 @@ type Arguments constexpr 'CodeStubArguments*'; ...@@ -6,7 +6,10 @@ type Arguments constexpr 'CodeStubArguments*';
type void generates 'void'; type void generates 'void';
type never generates 'void'; type never generates 'void';
type Object generates 'TNode<Object>'; type Tagged generates 'TNode<Object>';
type Smi extends Tagged generates 'TNode<Smi>';
type HeapObject extends Tagged generates 'TNode<HeapObject>';
type Object = Smi | HeapObject;
type int32 generates 'TNode<Int32T>' constexpr 'int32_t'; type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t'; type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
type float64 generates 'TNode<Float64T>' constexpr 'double'; type float64 generates 'TNode<Float64T>' constexpr 'double';
...@@ -14,9 +17,6 @@ type bool generates 'TNode<BoolT>' constexpr 'bool'; ...@@ -14,9 +17,6 @@ type bool generates 'TNode<BoolT>' constexpr 'bool';
type int31 extends int32 generates 'TNode<Int32T>' constexpr 'int32_t'; type int31 extends int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*'; type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*';
type Number extends Object generates 'TNode<Number>';
type Smi extends Number generates 'TNode<Smi>';
type HeapObject extends Object generates 'TNode<HeapObject>';
type AbstractCode extends HeapObject generates 'TNode<AbstractCode>'; type AbstractCode extends HeapObject generates 'TNode<AbstractCode>';
type Code extends AbstractCode generates 'TNode<Code>'; type Code extends AbstractCode generates 'TNode<Code>';
type JSReceiver extends HeapObject generates 'TNode<JSReceiver>'; type JSReceiver extends HeapObject generates 'TNode<JSReceiver>';
...@@ -24,11 +24,14 @@ type Context extends HeapObject generates 'TNode<Context>'; ...@@ -24,11 +24,14 @@ type Context extends HeapObject generates 'TNode<Context>';
type String extends HeapObject generates 'TNode<String>'; type String extends HeapObject generates 'TNode<String>';
type Oddball extends HeapObject generates 'TNode<Oddball>'; type Oddball extends HeapObject generates 'TNode<Oddball>';
type HeapNumber extends HeapObject generates 'TNode<HeapNumber>'; type HeapNumber extends HeapObject generates 'TNode<HeapNumber>';
type Number = Smi | HeapNumber;
type Boolean extends Oddball generates 'TNode<Oddball>'; type Boolean extends Oddball generates 'TNode<Oddball>';
type JSProxy extends JSReceiver generates 'TNode<JSProxy>';
type JSObject extends JSReceiver generates 'TNode<JSObject>'; type JSObject extends JSReceiver generates 'TNode<JSObject>';
type JSArray extends JSObject generates 'TNode<JSArray>'; type JSArray extends JSObject generates 'TNode<JSArray>';
type Callable extends JSReceiver generates 'TNode<JSReceiver>'; type JSFunction extends JSObject generates 'TNode<JSFunction>';
type JSFunction extends Callable generates 'TNode<JSFunction>'; type JSBoundFunction extends JSObject generates 'TNode<JSBoundFunction>';
type Callable = JSFunction | JSBoundFunction | JSProxy;
type Map extends HeapObject generates 'TNode<Map>'; type Map extends HeapObject generates 'TNode<Map>';
type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>'; type FixedArrayBase extends HeapObject generates 'TNode<FixedArrayBase>';
type FixedArray extends FixedArrayBase generates 'TNode<FixedArray>'; type FixedArray extends FixedArrayBase generates 'TNode<FixedArray>';
......
...@@ -120,7 +120,10 @@ DECIMAL_LITERAL ...@@ -120,7 +120,10 @@ DECIMAL_LITERAL
type : CONSTEXPR? IDENTIFIER type : CONSTEXPR? IDENTIFIER
| BUILTIN '(' typeList ')' '=>' type | BUILTIN '(' typeList ')' '=>' type
| type BIT_OR type
| '(' type ')'
; ;
typeList : (type (',' type)*)?; typeList : (type (',' type)*)?;
genericSpecializationTypeList: '<' typeList '>'; genericSpecializationTypeList: '<' typeList '>';
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -262,7 +262,9 @@ class TorqueParser : public antlr4::Parser { ...@@ -262,7 +262,9 @@ class TorqueParser : public antlr4::Parser {
antlr4::tree::TerminalNode* CONSTEXPR(); antlr4::tree::TerminalNode* CONSTEXPR();
antlr4::tree::TerminalNode* BUILTIN(); antlr4::tree::TerminalNode* BUILTIN();
TypeListContext* typeList(); TypeListContext* typeList();
TypeContext* type(); std::vector<TypeContext*> type();
TypeContext* type(size_t i);
antlr4::tree::TerminalNode* BIT_OR();
void enterRule(antlr4::tree::ParseTreeListener* listener) override; void enterRule(antlr4::tree::ParseTreeListener* listener) override;
void exitRule(antlr4::tree::ParseTreeListener* listener) override; void exitRule(antlr4::tree::ParseTreeListener* listener) override;
...@@ -271,7 +273,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -271,7 +273,7 @@ class TorqueParser : public antlr4::Parser {
}; };
TypeContext* type(); TypeContext* type();
TypeContext* type(int precedence);
class TypeListContext : public antlr4::ParserRuleContext { class TypeListContext : public antlr4::ParserRuleContext {
public: public:
TypeListContext(antlr4::ParserRuleContext* parent, size_t invokingState); TypeListContext(antlr4::ParserRuleContext* parent, size_t invokingState);
...@@ -1481,6 +1483,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -1481,6 +1483,7 @@ class TorqueParser : public antlr4::Parser {
bool sempred(antlr4::RuleContext* _localctx, size_t ruleIndex, bool sempred(antlr4::RuleContext* _localctx, size_t ruleIndex,
size_t predicateIndex) override; size_t predicateIndex) override;
bool typeSempred(TypeContext* _localctx, size_t predicateIndex);
bool conditionalExpressionSempred(ConditionalExpressionContext* _localctx, bool conditionalExpressionSempred(ConditionalExpressionContext* _localctx,
size_t predicateIndex); size_t predicateIndex);
bool logicalORExpressionSempred(LogicalORExpressionContext* _localctx, bool logicalORExpressionSempred(LogicalORExpressionContext* _localctx,
......
...@@ -76,14 +76,20 @@ LabelAndTypesVector AstGenerator::GetOptionalLabelAndTypeList( ...@@ -76,14 +76,20 @@ LabelAndTypesVector AstGenerator::GetOptionalLabelAndTypeList(
TypeExpression* AstGenerator::GetType(TorqueParser::TypeContext* context) { TypeExpression* AstGenerator::GetType(TorqueParser::TypeContext* context) {
if (context->BUILTIN()) { if (context->BUILTIN()) {
ParameterList parameters = context->typeList()->accept(this); ParameterList parameters = context->typeList()->accept(this);
TypeExpression* return_type = GetType(context->type()); TypeExpression* return_type = GetType(context->type(0));
return RegisterNode( return RegisterNode(
new FunctionTypeExpression(Pos(context), parameters, return_type)); new FunctionTypeExpression(Pos(context), parameters, return_type));
} else { } else if (context->BIT_OR()) {
return RegisterNode(new UnionTypeExpression(
Pos(context), GetType(context->type(0)), GetType(context->type(1))));
} else if (context->IDENTIFIER()) {
bool is_constexpr = context->CONSTEXPR() != nullptr; bool is_constexpr = context->CONSTEXPR() != nullptr;
std::string name = context->IDENTIFIER()->getSymbol()->getText(); std::string name = context->IDENTIFIER()->getSymbol()->getText();
return RegisterNode( return RegisterNode(
new BasicTypeExpression(Pos(context), is_constexpr, std::move(name))); new BasicTypeExpression(Pos(context), is_constexpr, std::move(name)));
} else {
DCHECK_EQ(1, context->type().size());
return GetType(context->type(0));
} }
} }
......
...@@ -44,7 +44,8 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition) ...@@ -44,7 +44,8 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition)
#define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \ #define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
V(BasicTypeExpression) \ V(BasicTypeExpression) \
V(FunctionTypeExpression) V(FunctionTypeExpression) \
V(UnionTypeExpression)
#define AST_STATEMENT_NODE_KIND_LIST(V) \ #define AST_STATEMENT_NODE_KIND_LIST(V) \
V(BlockStatement) \ V(BlockStatement) \
...@@ -380,6 +381,14 @@ struct FunctionTypeExpression : TypeExpression { ...@@ -380,6 +381,14 @@ struct FunctionTypeExpression : TypeExpression {
TypeExpression* return_type; TypeExpression* return_type;
}; };
struct UnionTypeExpression : TypeExpression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(UnionTypeExpression)
UnionTypeExpression(SourcePosition pos, TypeExpression* a, TypeExpression* b)
: TypeExpression(kKind, pos), a(a), b(b) {}
TypeExpression* a;
TypeExpression* b;
};
struct ExpressionStatement : Statement { struct ExpressionStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ExpressionStatement) DEFINE_AST_NODE_LEAF_BOILERPLATE(ExpressionStatement)
ExpressionStatement(SourcePosition p, Expression* e) ExpressionStatement(SourcePosition p, Expression* e)
......
...@@ -85,8 +85,9 @@ class DeclarationVisitor : public FileVisitor { ...@@ -85,8 +85,9 @@ class DeclarationVisitor : public FileVisitor {
} }
void Visit(TypeAliasDeclaration* decl) { void Visit(TypeAliasDeclaration* decl) {
declarations()->DeclareType(decl->name, const Type* type = declarations()->GetType(decl->type);
declarations()->GetType(decl->type)); type->AddAlias(decl->name);
declarations()->DeclareType(decl->name, type);
} }
Builtin* BuiltinDeclarationCommon(BuiltinDeclaration* decl, bool external, Builtin* BuiltinDeclarationCommon(BuiltinDeclaration* decl, bool external,
......
...@@ -72,18 +72,31 @@ const AbstractType* Declarations::GetAbstractType(const Type* parent, ...@@ -72,18 +72,31 @@ const AbstractType* Declarations::GetAbstractType(const Type* parent,
return result; return result;
} }
const Type* Declarations::GetFunctionPointerType(TypeVector argument_types, const FunctionPointerType* Declarations::GetFunctionPointerType(
const Type* return_type) { TypeVector argument_types, const Type* return_type) {
const Type* code_type = LookupGlobalType(CODE_TYPE_STRING); const Type* code_type = LookupGlobalType(CODE_TYPE_STRING);
return function_pointer_types_.Add( return function_pointer_types_.Add(
FunctionPointerType(code_type, argument_types, return_type)); FunctionPointerType(code_type, argument_types, return_type));
} }
const Type* Declarations::GetUnionType(const Type* a, const Type* b) {
if (a->IsSubtypeOf(b)) return b;
if (b->IsSubtypeOf(a)) return a;
UnionType result = UnionType::FromType(a);
result.Extend(b);
if (base::Optional<const Type*> single = result.GetSingleMember()) {
return *single;
}
return union_types_.Add(std::move(result));
}
const Type* Declarations::GetType(TypeExpression* type_expression) { const Type* Declarations::GetType(TypeExpression* type_expression) {
if (auto* basic = BasicTypeExpression::DynamicCast(type_expression)) { if (auto* basic = BasicTypeExpression::DynamicCast(type_expression)) {
std::string name = std::string name =
(basic->is_constexpr ? CONSTEXPR_TYPE_PREFIX : "") + basic->name; (basic->is_constexpr ? CONSTEXPR_TYPE_PREFIX : "") + basic->name;
return LookupType(name); return LookupType(name);
} else if (auto* union_type = UnionTypeExpression::cast(type_expression)) {
return GetUnionType(GetType(union_type->a), GetType(union_type->b));
} else { } else {
auto* function_type_exp = FunctionTypeExpression::cast(type_expression); auto* function_type_exp = FunctionTypeExpression::cast(type_expression);
TypeVector argument_types; TypeVector argument_types;
......
...@@ -49,9 +49,11 @@ class Declarations { ...@@ -49,9 +49,11 @@ class Declarations {
const AbstractType* GetAbstractType(const Type* parent, std::string name, const AbstractType* GetAbstractType(const Type* parent, std::string name,
std::string generated); std::string generated);
const Type* GetFunctionPointerType(TypeVector argument_types, const FunctionPointerType* GetFunctionPointerType(TypeVector argument_types,
const Type* return_type); const Type* return_type);
const Type* GetUnionType(const Type* a, const Type* b);
Builtin* FindSomeInternalBuiltinWithType(const FunctionPointerType* type); Builtin* FindSomeInternalBuiltinWithType(const FunctionPointerType* type);
Value* LookupValue(const std::string& name); Value* LookupValue(const std::string& name);
...@@ -136,6 +138,7 @@ class Declarations { ...@@ -136,6 +138,7 @@ class Declarations {
Statement* next_body_; Statement* next_body_;
std::vector<std::unique_ptr<Declarable>> declarables_; std::vector<std::unique_ptr<Declarable>> declarables_;
Deduplicator<FunctionPointerType> function_pointer_types_; Deduplicator<FunctionPointerType> function_pointer_types_;
Deduplicator<UnionType> union_types_;
std::vector<std::unique_ptr<Type>> nominal_types_; std::vector<std::unique_ptr<Type>> nominal_types_;
std::map<std::pair<const AstNode*, TypeVector>, Scope*> scopes_; std::map<std::pair<const AstNode*, TypeVector>, Scope*> scopes_;
std::map<Generic*, ScopeChain::Snapshot> generic_declaration_scopes_; std::map<Generic*, ScopeChain::Snapshot> generic_declaration_scopes_;
......
...@@ -12,7 +12,29 @@ namespace v8 { ...@@ -12,7 +12,29 @@ namespace v8 {
namespace internal { namespace internal {
namespace torque { namespace torque {
std::string Type::ToString() const {
if (aliases_.size() == 0) return ToExplicitString();
if (aliases_.size() == 1) return *aliases_.begin();
std::stringstream result;
int i = 0;
for (const std::string& alias : aliases_) {
if (i == 0) {
result << alias << " (aka. ";
} else if (i == 1) {
result << alias;
} else {
result << ", " << alias;
}
++i;
}
result << ")";
return result.str();
}
bool Type::IsSubtypeOf(const Type* supertype) const { bool Type::IsSubtypeOf(const Type* supertype) const {
if (const UnionType* union_type = UnionType::DynamicCast(supertype)) {
return union_type->IsSupertypeOf(this);
}
const Type* subtype = this; const Type* subtype = this;
while (subtype != nullptr) { while (subtype != nullptr) {
if (subtype == supertype) return true; if (subtype == supertype) return true;
...@@ -21,6 +43,30 @@ bool Type::IsSubtypeOf(const Type* supertype) const { ...@@ -21,6 +43,30 @@ bool Type::IsSubtypeOf(const Type* supertype) const {
return false; return false;
} }
// static
const Type* Type::CommonSupertype(const Type* a, const Type* b) {
int diff = a->Depth() - b->Depth();
const Type* a_supertype = a;
const Type* b_supertype = b;
for (; diff > 0; --diff) a_supertype = a_supertype->parent();
for (; diff < 0; ++diff) b_supertype = b_supertype->parent();
while (a_supertype && b_supertype) {
if (a_supertype == b_supertype) return a_supertype;
a_supertype = a_supertype->parent();
b_supertype = b_supertype->parent();
}
ReportError("types " + a->ToString() + " and " + b->ToString() +
" have no common supertype");
}
int Type::Depth() const {
int result = 0;
for (const Type* current = parent_; current; current = current->parent_) {
++result;
}
return result;
}
bool Type::IsAbstractName(const std::string& name) const { bool Type::IsAbstractName(const std::string& name) const {
if (!IsAbstractType()) return false; if (!IsAbstractType()) return false;
return AbstractType::cast(this)->name() == name; return AbstractType::cast(this)->name() == name;
...@@ -33,7 +79,7 @@ std::string AbstractType::GetGeneratedTNodeTypeName() const { ...@@ -33,7 +79,7 @@ std::string AbstractType::GetGeneratedTNodeTypeName() const {
return result; return result;
} }
std::string FunctionPointerType::ToString() const { std::string FunctionPointerType::ToExplicitString() const {
std::stringstream result; std::stringstream result;
result << "builtin ("; result << "builtin (";
bool first = true; bool first = true;
...@@ -51,20 +97,56 @@ std::string FunctionPointerType::ToString() const { ...@@ -51,20 +97,56 @@ std::string FunctionPointerType::ToString() const {
std::string FunctionPointerType::MangledName() const { std::string FunctionPointerType::MangledName() const {
std::stringstream result; std::stringstream result;
result << "FT"; result << "FT";
bool first = true;
for (const Type* t : parameter_types_) { for (const Type* t : parameter_types_) {
std::string arg_type_string = t->MangledName();
result << arg_type_string.size() << arg_type_string;
}
std::string return_type_string = return_type_->MangledName();
result << return_type_string.size() << return_type_string;
return result.str();
}
std::string UnionType::ToExplicitString() const {
std::stringstream result;
result << "(";
bool first = true;
for (const Type* t : types_) {
if (!first) { if (!first) {
result << ", "; result << " | ";
}
first = false; first = false;
result << t;
} }
result << ")";
return result.str();
}
std::string UnionType::MangledName() const {
std::stringstream result;
result << "UT";
for (const Type* t : types_) {
std::string arg_type_string = t->MangledName(); std::string arg_type_string = t->MangledName();
result << arg_type_string.size() << arg_type_string; result << arg_type_string.size() << arg_type_string;
} }
std::string return_type_string = return_type_->MangledName();
result << return_type_string.size() << return_type_string;
return result.str(); return result.str();
} }
std::string UnionType::GetGeneratedTNodeTypeName() const {
if (types_.size() <= 3) {
std::set<std::string> members;
for (const Type* t : types_) {
members.insert(t->GetGeneratedTNodeTypeName());
}
if (members == std::set<std::string>{"Smi", "HeapNumber"}) {
return "Number";
}
if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) {
return "Numeric";
}
}
return parent()->GetGeneratedTNodeTypeName();
}
std::ostream& operator<<(std::ostream& os, const Signature& sig) { std::ostream& operator<<(std::ostream& os, const Signature& sig) {
os << "("; os << "(";
for (size_t i = 0; i < sig.parameter_names.size(); ++i) { for (size_t i = 0; i < sig.parameter_names.size(); ++i) {
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef V8_TORQUE_TYPES_H_ #ifndef V8_TORQUE_TYPES_H_
#define V8_TORQUE_TYPES_H_ #define V8_TORQUE_TYPES_H_
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include "src/base/optional.h"
#include "src/torque/utils.h" #include "src/torque/utils.h"
namespace v8 { namespace v8 {
...@@ -33,12 +35,13 @@ class Label; ...@@ -33,12 +35,13 @@ class Label;
class TypeBase { class TypeBase {
public: public:
enum class Kind { kAbstractType, kFunctionPointerType }; enum class Kind { kAbstractType, kFunctionPointerType, kUnionType };
virtual ~TypeBase() {} virtual ~TypeBase() {}
bool IsAbstractType() const { return kind() == Kind::kAbstractType; } bool IsAbstractType() const { return kind() == Kind::kAbstractType; }
bool IsFunctionPointerType() const { bool IsFunctionPointerType() const {
return kind() == Kind::kFunctionPointerType; return kind() == Kind::kFunctionPointerType;
} }
bool IsUnionType() const { return kind() == Kind::kUnionType; }
protected: protected:
explicit TypeBase(Kind kind) : kind_(kind) {} explicit TypeBase(Kind kind) : kind_(kind) {}
...@@ -70,8 +73,9 @@ class TypeBase { ...@@ -70,8 +73,9 @@ class TypeBase {
class Type : public TypeBase { class Type : public TypeBase {
public: public:
bool IsSubtypeOf(const Type* supertype) const; virtual bool IsSubtypeOf(const Type* supertype) const;
virtual std::string ToString() const = 0;
std::string ToString() const;
virtual std::string MangledName() const = 0; virtual std::string MangledName() const = 0;
bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); } bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); }
bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); } bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); }
...@@ -80,20 +84,26 @@ class Type : public TypeBase { ...@@ -80,20 +84,26 @@ class Type : public TypeBase {
return IsAbstractName(CONSTEXPR_BOOL_TYPE_STRING); return IsAbstractName(CONSTEXPR_BOOL_TYPE_STRING);
} }
bool IsVoidOrNever() const { return IsVoid() || IsNever(); } bool IsVoidOrNever() const { return IsVoid() || IsNever(); }
virtual const std::string& GetGeneratedTypeName() const = 0; virtual std::string GetGeneratedTypeName() const = 0;
virtual std::string GetGeneratedTNodeTypeName() const = 0; virtual std::string GetGeneratedTNodeTypeName() const = 0;
virtual bool IsConstexpr() const = 0; virtual bool IsConstexpr() const = 0;
static const Type* CommonSupertype(const Type* a, const Type* b);
void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); }
protected: protected:
Type(TypeBase::Kind kind, const Type* parent) Type(TypeBase::Kind kind, const Type* parent)
: TypeBase(kind), parent_(parent) {} : TypeBase(kind), parent_(parent) {}
const Type* parent() const { return parent_; } const Type* parent() const { return parent_; }
void set_parent(const Type* t) { parent_ = t; }
int Depth() const;
virtual std::string ToExplicitString() const = 0;
private: private:
bool IsAbstractName(const std::string& name) const; bool IsAbstractName(const std::string& name) const;
// If {parent_} is not nullptr, then this type is a subtype of {parent_}. // If {parent_} is not nullptr, then this type is a subtype of {parent_}.
const Type* const parent_; const Type* parent_;
mutable std::set<std::string> aliases_;
}; };
using TypeVector = std::vector<const Type*>; using TypeVector = std::vector<const Type*>;
...@@ -102,11 +112,9 @@ class AbstractType final : public Type { ...@@ -102,11 +112,9 @@ class AbstractType final : public Type {
public: public:
DECLARE_TYPE_BOILERPLATE(AbstractType); DECLARE_TYPE_BOILERPLATE(AbstractType);
const std::string& name() const { return name_; } const std::string& name() const { return name_; }
std::string ToString() const override { return name(); } std::string ToExplicitString() const override { return name(); }
std::string MangledName() const override { return "AT" + name(); } std::string MangledName() const override { return "AT" + name(); }
const std::string& GetGeneratedTypeName() const override { std::string GetGeneratedTypeName() const override { return generated_type_; }
return generated_type_;
}
std::string GetGeneratedTNodeTypeName() const override; std::string GetGeneratedTNodeTypeName() const override;
bool IsConstexpr() const override { bool IsConstexpr() const override {
return name().substr(0, strlen(CONSTEXPR_TYPE_PREFIX)) == return name().substr(0, strlen(CONSTEXPR_TYPE_PREFIX)) ==
...@@ -130,9 +138,9 @@ class AbstractType final : public Type { ...@@ -130,9 +138,9 @@ class AbstractType final : public Type {
class FunctionPointerType final : public Type { class FunctionPointerType final : public Type {
public: public:
DECLARE_TYPE_BOILERPLATE(FunctionPointerType); DECLARE_TYPE_BOILERPLATE(FunctionPointerType);
std::string ToString() const override; std::string ToExplicitString() const override;
std::string MangledName() const override; std::string MangledName() const override;
const std::string& GetGeneratedTypeName() const override { std::string GetGeneratedTypeName() const override {
return parent()->GetGeneratedTypeName(); return parent()->GetGeneratedTypeName();
} }
std::string GetGeneratedTNodeTypeName() const override { std::string GetGeneratedTNodeTypeName() const override {
...@@ -167,6 +175,91 @@ class FunctionPointerType final : public Type { ...@@ -167,6 +175,91 @@ class FunctionPointerType final : public Type {
const Type* const return_type_; const Type* const return_type_;
}; };
class UnionType final : public Type {
public:
DECLARE_TYPE_BOILERPLATE(UnionType);
std::string ToExplicitString() const override;
std::string MangledName() const override;
std::string GetGeneratedTypeName() const override {
return "TNode<" + GetGeneratedTNodeTypeName() + ">";
}
std::string GetGeneratedTNodeTypeName() const override;
bool IsConstexpr() const override {
DCHECK_EQ(false, parent()->IsConstexpr());
return false;
}
friend size_t hash_value(const UnionType& p) {
size_t result = 0;
for (const Type* t : p.types_) {
result = base::hash_combine(result, t);
}
return result;
}
bool operator==(const UnionType& other) const {
return types_ == other.types_;
}
base::Optional<const Type*> GetSingleMember() const {
if (types_.size() == 1) {
DCHECK_EQ(*types_.begin(), parent());
return *types_.begin();
}
return base::nullopt;
}
const Type* Normalize() const {
if (types_.size() == 1) {
return parent();
}
return this;
}
bool IsSubtypeOf(const Type* other) const override {
for (const Type* member : types_) {
if (!member->IsSubtypeOf(other)) return false;
}
return true;
}
bool IsSupertypeOf(const Type* other) const {
for (const Type* member : types_) {
if (other->IsSubtypeOf(member)) {
return true;
}
}
return false;
}
void Extend(const Type* t) {
if (const UnionType* union_type = UnionType::DynamicCast(t)) {
for (const Type* member : union_type->types_) {
Extend(member);
}
} else {
if (t->IsSubtypeOf(this)) return;
set_parent(CommonSupertype(parent(), t));
for (const Type* member : types_) {
if (member->IsSubtypeOf(t)) {
types_.erase(member);
}
}
types_.insert(t);
}
}
static UnionType FromType(const Type* t) {
const UnionType* union_type = UnionType::DynamicCast(t);
return union_type ? UnionType(*union_type) : UnionType(t);
}
private:
explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {}
std::set<const Type*> types_;
};
inline std::ostream& operator<<(std::ostream& os, const Type* t) { inline std::ostream& operator<<(std::ostream& os, const Type* t) {
os << t->ToString(); os << t->ToString();
return os; return os;
......
...@@ -18,7 +18,7 @@ std::string CurrentPositionAsString() { ...@@ -18,7 +18,7 @@ std::string CurrentPositionAsString() {
return PositionAsString(CurrentSourcePosition::Get()); return PositionAsString(CurrentSourcePosition::Get());
} }
void ReportError(const std::string& error) { [[noreturn]] void ReportError(const std::string& error) {
std::cerr << CurrentPositionAsString() << ": Torque error: " << error << "\n"; std::cerr << CurrentPositionAsString() << ": Torque error: " << error << "\n";
throw(-1); throw(-1);
} }
......
...@@ -17,7 +17,7 @@ namespace torque { ...@@ -17,7 +17,7 @@ namespace torque {
typedef std::vector<std::string> NameVector; typedef std::vector<std::string> NameVector;
void ReportError(const std::string& error); [[noreturn]] void ReportError(const std::string& error);
std::string CamelifyString(const std::string& underscore_string); std::string CamelifyString(const std::string& underscore_string);
std::string DashifyString(const std::string& underscore_string); std::string DashifyString(const std::string& underscore_string);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment