Parse -> ref T as a primitive return form (#7911)

Previously `-> ref T` was parsed as a type expression whose outermost
node is a `ref` prefix operator (the same one used for `F(ref x)`
arguments), and `ReturnExprAsForm` recognized the resulting `RefTagExpr`
and turned it into a `RefForm`.

Per p5434, a return form that begins with `val`, `ref`, or `var` is not
a type expression. Parse a leading `ref` after `->` as a
`RefPrimitiveForm` node wrapping the type expression, reusing the node
produced by `form(ref T)`, and check it as a form. This prepares for
supporting `-> val T` and `-> var T` in the same way.

The only SemIR change is that the `ref_tag` instruction is no longer
emitted, and the return slot pattern refers to a `type_component_of` the
form, matching `->? form(ref T)`.

---------

Co-authored-by: Nicholas Bishop <nbishop@nbishop.net>
This commit is contained in:
David BlaikieandNicholas Bishop authored and GitHub committed 2026-10-07 23:05:55 +00:00
1 parent 72068410c2
commit 059ee7b9ed
7 files changed
+143 -50

No files matched your search

+5 -1
View File
@@ -55,7 +55,11 @@ static auto HandleReturnDecl(Context& context, Parse::AnyReturnDeclId node_id)
-> bool {
auto [expr_node_id, expr_inst_id] = context.node_stack().PopExprWithNodeId();
Context::FormExpr form_expr = [&] {
if (context.parse_tree().node_kind(node_id) == Parse::ReturnTypeId::Kind) {
// `-> T` provides a type expression, whereas `-> ref T` and `->? F`
// provide a form.
if (context.parse_tree().node_kind(node_id) == Parse::ReturnTypeId::Kind &&
context.parse_tree().node_kind(expr_node_id) !=
Parse::RefPrimitiveFormId::Kind) {
return ReturnExprAsForm(context, expr_node_id, expr_inst_id);
} else {
return FormExprAsForm(context, expr_node_id, expr_inst_id);