Skip to content

Commit a69c263

Browse files
josh11bgeoffromer
andauthored
Replace InterfaceType with FacetType (#4499)
This does a few things: * Replaces the single `TypeId` in the `FacetTypeInfo` struct with a vector of `InterfaceId`, `SpecificId` pairs (sorted in id order) representing the set of interface requirements of the facet type. This will later be used to support facet types with multiple interface requirements (as in `I & J` or `I where .Self impls J`). * Replace `InterfaceType` instructions (used as the type of an `InterfaceDecl` instruction) with `FacetType` instructions (introduced in #4460) with a (newly introduced) `FacetTypeFromInterface()` function. * Replace code that consumed `InterfaceType` values with code that consumed `FaceType` values. I've generally left the assumption in the code that it is dealing with a single interface, using the (newly introduced) `FacetTypeInfo::TryAsSingleInterface`, and producing an error otherwise. There isn't yet support for the `&` operator or `where .Self impls`, so this is generally a good assumption for now, except you can get a facet type with no associated interfaces from a `type where`... expression. In some cases, the facet type value is pulled from the evaluation of an `InterfaceDecl` instruction, where the single interface assumption will hold permanently. * Some related cleans up: nicer stringification and formatting of facet types, suppression of some errors when there already was an error. There is still a lot left to do, including: * Type `type` should be a facet type with a reserved id, replacing the built-in instruction. * Code using `TryAsSingleInterface` should generally be upgraded to handle more than (or less than) one interface. Name lookup should be particularly exciting. * Operator `&` should be defined on facet types, unioning their interface and other requirements. * Requirements from a `where` clause don't do anything yet. * Impls and impl lookup need to resolve facet types, and do things like determine if all the associated constants are given values. --------- Co-authored-by: Josh L <[email protected]> Co-authored-by: Geoff Romer <[email protected]>
1 parent 6dce164 commit a69c263

File tree

177 files changed

+1596
-1163
lines changed

Some content is hidden

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

177 files changed

+1596
-1163
lines changed

toolchain/check/call.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,8 @@ static auto PerformCallToGenericInterface(
117117
if (!callee_specific_id) {
118118
return SemIR::InstId::BuiltinError;
119119
}
120-
return context.GetOrAddInst<SemIR::InterfaceType>(
121-
loc_id, {.type_id = SemIR::TypeId::TypeType,
122-
.interface_id = interface_id,
123-
.specific_id = *callee_specific_id});
120+
return context.GetOrAddInst(loc_id, context.FacetTypeFromInterface(
121+
interface_id, *callee_specific_id));
124122
}
125123

126124
auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,

toolchain/check/context.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,10 @@ class TypeCompleter {
10691069
}
10701070

10711071
template <typename InstT>
1072-
requires(
1073-
InstT::Kind
1074-
.template IsAnyOf<SemIR::AssociatedEntityType, SemIR::FacetType,
1075-
SemIR::FunctionType, SemIR::GenericClassType,
1076-
SemIR::GenericInterfaceType, SemIR::InterfaceType,
1077-
SemIR::UnboundElementType, SemIR::WhereExpr>())
1072+
requires(InstT::Kind.template IsAnyOf<
1073+
SemIR::AssociatedEntityType, SemIR::FacetType, SemIR::FunctionType,
1074+
SemIR::GenericClassType, SemIR::GenericInterfaceType,
1075+
SemIR::UnboundElementType, SemIR::WhereExpr>())
10781076
auto BuildValueReprForInst(SemIR::TypeId /*type_id*/, InstT /*inst*/) const
10791077
-> SemIR::ValueRepr {
10801078
// These types have no runtime operations, so we use an empty value
@@ -1187,7 +1185,18 @@ auto Context::TryToDefineType(SemIR::TypeId type_id,
11871185
return false;
11881186
}
11891187

1190-
if (auto interface = types().TryGetAs<SemIR::InterfaceType>(type_id)) {
1188+
if (auto facet_type = types().TryGetAs<SemIR::FacetType>(type_id)) {
1189+
const auto& facet_type_info =
1190+
sem_ir().facet_types().Get(facet_type->facet_type_id);
1191+
auto interface = facet_type_info.TryAsSingleInterface();
1192+
if (!interface) {
1193+
auto builder = diagnoser();
1194+
CARBON_DIAGNOSTIC(SingleInterfaceFacetTypeOnly, Note,
1195+
"only single interface facet types supported so far");
1196+
builder.Note(SemIR::LocId::Invalid, SingleInterfaceFacetTypeOnly);
1197+
builder.Emit();
1198+
return false;
1199+
}
11911200
auto interface_id = interface->interface_id;
11921201
if (!interfaces().Get(interface_id).is_defined()) {
11931202
auto builder = diagnoser();
@@ -1218,6 +1227,16 @@ auto Context::GetTypeIdForTypeConstant(SemIR::ConstantId constant_id)
12181227
return SemIR::TypeId::ForTypeConstant(constant_id);
12191228
}
12201229

1230+
auto Context::FacetTypeFromInterface(SemIR::InterfaceId interface_id,
1231+
SemIR::SpecificId specific_id)
1232+
-> SemIR::FacetType {
1233+
SemIR::FacetTypeId facet_type_id =
1234+
sem_ir().facet_types().Add(SemIR::FacetTypeInfo{
1235+
.impls_constraints = {{interface_id, specific_id}},
1236+
.requirement_block_id = SemIR::InstBlockId::Invalid});
1237+
return {.type_id = SemIR::TypeId::TypeType, .facet_type_id = facet_type_id};
1238+
}
1239+
12211240
// Gets or forms a type_id for a type, given the instruction kind and arguments.
12221241
template <typename InstT, typename... EachArgT>
12231242
static auto GetTypeImpl(Context& context, EachArgT... each_arg)

toolchain/check/context.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,15 @@ class Context {
361361
// Returns whether `type_id` represents a facet type.
362362
auto IsFacetType(SemIR::TypeId type_id) -> bool {
363363
return type_id == SemIR::TypeId::TypeType ||
364-
types().Is<SemIR::InterfaceType>(type_id);
364+
types().Is<SemIR::FacetType>(type_id);
365365
}
366366

367+
// Create a FacetType typed instruction object consisting of a single
368+
// interface.
369+
auto FacetTypeFromInterface(SemIR::InterfaceId interface_id,
370+
SemIR::SpecificId specific_id)
371+
-> SemIR::FacetType;
372+
367373
// TODO: Consider moving these `Get*Type` functions to a separate class.
368374

369375
// Gets the type for the name of an associated entity.

toolchain/check/convert.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
894894
// the case where F1 is an interface type and F2 is `type`.
895895
// TODO: Support converting tuple and struct values to facet types,
896896
// combining the above conversions and this one in a single conversion.
897-
if (sem_ir.types().Is<SemIR::InterfaceType>(value_type_id)) {
897+
if (sem_ir.types().Is<SemIR::FacetType>(value_type_id)) {
898898
return context.AddInst<SemIR::FacetTypeAccess>(
899899
loc_id, {.type_id = target.type_id, .facet_id = value_id});
900900
}

toolchain/check/deduce.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,29 @@ class DeductionWorklist {
114114
needs_substitution);
115115
}
116116

117+
auto AddAll(SemIR::FacetTypeId params, SemIR::FacetTypeId args,
118+
bool needs_substitution) -> void {
119+
const auto& param_impls =
120+
context_.sem_ir().facet_types().Get(params).impls_constraints;
121+
const auto& arg_impls =
122+
context_.sem_ir().facet_types().Get(args).impls_constraints;
123+
if (param_impls.size() != arg_impls.size()) {
124+
// TODO: Decide whether to error on this or just treat the parameter list
125+
// as non-deduced. For now we treat it as non-deduced.
126+
return;
127+
}
128+
for (auto [param, arg] :
129+
llvm::reverse(llvm::zip_equal(param_impls, arg_impls))) {
130+
Add(param.specific_id, arg.specific_id, needs_substitution);
131+
}
132+
}
133+
117134
// Adds a (param, arg) pair for an instruction argument, given its kind.
118135
auto AddInstArg(SemIR::IdKind kind, int32_t param, int32_t arg,
119136
bool needs_substitution) -> void {
120137
switch (kind) {
121138
case SemIR::IdKind::None:
122139
case SemIR::IdKind::For<SemIR::ClassId>:
123-
case SemIR::IdKind::For<SemIR::InterfaceId>:
124140
case SemIR::IdKind::For<SemIR::IntKind>:
125141
break;
126142
case SemIR::IdKind::For<SemIR::InstId>:
@@ -145,6 +161,10 @@ class DeductionWorklist {
145161
Add(SemIR::SpecificId(param), SemIR::SpecificId(arg),
146162
needs_substitution);
147163
break;
164+
case SemIR::IdKind::For<SemIR::FacetTypeId>:
165+
AddAll(SemIR::FacetTypeId(param), SemIR::FacetTypeId(arg),
166+
needs_substitution);
167+
break;
148168
default:
149169
CARBON_FATAL("unexpected argument kind");
150170
}
@@ -400,8 +420,8 @@ auto DeductionContext::Deduce() -> bool {
400420
case SemIR::ArrayType::Kind:
401421
case SemIR::ClassType::Kind:
402422
case SemIR::ConstType::Kind:
423+
case SemIR::FacetType::Kind:
403424
case SemIR::FloatType::Kind:
404-
case SemIR::InterfaceType::Kind:
405425
case SemIR::IntType::Kind:
406426
case SemIR::PointerType::Kind:
407427
case SemIR::StructType::Kind:

toolchain/check/eval.cpp

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,21 @@ static auto GetConstantValue(EvalContext& eval_context,
391391
return MakeSpecific(eval_context.context(), specific.generic_id, args_id);
392392
}
393393

394+
// Like `GetConstantValue` but does a `FacetTypeId` -> `FacetTypeInfo`
395+
// conversion.
396+
static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
397+
SemIR::FacetTypeId facet_type_id,
398+
Phase* phase) -> SemIR::FacetTypeInfo {
399+
SemIR::FacetTypeInfo info = eval_context.facet_types().Get(facet_type_id);
400+
for (auto& interface : info.impls_constraints) {
401+
interface.specific_id =
402+
GetConstantValue(eval_context, interface.specific_id, phase);
403+
}
404+
std::sort(info.impls_constraints.begin(), info.impls_constraints.end());
405+
// TODO: Process & canonicalize other requirements.
406+
return info;
407+
}
408+
394409
// Replaces the specified field of the given typed instruction with its constant
395410
// value, if it has constant phase. Returns true on success, false if the value
396411
// has runtime phase.
@@ -1141,12 +1156,9 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
11411156

11421157
// Creates a FacetType constant.
11431158
static auto MakeFacetTypeResult(Context& context,
1144-
SemIR::TypeId base_facet_type_id,
1145-
SemIR::InstBlockId requirement_block_id,
1146-
Phase phase) -> SemIR::ConstantId {
1147-
SemIR::FacetTypeId facet_type_id = context.sem_ir().facet_types().Add(
1148-
SemIR::FacetTypeInfo{.base_facet_type_id = base_facet_type_id,
1149-
.requirement_block_id = requirement_block_id});
1159+
const SemIR::FacetTypeInfo& info, Phase phase)
1160+
-> SemIR::ConstantId {
1161+
SemIR::FacetTypeId facet_type_id = context.sem_ir().facet_types().Add(info);
11501162
return MakeConstantResult(context,
11511163
SemIR::FacetType{.type_id = SemIR::TypeId::TypeType,
11521164
.facet_type_id = facet_type_id},
@@ -1230,9 +1242,6 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
12301242
return RebuildIfFieldsAreConstant(
12311243
eval_context, inst,
12321244
&SemIR::GenericInterfaceType::enclosing_specific_id);
1233-
case SemIR::InterfaceType::Kind:
1234-
return RebuildIfFieldsAreConstant(eval_context, inst,
1235-
&SemIR::InterfaceType::specific_id);
12361245
case SemIR::InterfaceWitness::Kind:
12371246
return RebuildIfFieldsAreConstant(eval_context, inst,
12381247
&SemIR::InterfaceWitness::elements_id);
@@ -1332,20 +1341,11 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
13321341
}
13331342

13341343
case CARBON_KIND(SemIR::FacetType facet_type): {
1335-
SemIR::FacetTypeInfo info =
1336-
eval_context.facet_types().Get(facet_type.facet_type_id);
13371344
Phase phase = Phase::Template;
1338-
SemIR::TypeId base_facet_type_id =
1339-
GetConstantValue(eval_context, info.base_facet_type_id, &phase);
1340-
// TODO: Process & canonicalize requirements.
1341-
SemIR::InstBlockId requirement_block_id = info.requirement_block_id;
1342-
// If nothing changed, can reuse this instruction.
1343-
if (base_facet_type_id == info.base_facet_type_id &&
1344-
requirement_block_id == info.requirement_block_id) {
1345-
return MakeConstantResult(eval_context.context(), inst, phase);
1346-
}
1347-
return MakeFacetTypeResult(eval_context.context(), base_facet_type_id,
1348-
requirement_block_id, phase);
1345+
SemIR::FacetTypeInfo info = GetConstantFacetTypeInfo(
1346+
eval_context, facet_type.facet_type_id, &phase);
1347+
// TODO: Reuse `inst` if we can detect that nothing has changed.
1348+
return MakeFacetTypeResult(eval_context.context(), info, phase);
13491349
}
13501350

13511351
case CARBON_KIND(SemIR::InterfaceDecl interface_decl): {
@@ -1363,12 +1363,11 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
13631363
},
13641364
&SemIR::InterfaceDecl::type_id);
13651365
}
1366-
// A non-generic interface declaration evaluates to the interface type.
1366+
// A non-generic interface declaration evaluates to a facet type.
13671367
return MakeConstantResult(
13681368
eval_context.context(),
1369-
SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType,
1370-
.interface_id = interface_decl.interface_id,
1371-
.specific_id = SemIR::SpecificId::Invalid},
1369+
eval_context.context().FacetTypeFromInterface(
1370+
interface_decl.interface_id, SemIR::SpecificId::Invalid),
13721371
Phase::Template);
13731372
}
13741373

@@ -1506,15 +1505,28 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
15061505
return eval_context.GetConstantValue(typed_inst.facet_id);
15071506
}
15081507
case CARBON_KIND(SemIR::WhereExpr typed_inst): {
1508+
Phase phase = Phase::Template;
15091509
SemIR::TypeId base_facet_type_id =
15101510
eval_context.insts().Get(typed_inst.period_self_id).type_id();
1511-
Phase phase = Phase::Template;
1512-
base_facet_type_id =
1513-
GetConstantValue(eval_context, base_facet_type_id, &phase);
1514-
SemIR::InstBlockId requirement_block_id = typed_inst.requirements_id;
1515-
// TODO: Process & canonicalize requirements.
1516-
return MakeFacetTypeResult(eval_context.context(), base_facet_type_id,
1517-
requirement_block_id, phase);
1511+
SemIR::Inst base_facet_inst =
1512+
eval_context.GetConstantValueAsInst(base_facet_type_id);
1513+
SemIR::FacetTypeInfo info = {.requirement_block_id =
1514+
SemIR::InstBlockId::Invalid};
1515+
// `where` provides that the base facet is an error, `type`, or a facet
1516+
// type.
1517+
if (auto facet_type = base_facet_inst.TryAs<SemIR::FacetType>()) {
1518+
info = GetConstantFacetTypeInfo(eval_context, facet_type->facet_type_id,
1519+
&phase);
1520+
} else if (base_facet_type_id == SemIR::TypeId::Error) {
1521+
return SemIR::ConstantId::Error;
1522+
} else {
1523+
CARBON_CHECK(base_facet_type_id == SemIR::TypeId::TypeType,
1524+
"Unexpected type_id: {0}, inst: {1}", base_facet_type_id,
1525+
base_facet_inst);
1526+
}
1527+
// TODO: Combine other requirements, and then process & canonicalize them.
1528+
info.requirement_block_id = typed_inst.requirements_id;
1529+
return MakeFacetTypeResult(eval_context.context(), info, phase);
15181530
}
15191531

15201532
// `not true` -> `false`, `not false` -> `true`.

toolchain/check/handle_impl.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,18 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
173173
diag.Emit();
174174
}
175175

176-
auto interface_type =
177-
context.types().TryGetAs<SemIR::InterfaceType>(constraint_id);
176+
auto facet_type = context.types().TryGetAs<SemIR::FacetType>(constraint_id);
177+
if (!facet_type) {
178+
context.TODO(node_id, "extending non-facet-type constraint");
179+
parent_scope.has_error = true;
180+
return;
181+
}
182+
const SemIR::FacetTypeInfo& info =
183+
context.sem_ir().facet_types().Get(facet_type->facet_type_id);
184+
185+
auto interface_type = info.TryAsSingleInterface();
178186
if (!interface_type) {
179-
context.TODO(node_id, "extending non-interface constraint");
187+
context.TODO(node_id, "extending non-single-interface facet type");
180188
parent_scope.has_error = true;
181189
return;
182190
}

toolchain/check/handle_index.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static auto GetIndexWithArgs(Context& context, Parse::NodeId node_id,
3434
auto index_with_inst_id = context.LookupNameInCore(node_id, "IndexWith");
3535
// If the `IndexWith` interface doesn't have generic arguments then return an
3636
// empty reference.
37-
if (context.insts().Is<SemIR::InterfaceType>(index_with_inst_id)) {
37+
if (context.insts().Is<SemIR::FacetType>(index_with_inst_id)) {
3838
return llvm::ArrayRef<SemIR::InstId>();
3939
}
4040

@@ -59,12 +59,17 @@ static auto GetIndexWithArgs(Context& context, Parse::NodeId node_id,
5959
if (impl_self_type_id != self_id) {
6060
continue;
6161
}
62-
auto interface_type =
63-
context.types().TryGetAs<SemIR::InterfaceType>(impl_constraint_type_id);
62+
auto facet_type =
63+
context.types().TryGetAs<SemIR::FacetType>(impl_constraint_type_id);
64+
if (!facet_type) {
65+
continue;
66+
}
67+
const auto& facet_type_info =
68+
context.sem_ir().facet_types().Get(facet_type->facet_type_id);
69+
auto interface_type = facet_type_info.TryAsSingleInterface();
6470
if (!interface_type) {
6571
continue;
6672
}
67-
6873
if (index_with_interface->interface_id != interface_type->interface_id) {
6974
continue;
7075
}

toolchain/check/handle_interface.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,10 @@ auto HandleParseNode(Context& context,
160160

161161
// Declare and introduce `Self`.
162162
if (!interface_info.is_defined()) {
163-
auto interface_type =
164-
SemIR::InterfaceType{.type_id = SemIR::TypeId::TypeType,
165-
.interface_id = interface_id,
166-
.specific_id = self_specific_id};
163+
SemIR::FacetType facet_type =
164+
context.FacetTypeFromInterface(interface_id, self_specific_id);
167165
SemIR::TypeId self_type_id = context.GetTypeIdForTypeConstant(
168-
TryEvalInst(context, SemIR::InstId::Invalid, interface_type));
166+
TryEvalInst(context, SemIR::InstId::Invalid, facet_type));
169167

170168
// We model `Self` as a symbolic binding whose type is the interface.
171169
// Because there is no equivalent non-symbolic value, we use `Invalid` as

toolchain/check/handle_where.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ auto HandleParseNode(Context& context, Parse::WhereOperandId node_id) -> bool {
1616
auto [self_node, self_id] = context.node_stack().PopExprWithNodeId();
1717
auto self_type_id = ExprAsType(context, self_node, self_id).type_id;
1818
// Only facet types may have `where` restrictions.
19-
if (!context.IsFacetType(self_type_id)) {
19+
if (self_type_id != SemIR::TypeId::Error &&
20+
!context.IsFacetType(self_type_id)) {
2021
CARBON_DIAGNOSTIC(WhereOnNonFacetType, Error,
2122
"left argument of `where` operator must be a facet type");
2223
context.emitter().Emit(self_node, WhereOnNonFacetType);

0 commit comments

Comments
 (0)