Skip to content

Commit 4b0e2b0

Browse files
danakjjonmeow
andauthored
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 <[email protected]>
1 parent 2e509e9 commit 4b0e2b0

File tree

172 files changed

+2379
-1032
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

172 files changed

+2379
-1032
lines changed

toolchain/check/facet_type.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,4 +614,26 @@ auto ResolveFacetTypeRewriteConstraints(
614614
return true;
615615
}
616616

617+
auto MakePeriodSelfFacetValue(Context& context, SemIR::TypeId self_type_id)
618+
-> SemIR::InstId {
619+
auto entity_name_id = context.entity_names().AddCanonical({
620+
.name_id = SemIR::NameId::PeriodSelf,
621+
.parent_scope_id = context.scope_stack().PeekNameScopeId(),
622+
});
623+
auto inst_id = AddInst(
624+
context, SemIR::LocIdAndInst::NoLoc<SemIR::BindSymbolicName>({
625+
.type_id = self_type_id,
626+
.entity_name_id = entity_name_id,
627+
// `None` because there is no equivalent non-symbolic value.
628+
.value_id = SemIR::InstId::None,
629+
}));
630+
// TODO: LookupOrAddName should (optionally?) take a callback to run and
631+
// construct the `inst_id` only if it's not found by lookup.
632+
auto existing =
633+
context.scope_stack().LookupOrAddName(SemIR::NameId::PeriodSelf, inst_id);
634+
// Shouldn't have any names in newly created scope.
635+
CARBON_CHECK(!existing.has_value());
636+
return inst_id;
637+
}
638+
617639
} // namespace Carbon::Check

toolchain/check/facet_type.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ auto ResolveFacetTypeRewriteConstraints(
9595
llvm::SmallVector<SemIR::FacetTypeInfo::RewriteConstraint>& rewrites)
9696
-> bool;
9797

98+
// Introduce `.Self` as a symbolic binding into the current scope, and return
99+
// the `BindSymbolicName` instruction.
100+
//
101+
// The `self_type_id` is either a facet type (as `FacetType`) or `type` (as
102+
// `TypeType`).
103+
auto MakePeriodSelfFacetValue(Context& context, SemIR::TypeId self_type_id)
104+
-> SemIR::InstId;
105+
98106
} // namespace Carbon::Check
99107

100108
#endif // CARBON_TOOLCHAIN_CHECK_FACET_TYPE_H_

toolchain/check/handle_binding_pattern.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "toolchain/check/context.h"
66
#include "toolchain/check/convert.h"
7+
#include "toolchain/check/facet_type.h"
78
#include "toolchain/check/handle.h"
89
#include "toolchain/check/inst.h"
910
#include "toolchain/check/interface.h"
@@ -57,6 +58,12 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
5758
AddBindingPattern(context, name_node, name_id, cast_type_id,
5859
type_expr_region_id, is_generic, is_template);
5960

61+
// TODO: If `is_generic`, then `binding.bind_id is a BindSymbolicName. Subst
62+
// the `.Self` of type `type` in the `cast_type_id` type (a `FacetType`)
63+
// with the `binding.bind_id` itself, and build a new pattern with that.
64+
// This is kind of cyclical. So we need to reuse the EntityNameId, which
65+
// will also reuse the CompileTimeBinding for the new BindSymbolicName.
66+
6067
if (name_id != SemIR::NameId::Underscore) {
6168
// Add name to lookup immediately, so it can be used in the rest of the
6269
// enclosing pattern.
@@ -273,11 +280,28 @@ auto HandleParseNode(Context& context, Parse::VarBindingPatternId node_id)
273280
Parse::NodeKind::VarBindingPattern);
274281
}
275282

283+
auto HandleParseNode(Context& context,
284+
Parse::CompileTimeBindingPatternStartId /*node_id*/)
285+
-> bool {
286+
// Make a scope to contain the `.Self` facet value for use in the type of the
287+
// compile time binding. This is popped when handling the
288+
// CompileTimeBindingPatternId.
289+
context.scope_stack().PushForSameRegion();
290+
MakePeriodSelfFacetValue(context, SemIR::TypeType::TypeId);
291+
return true;
292+
}
293+
276294
auto HandleParseNode(Context& context,
277295
Parse::CompileTimeBindingPatternId node_id) -> bool {
296+
// Pop the `.Self` facet value name introduced by the
297+
// CompileTimeBindingPatternStart.
298+
context.scope_stack().Pop();
299+
278300
auto node_kind = Parse::NodeKind::CompileTimeBindingPattern;
279-
if (context.decl_introducer_state_stack().innermost().kind ==
280-
Lex::TokenKind::Let) {
301+
302+
const DeclIntroducerState& introducer =
303+
context.decl_introducer_state_stack().innermost();
304+
if (introducer.kind == Lex::TokenKind::Let) {
281305
// Disallow `let` outside of function and interface definitions.
282306
// TODO: Find a less brittle way of doing this. A `scope_inst_id` of `None`
283307
// can represent a block scope, but is also used for other kinds of scopes

toolchain/check/handle_where.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,8 @@ auto HandleParseNode(Context& context, Parse::WhereOperandId node_id) -> bool {
5454
context.scope_stack().PushForSameRegion();
5555
// Introduce `.Self` as a symbolic binding. Its type is the value of the
5656
// expression to the left of `where`, so `MyInterface` in the example above.
57-
//
58-
// It uses the `Self` type _without_ any constraints so that the `Self` is the
59-
// same at all levels of a nested facet type such as:
60-
// `(Z where .X = {}) where .X = {}`.
61-
auto entity_name_id = context.entity_names().AddCanonical(
62-
{.name_id = SemIR::NameId::PeriodSelf,
63-
.parent_scope_id = context.scope_stack().PeekNameScopeId()});
64-
auto period_self_inst_id = AddInst(
65-
context, SemIR::LocIdAndInst::NoLoc<SemIR::BindSymbolicName>({
66-
.type_id = self_without_constraints_type_id,
67-
.entity_name_id = entity_name_id,
68-
// `None` because there is no equivalent non-symbolic value.
69-
.value_id = SemIR::InstId::None,
70-
}));
71-
auto existing = context.scope_stack().LookupOrAddName(
72-
SemIR::NameId::PeriodSelf, period_self_inst_id);
73-
// Shouldn't have any names in newly created scope.
74-
CARBON_CHECK(!existing.has_value());
57+
auto period_self_inst_id =
58+
MakePeriodSelfFacetValue(context, self_without_constraints_type_id);
7559

7660
// Save the `.Self` symbolic binding on the node stack. It will become the
7761
// first argument to the `WhereExpr` instruction.

toolchain/check/node_stack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ class NodeStack {
479479
case Parse::NodeKind::CallExprComma:
480480
case Parse::NodeKind::ChoiceAlternativeListComma:
481481
case Parse::NodeKind::CodeBlock:
482+
case Parse::NodeKind::CompileTimeBindingPatternStart:
482483
case Parse::NodeKind::ContinueStatementStart:
483484
case Parse::NodeKind::CorePackageName:
484485
case Parse::NodeKind::ExportIntroducer:

0 commit comments

Comments
 (0)