Semantic analysis for if expressions (#2893)

Add semantic analysis and semantics IR building for `if` expressions, and add the first parts of control flow handling to semantics IR. After discussion with @chandlerc, use [block arguments](https://en.wikipedia.org/wiki/Static_single-assignment_form#Block_arguments) to convey values from the two arms of the `if` to the result. For now, only a single block argument is supported, but we should revisit this as we explore more of the requirements of the Semantics IR form.

Functions can now contain multiple code blocks, so grab the entry block up-front instead of assuming the entry block will be at the top of the block stack when we reach the end of function emission.

Add trivial support for `bool` type literal, because without it we can't write testcases.
This commit is contained in:
Richard Smith
2023-06-13 14:38:27 -07:00
committed by GitHub
parent 9606ce2127
commit 202d3f5993
43 changed files with 646 additions and 161 deletions
@@ -18,17 +18,10 @@ auto SemanticsHandleFunctionDefinition(SemanticsContext& context,
ParseNodeKind::FunctionDefinitionStart) {
context.node_stack().PopAndIgnore();
}
auto function_id = context.node_stack().Pop<SemanticsFunctionId>(
ParseNodeKind::FunctionDefinitionStart);
context.node_stack().PopAndDiscardId(ParseNodeKind::FunctionDefinitionStart);
context.return_scope_stack().pop_back();
context.PopScope();
auto body_id = context.node_block_stack().Pop();
auto& function = context.semantics_ir().GetFunction(function_id);
CARBON_CHECK(!function.body_id.is_valid())
<< "Already have function body: " << function.body_id;
function.body_id = body_id;
context.node_block_stack().Pop();
return true;
}
@@ -54,18 +47,21 @@ auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context,
auto name_str = context.parse_tree().GetNodeText(name_node);
auto name_id = context.semantics_ir().AddString(name_str);
// Add the callable, but with an invalid body for now. The body ID is only
// finalized on function completion.
// Create the entry block.
auto outer_block = context.node_block_stack().PeekForAdd();
context.node_block_stack().Push();
// Add the callable.
auto function_id = context.semantics_ir().AddFunction(
{.name_id = name_id,
.param_refs_id = param_refs_id,
.return_type_id = return_type_id,
.body_id = SemanticsNodeBlockId::Invalid});
auto decl_id = context.AddNode(
.body_id = context.node_block_stack().PeekForAdd()});
auto decl_id = context.AddNodeToBlock(
outer_block,
SemanticsNode::FunctionDeclaration::Make(fn_node, function_id));
context.AddNameToLookup(name_node, name_id, decl_id);
context.node_block_stack().Push();
context.PushScope();
for (auto ref_id : context.semantics_ir().GetNodeBlock(param_refs_id)) {
auto ref = context.semantics_ir().GetNode(ref_id);