Skip to content

Commit 5f888e1

Browse files
authored
Treat associated constants as entities parameterized by Self (#4837)
Add a full entity representation for associated constants, and build a `Generic` object for them. This `Generic` is parameterized by the enclosing `Self` type, allowing the use of `Self` within the type of the associated constant to be supported. When performing impl lookup for an associated constant, produce the type with the provided self type substituted for its `Self` along with any generic parameters of the interface. Split the handling of associated constant declarations into two parts, corresponding to the code before the `=`, and the code between the `=` and `;` (if any). The former goes into the generic declaration region; the latter into the generic definition region. This prepares us to handle the default value for an associated constant, but for now we're just storing the information and not actually using it. Remove the entity type field from `assoc_entity_type`, because it's almost unused and is an attractive nuisance -- it must necessarily be a type in the generic scope of the associated constant rather than in the scope of the instruction (because there is no `Self` anywhere else), which means that it's hard to substitute into or derive meaning from. See `toolchain/check/testdata/impl/assoc_const_self.carbon` for tests of the new functionality; these used to cause the toolchain to crash.
1 parent b06fcc9 commit 5f888e1

File tree

108 files changed

+3726
-1680
lines changed

Some content is hidden

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

108 files changed

+3726
-1680
lines changed

toolchain/check/BUILD

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ cc_library(
2929
"import_cpp.cpp",
3030
"import_ref.cpp",
3131
"inst_block_stack.cpp",
32+
"interface.cpp",
3233
"literal.cpp",
3334
"member_access.cpp",
3435
"merge.cpp",
@@ -56,6 +57,7 @@ cc_library(
5657
"import_cpp.h",
5758
"import_ref.h",
5859
"inst_block_stack.h",
60+
"interface.h",
5961
"keyword_modifier_set.h",
6062
"literal.h",
6163
"member_access.h",
@@ -137,7 +139,6 @@ cc_library(
137139
":context",
138140
":dump",
139141
":impl",
140-
":interface",
141142
":pointer_dereference",
142143
":sem_ir_diagnostic_converter",
143144
"//common:check",
@@ -210,19 +211,6 @@ cc_library(
210211
],
211212
)
212213

213-
cc_library(
214-
name = "interface",
215-
srcs = ["interface.cpp"],
216-
hdrs = ["interface.h"],
217-
deps = [
218-
":context",
219-
"//common:check",
220-
"//toolchain/sem_ir:file",
221-
"//toolchain/sem_ir:inst",
222-
"//toolchain/sem_ir:typed_insts",
223-
],
224-
)
225-
226214
cc_library(
227215
name = "node_stack",
228216
srcs = ["node_stack.cpp"],

toolchain/check/context.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,19 @@ auto Context::RequireDefinedType(SemIR::TypeId type_id, SemIR::LocId loc_id,
14541454
}
14551455
}
14561456
// TODO: Finish facet type resolution.
1457+
//
1458+
// Note that we will need Self to be passed into facet type resolution.
1459+
// The `.Self` of a facet type created by `where` will then be bound to the
1460+
// provided self type.
1461+
//
1462+
// For example, in `T:! X where ...`, we will bind the `.Self` of the
1463+
// `where` facet type to `T`, and in `(X where ...) where ...`, we will bind
1464+
// the inner `.Self` to the outer `.Self`.
1465+
//
1466+
// If the facet type contains a rewrite, we may have deferred converting the
1467+
// rewritten value to the type of the associated constant. That conversion
1468+
// should also be performed as part of resolution, and may depend on the
1469+
// Self type.
14571470
}
14581471

14591472
return true;
@@ -1516,11 +1529,9 @@ auto Context::GetTupleType(llvm::ArrayRef<SemIR::TypeId> type_ids)
15161529
type_blocks().AddCanonical(type_ids));
15171530
}
15181531

1519-
auto Context::GetAssociatedEntityType(SemIR::TypeId interface_type_id,
1520-
SemIR::TypeId entity_type_id)
1532+
auto Context::GetAssociatedEntityType(SemIR::TypeId interface_type_id)
15211533
-> SemIR::TypeId {
1522-
return GetTypeImpl<SemIR::AssociatedEntityType>(*this, interface_type_id,
1523-
entity_type_id);
1534+
return GetTypeImpl<SemIR::AssociatedEntityType>(*this, interface_type_id);
15241535
}
15251536

