Reconcile function default values between decl and def (#7665)

Updates the pattern matching code to support unspecified default values.
Adds logic to decl and def merge code to diagnose mismatches in defaults
if specified in both places, or if let entirely unspecified.

Per https://github.com/carbon-language/carbon-lang/pull/7521.
This commit is contained in:
Lucile Rose Nihlen
2026-09-08 20:41:58 +00:00
committed by GitHub
parent 5a07a14fe9
commit ca9e985fa8
30 changed files with 4624 additions and 3875 deletions
+64
View File
@@ -5,6 +5,7 @@
#include "toolchain/check/merge.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/eval.h"
#include "toolchain/check/import.h"
#include "toolchain/check/import_ref.h"
#include "toolchain/diagnostics/format_providers.h"
@@ -323,6 +324,20 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
}
break;
}
case CARBON_KIND(SemIR::DefaultValuePattern new_default_value_pattern): {
auto prev_default_value_pattern =
prev_param_pattern.As<SemIR::DefaultValuePattern>();
pattern_stack.push_back(
{.prev_id = prev_default_value_pattern.subpattern_id,
.new_id = new_default_value_pattern.subpattern_id});
// The node kind comparison should catch this on the mismatched patterns
// prior to this, so the indices should never mismatch.
CARBON_CHECK(prev_default_value_pattern.default_value_id.index ==
new_default_value_pattern.default_value_id.index);
break;
}
default: {
CARBON_FATAL("Unexpected inst kind in parameter pattern: {0}",
new_param_pattern.kind());
@@ -499,6 +514,14 @@ static auto CheckRedeclParamSyntax(Context& context,
++new_iter;
continue;
}
// We don't require default values to be repeated on re-declaration,
// so skip over any comparisons to unspecified default values.
if (prev_node_kind == Parse::NodeKind::DefaultValueUnspecified ||
new_node_kind == Parse::NodeKind::DefaultValueUnspecified) {
++prev_iter;
++new_iter;
continue;
}
if (!diagnose) {
return false;
}
@@ -659,6 +682,43 @@ static auto FillPrevEntityInfo(Context& context,
}
}
// Updates the default values in `prev_function` to include any of those not
// previously specified and that are now specified in `new_function`.
static auto MergeFunctionParamDefaultValues(Context& context,
SemIR::Function& prev_function,
const SemIR::Function& new_function)
-> void {
CARBON_CHECK(prev_function.call_param_default_values_id.has_value() ==
new_function.call_param_default_values_id.has_value());
if (!prev_function.call_param_default_values_id.has_value()) {
return;
}
auto prev_value_inst_ids =
context.inst_blocks().Get(prev_function.call_param_default_values_id);
auto new_value_inst_ids =
context.inst_blocks().Get(new_function.call_param_default_values_id);
CARBON_CHECK(prev_value_inst_ids.size() == new_value_inst_ids.size());
llvm::SmallVector<SemIR::InstId> merged_value_inst_ids;
bool merge_has_new_info = false;
merged_value_inst_ids.reserve(prev_value_inst_ids.size());
for (size_t i = 0; i < prev_value_inst_ids.size(); ++i) {
bool had_value =
!context.insts().Is<SemIR::UnspecifiedValue>(prev_value_inst_ids[i]);
auto merged_id = had_value ? prev_value_inst_ids[i] : new_value_inst_ids[i];
merge_has_new_info |=
!had_value && !context.insts().Is<SemIR::UnspecifiedValue>(merged_id);
merged_value_inst_ids.push_back(merged_id);
}
if (merge_has_new_info) {
auto merged_block_id = context.inst_blocks().Add(merged_value_inst_ids);
prev_function.call_param_default_values_id = merged_block_id;
}
}
template <typename EntityT>
auto TryMergeRedecl(Context& context,
const DeclNameStack::NameContext& name_context,
@@ -833,6 +893,10 @@ auto TryMergeRedecl(Context& context,
if (is_definition) {
prev_entity.MergeDefinition(entity_info.new_entity);
if constexpr (IsFunction) {
MergeFunctionParamDefaultValues(context, prev_entity,
entity_info.new_entity);
}
}
auto replace_prev_inst = prev_import_ir_id.has_value();