Commit 8a002278 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] allow type annotations on enum cases

If an enum case has a type annotation, the corresponding enum constant
has this type. This is useful for typing context slots.

Bug: v8:7793
Change-Id: I8b91c3bd3686048f98cce3c034eec4e36f925e5b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2329631
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69165}
parent 320d9870
...@@ -54,6 +54,8 @@ enum class ParseResultHolderBase::TypeId { ...@@ -54,6 +54,8 @@ enum class ParseResultHolderBase::TypeId {
kOptionalTypeExpressionPtr, kOptionalTypeExpressionPtr,
kTryHandlerPtr, kTryHandlerPtr,
kNameAndTypeExpression, kNameAndTypeExpression,
kEnumEntry,
kStdVectorOfEnumEntry,
kImplicitParameters, kImplicitParameters,
kOptionalImplicitParameters, kOptionalImplicitParameters,
kNameAndExpression, kNameAndExpression,
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/torque/torque-parser.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <set> #include <set>
...@@ -13,7 +15,6 @@ ...@@ -13,7 +15,6 @@
#include "src/torque/constants.h" #include "src/torque/constants.h"
#include "src/torque/declarations.h" #include "src/torque/declarations.h"
#include "src/torque/earley-parser.h" #include "src/torque/earley-parser.h"
#include "src/torque/torque-parser.h"
#include "src/torque/utils.h" #include "src/torque/utils.h"
namespace v8 { namespace v8 {
...@@ -36,6 +37,11 @@ struct TypeswitchCase { ...@@ -36,6 +37,11 @@ struct TypeswitchCase {
Statement* block; Statement* block;
}; };
struct EnumEntry {
Identifier* name;
base::Optional<TypeExpression*> type;
};
class BuildFlags : public ContextualClass<BuildFlags> { class BuildFlags : public ContextualClass<BuildFlags> {
public: public:
BuildFlags() { BuildFlags() {
...@@ -106,6 +112,13 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ...@@ -106,6 +112,13 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndTypeExpression>::id = ParseResultHolder<NameAndTypeExpression>::id =
ParseResultTypeId::kNameAndTypeExpression; ParseResultTypeId::kNameAndTypeExpression;
template <> template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<EnumEntry>::id =
ParseResultTypeId::kEnumEntry;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<EnumEntry>>::id =
ParseResultTypeId::kStdVectorOfEnumEntry;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndExpression>::id = ParseResultHolder<NameAndExpression>::id =
ParseResultTypeId::kNameAndExpression; ParseResultTypeId::kNameAndExpression;
...@@ -1228,7 +1241,7 @@ base::Optional<ParseResult> MakeEnumDeclaration( ...@@ -1228,7 +1241,7 @@ base::Optional<ParseResult> MakeEnumDeclaration(
child_results->NextAs<base::Optional<TypeExpression*>>(); child_results->NextAs<base::Optional<TypeExpression*>>();
auto constexpr_generates_opt = auto constexpr_generates_opt =
child_results->NextAs<base::Optional<std::string>>(); child_results->NextAs<base::Optional<std::string>>();
auto entries = child_results->NextAs<std::vector<Identifier*>>(); auto entries = child_results->NextAs<std::vector<EnumEntry>>();
const bool is_open = child_results->NextAs<bool>(); const bool is_open = child_results->NextAs<bool>();
CurrentSourcePosition::Scope current_source_position( CurrentSourcePosition::Scope current_source_position(
child_results->matched_input().pos); child_results->matched_input().pos);
...@@ -1267,9 +1280,10 @@ base::Optional<ParseResult> MakeEnumDeclaration( ...@@ -1267,9 +1280,10 @@ base::Optional<ParseResult> MakeEnumDeclaration(
name_type_expression->pos = name_identifier->pos; name_type_expression->pos = name_identifier->pos;
std::vector<Declaration*> entry_decls; std::vector<Declaration*> entry_decls;
for (const auto& entry_name_identifier : entries) { for (const auto& entry : entries) {
entry_decls.push_back(MakeNode<AbstractTypeDeclaration>( entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
entry_name_identifier, false, name_type_expression, base::nullopt)); entry.name, false, entry.type.value_or(name_type_expression),
base::nullopt));
} }
result.push_back(type_decl); result.push_back(type_decl);
...@@ -1286,12 +1300,13 @@ base::Optional<ParseResult> MakeEnumDeclaration( ...@@ -1286,12 +1300,13 @@ base::Optional<ParseResult> MakeEnumDeclaration(
// type Enum = Enum::kEntry0 | ... | Enum::kEntryN; // type Enum = Enum::kEntry0 | ... | Enum::kEntryN;
TypeExpression* union_type = nullptr; TypeExpression* union_type = nullptr;
std::vector<Declaration*> entry_decls; std::vector<Declaration*> entry_decls;
for (const auto& entry_name_identifier : entries) { for (const auto& entry : entries) {
entry_decls.push_back(MakeNode<AbstractTypeDeclaration>( entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
entry_name_identifier, false, base_type_expression, base::nullopt)); entry.name, false, entry.type.value_or(*base_type_expression),
base::nullopt));
auto entry_type = MakeNode<BasicTypeExpression>( auto entry_type = MakeNode<BasicTypeExpression>(
std::vector<std::string>{name}, entry_name_identifier->value, std::vector<std::string>{name}, entry.name->value,
std::vector<TypeExpression*>{}); std::vector<TypeExpression*>{});
if (union_type) { if (union_type) {
union_type = MakeNode<UnionTypeExpression>(union_type, entry_type); union_type = MakeNode<UnionTypeExpression>(union_type, entry_type);
...@@ -1356,10 +1371,10 @@ base::Optional<ParseResult> MakeEnumDeclaration( ...@@ -1356,10 +1371,10 @@ base::Optional<ParseResult> MakeEnumDeclaration(
EnumDescription enum_description{CurrentSourcePosition::Get(), name, EnumDescription enum_description{CurrentSourcePosition::Get(), name,
constexpr_generates, is_open}; constexpr_generates, is_open};
std::vector<Declaration*> entry_decls; std::vector<Declaration*> entry_decls;
for (const auto& entry_name_identifier : entries) { for (const auto& entry : entries) {
const std::string entry_name = entry_name_identifier->value; const std::string entry_name = entry.name->value;
const std::string entry_constexpr_type = const std::string entry_constexpr_type =
std::string(CONSTEXPR_TYPE_PREFIX) + entry_name; CONSTEXPR_TYPE_PREFIX + entry_name;
enum_description.entries.push_back(constexpr_generates + enum_description.entries.push_back(constexpr_generates +
"::" + entry_name); "::" + entry_name);
...@@ -1367,15 +1382,49 @@ base::Optional<ParseResult> MakeEnumDeclaration( ...@@ -1367,15 +1382,49 @@ base::Optional<ParseResult> MakeEnumDeclaration(
MakeNode<Identifier>(entry_constexpr_type), false, MakeNode<Identifier>(entry_constexpr_type), false,
constexpr_type_expression, constexpr_generates)); constexpr_type_expression, constexpr_generates));
// namespace Enum { bool generate_typed_constant = entry.type.has_value();
// const kEntry0: constexpr kEntry0 constexpr 'Enum::kEntry0'; if (generate_typed_constant) {
// } // namespace Enum {
entry_decls.push_back(MakeNode<ExternConstDeclaration>( // const constexpr_constant_kEntry0: constexpr kEntry0 constexpr
entry_name_identifier, // 'Enum::kEntry0'; const kEntry0 = %RawDownCast<T,
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, // Base>(FromConstexpr<Enum>(constexpr_constant_kEntry0));
entry_constexpr_type, // }
std::vector<TypeExpression*>{}), if (!generate_nonconstexpr) {
constexpr_generates + "::" + entry_name)); Error(
"Enum constants with custom types require an enum with an "
"extends clause.")
.Position((*entry.type)->pos);
}
Identifier* constexpr_constant_name =
MakeNode<Identifier>("constexpr constant " + entry_name);
entry_decls.push_back(MakeNode<ExternConstDeclaration>(
constexpr_constant_name,
MakeNode<BasicTypeExpression>(std::vector<std::string>{},
entry_constexpr_type,
std::vector<TypeExpression*>{}),
constexpr_generates + "::" + entry_name));
entry_decls.push_back(MakeNode<ConstDeclaration>(
entry.name, *entry.type,
MakeNode<IntrinsicCallExpression>(
MakeNode<Identifier>("%RawDownCast"),
std::vector<TypeExpression*>{*entry.type,
*base_type_expression},
std::vector<Expression*>{MakeCall(
MakeNode<Identifier>("FromConstexpr"), {type_expr},
{MakeNode<IdentifierExpression>(std::vector<std::string>{},
constexpr_constant_name)},
{})})));
} else {
// namespace Enum {
// const kEntry0: constexpr kEntry0 constexpr 'Enum::kEntry0';
// }
entry_decls.push_back(MakeNode<ExternConstDeclaration>(
entry.name,
MakeNode<BasicTypeExpression>(std::vector<std::string>{},
entry_constexpr_type,
std::vector<TypeExpression*>{}),
constexpr_generates + "::" + entry_name));
}
// FromConstexpr<Enum, Enum::constexpr kEntry0>( // FromConstexpr<Enum, Enum::constexpr kEntry0>(
// : Enum::constexpr kEntry0): Enum // : Enum::constexpr kEntry0): Enum
...@@ -1828,6 +1877,12 @@ base::Optional<ParseResult> MakeNameAndType( ...@@ -1828,6 +1877,12 @@ base::Optional<ParseResult> MakeNameAndType(
return ParseResult{NameAndTypeExpression{name, type}}; return ParseResult{NameAndTypeExpression{name, type}};
} }
base::Optional<ParseResult> MakeEnumEntry(ParseResultIterator* child_results) {
auto name = child_results->NextAs<Identifier*>();
auto type = child_results->NextAs<base::Optional<TypeExpression*>>();
return ParseResult{EnumEntry{name, type}};
}
base::Optional<ParseResult> MakeNameAndExpression( base::Optional<ParseResult> MakeNameAndExpression(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto name = child_results->NextAs<Identifier*>(); auto name = child_results->NextAs<Identifier*>();
...@@ -2362,6 +2417,9 @@ struct TorqueGrammar : Grammar { ...@@ -2362,6 +2417,9 @@ struct TorqueGrammar : Grammar {
Symbol* optionalTypeSpecifier = Symbol* optionalTypeSpecifier =
Optional<TypeExpression*>(Sequence({Token(":"), &type})); Optional<TypeExpression*>(Sequence({Token(":"), &type}));
// Result: EnumEntry
Symbol enumEntry = {Rule({&name, optionalTypeSpecifier}, MakeEnumEntry)};
// Result: Statement* // Result: Statement*
Symbol varDeclaration = { Symbol varDeclaration = {
Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier}, Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier},
...@@ -2525,7 +2583,7 @@ struct TorqueGrammar : Grammar { ...@@ -2525,7 +2583,7 @@ struct TorqueGrammar : Grammar {
Optional<TypeExpression*>(Sequence({Token("extends"), &type})), Optional<TypeExpression*>(Sequence({Token("extends"), &type})),
Optional<std::string>( Optional<std::string>(
Sequence({Token("constexpr"), &externalString})), Sequence({Token("constexpr"), &externalString})),
Token("{"), NonemptyList<Identifier*>(&name, Token(",")), Token("{"), NonemptyList<EnumEntry>(&enumEntry, Token(",")),
CheckIf(Sequence({Token(","), Token("...")})), Token("}")}, CheckIf(Sequence({Token(","), Token("...")})), Token("}")},
MakeEnumDeclaration), MakeEnumDeclaration),
Rule({Token("namespace"), &identifier, Token("{"), &declarationList, Rule({Token("namespace"), &identifier, Token("{"), &declarationList,
......
...@@ -677,6 +677,23 @@ TEST(Torque, EnumInTypeswitch) { ...@@ -677,6 +677,23 @@ TEST(Torque, EnumInTypeswitch) {
)"); )");
} }
TEST(Torque, EnumTypeAnnotations) {
ExpectSuccessfulCompilation(R"(
type Type1 extends intptr;
type Type2 extends intptr;
extern enum MyEnum extends intptr {
kValue1: Type1,
kValue2: Type2,
kValue3
}
@export macro Foo() {
const _a: Type1 = MyEnum::kValue1;
const _b: Type2 = MyEnum::kValue2;
const _c: intptr = MyEnum::kValue3;
}
)");
}
TEST(Torque, ConstClassFields) { TEST(Torque, ConstClassFields) {
ExpectSuccessfulCompilation(R"( ExpectSuccessfulCompilation(R"(
class Foo extends HeapObject { class Foo extends HeapObject {
......
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