mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-15 13:28:36 +00:00
Initial support for fn expressions. (#7893)
Support for `fn` expressions with the same feature set as `fn` declarations. In particular, there is no support for captures, positional parameters, `=>` bodies, or `auto` return types. Note that this results in two parse nodes for each `=>` token. That's a bug, but it matches the behavior of function declarations, and will be fixed in a follow-up change. Assisted-by: Gemini via Antigravity
This commit is contained in:
1 parent
66bf1415ac
commit
1b0a5709e6
24 files changed
+2015
-308
No files matched your search
@@ -3,17 +3,144 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/decl_introducer_state.h"
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/pattern_match.h"
|
||||
#include "toolchain/lex/token_kind.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::LambdaIntroducerId node_id)
|
||||
-> bool {
|
||||
return context.TODO(node_id, "HandleLambdaIntroducer");
|
||||
// The function expression is potentially generic.
|
||||
StartGenericDecl(context);
|
||||
StartFunctionSignature(context);
|
||||
context.node_stack().Push(node_id);
|
||||
context.decl_introducer_state_stack().Push<Lex::TokenKind::Fn>();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::LambdaDefinitionStartId node_id)
|
||||
-> bool {
|
||||
auto return_pattern_id = SemIR::InstId::None;
|
||||
auto return_type_inst_id = SemIR::TypeInstId::None;
|
||||
auto return_form_inst_id = SemIR::InstId::None;
|
||||
if (auto [return_node, maybe_return_pattern_id] =
|
||||
context.node_stack()
|
||||
.PopWithNodeIdIf<Parse::NodeCategory::ReturnDecl>();
|
||||
maybe_return_pattern_id) {
|
||||
return_pattern_id = *maybe_return_pattern_id;
|
||||
auto return_form = context.PopReturnForm();
|
||||
return_type_inst_id = return_form.type_component_inst_id;
|
||||
return_form_inst_id = return_form.form_inst_id;
|
||||
}
|
||||
|
||||
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) {
|
||||
first_param_node_id =
|
||||
context.node_stack()
|
||||
.PopForSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
|
||||
if (!last_param_node_id.has_value()) {
|
||||
last_param_node_id = implicit_params_node_id;
|
||||
}
|
||||
} else {
|
||||
implicit_param_patterns_id = SemIR::InstBlockId::None;
|
||||
}
|
||||
|
||||
auto match_results =
|
||||
CalleePatternMatch(context, *implicit_param_patterns_id,
|
||||
*param_patterns_id, return_pattern_id);
|
||||
context.full_pattern_stack().PopFullPattern();
|
||||
auto pattern_block_id = context.pattern_block_stack().Pop();
|
||||
if (!param_patterns_id->has_value() &&
|
||||
!implicit_param_patterns_id->has_value() &&
|
||||
!return_pattern_id.has_value()) {
|
||||
pattern_block_id = SemIR::InstBlockId::None;
|
||||
}
|
||||
auto decl_block_id = context.inst_block_stack().Pop();
|
||||
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::LambdaIntroducer>();
|
||||
context.decl_introducer_state_stack().Pop<Lex::TokenKind::Fn>();
|
||||
|
||||
// Function expressions may not take `self` as a parameter. (`self` in the
|
||||
// implicit parameter list is already diagnosed by `SelfInImplicitParamList`.)
|
||||
if (auto self_param_id = FindSelfPattern(context, SemIR::InstBlockId::None,
|
||||
*param_patterns_id);
|
||||
self_param_id.has_value()) {
|
||||
CARBON_DIAGNOSTIC(SelfParameterInLambda, Error,
|
||||
"`self` parameter in function expression");
|
||||
context.emitter().Emit(SemIR::LocId(self_param_id), SelfParameterInLambda);
|
||||
}
|
||||
|
||||
auto [decl_id, function_id] = MakeFunctionDecl(
|
||||
context, node_id, decl_block_id, /*build_generic=*/true,
|
||||
/*is_definition=*/true,
|
||||
SemIR::Function{
|
||||
{
|
||||
.name_id = SemIR::NameId::None,
|
||||
.parent_scope_id = SemIR::NameScopeId::None,
|
||||
.generic_id = SemIR::GenericId::None,
|
||||
.first_param_node_id = first_param_node_id,
|
||||
.last_param_node_id = last_param_node_id,
|
||||
.pattern_block_id = pattern_block_id,
|
||||
.implicit_param_patterns_id = *implicit_param_patterns_id,
|
||||
.param_patterns_id = *param_patterns_id,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = SemIR::InstId::None,
|
||||
},
|
||||
{
|
||||
.call_param_patterns_id = match_results.call_param_patterns_id,
|
||||
.call_params_id = match_results.call_params_id,
|
||||
.call_param_ranges = match_results.param_ranges,
|
||||
.return_type_inst_id = return_type_inst_id,
|
||||
.return_form_inst_id = return_form_inst_id,
|
||||
.return_pattern_id = return_pattern_id,
|
||||
}});
|
||||
context.inst_block_stack().AddInstId(decl_id);
|
||||
|
||||
CheckFunctionParams(context, context.functions().Get(function_id));
|
||||
|
||||
StartFunctionDefinition(context, decl_id, function_id);
|
||||
context.node_stack().Push(node_id, function_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::LambdaId node_id) -> bool {
|
||||
return context.TODO(node_id, "HandleLambda");
|
||||
auto function_id =
|
||||
context.node_stack().Pop<Parse::NodeKind::LambdaDefinitionStart>();
|
||||
CheckFunctionReturnOnFinish(context, node_id, function_id);
|
||||
FinishFunctionDefinition(context, function_id);
|
||||
context.scope_stack().Pop(/*check_unused=*/true);
|
||||
context.node_stack().Push(
|
||||
node_id, context.functions().Get(function_id).first_owning_decl_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::TerseBodyArrowId node_id)
|
||||
|
||||
Reference in new issue
Block a user