15261537
auto Context::GetSingletonType(SemIR::InstId singleton_id) -> SemIR::TypeId {

toolchain/check/context.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,14 @@ class Context {
467467

468468
// TODO: Consider moving these `Get*Type` functions to a separate class.
469469

470-
// Gets the type for the name of an associated entity.
471-
auto GetAssociatedEntityType(SemIR::TypeId interface_type_id,
472-
SemIR::TypeId entity_type_id) -> SemIR::TypeId;
470+
// Gets the type to use for an unbound associated entity declared in this
471+
// interface. For example, this is the type of `I.T` after
472+
// `interface I { let T:! type; }`.
473+
// The name of the interface is used for diagnostics.
474+
// TODO: Should we use a different type for each such entity, or the same type
475+
// for all associated entities?
476+
auto GetAssociatedEntityType(SemIR::TypeId interface_type_id)
477+
-> SemIR::TypeId;
473478

474479
// Gets a singleton type. The returned type will be complete. Requires that
475480
// `singleton_id` is already validated to be a singleton.
@@ -628,6 +633,9 @@ class Context {
628633
auto interfaces() -> ValueStore<SemIR::InterfaceId>& {
629634
return sem_ir().interfaces();
630635
}
636+
auto associated_constants() -> ValueStore<SemIR::AssociatedConstantId>& {
637+
return sem_ir().associated_constants();
638+
}
631639
auto facet_types() -> CanonicalValueStore<SemIR::FacetTypeId>& {
632640
return sem_ir().facet_types();
633641
}

toolchain/check/eval.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,8 +1568,7 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
15681568
&SemIR::AssociatedEntity::type_id);
15691569
case SemIR::AssociatedEntityType::Kind:
15701570
return RebuildIfFieldsAreConstant(
1571-
eval_context, inst, &SemIR::AssociatedEntityType::interface_type_id,
1572-
&SemIR::AssociatedEntityType::entity_type_id);
1571+
eval_context, inst, &SemIR::AssociatedEntityType::interface_type_id);
15731572
case SemIR::BoundMethod::Kind:
15741573
return RebuildIfFieldsAreConstant(eval_context, inst,
15751574
&SemIR::BoundMethod::type_id,

toolchain/check/generic.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "toolchain/check/eval.h"
1010
#include "toolchain/check/generic_region_stack.h"
1111
#include "toolchain/check/subst.h"
12+
#include "toolchain/sem_ir/generic.h"
1213
#include "toolchain/sem_ir/ids.h"
1314
#include "toolchain/sem_ir/inst.h"
1415
#include "toolchain/sem_ir/typed_insts.h"
@@ -506,6 +507,10 @@ auto GetInstForSpecific(Context& context, SemIR::SpecificId specific_id)
506507
.callee_id = generic.decl_id,
507508
.specific_id = specific_id}));
508509
}
510+
case SemIR::AssociatedConstantDecl::Kind: {
511+
// TODO: We don't have a good instruction to use here.
512+
return generic.decl_id;
513+
}
509514
default: {
510515
CARBON_FATAL("Unknown kind for generic declaration {0}", decl);
511516
}

toolchain/check/generic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ auto ResolveSpecificDefinition(Context& context, SemIRLoc loc,
8484
SemIR::SpecificId specific_id) -> bool;
8585

8686
// Returns an instruction describing the entity named by the given specific.
87+
// This is used to name the entity in diagnostics.
8788
auto GetInstForSpecific(Context& context, SemIR::SpecificId specific_id)
8889
-> SemIR::InstId;
8990

toolchain/check/handle_binding_pattern.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,23 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
159159
return context.emitter().Build(type_node, IncompleteTypeInAssociatedDecl,
160160
cast_type_id);
161161
});
162-
context.entity_names().Add(
162+
163+
SemIR::AssociatedConstantDecl assoc_const_decl = {
164+
.type_id = cast_type_id,
165+
.assoc_const_id = SemIR::AssociatedConstantId::None,
166+
.decl_block_id = SemIR::InstBlockId::None};
167+
auto decl_id = context.AddPlaceholderInstInNoBlock(SemIR::LocIdAndInst(
168+
context.parse_tree().As<Parse::CompileTimeBindingPatternId>(node_id),
169+
assoc_const_decl));
170+
assoc_const_decl.assoc_const_id = context.associated_constants().Add(
163171
{.name_id = name_id,
164172
.parent_scope_id = context.scope_stack().PeekNameScopeId(),
165-
.bind_index = SemIR::CompileTimeBindIndex::None});
173+
.decl_id = decl_id,
174+
.generic_id = SemIR::GenericId::None,
175+
.default_value_id = SemIR::InstId::None});
176+
context.ReplaceInstBeforeConstantUse(decl_id, assoc_const_decl);
166177

167-
SemIR::InstId decl_id = context.AddInst<SemIR::AssociatedConstantDecl>(
168-
context.parse_tree().As<Parse::CompileTimeBindingPatternId>(node_id),
169-
{cast_type_id, name_id});
170178
context.node_stack().Push(node_id, decl_id);
171-
172-
// Add an associated entity name to the interface scope.
173-
auto assoc_id = BuildAssociatedEntity(
174-
context, parent_interface_decl->interface_id, decl_id);
175-
auto name_context =
176-
context.decl_name_stack().MakeUnqualifiedName(node_id, name_id);
177-
context.decl_name_stack().AddNameOrDiagnose(
178-
name_context, assoc_id, introducer.modifier_set.GetAccessKind());
179179
return true;
180180
}
181181

0 commit comments

Comments
 (0)