Superficial support for template modifier on symbolic bindings. (#4948)

Change parse tree from `template (T:! type)` to `(template T):! type`,
so that we have information about whether a binding is a template
binding available when forming the representation of the binding
pattern. This incidentally fixes a bug that we would accept `template
addr A:! B` instead of the intended `addr template A:! B`.

Track whether a symbolic binding is a template binding on the
`EntityName` object. I'm borrowing a bit from the `CompileTimeBindIndex`
for this in order to avoid making `EntityName`s larger. Longer-term, we
should think about using a different representation for symbolic
bindings, to avoid including these fields in all `EntityName`s, but
that's out of scope for this change.

So far, template bindings are treated as having the same phase as
checked bindings, but that will change in a future PR.
This commit is contained in:
Richard Smith
2025-02-13 02:15:22 +00:00
committed by GitHub
parent f502e8d6ff
commit 6dda094928
32 changed files with 705 additions and 165 deletions
+18 -21
View File
@@ -11,15 +11,8 @@ namespace Carbon::Parse {
auto HandleBindingPattern(Context& context) -> void {
auto state = context.PopState();
// Parameters may have keywords prefixing the pattern. They become the parent
// for the full BindingPattern.
if (auto token = context.ConsumeIf(Lex::TokenKind::Template)) {
context.PushState({.state = State::BindingPatternTemplate,
.in_var_pattern = state.in_var_pattern,
.token = *token,
.subtree_start = state.subtree_start});
}
// An `addr` pattern may wrap the binding, and becomes the parent of the
// `BindingPattern`.
if (auto token = context.ConsumeIf(Lex::TokenKind::Addr)) {
context.PushState({.state = State::BindingPatternAddr,
.in_var_pattern = state.in_var_pattern,
@@ -39,6 +32,9 @@ auto HandleBindingPattern(Context& context) -> void {
}
};
// A `template` keyword may precede the name.
auto template_token = context.ConsumeIf(Lex::TokenKind::Template);
// The first item should be an identifier or `self`.
bool has_name = false;
if (auto identifier = context.ConsumeIf(Lex::TokenKind::Identifier)) {
@@ -57,9 +53,21 @@ auto HandleBindingPattern(Context& context) -> void {
*context.position(), /*has_error=*/true);
on_error(/*expected_name=*/true);
}
if (auto kind = context.PositionKind();
kind == Lex::TokenKind::Colon || kind == Lex::TokenKind::ColonExclaim) {
// Add the wrapper node for the `template` keyword if present.
if (template_token) {
if (kind != Lex::TokenKind::ColonExclaim && !state.has_error) {
CARBON_DIAGNOSTIC(ExpectedGenericBindingPatternAfterTemplate, Error,
"expected `:!` binding after `template`");
context.emitter().Emit(*template_token,
ExpectedGenericBindingPatternAfterTemplate);
state.has_error = true;
}
context.AddNode(NodeKind::TemplateBindingName, *template_token,
state.has_error);
}
state.state = kind == Lex::TokenKind::Colon
? State::BindingPatternFinishAsRegular
: State::BindingPatternFinishAsGeneric;
@@ -125,15 +133,4 @@ auto HandleBindingPatternAddr(Context& context) -> void {
}
}
auto HandleBindingPatternTemplate(Context& context) -> void {
auto state = context.PopState();
context.AddNode(NodeKind::Template, state.token, state.has_error);
// If an error was encountered, propagate it while adding a node.
if (state.has_error) {
context.ReturnErrorOnState();
}
}
} // namespace Carbon::Parse