Skip to content

Commit ebaf62e

Browse files
authored
Associated constants can be used in member function signatures (#5089)
This required allowing incomplete facet types where previously completeness was required. Once we support named constraints, we will need a way to consistently go from an interface to a facet type witness index without requiring the interface to be complete in these cases. --------- Co-authored-by: Josh L <[email protected]>
1 parent 68f6906 commit ebaf62e

37 files changed

+4530
-1285
lines changed

toolchain/check/convert.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,10 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
11481148
return SemIR::ErrorInst::SingletonInstId;
11491149
}
11501150

1151-
// We can only perform initialization for complete, non-abstract types.
1151+
// We can only perform initialization for complete, non-abstract types. Note
1152+
// that `RequireConcreteType` returns true for facet types, since their
1153+
// representation is fixed. This allows us to support using the `Self` of an
1154+
// interface inside its definition.
11521155
if (!RequireConcreteType(
11531156
context, target.type_id, loc_id,
11541157
[&] {

toolchain/check/handle_interface.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ auto HandleParseNode(Context& context,
154154
interface_info.definition_id = interface_decl_id;
155155
interface_info.scope_id = context.name_scopes().Add(
156156
interface_decl_id, SemIR::NameId::None, interface_info.parent_scope_id);
157+
context.name_scopes()
158+
.Get(interface_info.scope_id)
159+
.set_is_interface_definition();
157160

158161
auto self_specific_id =
159162
context.generics().GetSelfSpecific(interface_info.generic_id);

toolchain/check/impl_lookup.cpp

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -165,28 +165,17 @@ static auto FindAndDiagnoseImplLookupCycle(
165165
static auto GetInterfacesFromConstantId(
166166
Context& context, SemIR::ConstantId query_facet_type_const_id,
167167
bool& has_other_requirements)
168-
-> llvm::SmallVector<SemIR::CompleteFacetType::RequiredInterface> {
169-
// The `query_facet_type_const_id` is a constant value for some facet type. We
170-
// do this long chain of steps to go from that constant value to the
171-
// `FacetTypeId` found on the `FacetType` instruction of this constant value,
172-
// and finally to the `CompleteFacetType`.
168+
-> llvm::SmallVector<SemIR::SpecificInterface> {
173169
auto facet_type_inst_id =
174170
context.constant_values().GetInstId(query_facet_type_const_id);
175171
auto facet_type_inst =
176172
context.insts().GetAs<SemIR::FacetType>(facet_type_inst_id);
177-
auto facet_type_id = facet_type_inst.facet_type_id;
178-
auto complete_facet_type_id =
179-
context.complete_facet_types().TryGetId(facet_type_id);
180-
// The facet type will already be completed before coming here. If we're
181-
// converting from a concrete type to a facet type, the conversion step
182-
// requires everything to be complete before doing impl lookup.
183-
CARBON_CHECK(complete_facet_type_id.has_value());
184-
const auto& complete_facet_type =
185-
context.complete_facet_types().Get(complete_facet_type_id);
186-
187-
has_other_requirements =
188-
context.facet_types().Get(facet_type_id).other_requirements;
189-
return complete_facet_type.required_interfaces;
173+
const auto& facet_type_info =
174+
context.facet_types().Get(facet_type_inst.facet_type_id);
175+
has_other_requirements = facet_type_info.other_requirements;
176+
// TODO: Once we add support for named constraints, we will need to change
177+
// this to return the same interfaces as in the complete facet type.
178+
return facet_type_info.impls_constraints;
190179
}
191180

192181
static auto GetWitnessIdForImpl(
@@ -257,23 +246,20 @@ static auto GetWitnessIdForImpl(
257246
context.insts()
258247
.GetAs<SemIR::FacetType>(deduced_constraint_id)
259248
.facet_type_id;
260-
const auto& deduced_constraint_complete_facet_type =
261-
context.complete_facet_types().Get(
262-
context.complete_facet_types().TryGetId(
263-
deduced_constraint_facet_type_id));
264-
CARBON_CHECK(deduced_constraint_complete_facet_type.num_to_impl == 1);
265-
266-
if (context.facet_types()
267-
.Get(deduced_constraint_facet_type_id)
268-
.other_requirements) {
249+
const auto& deduced_constraint_facet_type_info =
250+
context.facet_types().Get(deduced_constraint_facet_type_id);
251+
CARBON_CHECK(deduced_constraint_facet_type_info.impls_constraints.size() ==
252+
1);
253+
254+
if (deduced_constraint_facet_type_info.other_requirements) {
269255
// TODO: Remove this when other requirements goes away.
270256
return SemIR::InstId::None;
271257
}
272258

273259
// The specifics in the queried interface must match the deduced specifics in
274260
// the impl's constraint facet type.
275261
auto impl_interface_specific_id =
276-
deduced_constraint_complete_facet_type.required_interfaces[0].specific_id;
262+
deduced_constraint_facet_type_info.impls_constraints[0].specific_id;
277263
auto query_interface_specific_id = interface.specific_id;
278264
if (impl_interface_specific_id != query_interface_specific_id) {
279265
return SemIR::InstId::None;

toolchain/check/import_ref.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,6 +2314,7 @@ static auto AddInterfaceDefinition(ImportContext& context,
23142314
new_interface.first_owning_decl_id, SemIR::NameId::None,
23152315
new_interface.parent_scope_id);
23162316
auto& new_scope = context.local_name_scopes().Get(new_interface.scope_id);
2317+
new_scope.set_is_interface_definition();
23172318
const auto& import_scope =
23182319
context.import_name_scopes().Get(import_interface.scope_id);
23192320

toolchain/check/member_access.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,6 @@ auto PerformCompoundMemberAccess(Context& context, SemIR::LocId loc_id,
568568
auto interface_type = GetInterfaceFromFacetType(context, interface_type_id);
569569
// An associated entity is always associated with a single interface.
570570
CARBON_CHECK(interface_type);
571-
const auto& interface =
572-
context.interfaces().Get(interface_type->interface_id);
573-
auto assoc_entities =
574-
context.inst_blocks().Get(interface.associated_entities_id);
575571
auto value_inst_id = context.constant_values().GetConstantInstId(member_id);
576572
// TODO: According to
577573
// https://docs.carbon-lang.dev/docs/design/expressions/member_access.html#member-resolution
@@ -584,7 +580,7 @@ auto PerformCompoundMemberAccess(Context& context, SemIR::LocId loc_id,
584580
}
585581
auto assoc_entity =
586582
context.insts().GetAs<SemIR::AssociatedEntity>(value_inst_id);
587-
auto decl_id = assoc_entities[assoc_entity.index.index];
583+
auto decl_id = assoc_entity.decl_id;
588584
LoadImportRef(context, decl_id);
589585
auto decl_value_id = context.constant_values().GetConstantInstId(decl_id);
590586
auto decl_type_id = context.insts().Get(decl_value_id).type_id();

toolchain/check/name_lookup.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "toolchain/check/import.h"
99
#include "toolchain/check/import_cpp.h"
1010
#include "toolchain/check/import_ref.h"
11+
#include "toolchain/check/member_access.h"
1112
#include "toolchain/check/type_completion.h"
1213
#include "toolchain/diagnostics/format_providers.h"
1314
#include "toolchain/sem_ir/name_scope.h"
@@ -101,6 +102,27 @@ auto LookupUnqualifiedName(Context& context, Parse::NodeId node_id,
101102
.specific_id = specific_id},
102103
/*required=*/false);
103104
non_lexical_result.scope_result.is_found()) {
105+
// In an interface definition, replace associated entity `M` with
106+
// `Self.M` (where the `Self` is the `Self` of the interface).
107+
const auto& scope = context.name_scopes().Get(lookup_scope_id);
108+
if (scope.is_interface_definition()) {
109+
SemIR::InstId target_inst_id =
110+
non_lexical_result.scope_result.target_inst_id();
111+
if (context.types().Is<SemIR::AssociatedEntityType>(
112+
context.insts().Get(target_inst_id).type_id())) {
113+
auto interface_decl =
114+
context.insts().GetAs<SemIR::InterfaceDecl>(scope.inst_id());
115+
const auto& interface =
116+
context.interfaces().Get(interface_decl.interface_id);
117+
// TODO: Refactor the code so that we can call the "no instance
118+
// binding" case from `PerformCompoundMemberAccess` as a separate
119+
// function (`GetAssociatedValue`).
120+
SemIR::InstId result_inst_id = PerformCompoundMemberAccess(
121+
context, node_id, interface.self_param_id, target_inst_id);
122+
non_lexical_result.scope_result = SemIR::ScopeLookupResult::MakeFound(
123+
result_inst_id, non_lexical_result.scope_result.access_kind());
124+
}
125+
}
104126
return non_lexical_result;
105127
}
106128
}

toolchain/check/testdata/builtin_conversions/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
7878
// CHECK:STDOUT: %BitAnd.assoc_type: type = assoc_entity_type %BitAnd.type [concrete]
7979
// CHECK:STDOUT: %assoc0: %BitAnd.assoc_type = assoc_entity element0, imports.%Core.import_ref.a93 [concrete]
8080
// CHECK:STDOUT: %Op.type.27a: type = fn_type @Op.1 [concrete]
81-
// CHECK:STDOUT: %Op.ab9: %Op.type.27a = struct_value () [concrete]
8281
// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self.25f [symbolic]
8382
// CHECK:STDOUT: %T.8b3: type = bind_symbolic_name T, 0 [symbolic]
8483
// CHECK:STDOUT: %T.patt.e01: type = symbolic_binding_pattern T, 0 [symbolic]
@@ -115,7 +114,7 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
115114
// CHECK:STDOUT: }
116115
// CHECK:STDOUT: %Core.import_ref.ad0 = import_ref Core//prelude, inst100 [no loc], unloaded
117116
// CHECK:STDOUT: %Core.import_ref.08d: %BitAnd.assoc_type = import_ref Core//prelude, loc18_41, loaded [concrete = constants.%assoc0]
118-
// CHECK:STDOUT: %Core.Op: %Op.type.27a = import_ref Core//prelude, Op, loaded [concrete = constants.%Op.ab9]
117+
// CHECK:STDOUT: %Core.Op = import_ref Core//prelude, Op, unloaded
119118
// CHECK:STDOUT: %Core.import_ref.040: %BitAnd.type = import_ref Core//prelude, inst100 [no loc], loaded [symbolic = constants.%Self.25f]
120119
// CHECK:STDOUT: %Core.import_ref.51c: <witness> = import_ref Core//prelude, loc21_36, loaded [symbolic = @impl.%impl_witness (constants.%impl_witness.b81)]
121120
// CHECK:STDOUT: %Core.import_ref.5ab3ec.1: type = import_ref Core//prelude, loc21_14, loaded [symbolic = @impl.%T (constants.%T.8b3)]
@@ -345,7 +344,6 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
345344
// CHECK:STDOUT: %BitAnd.assoc_type: type = assoc_entity_type %BitAnd.type [concrete]
346345
// CHECK:STDOUT: %assoc0: %BitAnd.assoc_type = assoc_entity element0, imports.%Core.import_ref.a93 [concrete]
347346
// CHECK:STDOUT: %Op.type.27a: type = fn_type @Op.1 [concrete]
348-
// CHECK:STDOUT: %Op.ab9: %Op.type.27a = struct_value () [concrete]
349347
// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self.25f [symbolic]
350348
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
351349
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
@@ -395,7 +393,7 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
395393
// CHECK:STDOUT: }
396394
// CHECK:STDOUT: %Core.import_ref.ad0 = import_ref Core//prelude, inst100 [no loc], unloaded
397395
// CHECK:STDOUT: %Core.import_ref.08d: %BitAnd.assoc_type = import_ref Core//prelude, loc18_41, loaded [concrete = constants.%assoc0]
398-
// CHECK:STDOUT: %Core.Op: %Op.type.27a = import_ref Core//prelude, Op, loaded [concrete = constants.%Op.ab9]
396+
// CHECK:STDOUT: %Core.Op = import_ref Core//prelude, Op, unloaded
399397
// CHECK:STDOUT: %Core.import_ref.040: %BitAnd.type = import_ref Core//prelude, inst100 [no loc], loaded [symbolic = constants.%Self.25f]
400398
// CHECK:STDOUT: %Core.import_ref.51c: <witness> = import_ref Core//prelude, loc21_36, loaded [symbolic = @impl.%impl_witness (constants.%impl_witness.b81)]
401399
// CHECK:STDOUT: %Core.import_ref.5ab3ec.1: type = import_ref Core//prelude, loc21_14, loaded [symbolic = @impl.%T (constants.%T)]
@@ -659,7 +657,6 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
659657
// CHECK:STDOUT: %BitAnd.assoc_type: type = assoc_entity_type %BitAnd.type [concrete]
660658
// CHECK:STDOUT: %assoc0.a63: %BitAnd.assoc_type = assoc_entity element0, imports.%Core.import_ref.a93 [concrete]
661659
// CHECK:STDOUT: %Op.type.27a: type = fn_type @Op.1 [concrete]
662-
// CHECK:STDOUT: %Op.ab9: %Op.type.27a = struct_value () [concrete]
663660
// CHECK:STDOUT: %Self.as_type.19f: type = facet_access_type %Self.25f [symbolic]
664661
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
665662
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
@@ -704,13 +701,13 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
704701
// CHECK:STDOUT: %Convert.42e: %Convert.type.275 = struct_value () [symbolic]
705702
// CHECK:STDOUT: %Self.as_type.40a: type = facet_access_type %Self.519 [symbolic]
706703
// CHECK:STDOUT: %ImplicitAs.assoc_type.837: type = assoc_entity_type %ImplicitAs.type.d62 [symbolic]
707-
// CHECK:STDOUT: %assoc0.43db8b.1: %ImplicitAs.assoc_type.837 = assoc_entity element0, imports.%Core.import_ref.207961.1 [symbolic]
704+
// CHECK:STDOUT: %assoc0.02f: %ImplicitAs.assoc_type.837 = assoc_entity element0, imports.%Core.import_ref.1c7 [symbolic]
708705
// CHECK:STDOUT: %ImplicitAs.type.dbb: type = facet_type <@ImplicitAs, @ImplicitAs(%facet_type.6ff)> [concrete]
709706
// CHECK:STDOUT: %Convert.type.bd1: type = fn_type @Convert, @ImplicitAs(%facet_type.6ff) [concrete]
710707
// CHECK:STDOUT: %Convert.af7: %Convert.type.bd1 = struct_value () [concrete]
711708
// CHECK:STDOUT: %ImplicitAs.assoc_type.f1b: type = assoc_entity_type %ImplicitAs.type.dbb [concrete]
712-
// CHECK:STDOUT: %assoc0.976: %ImplicitAs.assoc_type.f1b = assoc_entity element0, imports.%Core.import_ref.207961.1 [concrete]
713-
// CHECK:STDOUT: %assoc0.43db8b.2: %ImplicitAs.assoc_type.837 = assoc_entity element0, imports.%Core.import_ref.207961.2 [symbolic]
709+
// CHECK:STDOUT: %assoc0.15b: %ImplicitAs.assoc_type.f1b = assoc_entity element0, imports.%Core.import_ref.1c7 [concrete]
710+
// CHECK:STDOUT: %assoc0.43d: %ImplicitAs.assoc_type.837 = assoc_entity element0, imports.%Core.import_ref.207 [symbolic]
714711
// CHECK:STDOUT: }
715712
// CHECK:STDOUT:
716713
// CHECK:STDOUT: imports {
@@ -721,7 +718,7 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
721718
// CHECK:STDOUT: }
722719
// CHECK:STDOUT: %Core.import_ref.ad0 = import_ref Core//prelude, inst100 [no loc], unloaded
723720
// CHECK:STDOUT: %Core.import_ref.08d: %BitAnd.assoc_type = import_ref Core//prelude, loc18_41, loaded [concrete = constants.%assoc0.a63]
724-
// CHECK:STDOUT: %Core.Op: %Op.type.27a = import_ref Core//prelude, Op, loaded [concrete = constants.%Op.ab9]
721+
// CHECK:STDOUT: %Core.Op = import_ref Core//prelude, Op, unloaded
725722
// CHECK:STDOUT: %Core.import_ref.040: %BitAnd.type = import_ref Core//prelude, inst100 [no loc], loaded [symbolic = constants.%Self.25f]
726723
// CHECK:STDOUT: %Core.import_ref.51c: <witness> = import_ref Core//prelude, loc21_36, loaded [symbolic = @impl.f92.%impl_witness (constants.%impl_witness.b81)]
727724
// CHECK:STDOUT: %Core.import_ref.5ab3ec.1: type = import_ref Core//prelude, loc21_14, loaded [symbolic = @impl.f92.%T (constants.%T)]
@@ -731,11 +728,11 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
731728
// CHECK:STDOUT: %Core.import_ref.5ab3ec.2: type = import_ref Core//prelude, loc21_14, loaded [symbolic = @impl.f92.%T (constants.%T)]
732729
// CHECK:STDOUT: %Core.import_ref.5ab3ec.3: type = import_ref Core//prelude, loc13_22, loaded [symbolic = @ImplicitAs.%Dest (constants.%Dest)]
733730
// CHECK:STDOUT: %Core.import_ref.ff5 = import_ref Core//prelude, inst65 [no loc], unloaded
734-
// CHECK:STDOUT: %Core.import_ref.630: @ImplicitAs.%ImplicitAs.assoc_type (%ImplicitAs.assoc_type.837) = import_ref Core//prelude, loc14_35, loaded [symbolic = @ImplicitAs.%assoc0 (constants.%assoc0.43db8b.2)]
735-
// CHECK:STDOUT: %Core.Convert: @ImplicitAs.%Convert.type (%Convert.type.275) = import_ref Core//prelude, Convert, loaded [symbolic = @ImplicitAs.%Convert (constants.%Convert.42e)]
731+
// CHECK:STDOUT: %Core.import_ref.630: @ImplicitAs.%ImplicitAs.assoc_type (%ImplicitAs.assoc_type.837) = import_ref Core//prelude, loc14_35, loaded [symbolic = @ImplicitAs.%assoc0 (constants.%assoc0.43d)]
732+
// CHECK:STDOUT: %Core.Convert = import_ref Core//prelude, Convert, unloaded
736733
// CHECK:STDOUT: %Core.import_ref.5ab3ec.4: type = import_ref Core//prelude, loc13_22, loaded [symbolic = @ImplicitAs.%Dest (constants.%Dest)]
737734
// CHECK:STDOUT: %Core.import_ref.ce1: @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.d62) = import_ref Core//prelude, inst65 [no loc], loaded [symbolic = @ImplicitAs.%Self (constants.%Self.519)]
738-
// CHECK:STDOUT: %Core.import_ref.207961.1 = import_ref Core//prelude, loc14_35, unloaded
735+
// CHECK:STDOUT: %Core.import_ref.1c7: @ImplicitAs.%Convert.type (%Convert.type.275) = import_ref Core//prelude, loc14_35, loaded [symbolic = @ImplicitAs.%Convert (constants.%Convert.42e)]
739736
// CHECK:STDOUT: }
740737
// CHECK:STDOUT:
741738
// CHECK:STDOUT: file {
@@ -855,7 +852,7 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
855852
// CHECK:STDOUT: %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.275)]
856853
// CHECK:STDOUT: %Convert: @ImplicitAs.%Convert.type (%Convert.type.275) = struct_value () [symbolic = %Convert (constants.%Convert.42e)]
857854
// CHECK:STDOUT: %ImplicitAs.assoc_type: type = assoc_entity_type @ImplicitAs.%ImplicitAs.type (%ImplicitAs.type.d62) [symbolic = %ImplicitAs.assoc_type (constants.%ImplicitAs.assoc_type.837)]
858-
// CHECK:STDOUT: %assoc0: @ImplicitAs.%ImplicitAs.assoc_type (%ImplicitAs.assoc_type.837) = assoc_entity element0, imports.%Core.import_ref.207961.1 [symbolic = %assoc0 (constants.%assoc0.43db8b.1)]
855+
// CHECK:STDOUT: %assoc0: @ImplicitAs.%ImplicitAs.assoc_type (%ImplicitAs.assoc_type.837) = assoc_entity element0, imports.%Core.import_ref.1c7 [symbolic = %assoc0 (constants.%assoc0.02f)]
859856
// CHECK:STDOUT:
860857
// CHECK:STDOUT: interface {
861858
// CHECK:STDOUT: !members:
@@ -1050,7 +1047,7 @@ fn HandleTameAnimal2[W:! Animal & Tame](w: W) {
10501047
// CHECK:STDOUT: %Convert.type => constants.%Convert.type.bd1
10511048
// CHECK:STDOUT: %Convert => constants.%Convert.af7
10521049
// CHECK:STDOUT: %ImplicitAs.assoc_type => constants.%ImplicitAs.assoc_type.f1b
1053-
// CHECK:STDOUT: %assoc0 => constants.%assoc0.976
1050+
// CHECK:STDOUT: %assoc0 => constants.%assoc0.15b
10541051
// CHECK:STDOUT: }
10551052
// CHECK:STDOUT:
10561053
// CHECK:STDOUT: --- toolchain/testing/min_prelude/facet_types.carbon

0 commit comments

Comments
 (0)