Files
carbon-lang/toolchain/check/name_component.cpp
T
Richard Smith bf5d2a2ace Add support for -> auto deduced return types. (#7931)
The return type is deduced from the function's `return` statements
(currently required to all have the same type), or from its first
`returned var`. Calls to generic functions with deduced return types are
not yet supported.

When a function has a deduced return type, we defer the return type
portion of the callee pattern match until deduction, and during
deduction we extend the decl block and the pattern block with the
return-related instructions.

Conversions for `return expr;` statements are deferred until the return
type has been deduced. The design requires that we take the common type
of the returned types as the deduced return type, so we can't in general
perform any conversions for returned expressions until we reach the end
of the function. This is accomplished by inserting a `splice_block`
where the conversions will go, and later updating that instruction to
contain the conversion.

Assisted-by: Claude Opus 5.5 via Antigravity
2026-10-15 00:30:09 +00:00

104 lines
4.1 KiB
C++

// 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/check/name_component.h"
#include "toolchain/check/context.h"
#include "toolchain/check/pattern_match.h"
namespace Carbon::Check {
auto PopNameComponent(Context& context, SemIR::InstId return_pattern_id,
bool has_return_specifier) -> NameComponent {
CARBON_CHECK(has_return_specifier || !return_pattern_id.has_value());
Parse::NodeId first_param_node_id = Parse::NoneNodeId();
Parse::NodeId last_param_node_id = Parse::NoneNodeId();
// Explicit params.
auto [params_node_id, param_patterns_id] =
context.node_stack()
.PopWithNodeIdIf<Parse::NodeKind::ExplicitParamList>();
if (param_patterns_id) {
first_param_node_id =
context.node_stack()
.PopForSoloNodeId<Parse::NodeKind::ExplicitParamListStart>();
last_param_node_id = params_node_id;
} else {
param_patterns_id = SemIR::InstBlockId::None;
}
// Implicit params.
auto [implicit_params_node_id, implicit_param_patterns_id] =
context.node_stack()
.PopWithNodeIdIf<Parse::NodeKind::ImplicitParamList>();
if (implicit_param_patterns_id) {
// Implicit params always come before explicit params.
first_param_node_id =
context.node_stack()
.PopForSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
// Only use the end of implicit params if there weren't explicit params.
if (!last_param_node_id.has_value()) {
last_param_node_id = implicit_params_node_id;
}
} else {
implicit_param_patterns_id = SemIR::InstBlockId::None;
}
auto call_param_patterns_id = SemIR::InstBlockId::None;
auto call_params_id = SemIR::InstBlockId::None;
auto param_ranges = SemIR::Function::CallParamIndexRanges::Empty;
auto pattern_block_id = SemIR::InstBlockId::None;
if (param_patterns_id->has_value() ||
implicit_param_patterns_id->has_value() || has_return_specifier) {
auto results = CalleePatternMatch(context, *implicit_param_patterns_id,
*param_patterns_id, return_pattern_id);
call_param_patterns_id = results.call_param_patterns_id;
call_params_id = results.call_params_id;
param_ranges = results.param_ranges;
pattern_block_id = context.pattern_block_stack().Pop();
context.full_pattern_stack().PopFullPattern();
}
auto [name_loc_id, name_id] =
context.node_stack().PopWithNodeId<Parse::NodeCategory::NonExprName>();
return {.name_loc_id = name_loc_id,
.name_id = name_id,
.first_param_node_id = first_param_node_id,
.last_param_node_id = last_param_node_id,
.implicit_params_loc_id = implicit_params_node_id,
.implicit_param_patterns_id = *implicit_param_patterns_id,
.params_loc_id = params_node_id,
.param_patterns_id = *param_patterns_id,
.call_param_patterns_id = call_param_patterns_id,
.call_params_id = call_params_id,
.param_ranges = param_ranges,
.pattern_block_id = pattern_block_id};
}
// Pop the name of a declaration from the node stack, and diagnose if it has
// parameters.
auto PopNameComponentWithoutParams(Context& context, Lex::TokenKind introducer,
bool* diagnosed_params) -> NameComponent {
NameComponent name = PopNameComponent(context);
if (name.call_params_id.has_value()) {
CARBON_DIAGNOSTIC(UnexpectedDeclNameParams, Error,
"`{0}` declaration cannot have parameters",
Lex::TokenKind);
// Point to the lexically first parameter list in the diagnostic.
context.emitter().Emit(name.implicit_param_patterns_id.has_value()
? name.implicit_params_loc_id
: name.params_loc_id,
UnexpectedDeclNameParams, introducer);
name.call_params_id = SemIR::InstBlockId::None;
if (diagnosed_params) {
*diagnosed_params = true;
}
}
return name;
}
} // namespace Carbon::Check