Deduce facet values for arguments to generic fns receiving a facet type (#4865)

The fn receiving a facet type needs to deduce a type from a
FacetAccessType, which is the SemIR type representing the parameter type
that is a generic parameter. For example:

```
  fn F[T: Interface](val: T);
```

Here T is a generic parameter that is a facet value, but the `val`
parameter's type is the facet value converted from a FacetType to a
TypeType, with `as type`. The result of that conversion is a
FacetAccessType. So the deduction code sees a FacetAccessType for the
type of `val`.

We make deduction undo the `as type` conversion to move back to the `T`
parameter declaration, which has type FacetType in order to deduce the
required facet value (which is itself a type constrained by the
FacetType). And when we have a facet value (of type FacetType) to be
deduced, we will also convert the argument if it is of an appropriate
type to a FacetValue that matches the FacetType using the changes from
PR #4863.

Tests with `impl forall` can cause impl deduction to recurse forever and
crash, so those tests are omitted in this PR and they will come in
follow-up work that address the infinite recursion.

Rebased on top of PR #4885
This commit is contained in:
Dana Jansens
2025-02-11 02:03:33 +00:00
committed by GitHub
parent d0fec30776
commit 316a6c59e9
8 changed files with 2348 additions and 155 deletions
+17 -1
View File
@@ -335,6 +335,9 @@ auto DeductionContext::Deduce() -> bool {
DiagnosticAnnotationScope annotate_diagnostics(
&context().emitter(),
[&](auto& builder) { NoteInitializingParam(param_id, builder); });
// TODO: The call logic should reuse the conversion here (if any) instead
// of doing the same conversion again. At the moment we throw away the
// converted arg_id.
arg_id = ConvertToValueOfType(context(), loc_id_, arg_id, param_type_id);
if (arg_id == SemIR::ErrorInst::SingletonInstId) {
return false;
@@ -435,6 +438,20 @@ auto DeductionContext::Deduce() -> bool {
// TODO: Match field name order between param and arg.
break;
case SemIR::FacetAccessType::Kind:
// Given `fn F[G:! Interface](g: G)`, the type of `g` is `G as type`.
// `G` is a symbolic binding, whose type is a facet type, but `G as
// type` converts into a `FacetAccessType`.
//
// When we see a `FacetAccessType` parameter here, we want to deduce the
// facet type of `G`, not `G as type`, for the argument (so that the
// argument would be a facet value, whose type is the same facet type of
// `G`. So here we "undo" the `as type` operation that's built into the
// `g` parameter's type.
Add(param_inst.As<SemIR::FacetAccessType>().facet_value_inst_id, arg_id,
needs_substitution);
continue;
// TODO: Handle more cases.
default:
@@ -534,7 +551,6 @@ auto DeductionContext::CheckDeductionIsComplete() -> bool {
auto param_type_const_id = SubstConstant(
context(), binding_type_id.AsConstantId(), substitutions_);
CARBON_CHECK(param_type_const_id.has_value());
CARBON_CHECK(!param_type_const_id.is_symbolic());
binding_type_id = context().GetTypeIdForTypeConstant(param_type_const_id);
// TODO: Suppress diagnostics here if `diagnose_` is false.