diff --git a/toolchain/driver/testdata/semantics_builtin_nodes.carbon b/toolchain/driver/testdata/semantics_builtin_nodes.carbon index ba3dfd4756df..75b13af639b8 100644 --- a/toolchain/driver/testdata/semantics_builtin_nodes.carbon +++ b/toolchain/driver/testdata/semantics_builtin_nodes.carbon @@ -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}, diff --git a/toolchain/lexer/token_kind.def b/toolchain/lexer/token_kind.def index 9ce9970625d1..686de1ef4a57 100644 --- a/toolchain/lexer/token_kind.def +++ b/toolchain/lexer/token_kind.def @@ -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") diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp index 88f4666fc66a..0e692dde2444 100644 --- a/toolchain/lowering/lowering_handle.cpp +++ b/toolchain/lowering/lowering_handle.cpp @@ -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 { diff --git a/toolchain/parser/parse_node_kind.def b/toolchain/parser/parse_node_kind.def index 7d628c53666e..0834e04469a4 100644 --- a/toolchain/parser/parse_node_kind.def +++ b/toolchain/parser/parse_node_kind.def @@ -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 diff --git a/toolchain/parser/parser_handle_expression.cpp b/toolchain/parser/parser_handle_expression.cpp index 7bae24ab9deb..e2bba4182303 100644 --- a/toolchain/parser/parser_handle_expression.cpp +++ b/toolchain/parser/parser_handle_expression.cpp @@ -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 { diff --git a/toolchain/parser/parser_state.def b/toolchain/parser/parser_state.def index b570870ba55a..1ef944ea8c1f 100644 --- a/toolchain/parser/parser_state.def +++ b/toolchain/parser/parser_state.def @@ -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. diff --git a/toolchain/parser/testdata/if_expression/basic.carbon b/toolchain/parser/testdata/if_expression/basic.carbon index aaf62427d6d1..c5056c1ee66c 100644 --- a/toolchain/parser/testdata/if_expression/basic.carbon +++ b/toolchain/parser/testdata/if_expression/basic.carbon @@ -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: ''}, diff --git a/toolchain/parser/testdata/if_expression/fail_condition_missing.carbon b/toolchain/parser/testdata/if_expression/fail_condition_missing.carbon index c8fc41f10493..7197aad32a35 100644 --- a/toolchain/parser/testdata/if_expression/fail_condition_missing.carbon +++ b/toolchain/parser/testdata/if_expression/fail_condition_missing.carbon @@ -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: ] diff --git a/toolchain/parser/testdata/if_expression/fail_else_expr_missing.carbon b/toolchain/parser/testdata/if_expression/fail_else_expr_missing.carbon index 021332457980..0b817742042d 100644 --- a/toolchain/parser/testdata/if_expression/fail_else_expr_missing.carbon +++ b/toolchain/parser/testdata/if_expression/fail_else_expr_missing.carbon @@ -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: ''}, diff --git a/toolchain/parser/testdata/if_expression/fail_else_missing.carbon b/toolchain/parser/testdata/if_expression/fail_else_missing.carbon index 23fcaa30a067..336663d19ed5 100644 --- a/toolchain/parser/testdata/if_expression/fail_else_missing.carbon +++ b/toolchain/parser/testdata/if_expression/fail_else_missing.carbon @@ -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: ''}, diff --git a/toolchain/parser/testdata/if_expression/fail_then_expr_missing.carbon b/toolchain/parser/testdata/if_expression/fail_then_expr_missing.carbon index 3c78e4d1e3e5..ec136930c384 100644 --- a/toolchain/parser/testdata/if_expression/fail_then_expr_missing.carbon +++ b/toolchain/parser/testdata/if_expression/fail_then_expr_missing.carbon @@ -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: ''}, diff --git a/toolchain/parser/testdata/if_expression/fail_then_missing.carbon b/toolchain/parser/testdata/if_expression/fail_then_missing.carbon index e6ad066d67b6..e26ef9042753 100644 --- a/toolchain/parser/testdata/if_expression/fail_then_missing.carbon +++ b/toolchain/parser/testdata/if_expression/fail_then_missing.carbon @@ -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: ] diff --git a/toolchain/parser/testdata/if_expression/precedence.carbon b/toolchain/parser/testdata/if_expression/precedence.carbon index d2c5dc990794..e69ff6eceb51 100644 --- a/toolchain/parser/testdata/if_expression/precedence.carbon +++ b/toolchain/parser/testdata/if_expression/precedence.carbon @@ -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: ''}, diff --git a/toolchain/semantics/semantics_builtin_kind.def b/toolchain/semantics/semantics_builtin_kind.def index c283024fa6bb..f54cbe9d6a32 100644 --- a/toolchain/semantics/semantics_builtin_kind.def +++ b/toolchain/semantics/semantics_builtin_kind.def @@ -50,6 +50,9 @@ CARBON_SEMANTICS_BUILTIN_KIND(InvalidType, "") // 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") diff --git a/toolchain/semantics/semantics_context.cpp b/toolchain/semantics/semantics_context.cpp index 412b4340991c..dd240e7144c3 100644 --- a/toolchain/semantics/semantics_context.cpp +++ b/toolchain/semantics/semantics_context.cpp @@ -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); } diff --git a/toolchain/semantics/semantics_context.h b/toolchain/semantics/semantics_context.h index ad0b373673e9..d44cc4efbb87 100644 --- a/toolchain/semantics/semantics_context.h +++ b/toolchain/semantics/semantics_context.h @@ -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; diff --git a/toolchain/semantics/semantics_handle.cpp b/toolchain/semantics/semantics_handle.cpp index 7c89cbb2d6f4..eafc8cfa6697 100644 --- a/toolchain/semantics/semantics_handle.cpp +++ b/toolchain/semantics/semantics_handle.cpp @@ -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") { diff --git a/toolchain/semantics/semantics_handle_function.cpp b/toolchain/semantics/semantics_handle_function.cpp index 9fe0de7bcece..029429dfc9a9 100644 --- a/toolchain/semantics/semantics_handle_function.cpp +++ b/toolchain/semantics/semantics_handle_function.cpp @@ -18,17 +18,10 @@ auto SemanticsHandleFunctionDefinition(SemanticsContext& context, ParseNodeKind::FunctionDefinitionStart) { context.node_stack().PopAndIgnore(); } - auto function_id = context.node_stack().Pop( - 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); diff --git a/toolchain/semantics/semantics_handle_if_expression.cpp b/toolchain/semantics/semantics_handle_if_expression.cpp new file mode 100644 index 000000000000..5294670c9aef --- /dev/null +++ b/toolchain/semantics/semantics_handle_if_expression.cpp @@ -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(); + + 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(); + auto [then_node, then_end_block_id] = + context.node_stack().PopWithParseNode( + ParseNodeKind::IfExpressionThen); + auto then_value_id = context.node_stack().Pop(); + 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 diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index 6df1cc559920..2d2a33d0d181 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -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: diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 6b05de13470e..521ac631040c 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -262,6 +262,19 @@ class SemanticsNode { SemanticsStringId /*name_id*/, SemanticsNodeId /*node_id*/>; + using BlockArg = Factory; + + using Branch = FactoryNoType; + + using BranchIf = FactoryNoType; + + using BranchWithArg = FactoryNoType; + class Builtin { public: static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsTypeId type_id) diff --git a/toolchain/semantics/semantics_node_block_stack.h b/toolchain/semantics/semantics_node_block_stack.h index 7a724b0cebf8..3d850bca0c83 100644 --- a/toolchain/semantics/semantics_node_block_stack.h +++ b/toolchain/semantics/semantics_node_block_stack.h @@ -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(); } diff --git a/toolchain/semantics/semantics_node_kind.def b/toolchain/semantics/semantics_node_kind.def index 784e222a9ae1..b70903dbfd23 100644 --- a/toolchain/semantics/semantics_node_kind.def +++ b/toolchain/semantics/semantics_node_kind.def @@ -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) diff --git a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon index 9fed8695edf8..439b679f61fa 100644 --- a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon +++ b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon @@ -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() { diff --git a/toolchain/semantics/testdata/function/call/fail_param_count.carbon b/toolchain/semantics/testdata/function/call/fail_param_count.carbon index 1b4162a4885f..c9641dea66ab 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_count.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_count.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/fail_param_type.carbon b/toolchain/semantics/testdata/function/call/fail_param_type.carbon index e83edf36a404..05f87b55c615 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_type.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_type.carbon @@ -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: ], diff --git a/toolchain/semantics/testdata/function/call/more_param_ir.carbon b/toolchain/semantics/testdata/function/call/more_param_ir.carbon index 5a2dfdcb2ff5..4225e5de0583 100644 --- a/toolchain/semantics/testdata/function/call/more_param_ir.carbon +++ b/toolchain/semantics/testdata/function/call/more_param_ir.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/params_one.carbon b/toolchain/semantics/testdata/function/call/params_one.carbon index f4f8e5b1e184..3094c285aed4 100644 --- a/toolchain/semantics/testdata/function/call/params_one.carbon +++ b/toolchain/semantics/testdata/function/call/params_one.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/params_one_comma.carbon b/toolchain/semantics/testdata/function/call/params_one_comma.carbon index 5ac3e2f7e1df..c3923fbcc37b 100644 --- a/toolchain/semantics/testdata/function/call/params_one_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_one_comma.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/params_two.carbon b/toolchain/semantics/testdata/function/call/params_two.carbon index 41beda7f60e1..333fba654a52 100644 --- a/toolchain/semantics/testdata/function/call/params_two.carbon +++ b/toolchain/semantics/testdata/function/call/params_two.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/params_two_comma.carbon b/toolchain/semantics/testdata/function/call/params_two_comma.carbon index 50afe4998794..f65b74d5ad74 100644 --- a/toolchain/semantics/testdata/function/call/params_two_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_two_comma.carbon @@ -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, diff --git a/toolchain/semantics/testdata/function/call/params_zero.carbon b/toolchain/semantics/testdata/function/call/params_zero.carbon index 50ea6007bbc4..111e132ebaa5 100644 --- a/toolchain/semantics/testdata/function/call/params_zero.carbon +++ b/toolchain/semantics/testdata/function/call/params_zero.carbon @@ -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: ] diff --git a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon index 1594468c8510..b09f4457a9bb 100644 --- a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon +++ b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon @@ -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. diff --git a/toolchain/semantics/testdata/function/definition/order.carbon b/toolchain/semantics/testdata/function/definition/order.carbon index 517e6e4b4084..6b25ef48edd3 100644 --- a/toolchain/semantics/testdata/function/definition/order.carbon +++ b/toolchain/semantics/testdata/function/definition/order.carbon @@ -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() {} diff --git a/toolchain/semantics/testdata/function/definition/params_one.carbon b/toolchain/semantics/testdata/function/definition/params_one.carbon index c0169825cd08..0ffe39d4df14 100644 --- a/toolchain/semantics/testdata/function/definition/params_one.carbon +++ b/toolchain/semantics/testdata/function/definition/params_one.carbon @@ -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) {} diff --git a/toolchain/semantics/testdata/function/definition/params_one_comma.carbon b/toolchain/semantics/testdata/function/definition/params_one_comma.carbon index d8f40919a478..88071f7e3489 100644 --- a/toolchain/semantics/testdata/function/definition/params_one_comma.carbon +++ b/toolchain/semantics/testdata/function/definition/params_one_comma.carbon @@ -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,) {} diff --git a/toolchain/semantics/testdata/function/definition/params_two.carbon b/toolchain/semantics/testdata/function/definition/params_two.carbon index 0e1b618101e5..fae5404c628e 100644 --- a/toolchain/semantics/testdata/function/definition/params_two.carbon +++ b/toolchain/semantics/testdata/function/definition/params_two.carbon @@ -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) {} diff --git a/toolchain/semantics/testdata/function/definition/params_two_comma.carbon b/toolchain/semantics/testdata/function/definition/params_two_comma.carbon index b508b2d1ddb7..dd8306af9458 100644 --- a/toolchain/semantics/testdata/function/definition/params_two_comma.carbon +++ b/toolchain/semantics/testdata/function/definition/params_two_comma.carbon @@ -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,) {} diff --git a/toolchain/semantics/testdata/function/definition/params_zero.carbon b/toolchain/semantics/testdata/function/definition/params_zero.carbon index b1fe8b956a8b..2d1be58c2a47 100644 --- a/toolchain/semantics/testdata/function/definition/params_zero.carbon +++ b/toolchain/semantics/testdata/function/definition/params_zero.carbon @@ -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() {} diff --git a/toolchain/semantics/testdata/function/definition/same_param_name.carbon b/toolchain/semantics/testdata/function/definition/same_param_name.carbon index 06ac0f3ae416..63c3d177d347 100644 --- a/toolchain/semantics/testdata/function/definition/same_param_name.carbon +++ b/toolchain/semantics/testdata/function/definition/same_param_name.carbon @@ -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) {} diff --git a/toolchain/semantics/testdata/if_expression/basic.carbon b/toolchain/semantics/testdata/if_expression/basic.carbon new file mode 100644 index 000000000000..ca2c2fe1f11c --- /dev/null +++ b/toolchain/semantics/testdata/if_expression/basic.carbon @@ -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; +} diff --git a/toolchain/semantics/testdata/if_expression/control_flow.carbon b/toolchain/semantics/testdata/if_expression/control_flow.carbon new file mode 100644 index 000000000000..deadb0688725 --- /dev/null +++ b/toolchain/semantics/testdata/if_expression/control_flow.carbon @@ -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(); +} diff --git a/toolchain/semantics/testdata/if_expression/nested.carbon b/toolchain/semantics/testdata/if_expression/nested.carbon new file mode 100644 index 000000000000..da14e4d65702 --- /dev/null +++ b/toolchain/semantics/testdata/if_expression/nested.carbon @@ -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; +}