Add the .Self name for the type expression of a compile time binding (#5937)

We add a virtual node (`CompileTimeBindingPatternStart`) as the first
child of `CompileTimeBindingPattern` which holds the identifier
underneath it, so that it is checked just before the type expression of
the `CompileTimeBindingPattern`. When we reach this virtual node during
check, we add `.Self` as a name in the current scope, and when we reach
`CompileTimeBindingPattern` we remove it from scope, which ensures it's
present during only the checking of the type expression for the compile
time pattern.

At the moment the `.Self` has a different type (it's a `TypeType`) than
other `.Self` in the facet type (which are a single `FacetType`), but
the intention is to immediately substitute it out of the facet type
entirely, replacing it with a reference to the compile time binding (a
`BindSymbolicName`) itself. A TODO has been added for this.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Dana Jansens
2025-08-12 16:27:07 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 2e509e9103
commit 4b0e2b03b6
172 changed files with 2381 additions and 1034 deletions
+26 -2
View File
@@ -4,6 +4,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/facet_type.h"
#include "toolchain/check/handle.h"
#include "toolchain/check/inst.h"
#include "toolchain/check/interface.h"
@@ -57,6 +58,12 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
AddBindingPattern(context, name_node, name_id, cast_type_id,
type_expr_region_id, is_generic, is_template);
// TODO: If `is_generic`, then `binding.bind_id is a BindSymbolicName. Subst
// the `.Self` of type `type` in the `cast_type_id` type (a `FacetType`)
// with the `binding.bind_id` itself, and build a new pattern with that.
// This is kind of cyclical. So we need to reuse the EntityNameId, which
// will also reuse the CompileTimeBinding for the new BindSymbolicName.
if (name_id != SemIR::NameId::Underscore) {
// Add name to lookup immediately, so it can be used in the rest of the
// enclosing pattern.
@@ -273,11 +280,28 @@ auto HandleParseNode(Context& context, Parse::VarBindingPatternId node_id)
Parse::NodeKind::VarBindingPattern);
}
auto HandleParseNode(Context& context,
Parse::CompileTimeBindingPatternStartId /*node_id*/)
-> bool {
// Make a scope to contain the `.Self` facet value for use in the type of the
// compile time binding. This is popped when handling the
// CompileTimeBindingPatternId.
context.scope_stack().PushForSameRegion();
MakePeriodSelfFacetValue(context, SemIR::TypeType::TypeId);
return true;
}
auto HandleParseNode(Context& context,
Parse::CompileTimeBindingPatternId node_id) -> bool {
// Pop the `.Self` facet value name introduced by the
// CompileTimeBindingPatternStart.
context.scope_stack().Pop();
auto node_kind = Parse::NodeKind::CompileTimeBindingPattern;
if (context.decl_introducer_state_stack().innermost().kind ==
Lex::TokenKind::Let) {
const DeclIntroducerState& introducer =
context.decl_introducer_state_stack().innermost();
if (introducer.kind == Lex::TokenKind::Let) {
// Disallow `let` outside of function and interface definitions.
// TODO: Find a less brittle way of doing this. A `scope_inst_id` of `None`
// can represent a block scope, but is also used for other kinds of scopes