Start node stack push/pop setting IdT based on ParseNodeKind. (#2985)

I think there's more we can do here, but this seemed like a good
checkpoint to make sure the path I'm going down is roughly what you
expected. There's one actual edit in if expression structure to match
the increased enforcement.
This commit is contained in:
Jon Ross-Perkins
2023-07-12 23:26:53 +00:00
committed by GitHub
parent c0d18a62eb
commit 9751b4701d
16 changed files with 167 additions and 66 deletions
+4 -4
View File
@@ -53,12 +53,11 @@ namespace Carbon::Internal {
// ```
template <typename DerivedT, typename EnumT>
class EnumBase {
protected:
public:
// An alias for the raw enum type. This is an implementation detail and
// shouldn't be used, but we need it for a signature so it is declared early.
// should rarely be used directly, only when an actual enum type is needed.
using RawEnumType = EnumT;
public:
using EnumType = DerivedT;
using UnderlyingType = std::underlying_type_t<RawEnumType>;
@@ -92,7 +91,8 @@ class EnumBase {
// the base itself. This should only be used in the `Create` function below.
constexpr EnumBase() = default;
// Create an instance from the raw enumerator, for internal use.
// Create an instance from the raw enumerator. Mainly used internally, but may
// be exposed for unusual use cases.
static constexpr auto Create(RawEnumType value) -> EnumType {
EnumType result;
result.value_ = value;
+2
View File
@@ -33,6 +33,8 @@ class ParseNodeKind : public CARBON_ENUM_BASE(ParseNodeKind) {
// Returns the number of children that the node must have, often 0. Requires
// that has_bracket is false.
auto child_count() const -> int32_t;
using EnumBase::Create;
};
#define CARBON_PARSE_NODE_KIND(Name) \
+2 -1
View File
@@ -307,7 +307,8 @@ auto SemanticsContext::PopDeclarationName() -> DeclarationNameContext {
ParseNodeKind::QualifiedDeclaration) {
// Any parts from a QualifiedDeclaration will already have been processed
// into the name.
node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::QualifiedDeclaration);
node_stack_
.PopAndDiscardSoloParseNode<ParseNodeKind::QualifiedDeclaration>();
} else {
// The name had no qualifiers, so we need to process the node now.
auto [parse_node, node_or_name_id] =
@@ -13,8 +13,8 @@ auto SemanticsHandleCallExpression(SemanticsContext& context,
// TODO: Convert to call expression.
auto [call_expr_parse_node, name_id] =
context.node_stack().PopWithParseNode<SemanticsNodeId>(
ParseNodeKind::CallExpressionStart);
context.node_stack()
.PopWithParseNode<ParseNodeKind::CallExpressionStart>();
auto name_node = context.semantics_ir().GetNode(name_id);
if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) {
// TODO: Work on error.
@@ -17,7 +17,7 @@ auto SemanticsHandleCodeBlockStart(SemanticsContext& context,
auto SemanticsHandleCodeBlock(SemanticsContext& context,
ParseTree::Node /*parse_node*/) -> bool {
context.PopScope();
context.node_stack().PopForSoloParseNode(ParseNodeKind::CodeBlockStart);
context.node_stack().PopForSoloParseNode<ParseNodeKind::CodeBlockStart>();
return true;
}
@@ -14,17 +14,16 @@ static auto BuildFunctionDeclaration(SemanticsContext& context)
SemanticsTypeId return_type_id = SemanticsTypeId::Invalid;
if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
ParseNodeKind::ReturnType) {
return_type_id =
context.node_stack().Pop<SemanticsTypeId>(ParseNodeKind::ReturnType);
return_type_id = context.node_stack().Pop<ParseNodeKind::ReturnType>();
} else {
// Canonicalize the empty tuple for the implicit return.
context.CanonicalizeType(SemanticsNodeId::BuiltinEmptyTupleType);
}
auto param_refs_id = context.node_stack().Pop<SemanticsNodeBlockId>(
ParseNodeKind::ParameterList);
SemanticsNodeBlockId param_refs_id =
context.node_stack().Pop<ParseNodeKind::ParameterList>();
auto name_context = context.PopDeclarationName();
auto fn_node = context.node_stack().PopForSoloParseNode(
ParseNodeKind::FunctionIntroducer);
auto fn_node = context.node_stack()
.PopForSoloParseNode<ParseNodeKind::FunctionIntroducer>();
// TODO: Support out-of-line definitions, which will have a resolved
// name_context. Right now, those become errors in AddNameToLookup.
@@ -50,8 +49,8 @@ auto SemanticsHandleFunctionDeclaration(SemanticsContext& context,
auto SemanticsHandleFunctionDefinition(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
auto function_id = context.node_stack().Pop<SemanticsFunctionId>(
ParseNodeKind::FunctionDefinitionStart);
SemanticsFunctionId function_id =
context.node_stack().Pop<ParseNodeKind::FunctionDefinitionStart>();
// If the `}` of the function is reachable, reject if we need a return value
// and otherwise add an implicit `return;`.
@@ -37,11 +37,10 @@ auto SemanticsHandleIfExpressionElse(SemanticsContext& context,
ParseTree::Node else_node) -> bool {
auto else_value_id = context.node_stack().Pop<SemanticsNodeId>();
auto [then_node, then_end_block_id] =
context.node_stack().PopWithParseNode<SemanticsNodeBlockId>(
ParseNodeKind::IfExpressionThen);
context.node_stack().PopWithParseNode<ParseNodeKind::IfExpressionThen>();
auto then_value_id = context.node_stack().Pop<SemanticsNodeId>();
auto if_node =
context.node_stack().PopForSoloParseNode(ParseNodeKind::IfExpressionIf);
context.node_stack().PopForSoloParseNode<ParseNodeKind::IfExpressionIf>();
// Convert the `else` value to the `then` value's type, and finish the `else`
// block.
@@ -58,7 +57,7 @@ auto SemanticsHandleIfExpressionElse(SemanticsContext& context,
context.AddCurrentCodeBlockToFunction();
// Push the result value.
context.node_stack().Push(if_node, chosen_value_id);
context.node_stack().Push(else_node, chosen_value_id);
return true;
}
@@ -37,7 +37,7 @@ auto SemanticsHandleIfCondition(SemanticsContext& context,
auto SemanticsHandleIfStatementElse(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
context.node_stack().PopAndDiscardSoloParseNode(ParseNodeKind::IfCondition);
context.node_stack().PopAndDiscardSoloParseNode<ParseNodeKind::IfCondition>();
// Switch to emitting the else block.
auto then_block_id = context.node_block_stack().PopForAdd();
@@ -56,8 +56,8 @@ auto SemanticsHandleIfStatement(SemanticsContext& context,
context.node_stack().PeekParseNode())) {
case ParseNodeKind::IfCondition: {
// Branch from then block to else block.
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::IfCondition);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::IfCondition>();
context.AddNodeToBlock(
sub_block_id,
SemanticsNode::Branch::Make(parse_node,
@@ -67,8 +67,8 @@ auto SemanticsHandleIfStatement(SemanticsContext& context,
case ParseNodeKind::IfStatementElse: {
// Branch from the then and else blocks to a new resumption block.
auto then_block_id = context.node_stack().Pop<SemanticsNodeBlockId>(
ParseNodeKind::IfStatementElse);
SemanticsNodeBlockId then_block_id =
context.node_stack().Pop<ParseNodeKind::IfStatementElse>();
context.AddConvergenceBlockAndPush(parse_node,
{then_block_id, sub_block_id});
break;
@@ -9,8 +9,7 @@ namespace Carbon {
auto SemanticsHandleMemberAccessExpression(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
auto name_id =
context.node_stack().Pop<SemanticsStringId>(ParseNodeKind::Name);
SemanticsStringId name_id = context.node_stack().Pop<ParseNodeKind::Name>();
auto base_id = context.node_stack().Pop<SemanticsNodeId>();
auto base = context.semantics_ir().GetNode(base_id);
@@ -30,8 +30,8 @@ auto SemanticsHandleParameterList(SemanticsContext& context,
context.node_block_stack().Pop();
context.PopScope();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::ParameterListStart);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::ParameterListStart>();
context.node_stack().Push(parse_node, refs_id);
return true;
}
@@ -9,8 +9,9 @@ namespace Carbon {
auto SemanticsHandleParenExpression(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
auto value_id = context.node_stack().Pop<SemanticsNodeId>();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::ParenExpressionOrTupleLiteralStart);
context.node_stack()
.PopAndDiscardSoloParseNode<
ParseNodeKind::ParenExpressionOrTupleLiteralStart>();
context.node_stack().Push(parse_node, value_id);
return true;
}
@@ -25,8 +25,7 @@ auto SemanticsHandlePatternBinding(SemanticsContext& context,
// Get the name.
auto [name_node, name_id] =
context.node_stack().PopWithParseNode<SemanticsStringId>(
ParseNodeKind::Name);
context.node_stack().PopWithParseNode<ParseNodeKind::Name>();
// Allocate storage, linked to the name for error locations.
auto storage_id =
@@ -27,8 +27,8 @@ auto SemanticsHandleReturnStatement(SemanticsContext& context,
if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
ParseNodeKind::ReturnStatementStart) {
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::ReturnStatementStart);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::ReturnStatementStart>();
if (callable.return_type_id.is_valid()) {
// TODO: Add a note pointing at the return type's parse node.
@@ -43,8 +43,8 @@ auto SemanticsHandleReturnStatement(SemanticsContext& context,
context.AddNode(SemanticsNode::Return::Make(parse_node));
} else {
auto arg = context.node_stack().Pop<SemanticsNodeId>();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::ReturnStatementStart);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::ReturnStatementStart>();
if (!callable.return_type_id.is_valid()) {
CARBON_DIAGNOSTIC(
@@ -32,8 +32,7 @@ auto SemanticsHandleStructFieldType(SemanticsContext& context,
SemanticsTypeId cast_type_id = context.ExpressionAsType(type_node, type_id);
auto [name_node, name_id] =
context.node_stack().PopWithParseNode<SemanticsStringId>(
ParseNodeKind::Name);
context.node_stack().PopWithParseNode<ParseNodeKind::Name>();
context.AddNode(
SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id));
@@ -50,8 +49,7 @@ auto SemanticsHandleStructFieldValue(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
auto [value_parse_node, value_node_id] =
context.node_stack().PopWithParseNode<SemanticsNodeId>();
auto name_id =
context.node_stack().Pop<SemanticsStringId>(ParseNodeKind::Name);
SemanticsStringId name_id = context.node_stack().Pop<ParseNodeKind::Name>();
// Store the name for the type.
auto type_block_id = context.args_type_info_stack().PeekForAdd();
@@ -72,8 +70,9 @@ auto SemanticsHandleStructLiteral(SemanticsContext& context,
/*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart);
context.PopScope();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::StructLiteralOrStructTypeLiteralStart);
context.node_stack()
.PopAndDiscardSoloParseNode<
ParseNodeKind::StructLiteralOrStructTypeLiteralStart>();
auto type_block_id = context.args_type_info_stack().Pop();
auto type_id = context.CanonicalizeStructType(parse_node, type_block_id);
@@ -102,8 +101,9 @@ auto SemanticsHandleStructTypeLiteral(SemanticsContext& context,
/*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart);
context.PopScope();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::StructLiteralOrStructTypeLiteralStart);
context.node_stack()
.PopAndDiscardSoloParseNode<
ParseNodeKind::StructLiteralOrStructTypeLiteralStart>();
// This is only used for value literals.
context.args_type_info_stack().Pop();
@@ -16,13 +16,13 @@ auto SemanticsHandleVariableDeclaration(SemanticsContext& context,
ParseNodeKind::PatternBinding;
if (has_init) {
expr_node_id = context.node_stack().Pop<SemanticsNodeId>();
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::VariableInitializer);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::VariableInitializer>();
}
// Get the storage and add it to name lookup.
auto binding_id =
context.node_stack().Pop<SemanticsNodeId>(ParseNodeKind::PatternBinding);
SemanticsNodeId binding_id =
context.node_stack().Pop<ParseNodeKind::PatternBinding>();
auto binding = context.semantics_ir().GetNode(binding_id);
auto [name_id, storage_id] = binding.GetAsBindName();
context.AddNameToLookup(binding.parse_node(), name_id, storage_id);
@@ -37,8 +37,8 @@ auto SemanticsHandleVariableDeclaration(SemanticsContext& context,
storage_id, cast_value_id));
}
context.node_stack().PopAndDiscardSoloParseNode(
ParseNodeKind::VariableIntroducer);
context.node_stack()
.PopAndDiscardSoloParseNode<ParseNodeKind::VariableIntroducer>();
return true;
}
+116 -15
View File
@@ -37,6 +37,9 @@ class SemanticsNodeStack {
// Pushes a solo parse tree node onto the stack. Used when there is no
// IR generated by the node.
auto Push(ParseTree::Node parse_node) -> void {
CARBON_CHECK(ParseNodeKindToIdKind(parse_tree_->node_kind(parse_node)) ==
IdKind::Unused)
<< "Parse kind expects an Id: " << parse_tree_->node_kind(parse_node);
CARBON_VLOG() << "Node Push " << stack_.size() << ": "
<< parse_tree_->node_kind(parse_node) << " -> <none>\n";
CARBON_CHECK(stack_.size() < (1 << 20))
@@ -47,6 +50,12 @@ class SemanticsNodeStack {
// Pushes a parse tree node onto the stack with an ID.
template <typename IdT>
auto Push(ParseTree::Node parse_node, IdT id) -> void {
CARBON_CHECK(ParseNodeKindToIdKind(parse_tree_->node_kind(parse_node)) ==
IdTypeToIdKind<IdT>())
<< "Parse kind expected a different IdT: "
<< parse_tree_->node_kind(parse_node) << " -> " << id << "\n";
CARBON_CHECK(id.is_valid()) << "Push called with invalid id: "
<< parse_tree_->node_kind(parse_node);
CARBON_VLOG() << "Node Push " << stack_.size() << ": "
<< parse_tree_->node_kind(parse_node) << " -> " << id << "\n";
CARBON_CHECK(stack_.size() < (1 << 20))
@@ -65,15 +74,17 @@ class SemanticsNodeStack {
}
// Pops the top of the stack and returns the parse_node.
auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node {
template <ParseNodeKind::RawEnumType PopParseKind>
auto PopForSoloParseNode() -> ParseTree::Node {
auto parse_node = PopForSoloParseNode();
RequireParseKind(parse_node, pop_parse_kind);
RequireParseKind(parse_node, ParseNodeKind::Create(PopParseKind));
return parse_node;
}
// Pops the top of the stack.
auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void {
PopForSoloParseNode(pop_parse_kind);
template <ParseNodeKind::RawEnumType PopParseKind>
auto PopAndDiscardSoloParseNode() -> void {
PopForSoloParseNode<PopParseKind>();
}
// Pops the top of the stack and returns the parse_node and the ID.
@@ -85,12 +96,38 @@ class SemanticsNodeStack {
}
// Pops the top of the stack and returns the parse_node and the ID.
template <typename IdT>
auto PopWithParseNode(ParseNodeKind pop_parse_kind)
-> std::pair<ParseTree::Node, IdT> {
auto back = PopWithParseNode<IdT>();
RequireParseKind(back.first, pop_parse_kind);
return back;
template <ParseNodeKind::RawEnumType PopParseKind>
auto PopWithParseNode() -> auto {
if constexpr (ParseNodeKindToIdKind(ParseNodeKind::Create(PopParseKind)) ==
IdKind::SemanticsNodeId) {
auto back = PopWithParseNode<SemanticsNodeId>();
RequireParseKind(back.first, ParseNodeKind::Create(PopParseKind));
return back;
}
if constexpr (ParseNodeKindToIdKind(ParseNodeKind::Create(PopParseKind)) ==
IdKind::SemanticsNodeBlockId) {
auto back = PopWithParseNode<SemanticsNodeBlockId>();
RequireParseKind(back.first, ParseNodeKind::Create(PopParseKind));
return back;
}
if constexpr (ParseNodeKindToIdKind(ParseNodeKind::Create(PopParseKind)) ==
IdKind::SemanticsFunctionId) {
auto back = PopWithParseNode<SemanticsFunctionId>();
RequireParseKind(back.first, ParseNodeKind::Create(PopParseKind));
return back;
}
if constexpr (ParseNodeKindToIdKind(ParseNodeKind::Create(PopParseKind)) ==
IdKind::SemanticsStringId) {
auto back = PopWithParseNode<SemanticsStringId>();
RequireParseKind(back.first, ParseNodeKind::Create(PopParseKind));
return back;
}
if constexpr (ParseNodeKindToIdKind(ParseNodeKind::Create(PopParseKind)) ==
IdKind::SemanticsTypeId) {
auto back = PopWithParseNode<SemanticsTypeId>();
RequireParseKind(back.first, ParseNodeKind::Create(PopParseKind));
return back;
}
}
// Pops the top of the stack and returns the ID.
@@ -100,17 +137,18 @@ class SemanticsNodeStack {
}
// Pops the top of the stack and returns the ID.
template <typename IdT>
auto Pop(ParseNodeKind pop_parse_kind) -> IdT {
return PopWithParseNode<IdT>(pop_parse_kind).second;
template <ParseNodeKind::RawEnumType PopParseKind>
auto Pop() -> auto {
return PopWithParseNode<PopParseKind>().second;
}
// Pops the top of the stack, and discards the ID.
auto PopAndDiscardId() -> void { PopWithParseNode<SemanticsNodeId>(); }
// Pops the top of the stack, and discards the ID.
auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void {
PopWithParseNode<SemanticsNodeId>(pop_parse_kind);
template <ParseNodeKind::RawEnumType PopParseKind>
auto PopAndDiscardId() -> void {
PopWithParseNode<PopParseKind>();
}
// Peeks at the parse_node of the top of the stack.
@@ -132,6 +170,15 @@ class SemanticsNodeStack {
auto size() const -> size_t { return stack_.size(); }
private:
enum class IdKind {
SemanticsNodeId,
SemanticsNodeBlockId,
SemanticsFunctionId,
SemanticsStringId,
SemanticsTypeId,
Unused,
};
// An entry in stack_.
struct Entry {
explicit Entry(ParseTree::Node parse_node, SemanticsNodeId node_id)
@@ -199,6 +246,60 @@ class SemanticsNodeStack {
};
static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
// Translate a parse node kind to the enum ID kind it should always provide.
static constexpr auto ParseNodeKindToIdKind(ParseNodeKind kind) -> IdKind {
switch (kind) {
case Carbon::ParseNodeKind::CallExpression:
case Carbon::ParseNodeKind::CallExpressionStart:
case Carbon::ParseNodeKind::IfExpressionElse:
case Carbon::ParseNodeKind::InfixOperator:
case Carbon::ParseNodeKind::Literal:
case Carbon::ParseNodeKind::MemberAccessExpression:
case Carbon::ParseNodeKind::NameExpression:
case Carbon::ParseNodeKind::ParenExpression:
case Carbon::ParseNodeKind::PatternBinding:
case Carbon::ParseNodeKind::PrefixOperator:
case Carbon::ParseNodeKind::ShortCircuitOperand:
case Carbon::ParseNodeKind::StructFieldValue:
case Carbon::ParseNodeKind::StructLiteral:
case Carbon::ParseNodeKind::StructTypeLiteral:
return IdKind::SemanticsNodeId;
case Carbon::ParseNodeKind::IfExpressionThen:
case Carbon::ParseNodeKind::IfStatementElse:
case Carbon::ParseNodeKind::ParameterList:
return IdKind::SemanticsNodeBlockId;
case Carbon::ParseNodeKind::FunctionDefinitionStart:
return IdKind::SemanticsFunctionId;
case Carbon::ParseNodeKind::Name:
return IdKind::SemanticsStringId;
case Carbon::ParseNodeKind::ReturnType:
return IdKind::SemanticsTypeId;
default:
return IdKind::Unused;
}
}
// Translates an ID type to the enum ID kind for comparison with
// ParseNodeKindToIdKind.
template <typename IdT>
static constexpr auto IdTypeToIdKind() -> IdKind {
if constexpr (std::is_same_v<IdT, SemanticsNodeId>) {
return IdKind::SemanticsNodeId;
}
if constexpr (std::is_same_v<IdT, SemanticsNodeBlockId>) {
return IdKind::SemanticsNodeBlockId;
}
if constexpr (std::is_same_v<IdT, SemanticsFunctionId>) {
return IdKind::SemanticsFunctionId;
}
if constexpr (std::is_same_v<IdT, SemanticsStringId>) {
return IdKind::SemanticsStringId;
}
if constexpr (std::is_same_v<IdT, SemanticsTypeId>) {
return IdKind::SemanticsTypeId;
}
}
// Pops an entry.
template <typename IdT>
auto PopEntry() -> Entry {