mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:11:08 +01:00
Rework how we check calls to support deduced implicit parameters (#4302)
Instead of the `call` instruction having a block with one argument per explicit argument, preceded optionally by `self` and followed optionally by a return slot, change the `call` to store only the *runtime* arguments. Store an index on the runtime parameters to make it easier to determine the correspondence between arguments and parameters in a call. Compile-time parameters, whether implicit or explicit, are no longer included in the call argument list. Instead, they're tracked only in the `specific_id` on the callee. For calls to generic classes and generic interfaces, it no longer makes sense to form a `call` instruction, given that the entirety of the result is determined by the `specific_id`, which is now formed when checking the call. Instead, the `call` instruction now only models function calls, and not calls to other kinds of parameterized entity names, and we create a `class_type` or `interface_type` instead of a `call` instruction to model these kinds of calls. Notionally the model here is that we're following the #3720 approach for calls, but for now we inline the `Call.Op` function when forming SemIR. We now also track the enclosing specific for a generic class or generic interface that appears within an enclosing generic. This is necessary in order for deduction of the inner generic parameters to not get confused by the outer generic parameters being absent. In order to not regress diagnostics, the template argument deduction mechanism has been extended to specify the name of the parameter we're deducing against when possible, and call arity mismatch errors are now diagnosed before performing deduction rather than afterwards.
This commit is contained in:
@@ -65,6 +65,51 @@ static auto DiagnoseModifiers(Context& context, DeclIntroducerState& introducer,
|
||||
RequireDefaultFinalOnlyInInterfaces(context, introducer, parent_scope_inst);
|
||||
}
|
||||
|
||||
// Checks that the parameter lists specified in a function declaration are
|
||||
// valid for a function declaration, and numbers the parameters.
|
||||
static auto CheckFunctionSignature(Context& context,
|
||||
const NameComponent& name_and_params)
|
||||
-> void {
|
||||
SemIR::RuntimeParamIndex next_index(0);
|
||||
for (auto param_id : llvm::concat<const SemIR::InstId>(
|
||||
context.inst_blocks().GetOrEmpty(name_and_params.implicit_params_id),
|
||||
context.inst_blocks().GetOrEmpty(name_and_params.params_id))) {
|
||||
auto param = context.insts().Get(param_id);
|
||||
|
||||
// Find the parameter in the pattern.
|
||||
// TODO: This duplicates work done by Function::GetParamFromParamRefId.
|
||||
if (auto addr_pattern = param.TryAs<SemIR::AddrPattern>()) {
|
||||
param_id = addr_pattern->inner_id;
|
||||
param = context.insts().Get(param_id);
|
||||
}
|
||||
|
||||
auto bind_name = param.TryAs<SemIR::AnyBindName>();
|
||||
if (bind_name) {
|
||||
param_id = bind_name->value_id;
|
||||
param = context.insts().Get(param_id);
|
||||
}
|
||||
|
||||
auto param_inst = param.TryAs<SemIR::Param>();
|
||||
if (!param_inst) {
|
||||
// Once we support more generalized patterns we will need to diagnose
|
||||
// parameters with unsupported patterns.
|
||||
context.TODO(param_id, "unexpected syntax for parameter");
|
||||
// TODO: Also repair the param ID so downstream code doesn't need to deal
|
||||
// with this.
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a runtime parameter, number it.
|
||||
if (bind_name && bind_name->kind == SemIR::BindName::Kind) {
|
||||
param_inst->runtime_index = next_index;
|
||||
context.ReplaceInstBeforeConstantUse(param_id, *param_inst);
|
||||
++next_index.index;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Also assign a parameter index to the return storage, if present.
|
||||
}
|
||||
|
||||
// Tries to merge new_function into prev_function_id. Since new_function won't
|
||||
// have a definition even if one is upcoming, set is_definition to indicate the
|
||||
// planned result.
|
||||
@@ -182,6 +227,10 @@ static auto BuildFunctionDecl(Context& context,
|
||||
context.TODO(node_id, "function with positional parameters");
|
||||
name.params_id = SemIR::InstBlockId::Empty;
|
||||
}
|
||||
|
||||
// Check that the function signature is valid and number the parameters.
|
||||
CheckFunctionSignature(context, name);
|
||||
|
||||
auto name_context = context.decl_name_stack().FinishName(name);
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::FunctionIntroducer>();
|
||||
@@ -315,26 +364,20 @@ static auto HandleFunctionDefinitionAfterSignature(
|
||||
SemIR::SpecificId::Invalid);
|
||||
|
||||
// Check the parameter types are complete.
|
||||
for (auto param_id : llvm::concat<const SemIR::InstId>(
|
||||
for (auto param_ref_id : llvm::concat<const SemIR::InstId>(
|
||||
context.inst_blocks().GetOrEmpty(function.implicit_param_refs_id),
|
||||
context.inst_blocks().GetOrEmpty(function.param_refs_id))) {
|
||||
auto param = context.insts().Get(param_id);
|
||||
|
||||
// Find the parameter in the pattern.
|
||||
// TODO: More general pattern handling?
|
||||
if (auto addr_pattern = param.TryAs<SemIR::AddrPattern>()) {
|
||||
param_id = addr_pattern->inner_id;
|
||||
param = context.insts().Get(param_id);
|
||||
}
|
||||
auto [param_id, param] =
|
||||
SemIR::Function::GetParamFromParamRefId(context.sem_ir(), param_ref_id);
|
||||
|
||||
// The parameter types need to be complete.
|
||||
context.TryToCompleteType(param.type_id(), [&] {
|
||||
context.TryToCompleteType(param.type_id, [&] {
|
||||
CARBON_DIAGNOSTIC(
|
||||
IncompleteTypeInFunctionParam, Error,
|
||||
"Parameter has incomplete type `{0}` in function definition.",
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(param_id, IncompleteTypeInFunctionParam,
|
||||
param.type_id());
|
||||
param.type_id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user