From 2adaeee2baff5a2a32d553539386ad2b3be01803 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Wed, 22 Feb 2023 11:55:32 -0800 Subject: [PATCH] Add handling for return types. (#2596) This starts handling return types on functions, and comparing types with `return` statements. Note, errors remain poor because the type literal is currently associated with a builtin, losing the parse_node that specified it. This means we don't have the original source location to associate with, even though it may be helpful to point at the type in source. We could point at the signature overall, but my leaning is that we wouldn't want that long-term, so TODOs for now and may want to change a little about how the parse node is tracked once things are a little further along. --- toolchain/diagnostics/diagnostic_kind.def | 4 ++ toolchain/semantics/BUILD | 1 + toolchain/semantics/semantics_ir.h | 37 +++++++---- .../semantics_parse_tree_handler.cpp | 66 +++++++++++++++++-- .../semantics/semantics_parse_tree_handler.h | 7 ++ .../testdata/operators/binary_op.carbon | 4 +- .../operators/fail_type_mismatch.carbon | 4 +- .../operators/fail_type_mismatch_once.carbon | 4 +- .../testdata/return/fail_type_mismatch.carbon | 52 +++++++++++++++ .../return/fail_value_disallowed.carbon | 53 +++++++++++++++ .../testdata/return/fail_value_missing.carbon | 49 ++++++++++++++ .../{trivial.carbon => no_value.carbon} | 0 .../return/{literal.carbon => value.carbon} | 4 +- 13 files changed, 259 insertions(+), 26 deletions(-) create mode 100644 toolchain/semantics/testdata/return/fail_type_mismatch.carbon create mode 100644 toolchain/semantics/testdata/return/fail_value_disallowed.carbon create mode 100644 toolchain/semantics/testdata/return/fail_value_missing.carbon rename toolchain/semantics/testdata/return/{trivial.carbon => no_value.carbon} (100%) rename toolchain/semantics/testdata/return/{literal.carbon => value.carbon} (95%) 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; }