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,6 +18,7 @@
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeTypeType, type: typeTypeType},
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeInvalidType, type: typeInvalidType},
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeBoolType, type: typeTypeType},
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: typeTypeType},
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: typeTypeType},
// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: typeTypeType},
+1
View File
@@ -121,6 +121,7 @@ CARBON_KEYWORD_TOKEN(Api, "api")
CARBON_KEYWORD_TOKEN(As, "as")
CARBON_KEYWORD_TOKEN(Auto, "auto")
CARBON_KEYWORD_TOKEN(Base, "base")
CARBON_KEYWORD_TOKEN(Bool, "bool")
CARBON_KEYWORD_TOKEN(Break, "break")
CARBON_KEYWORD_TOKEN(Case, "case")
CARBON_KEYWORD_TOKEN(Class, "class")
+24
View File
@@ -37,6 +37,30 @@ auto LoweringHandleBindName(LoweringContext& /*context*/,
// Probably need to do something here, but not necessary for now.
}
auto LoweringHandleBlockArg(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/, SemanticsNode node)
-> void {
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto LoweringHandleBranch(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/, SemanticsNode node)
-> void {
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto LoweringHandleBranchIf(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/, SemanticsNode node)
-> void {
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto LoweringHandleBranchWithArg(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/,
SemanticsNode node) -> void {
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto LoweringHandleBuiltin(LoweringContext& /*context*/,
SemanticsNodeId /*node_id*/, SemanticsNode node)
-> void {
+7 -7
View File
@@ -260,15 +260,15 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(InfixOperator, 2)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(PostfixOperator, 1)
// `if` expression + `then` + `else`:
// _external_: expression
// _external_: expression
// IfExpressionIf
// _external_: expression
// IfExpressionThen
// _external_: expression
// IfExpressionElse
// _external_: expression
// IfExpression
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpression, 5)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpressionThen, 0)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpressionElse, 0)
// IfExpressionElse
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpressionIf, 1)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpressionThen, 1)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExpressionElse, 3)
// Struct literals, such as `{.a = 0}`:
// StructLiteralOrStructTypeLiteralStart
+38 -22
View File
@@ -28,8 +28,8 @@ auto ParserHandleExpression(ParserContext& context) -> void {
}
if (context.PositionIs(TokenKind::If)) {
context.PushState(ParserState::ExpressionIfFinish);
context.PushState(ParserState::ExpressionThen);
context.PushState(ParserState::IfExpressionFinish);
context.PushState(ParserState::IfExpressionFinishCondition);
} else {
context.PushStateForExpressionLoop(ParserState::ExpressionLoopForPrefix,
state.ambient_precedence,
@@ -64,6 +64,7 @@ auto ParserHandleExpressionInPostfix(ParserContext& context) -> void {
case TokenKind::IntegerLiteral:
case TokenKind::RealLiteral:
case TokenKind::StringLiteral:
case TokenKind::Bool:
case TokenKind::IntegerTypeLiteral:
case TokenKind::UnsignedIntegerTypeLiteral:
case TokenKind::FloatingPointTypeLiteral:
@@ -209,12 +210,15 @@ auto ParserHandleExpressionLoopForPrefix(ParserContext& context) -> void {
context.PushState(state);
}
auto ParserHandleExpressionThen(ParserContext& context) -> void {
auto ParserHandleIfExpressionFinishCondition(ParserContext& context) -> void {
auto state = context.PopState();
if (context.ConsumeAndAddLeafNodeIf(TokenKind::Then,
ParseNodeKind::IfExpressionThen)) {
context.PushState(ParserState::ExpressionElse);
context.AddNode(ParseNodeKind::IfExpressionIf, state.token,
state.subtree_start, state.has_error);
if (context.PositionIs(TokenKind::Then)) {
context.PushState(ParserState::IfExpressionFinishThen);
context.ConsumeChecked(TokenKind::Then);
context.PushStateForExpression(*PrecedenceGroup::ForLeading(TokenKind::If));
} else {
// TODO: Include the location of the `if` token.
@@ -223,20 +227,24 @@ auto ParserHandleExpressionThen(ParserContext& context) -> void {
if (!state.has_error) {
context.emitter().Emit(*context.position(), ExpectedThenAfterIf);
}
// Add placeholders for `then expression else expression`.
for (int i = 0; i != 4; ++i) {
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
}
// Add placeholders for `IfExpressionThen` and final `Expression`.
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
context.ReturnErrorOnState();
}
}
auto ParserHandleExpressionElse(ParserContext& context) -> void {
auto ParserHandleIfExpressionFinishThen(ParserContext& context) -> void {
auto state = context.PopState();
if (context.ConsumeAndAddLeafNodeIf(TokenKind::Else,
ParseNodeKind::IfExpressionElse)) {
context.AddNode(ParseNodeKind::IfExpressionThen, state.token,
state.subtree_start, state.has_error);
if (context.PositionIs(TokenKind::Else)) {
context.PushState(ParserState::IfExpressionFinishElse);
context.ConsumeChecked(TokenKind::Else);
context.PushStateForExpression(*PrecedenceGroup::ForLeading(TokenKind::If));
} else {
// TODO: Include the location of the `if` token.
@@ -245,20 +253,28 @@ auto ParserHandleExpressionElse(ParserContext& context) -> void {
if (!state.has_error) {
context.emitter().Emit(*context.position(), ExpectedElseAfterIf);
}
// Add placeholders for `else expression`.
for (int i = 0; i != 2; ++i) {
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
}
// Add placeholder for the final `Expression`.
context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
context.ReturnErrorOnState();
}
}
auto ParserHandleExpressionIfFinish(ParserContext& context) -> void {
auto ParserHandleIfExpressionFinishElse(ParserContext& context) -> void {
auto else_state = context.PopState();
// Propagate the location of `else`.
auto if_state = context.PopState();
if_state.token = else_state.token;
if_state.has_error |= else_state.has_error;
context.PushState(if_state);
}
auto ParserHandleIfExpressionFinish(ParserContext& context) -> void {
auto state = context.PopState();
context.AddNode(ParseNodeKind::IfExpression, state.token, state.subtree_start,
state.has_error);
context.AddNode(ParseNodeKind::IfExpressionElse, state.token,
state.subtree_start, state.has_error);
}
auto ParserHandleExpressionStatementFinish(ParserContext& context) -> void {
+28 -20
View File
@@ -183,8 +183,8 @@ CARBON_PARSER_STATE_VARIANTS2(Designator, Expression, Struct)
//
// If `If`:
// 1. Expression
// 2. ExpressionThen
// 3. ExpressionIfFinish
// 2. IfExpressionCondition
// 3. IfExpressionFinish
// Else if valid prefix operator:
// 1. Expression
// 2. ExpressionLoopForPrefix
@@ -246,28 +246,36 @@ CARBON_PARSER_STATE(ExpressionLoopForBinary)
// 1. ExpressionLoop
CARBON_PARSER_STATE(ExpressionLoopForPrefix)
// Completes the condition of an `if` expression and handles the `then` token.
//
// If `Then`:
// 1. Expression
// 2. IfExpressionFinishThen
// Else:
// (state done)
CARBON_PARSER_STATE(IfExpressionFinishCondition)
// Completes the first alternative in an `if` expression and handles the `else`
// token.
//
// If `Else`:
// 1. Expression
// 2. IfExpressionFinishElse
// Else:
// (state done)
CARBON_PARSER_STATE(IfExpressionFinishThen)
// Completes the second alternative in an `if` expression.
//
// Always:
// (state done)
CARBON_PARSER_STATE(IfExpressionFinishElse)
// Completes an IfExpression.
//
// Always:
// (state done)
CARBON_PARSER_STATE(ExpressionIfFinish)
// Handles the `then` token in an `if` expression.
//
// If `Then`:
// 1. Expression
// 2. ExpressionElse
// Else:
// (state done)
CARBON_PARSER_STATE(ExpressionThen)
// Handles the `else` token in an `if` expression.
//
// If `Else`:
// 1. Expression
// Else:
// (state done)
CARBON_PARSER_STATE(ExpressionElse)
CARBON_PARSER_STATE(IfExpressionFinish)
// Handles the `;` for an expression statement, which is different from most
// keyword statements.
+7 -7
View File
@@ -8,7 +8,7 @@
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'},
// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'bool'},
// CHECK:STDOUT: {kind: 'Literal', text: 'bool'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ParameterListComma', text: ','},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'},
@@ -19,16 +19,16 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 13},
// CHECK:STDOUT: {kind: 'NameReference', text: 'bool'},
// CHECK:STDOUT: {kind: 'Literal', text: 'bool'},
// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 18},
// CHECK:STDOUT: {kind: 'ReturnStatementStart', text: 'return'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'x'},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'NameReference', text: 'x'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
// CHECK:STDOUT: {kind: 'NameReference', text: 'y'},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', subtree_size: 6},
// CHECK:STDOUT: {kind: 'ReturnStatement', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 27},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -14,14 +14,13 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', has_error: yes, subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 18},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'if', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 11},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 17},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
@@ -14,12 +14,12 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then'},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 18},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -14,12 +14,12 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then'},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'Literal', text: '1'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 18},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -14,12 +14,12 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', has_error: yes, subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 18},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -14,14 +14,13 @@
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'true'},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 18},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'if', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 11},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 17},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
+11 -11
View File
@@ -8,25 +8,25 @@
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'},
// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'bool'},
// CHECK:STDOUT: {kind: 'Literal', text: 'bool'},
// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'NameReference', text: 'bool'},
// CHECK:STDOUT: {kind: 'Literal', text: 'bool'},
// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 10},
// CHECK:STDOUT: {kind: 'ReturnStatementStart', text: 'return'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'InfixOperator', text: 'and', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'InfixOperator', text: 'and', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'InfixOperator', text: 'and', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 4},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'InfixOperator', text: 'and', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 4},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'NameReference', text: 'b'},
// CHECK:STDOUT: {kind: 'InfixOperator', text: 'or', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IfExpression', text: 'if', subtree_size: 12},
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', subtree_size: 12},
// CHECK:STDOUT: {kind: 'ReturnStatement', text: ';', subtree_size: 14},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 25},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -50,6 +50,9 @@ CARBON_SEMANTICS_BUILTIN_KIND(InvalidType, "<unknown>")
// Keeping distinct placeholders can help find usages for later fixes.
// -----------------------------------------------------------------------------
// The type of bool literals and branch conditions, bool.
CARBON_SEMANTICS_BUILTIN_KIND(BoolType, "bool")
// The type of integer values and integer literals, currently always i32.
CARBON_SEMANTICS_BUILTIN_KIND(IntegerType, "i32")
+5 -1
View File
@@ -61,7 +61,11 @@ auto SemanticsContext::VerifyOnFinish() -> void {
}
auto SemanticsContext::AddNode(SemanticsNode node) -> SemanticsNodeId {
auto block = node_block_stack_.PeekForAdd();
return AddNodeToBlock(node_block_stack_.PeekForAdd(), node);
}
auto SemanticsContext::AddNodeToBlock(SemanticsNodeBlockId block,
SemanticsNode node) -> SemanticsNodeId {
CARBON_VLOG() << "AddNode " << block << ": " << node << "\n";
return semantics_ir_->AddNode(block, node);
}
+4
View File
@@ -35,6 +35,10 @@ class SemanticsContext {
// Adds a node to the current block, returning the produced ID.
auto AddNode(SemanticsNode node) -> SemanticsNodeId;
// Adds a node to the given block, returning the produced ID.
auto AddNodeToBlock(SemanticsNodeBlockId block, SemanticsNode node)
-> SemanticsNodeId;
// Pushes a parse tree node onto the stack, storing the SemanticsNode as the
// result.
auto AddNodeAndPush(ParseTree::Node parse_node, SemanticsNode node) -> void;
+4 -15
View File
@@ -178,21 +178,6 @@ auto SemanticsHandleIfConditionStart(SemanticsContext& context,
return context.TODO(parse_node, "HandleIfConditionStart");
}
auto SemanticsHandleIfExpression(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
return context.TODO(parse_node, "HandleIfExpression");
}
auto SemanticsHandleIfExpressionElse(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
return context.TODO(parse_node, "HandleIfExpressionElse");
}
auto SemanticsHandleIfExpressionThen(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
return context.TODO(parse_node, "HandleIfExpressionThen");
}
auto SemanticsHandleIfStatement(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
return context.TODO(parse_node, "HandleIfStatement");
@@ -275,6 +260,10 @@ auto SemanticsHandleLiteral(SemanticsContext& context,
id));
break;
}
case TokenKind::Bool: {
context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinBoolType);
break;
}
case TokenKind::IntegerTypeLiteral: {
auto text = context.tokens().GetTokenText(token);
if (text != "i32") {
@@ -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);
@@ -0,0 +1,77 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/semantics/semantics_context.h"
namespace Carbon {
auto SemanticsHandleIfExpressionIf(SemanticsContext& context,
ParseTree::Node if_node) -> bool {
auto cond_value_id = context.node_stack().Pop<SemanticsNodeId>();
context.node_stack().Push(if_node);
// Convert the condition to `bool`.
cond_value_id = context.ImplicitAsRequired(
if_node, cond_value_id,
context.CanonicalizeType(SemanticsNodeId::BuiltinBoolType));
// Stop emitting the current block. We'll add some branch instructions to it
// later, but we don't want it on the stack any more.
auto if_block_id = context.node_block_stack().PeekForAdd();
context.node_block_stack().Pop();
// Create the resumption block, `else` block, and `then` block, and branches
// to them.
context.node_block_stack().Push();
auto else_block_id = context.node_block_stack().PushForAdd();
auto then_block_id = context.node_block_stack().PushForAdd();
context.AddNodeToBlock(
if_block_id,
SemanticsNode::BranchIf::Make(if_node, then_block_id, cond_value_id));
context.AddNodeToBlock(if_block_id,
SemanticsNode::Branch::Make(if_node, else_block_id));
return true;
}
auto SemanticsHandleIfExpressionThen(SemanticsContext& context,
ParseTree::Node then_node) -> bool {
context.node_stack().Push(then_node, context.node_block_stack().Pop());
return true;
}
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);
auto then_value_id = context.node_stack().Pop<SemanticsNodeId>();
auto if_node =
context.node_stack().PopForSoloParseNode(ParseNodeKind::IfExpressionIf);
// Convert the `else` value to the `then` value's type, and finish the `else`
// block.
// TODO: Find a common type, and convert both operands to it instead.
auto result_type_id = context.semantics_ir().GetNode(then_value_id).type_id();
else_value_id =
context.ImplicitAsRequired(else_node, else_value_id, result_type_id);
auto else_end_block_id = context.node_block_stack().Pop();
// Create branches to the resumption block.
auto resume_block_id = context.node_block_stack().PeekForAdd();
context.AddNodeToBlock(then_end_block_id,
SemanticsNode::BranchWithArg::Make(
then_node, resume_block_id, then_value_id));
context.AddNodeToBlock(else_end_block_id,
SemanticsNode::BranchWithArg::Make(
else_node, resume_block_id, else_value_id));
// Obtain the value in the resumption block and push it.
context.AddNodeAndPush(
if_node, SemanticsNode::BlockArg::Make(if_node, result_type_id));
return true;
}
} // namespace Carbon
+4
View File
@@ -198,6 +198,10 @@ auto SemanticsIR::StringifyType(SemanticsTypeId type_id) -> std::string {
case SemanticsNodeKind::Assign:
case SemanticsNodeKind::BinaryOperatorAdd:
case SemanticsNodeKind::BindName:
case SemanticsNodeKind::BlockArg:
case SemanticsNodeKind::Branch:
case SemanticsNodeKind::BranchIf:
case SemanticsNodeKind::BranchWithArg:
case SemanticsNodeKind::Builtin:
case SemanticsNodeKind::Call:
case SemanticsNodeKind::CodeBlock:
+13
View File
@@ -262,6 +262,19 @@ class SemanticsNode {
SemanticsStringId /*name_id*/,
SemanticsNodeId /*node_id*/>;
using BlockArg = Factory<SemanticsNodeKind::BlockArg>;
using Branch = FactoryNoType<SemanticsNodeKind::Branch,
SemanticsNodeBlockId /*target_id*/>;
using BranchIf = FactoryNoType<SemanticsNodeKind::BranchIf,
SemanticsNodeBlockId /*target_id*/,
SemanticsNodeId /*cond_id*/>;
using BranchWithArg = FactoryNoType<SemanticsNodeKind::BranchWithArg,
SemanticsNodeBlockId /*target_id*/,
SemanticsNodeId /*arg*/>;
class Builtin {
public:
static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsTypeId type_id)
@@ -27,6 +27,12 @@ class SemanticsNodeBlockStack {
// order to support lazy allocation.
auto Push() -> void;
// Allocates and pushes a new node block.
auto PushForAdd() -> SemanticsNodeBlockId {
Push();
return PeekForAdd();
}
// Peeks at the top node block. This does not trigger lazy allocation, so the
// returned node block may be invalid.
auto Peek() -> SemanticsNodeBlockId { return stack_.back(); }
@@ -23,6 +23,10 @@ CARBON_SEMANTICS_NODE_KIND(CrossReference)
CARBON_SEMANTICS_NODE_KIND(Assign)
CARBON_SEMANTICS_NODE_KIND(BinaryOperatorAdd)
CARBON_SEMANTICS_NODE_KIND(BindName)
CARBON_SEMANTICS_NODE_KIND(BlockArg)
CARBON_SEMANTICS_NODE_KIND(Branch)
CARBON_SEMANTICS_NODE_KIND(BranchIf)
CARBON_SEMANTICS_NODE_KIND(BranchWithArg)
CARBON_SEMANTICS_NODE_KIND(Builtin)
CARBON_SEMANTICS_NODE_KIND(Call)
CARBON_SEMANTICS_NODE_KIND(CodeBlock)
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -26,6 +26,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Main() {
@@ -5,10 +5,10 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block3, body: block0},
// CHECK:STDOUT: {name: str4, param_refs: block5, body: block0},
// CHECK:STDOUT: {name: str5, param_refs: block0, body: block6},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str2, param_refs: block4, body: block5},
// CHECK:STDOUT: {name: str4, param_refs: block7, body: block8},
// CHECK:STDOUT: {name: str5, param_refs: block0, body: block9},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -66,6 +66,8 @@
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
@@ -73,6 +75,8 @@
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -83,6 +87,8 @@
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+12,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -46,6 +46,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str3, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str4, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str4, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -50,7 +50,7 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+16, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int5, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+18, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -73,6 +73,8 @@
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -29,7 +29,7 @@
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -46,6 +46,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -30,10 +30,10 @@
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block7, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -50,6 +50,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -35,7 +35,7 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -55,6 +55,8 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -37,12 +37,12 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+11, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+13, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block7, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -62,6 +62,8 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block3},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -32,6 +32,8 @@
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -42,6 +42,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDERR: fail_param_name_conflict.carbon:[[@LINE+2]]:16: Redefining a in the same scope.
@@ -5,9 +5,9 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block3},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -34,6 +34,12 @@
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo() {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -37,6 +37,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -37,6 +37,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32,) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -43,6 +43,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32, b: i32) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -43,6 +43,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32, b: i32,) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -26,6 +26,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo() {}
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block5, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block6, body: block7},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -44,12 +44,16 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32) {}
+80
View File
@@ -0,0 +1,80 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str3, param_refs: block2, return_type: type1, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: b,
// CHECK:STDOUT: n,
// CHECK:STDOUT: m,
// CHECK:STDOUT: F,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
// CHECK:STDOUT: nodeBoolType,
// CHECK:STDOUT: nodeIntegerType,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: VarStorage, type: type0},
// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: type0},
// CHECK:STDOUT: {kind: VarStorage, type: type1},
// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: type1},
// CHECK:STDOUT: {kind: VarStorage, type: type1},
// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+4, type: type1},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: BranchIf, arg0: block6, arg1: node+0},
// CHECK:STDOUT: {kind: Branch, arg0: block5},
// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+2, arg1: node+4, type: type1},
// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+4, arg1: node+2, type: type1},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+9},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+10},
// CHECK:STDOUT: {kind: BlockArg, type: type1},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+13, type: type1},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+12,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+13,
// CHECK:STDOUT: node+14,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn F(b: bool, n: i32, m: i32) -> i32 {
return if b then n + m else m + n;
}
@@ -0,0 +1,93 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, return_type: type0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, return_type: type0, body: block3},
// CHECK:STDOUT: {name: str3, param_refs: block5, return_type: type0, body: block6},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
// CHECK:STDOUT: 2,
// CHECK:STDOUT: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: A,
// CHECK:STDOUT: B,
// CHECK:STDOUT: b,
// CHECK:STDOUT: F,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
// CHECK:STDOUT: nodeIntegerType,
// CHECK:STDOUT: nodeBoolType,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+1, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: VarStorage, type: type1},
// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+6, type: type1},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function2},
// CHECK:STDOUT: {kind: BranchIf, arg0: block8, arg1: node+6},
// CHECK:STDOUT: {kind: Branch, arg0: block7},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function0, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+11},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+12},
// CHECK:STDOUT: {kind: BlockArg, type: type0},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+15, type: type0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+12,
// CHECK:STDOUT: node+14,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+13,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+15,
// CHECK:STDOUT: node+16,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn A() -> i32 { return 1; }
fn B() -> i32 { return 2; }
fn F(b: bool) -> i32 {
return if b then A() else B();
}
+120
View File
@@ -0,0 +1,120 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str3, param_refs: block2, return_type: type1, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
// CHECK:STDOUT: 2,
// CHECK:STDOUT: 3,
// CHECK:STDOUT: 4,
// CHECK:STDOUT: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: a,
// CHECK:STDOUT: b,
// CHECK:STDOUT: c,
// CHECK:STDOUT: F,
// CHECK:STDOUT: ]
// CHECK:STDOUT: types: [
// CHECK:STDOUT: nodeBoolType,
// CHECK:STDOUT: nodeIntegerType,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: VarStorage, type: type0},
// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: type0},
// CHECK:STDOUT: {kind: VarStorage, type: type0},
// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: type0},
// CHECK:STDOUT: {kind: VarStorage, type: type0},
// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+4, type: type0},
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0},
// CHECK:STDOUT: {kind: BranchIf, arg0: block6, arg1: node+0},
// CHECK:STDOUT: {kind: Branch, arg0: block5},
// CHECK:STDOUT: {kind: BranchIf, arg0: block8, arg1: node+2},
// CHECK:STDOUT: {kind: Branch, arg0: block7},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type1},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+11},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+12},
// CHECK:STDOUT: {kind: BlockArg, type: type1},
// CHECK:STDOUT: {kind: BranchIf, arg0: block11, arg1: node+4},
// CHECK:STDOUT: {kind: Branch, arg0: block10},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: type1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: type1},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block12, arg1: node+18},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block12, arg1: node+19},
// CHECK:STDOUT: {kind: BlockArg, type: type1},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block13, arg1: node+15},
// CHECK:STDOUT: {kind: BranchWithArg, arg0: block13, arg1: node+22},
// CHECK:STDOUT: {kind: BlockArg, type: type1},
// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+25, type: type1},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+16,
// CHECK:STDOUT: node+17,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+12,
// CHECK:STDOUT: node+14,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+13,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+15,
// CHECK:STDOUT: node+23,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+19,
// CHECK:STDOUT: node+21,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+18,
// CHECK:STDOUT: node+20,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+22,
// CHECK:STDOUT: node+24,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+25,
// CHECK:STDOUT: node+26,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn F(a: bool, b: bool, c: bool) -> i32 {
return if a then if b then 1 else 2 else if c then 3 else 4;
}