Skip to content

Commit

Permalink
Use FacetAccessType when converting to a value of type FacetType
Browse files Browse the repository at this point in the history
When attempting to convert to a value of type FacetType, and the source
value is a FacetAccessType, then if the type of the underlying
FacetValue is the same as the target, we can use the FacetValue there
as the conversion output.

If the type of the FacetValue differs, then we still want to do impl
lookup with the FacetValue to see if it matches with the target
FacetType, but that is still a TODO.

This allows a generic function with a value whose type is constrained
by a FacetType (thus the value's type is a FacetAccessType), to call
other functions with the value as an argument when it is constrained
by the same FacetType:
```
fn F[T:! FacetType](x: T);
fn G[T:! FacetType](x: T) { F(x); }
```

It is also an optimization to avoid impl lookup where we've already done
it to produce the FacetAccessType.

Adds a bunch of new tests with values of types which are constrained by
a facet type (or "facet value value" for short), with some more tests
that currently fail and should be made to pass.
  • Loading branch information
danakj committed Feb 11, 2025
1 parent 0a55081 commit 5c758da
Show file tree
Hide file tree
Showing 8 changed files with 2,340 additions and 91 deletions.
30 changes: 26 additions & 4 deletions toolchain/check/convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,24 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
}

if (sem_ir.types().Is<SemIR::FacetType>(target.type_id)) {
if (sem_ir.types().Is<SemIR::FacetType>(value_type_id)) {
auto lookup_inst = value_id;

// `FacetAccessType` wraps an instruction that evaluates to a facet value
// (of type `FacetType`). If the `FacetType` matches the target
// `FacetType` then we don't need to do impl lookup. Otherwise, we want to
// try convert the result of the instruction in the `FacetAccessType`.
if (auto facet_access_type_value =
context.insts().TryGetAs<SemIR::FacetAccessType>(lookup_inst)) {
auto facet_value_inst_id = facet_access_type_value->facet_value_inst_id;
if (context.insts().Get(facet_value_inst_id).type_id() ==
target.type_id) {
return facet_value_inst_id;
}
lookup_inst = facet_access_type_value->facet_value_inst_id;
}

if (sem_ir.types().Is<SemIR::FacetType>(
sem_ir.insts().Get(lookup_inst).type_id())) {
// Conversion from a facet value (which has type `FacetType`) to a
// different facet value (which has type `FacetType`), if the value's
// `FacetType` satisfies the requirements of the target `FacetType`. The
Expand All @@ -1004,23 +1021,28 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
// so using that here would be like an implicit cast back to the concrete
// type.
context.TODO(loc_id, "Facet value converting to facet value");
} else if (sem_ir.types().Is<SemIR::TypeType>(value_type_id)) {
return value_id;
}

if (sem_ir.types().Is<SemIR::TypeType>(
sem_ir.insts().Get(lookup_inst).type_id())) {
// Conversion from a type value (which has type `type`) to a facet value
// (which has type `FacetType`), if the type satisfies the requirements of
// the target `FacetType`, as determined by finding an impl witness. This
// binds the value to the `FacetType` with a `FacetValue`.

auto witness_inst_id = LookupImplWitness(
context, loc_id,
// The value instruction evaluates to a type value (which has type
// `type`). This gets that type value if it's available at compile
// time, as a constant value.
context.constant_values().Get(value_id),
context.constant_values().Get(lookup_inst),
context.types().GetConstantId(target.type_id));
if (witness_inst_id != SemIR::InstId::None) {
return context.AddInst<SemIR::FacetValue>(
loc_id, {
.type_id = target.type_id,
.type_inst_id = value_id,
.type_inst_id = lookup_inst,
.witness_inst_id = witness_inst_id,
});
}
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

0 comments on commit 5c758da

Please sign in to comment.