diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 62ed56ff2946..d99ed45d0d8c 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -102,6 +102,10 @@ CARBON_DIAGNOSTIC_KIND(PreviousDefinition) CARBON_DIAGNOSTIC_KIND(NoMatchingCall) CARBON_DIAGNOSTIC_KIND(CallArgCountMismatch) CARBON_DIAGNOSTIC_KIND(CallArgTypeMismatch) +CARBON_DIAGNOSTIC_KIND(ReturnStatementDisallowExpression) +CARBON_DIAGNOSTIC_KIND(ReturnStatementImplicitNote) +CARBON_DIAGNOSTIC_KIND(ReturnStatementMissingExpression) +CARBON_DIAGNOSTIC_KIND(ReturnStatementTypeMismatch) // ============================================================================ // Other diagnostics diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index e1e4c0279f73..1cb8e9801ad5 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -80,6 +80,7 @@ cc_library( "//common:check", "//common:ostream", "//common:vlog", + "//toolchain/diagnostics:diagnostic_kind", "//toolchain/lexer:numeric_literal", "//toolchain/lexer:token_kind", "//toolchain/lexer:tokenized_buffer", diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 20c25931c302..5e5457145e01 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -31,14 +31,20 @@ struct SemanticsCall { // A callable object. struct SemanticsCallable { auto Print(llvm::raw_ostream& out) const -> void { - out << "{param_ir: " << param_ir_id << ", param_refs: " << param_refs_id - << "}"; + out << "{param_ir: " << param_ir_id << ", param_refs: " << param_refs_id; + if (return_type_id.is_valid()) { + out << ", return_type: " << return_type_id; + } + out << "}"; } // The full IR for parameters. SemanticsNodeBlockId param_ir_id; // A block containing a single reference node per parameter. SemanticsNodeBlockId param_refs_id; + // The return type. This will be invalid if the return type wasn't specified. + // The IR corresponding to the return type will be in a node block. + SemanticsNodeId return_type_id; }; struct SemanticsRealLiteral { @@ -83,28 +89,25 @@ class SemanticsIR { node_blocks_.resize(1); } - // Returns the requested node. - auto GetNode(SemanticsNodeId node_id) const -> const SemanticsNode& { - return nodes_[node_id.index]; - } - - // Returns the type of the requested node. - auto GetType(SemanticsNodeId node_id) -> SemanticsNodeId { - return GetNode(node_id).type(); - } - + // Adds a call, returning an ID to reference it. auto AddCall(SemanticsCall call) -> SemanticsCallId { SemanticsCallId id(calls_.size()); calls_.push_back(call); return id; } + // Adds a callable, returning an ID to reference it. auto AddCallable(SemanticsCallable callable) -> SemanticsCallableId { SemanticsCallableId id(callables_.size()); callables_.push_back(callable); return id; } + // Returns the requested callable. + auto GetCallable(SemanticsCallableId callable_id) -> SemanticsCallable { + return callables_[callable_id.index]; + } + // Adds an integer literal, returning an ID to reference it. auto AddIntegerLiteral(llvm::APInt integer_literal) -> SemanticsIntegerLiteralId { @@ -122,6 +125,16 @@ class SemanticsIR { return node_id; } + // Returns the requested node. + auto GetNode(SemanticsNodeId node_id) const -> const SemanticsNode& { + return nodes_[node_id.index]; + } + + // Returns the type of the requested node. + auto GetType(SemanticsNodeId node_id) -> SemanticsNodeId { + return GetNode(node_id).type(); + } + // Adds an empty new node block, returning an ID to reference it and add // items. auto AddNodeBlock() -> SemanticsNodeBlockId { diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index ba293ca24a83..54ae1ba114fa 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -9,6 +9,7 @@ #include "common/vlog.h" #include "llvm/Support/PrettyStackTrace.h" +#include "toolchain/diagnostics/diagnostic_kind.h" #include "toolchain/lexer/token_kind.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" @@ -320,7 +321,7 @@ auto SemanticsParseTreeHandler::HandleCallExpression(ParseTree::Node parse_node) } auto callable_id = name_node.GetAsFunctionDeclaration(); - auto callable = semantics_->callables_[callable_id.index]; + auto callable = semantics_->GetCallable(callable_id); if (!TryTypeConversionOnArgs(call_expr_parse_node, ir_id, refs_id, name_node.parse_node(), @@ -474,6 +475,7 @@ auto SemanticsParseTreeHandler::HandleFunctionDefinition( auto decl_id = node_stack_.PopForNodeId(ParseNodeKind::FunctionDefinitionStart); + return_scope_stack_.pop_back(); PopScope(); auto block_id = node_block_stack_.Pop(); AddNode(SemanticsNode::MakeFunctionDefinition(parse_node, decl_id, block_id)); @@ -484,14 +486,21 @@ auto SemanticsParseTreeHandler::HandleFunctionDefinition( auto SemanticsParseTreeHandler::HandleFunctionDefinitionStart( ParseTree::Node parse_node) -> bool { + SemanticsNodeId return_type_id = SemanticsNodeId::Invalid; + if (parse_tree_->node_kind(node_stack_.PeekParseNode()) == + ParseNodeKind::ReturnType) { + return_type_id = node_stack_.PopForNodeId(ParseNodeKind::ReturnType); + } node_stack_.PopForSoloParseNode(ParseNodeKind::ParameterList); auto [param_ir_id, param_refs_id] = finished_params_stack_.pop_back_val(); auto name_node = node_stack_.PopForSoloParseNode(ParseNodeKind::DeclaredName); auto fn_node = node_stack_.PopForSoloParseNode(ParseNodeKind::FunctionIntroducer); - auto callable_id = semantics_->AddCallable( - {.param_ir_id = param_ir_id, .param_refs_id = param_refs_id}); + auto callable_id = + semantics_->AddCallable({.param_ir_id = param_ir_id, + .param_refs_id = param_refs_id, + .return_type_id = return_type_id}); auto decl_id = AddNode(SemanticsNode::MakeFunctionDeclaration(fn_node, callable_id)); // TODO: Propagate the type of the function. @@ -499,6 +508,7 @@ auto SemanticsParseTreeHandler::HandleFunctionDefinitionStart( node_block_stack_.Push(); PushScope(); + return_scope_stack_.push_back(decl_id); node_stack_.Push(parse_node, decl_id); return true; @@ -772,14 +782,57 @@ auto SemanticsParseTreeHandler::HandlePrefixOperator(ParseTree::Node parse_node) auto SemanticsParseTreeHandler::HandleReturnStatement( ParseTree::Node parse_node) -> bool { + CARBON_CHECK(!return_scope_stack_.empty()); + const auto& fn_node = semantics_->GetNode(return_scope_stack_.back()); + const auto callable = + semantics_->GetCallable(fn_node.GetAsFunctionDeclaration()); + if (parse_tree_->node_kind(node_stack_.PeekParseNode()) == ParseNodeKind::ReturnStatementStart) { node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ReturnStatementStart); + + if (callable.return_type_id.is_valid()) { + // TODO: Stringify types, add a note pointing at the return + // type's parse node. + CARBON_DIAGNOSTIC(ReturnStatementMissingExpression, Error, + "Must return a {0}.", SemanticsNodeId); + emitter_ + ->Build(parse_node, ReturnStatementMissingExpression, + callable.return_type_id) + .Emit(); + } + AddNodeAndPush(parse_node, SemanticsNode::MakeReturn(parse_node)); } else { - auto arg = node_stack_.PopForNodeId(); + const auto arg = node_stack_.PopForNodeId(); auto arg_type = semantics_->GetType(arg); node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ReturnStatementStart); + + if (!callable.return_type_id.is_valid()) { + CARBON_DIAGNOSTIC( + ReturnStatementDisallowExpression, Error, + "No return expression should be provided in this context."); + CARBON_DIAGNOSTIC(ReturnStatementImplicitNote, Note, + "There was no return type provided."); + emitter_->Build(parse_node, ReturnStatementDisallowExpression) + .Note(fn_node.parse_node(), ReturnStatementImplicitNote) + .Emit(); + } else { + const auto new_type = CanTypeConvert(arg_type, callable.return_type_id); + if (!new_type.is_valid()) { + // TODO: Stringify types, add a note pointing at the return + // type's parse node. + CARBON_DIAGNOSTIC(ReturnStatementTypeMismatch, Error, + "Cannot convert {0} to {1}.", SemanticsNodeId, + SemanticsNodeId); + emitter_ + ->Build(parse_node, ReturnStatementTypeMismatch, arg_type, + callable.return_type_id) + .Emit(); + } + arg_type = new_type; + } + AddNodeAndPush(parse_node, SemanticsNode::MakeReturnExpression( parse_node, arg_type, arg)); } @@ -795,8 +848,9 @@ auto SemanticsParseTreeHandler::HandleReturnStatementStart( auto SemanticsParseTreeHandler::HandleReturnType(ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleReturnType"); - return false; + // Propagate the type expression. + node_stack_.Push(parse_node, node_stack_.PopForNodeId()); + return true; } auto SemanticsParseTreeHandler::HandleSelfDeducedParameter( diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_parse_tree_handler.h index b3989098f627..f007b2b261a7 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -168,9 +168,16 @@ class SemanticsParseTreeHandler { // node in blocks here. SemanticsNodeBlockStack params_or_args_stack_; + // Completed parameters that are held temporarily on a side-channel for a + // function. This can't use node_stack_ because it has space for only one + // value, whereas parameters return two values. llvm::SmallVector> finished_params_stack_; + // A stack of return scopes; i.e., targets for `return`. Inside a function, + // this will be a FunctionDeclaration. + llvm::SmallVector return_scope_stack_; + // A stack for scope context. llvm::SmallVector scope_stack_; diff --git a/toolchain/semantics/testdata/operators/binary_op.carbon b/toolchain/semantics/testdata/operators/binary_op.carbon index c510c5c51a71..302886f8659b 100644 --- a/toolchain/semantics/testdata/operators/binary_op.carbon +++ b/toolchain/semantics/testdata/operators/binary_op.carbon @@ -8,7 +8,7 @@ // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] // CHECK:STDOUT: callables: [ -// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 12, @@ -51,6 +51,6 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -fn Main() { +fn Main() -> i32 { return 12 + 34; } diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon index 617d5a8362a8..a031b830dc12 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon @@ -8,7 +8,7 @@ // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] // CHECK:STDOUT: callables: [ -// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 12, @@ -51,7 +51,7 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -fn Main() { +fn Main() -> i32 { // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node2, rhs is node3 return 12 + 3.4; } diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon index 15deed323a8b..a6c985504c73 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon @@ -8,7 +8,7 @@ // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] // CHECK:STDOUT: callables: [ -// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 12, @@ -56,7 +56,7 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -fn Main() { +fn Main() -> i32 { // The following line has two mismatches, but after the first, it shouldn't // keep erroring. // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node2, rhs is node3 diff --git a/toolchain/semantics/testdata/return/fail_type_mismatch.carbon b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon new file mode 100644 index 000000000000..938b0b5a8648 --- /dev/null +++ b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon @@ -0,0 +1,52 @@ +// 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 +// RUN: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: {mantissa: 10, exponent: -1, is_decimal: 1}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: Main, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node0, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node1, type: node1}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node2, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node3, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node4, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node5, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node6, type: node5}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: callable0}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node7}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: node3}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node9}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node7, arg1: block2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node7, +// CHECK:STDOUT: node8, +// CHECK:STDOUT: node11, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node9, +// CHECK:STDOUT: node10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +fn Main() -> i32 { + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_type_mismatch.carbon:[[@LINE+1]]:13: Cannot convert node3 to node2. + return 1.0; +} diff --git a/toolchain/semantics/testdata/return/fail_value_disallowed.carbon b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon new file mode 100644 index 000000000000..441080d13334 --- /dev/null +++ b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon @@ -0,0 +1,53 @@ +// 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 +// RUN: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 0, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: Main, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node0, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node1, type: node1}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node2, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node3, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node4, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node5, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node6, type: node5}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: callable0}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node7}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: node2}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node9, type: node2}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node7, arg1: block2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node7, +// CHECK:STDOUT: node8, +// CHECK:STDOUT: node11, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node9, +// CHECK:STDOUT: node10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +fn Main() { + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE+2]]:11: No return expression should be provided in this context. + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE-2]]:1: There was no return type provided. + return 0; +} diff --git a/toolchain/semantics/testdata/return/fail_value_missing.carbon b/toolchain/semantics/testdata/return/fail_value_missing.carbon new file mode 100644 index 000000000000..82154a3a9a50 --- /dev/null +++ b/toolchain/semantics/testdata/return/fail_value_missing.carbon @@ -0,0 +1,49 @@ +// 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 +// RUN: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: Main, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node0, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node1, type: node1}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node2, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node3, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node4, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node5, type: node0}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: node6, type: node5}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: callable0}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node7}, +// CHECK:STDOUT: {kind: Return}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node7, arg1: block2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node7, +// CHECK:STDOUT: node8, +// CHECK:STDOUT: node10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node9, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +fn Main() -> i32 { + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_missing.carbon:[[@LINE+1]]:9: Must return a node2. + return; +} diff --git a/toolchain/semantics/testdata/return/trivial.carbon b/toolchain/semantics/testdata/return/no_value.carbon similarity index 100% rename from toolchain/semantics/testdata/return/trivial.carbon rename to toolchain/semantics/testdata/return/no_value.carbon diff --git a/toolchain/semantics/testdata/return/literal.carbon b/toolchain/semantics/testdata/return/value.carbon similarity index 95% rename from toolchain/semantics/testdata/return/literal.carbon rename to toolchain/semantics/testdata/return/value.carbon index 71e77b4d1584..af072dbcbf47 100644 --- a/toolchain/semantics/testdata/return/literal.carbon +++ b/toolchain/semantics/testdata/return/value.carbon @@ -8,7 +8,7 @@ // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] // CHECK:STDOUT: callables: [ -// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: {param_ir: block0, param_refs: block0, return_type: node2}, // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 0, @@ -46,6 +46,6 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -fn Main() { +fn Main() -> i32 { return 0; }