mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Factor out some parts of builtin handling and add declaration checking. (#3815)
In preparation for adding more builtins, factor out the handling of builtin function kinds into separate files. Add checking for builtin function signatures. The mechanism used here is intended to provide a lot of flexibility for declaring generic builtin functions and pretty arbitrary constraints on the types of parameters of builtin functions. For now, these constraints are checked when the builtin function is declared. The hope is that this will suffice, but if not, it should be straightforward to switch to doing some of the checking on call and share logic between the checks. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com> Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
Carbon Infra Bot
parent
3763d0130a
commit
a3d77d9b74
@@ -10,6 +10,7 @@
|
||||
#include "toolchain/check/interface.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/parse/tree_node_diagnostic_converter.h"
|
||||
#include "toolchain/sem_ir/builtin_function_kind.h"
|
||||
#include "toolchain/sem_ir/entry_point.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
@@ -306,9 +307,7 @@ static auto LookupBuiltinFunctionKind(Context& context,
|
||||
auto builtin_name = context.string_literal_values().Get(
|
||||
context.tokens().GetStringLiteralValue(
|
||||
context.parse_tree().node_token(name_id)));
|
||||
auto kind = llvm::StringSwitch<SemIR::BuiltinFunctionKind>(builtin_name)
|
||||
.Case("int.add", SemIR::BuiltinFunctionKind::IntAdd)
|
||||
.Default(SemIR::BuiltinFunctionKind::None);
|
||||
auto kind = SemIR::BuiltinFunctionKind::ForBuiltinName(builtin_name);
|
||||
if (kind == SemIR::BuiltinFunctionKind::None) {
|
||||
CARBON_DIAGNOSTIC(UnknownBuiltinFunctionName, Error,
|
||||
"Unknown builtin function name \"{0}\".", std::string);
|
||||
@@ -318,17 +317,56 @@ static auto LookupBuiltinFunctionKind(Context& context,
|
||||
return kind;
|
||||
}
|
||||
|
||||
// Returns whether `function` is a valid declaration of the builtin
|
||||
// `builtin_kind`.
|
||||
static auto IsValidBuiltinDeclaration(Context& context,
|
||||
const SemIR::Function& function,
|
||||
SemIR::BuiltinFunctionKind builtin_kind)
|
||||
-> bool {
|
||||
// Form the list of parameter types for the declaration.
|
||||
llvm::SmallVector<SemIR::TypeId> param_type_ids;
|
||||
auto implicit_param_refs =
|
||||
context.inst_blocks().Get(function.implicit_param_refs_id);
|
||||
auto param_refs = context.inst_blocks().Get(function.param_refs_id);
|
||||
param_type_ids.reserve(implicit_param_refs.size() + param_refs.size());
|
||||
for (auto param_id :
|
||||
llvm::concat<SemIR::InstId>(implicit_param_refs, param_refs)) {
|
||||
// TODO: We also need to track whether the parameter is declared with
|
||||
// `var`.
|
||||
param_type_ids.push_back(context.insts().Get(param_id).type_id());
|
||||
}
|
||||
|
||||
// Get the return type. This is `()` if none was specified.
|
||||
auto return_type_id = function.return_type_id;
|
||||
if (!return_type_id.is_valid()) {
|
||||
return_type_id = context.GetTupleType({});
|
||||
}
|
||||
|
||||
return builtin_kind.IsValidType(context.sem_ir(), param_type_ids,
|
||||
return_type_id);
|
||||
}
|
||||
|
||||
auto HandleBuiltinFunctionDefinition(
|
||||
Context& context, Parse::BuiltinFunctionDefinitionId /*node_id*/) -> bool {
|
||||
auto name_id =
|
||||
context.node_stack().PopForSoloNodeId<Parse::NodeKind::BuiltinName>();
|
||||
auto function_id =
|
||||
auto [fn_node_id, function_id] =
|
||||
context.node_stack()
|
||||
.Pop<Parse::NodeKind::BuiltinFunctionDefinitionStart>();
|
||||
|
||||
auto& function = context.functions().Get(function_id);
|
||||
function.builtin_kind = LookupBuiltinFunctionKind(context, name_id);
|
||||
.PopWithNodeId<Parse::NodeKind::BuiltinFunctionDefinitionStart>();
|
||||
|
||||
auto builtin_kind = LookupBuiltinFunctionKind(context, name_id);
|
||||
if (builtin_kind != SemIR::BuiltinFunctionKind::None) {
|
||||
auto& function = context.functions().Get(function_id);
|
||||
if (IsValidBuiltinDeclaration(context, function, builtin_kind)) {
|
||||
function.builtin_kind = builtin_kind;
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(InvalidBuiltinSignature, Error,
|
||||
"Invalid signature for builtin function \"{0}\".",
|
||||
std::string);
|
||||
context.emitter().Emit(fn_node_id, InvalidBuiltinSignature,
|
||||
builtin_kind.name().str());
|
||||
}
|
||||
}
|
||||
context.decl_name_stack().PopScope();
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user