Files
carbon-lang/toolchain/check/handle_call_expression.cpp
T
Richard Smith fea6cf88fc Unify initialization and conversion logic (#3255)
Combine the initialization, implicit conversion, and value category
conversion functions into a single function.

This substantially reduces the duplication between these steps, and
ensures that we support the same set of conversions in all these
contexts. This also fixes some issues where we would not use the proper
value representation for tuples and structs after performing implicit
conversions.
2023-10-02 21:53:52 +00:00

79 lines
2.8 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/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/sem_ir/node.h"
namespace Carbon::Check {
auto HandleCallExpression(Context& context, Parse::Node parse_node) -> bool {
// Process the final explicit call argument, but leave the arguments block on
// the stack until we add the return slot argument.
context.ParamOrArgEndNoPop(Parse::NodeKind::CallExpressionStart);
// TODO: Convert to call expression.
auto [call_expr_parse_node, name_id] =
context.node_stack()
.PopWithParseNode<Parse::NodeKind::CallExpressionStart>();
auto name_node = context.semantics_ir().GetNode(name_id);
if (name_node.kind() != SemIR::NodeKind::FunctionDeclaration) {
// TODO: Work on error.
context.TODO(parse_node, "Not a callable name");
context.node_stack().Push(parse_node, name_id);
context.ParamOrArgPop();
return true;
}
auto function_id = name_node.GetAsFunctionDeclaration();
const auto& callable = context.semantics_ir().GetFunction(function_id);
// For functions with an implicit return type, the return type is the empty
// tuple type.
SemIR::TypeId type_id = callable.return_type_id;
if (!type_id.is_valid()) {
type_id = context.CanonicalizeTupleType(call_expr_parse_node, {});
}
// If there is a return slot, add a corresponding argument.
if (callable.return_slot_id.is_valid()) {
// Tentatively put storage for a temporary in the function's return slot.
// This will be replaced if necessary when we perform initialization.
auto temp_id = context.AddNode(SemIR::Node::TemporaryStorage::Make(
call_expr_parse_node, callable.return_type_id));
context.ParamOrArgSave(temp_id);
}
// Convert the arguments to match the parameters.
auto refs_id = context.ParamOrArgPop();
if (!ConvertCallArgs(context, call_expr_parse_node, refs_id,
name_node.parse_node(), callable.param_refs_id,
callable.return_slot_id.is_valid())) {
context.node_stack().Push(parse_node, SemIR::NodeId::BuiltinError);
return true;
}
auto call_node_id = context.AddNode(SemIR::Node::Call::Make(
call_expr_parse_node, type_id, refs_id, function_id));
context.node_stack().Push(parse_node, call_node_id);
return true;
}
auto HandleCallExpressionComma(Context& context, Parse::Node /*parse_node*/)
-> bool {
context.ParamOrArgComma();
return true;
}
auto HandleCallExpressionStart(Context& context, Parse::Node parse_node)
-> bool {
auto name_id = context.node_stack().PopExpression();
context.node_stack().Push(parse_node, name_id);
context.ParamOrArgStart();
return true;
}
} // namespace Carbon::Check