Support ref tags on arguments to ref params (#6312)

The issue of whether/how to include `ref` tags in the textual and
in-memory SemIR (see discussion
[here](https://discord.com/channels/655572317891461132/655578254970716160/1431316355742961805))
is left as future work.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Geoff Romer
2025-11-11 20:30:19 +00:00
committed by GitHub
co-authored by Richard Smith
parent b36f85c2a5
commit 43ffd721a4
39 changed files with 798 additions and 337 deletions
+23 -28
View File
@@ -103,9 +103,11 @@ class MatchContext {
auto DoEmitPatternMatch(Context& context,
SemIR::ValueParamPattern param_pattern,
WorkItem entry) -> void;
auto DoEmitPatternMatch(Context& context,
SemIR::RefParamPattern param_pattern, WorkItem entry)
-> void;
template <typename RefParamPatternT>
requires std::is_same_v<RefParamPatternT, SemIR::RefParamPattern> ||
std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>
auto DoEmitPatternMatch(Context& context, RefParamPatternT param_pattern,
WorkItem entry) -> void;
auto DoEmitPatternMatch(Context& context,
SemIR::OutParamPattern param_pattern, WorkItem entry)
-> void;
@@ -337,8 +339,11 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
}
}
template <typename RefParamPatternT>
requires std::is_same_v<RefParamPatternT, SemIR::RefParamPattern> ||
std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>
auto MatchContext::DoEmitPatternMatch(Context& context,
SemIR::RefParamPattern param_pattern,
RefParamPatternT param_pattern,
WorkItem entry) -> void {
switch (kind_) {
case MatchKind::Caller: {
@@ -348,31 +353,17 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
param_pattern.index.index);
CARBON_CHECK(entry.scrutinee_id.has_value());
// TODO: If this is a `ref` pattern and !entry.is_self, require the
// scrutinee to have a `ref` tag.
auto scrutinee_ref_id = ConvertToValueOrRefOfType(
context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id,
ExtractScrutineeType(
context.sem_ir(),
SemIR::GetTypeOfInstInSpecific(
context.sem_ir(), callee_specific_id_, entry.pattern_id)));
switch (SemIR::GetExprCategory(context.sem_ir(), scrutinee_ref_id)) {
case SemIR::ExprCategory::Error:
case SemIR::ExprCategory::DurableRef:
case SemIR::ExprCategory::EphemeralRef:
break;
default:
CARBON_DIAGNOSTIC(ValueForRefParam, Error,
"value expression passed to reference parameter");
context.emitter().Emit(entry.scrutinee_id, ValueForRefParam);
// Add fake reference expression to preserve invariants.
auto scrutinee = context.insts().GetWithLocId(entry.scrutinee_id);
scrutinee_ref_id = AddInst<SemIR::TemporaryStorage>(
context, scrutinee.loc_id, {.type_id = scrutinee.inst.type_id()});
if (std::is_same_v<RefParamPatternT, SemIR::VarParamPattern>) {
results_.push_back(entry.scrutinee_id);
break;
}
results_.push_back(scrutinee_ref_id);
auto scrutinee_type_id = ExtractScrutineeType(
context.sem_ir(),
SemIR::GetTypeOfInstInSpecific(context.sem_ir(), callee_specific_id_,
entry.pattern_id));
results_.push_back(Convert(
context, SemIR::LocId(entry.scrutinee_id), entry.scrutinee_id,
{.kind = ConversionTarget::RefParam, .type_id = scrutinee_type_id}));
// Do not traverse farther, because the caller side of the pattern
// ends here.
break;
@@ -627,6 +618,10 @@ auto MatchContext::EmitPatternMatch(Context& context,
DoEmitPatternMatch(context, param_pattern, entry);
break;
}
case CARBON_KIND(SemIR::VarParamPattern param_pattern): {
DoEmitPatternMatch(context, param_pattern, entry);
break;
}
case CARBON_KIND(SemIR::OutParamPattern param_pattern): {
DoEmitPatternMatch(context, param_pattern, entry);
break;