Compare ImplWitnessAccess into Self as canonical constants (#5883)

This makes all `.Self` references in a facet type canonically the same
(which will remain true iff they refer to the same `Self` type in the
future), removing the need to do more complex comparisons between them
using the EntityName, interface, and index. This allows the comparison
of types containing `.Self` references to be done correctly regardless
of where the `.Self` appears, as such type expressions will all be
canonically equal if they otherwise equal now, regardless of whether
they are written in the context where `.Self` could have seen different
`Self` facet types.

In order to retain access to constraints on a base `.Self` facet type,
in the case of applying `where` to an existing facet type, we:
- Give the base facet type as a `RequirementBaseFacetType` constraint so
that eval of `WhereExpr` can find and copy all the constraints off of
it.
- Introduce eager/early rewrite constraint resolution, which allows a
constraint to eagerly resolve access to earlier rewrite constraints
(`where .A = () and .B = .A` is eagerly transformed into `where .A = ()
and .B = ()`) before the full constraint resolution step. This allows
use of rewrite constraints in larger type expressions, such as `where .A
= () and .B = C(.A)` and `C` will know that the argument is `()`.
This commit is contained in:
Dana Jansens
2025-08-08 18:36:39 +00:00
committed by GitHub
parent edcc24ecf7
commit 3d77c4441b
39 changed files with 558 additions and 207 deletions
+27 -18
View File
@@ -18,6 +18,7 @@
#include "toolchain/check/facet_type.h"
#include "toolchain/check/generic.h"
#include "toolchain/check/import_ref.h"
#include "toolchain/check/name_lookup.h"
#include "toolchain/check/type.h"
#include "toolchain/check/type_completion.h"
#include "toolchain/diagnostics/diagnostic.h"
@@ -637,6 +638,13 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
// canonical instruction, so that in a `WhereExpr` we can work with the
// `ImplWitnessAccess` references to `.Self` on the LHS of the constraints
// rather than the value of the associated constant they reference.
//
// This also implies that we may find `ImplWitnessAccessSubstituted`
// instructions in the LHS and RHS of these constraints, which are preserved
// to maintain them as an unresolved reference to an associated constant, but
// which must be handled gracefully during resolution. They will be replaced
// with the constant value of the `ImplWitnessAccess` below when they are
// substituted with a constant value.
info.rewrite_constraints = orig.rewrite_constraints;
if (!ResolveFacetTypeRewriteConstraints(eval_context.context(), loc_id,
info.rewrite_constraints)) {
@@ -2049,31 +2057,32 @@ auto TryEvalTypedInst<SemIR::WhereExpr>(EvalContext& eval_context,
auto typed_inst = inst.As<SemIR::WhereExpr>();
Phase phase = Phase::Concrete;
SemIR::TypeId base_facet_type_id =
eval_context.GetTypeOfInst(typed_inst.period_self_id);
SemIR::Inst base_facet_inst =
eval_context.types().GetAsInst(base_facet_type_id);
SemIR::FacetTypeInfo info = {.other_requirements = false};
// `where` provides that the base facet is an error, `type`, or a facet
// type.
if (auto facet_type = base_facet_inst.TryAs<SemIR::FacetType>()) {
info = eval_context.facet_types().Get(facet_type->facet_type_id);
} else if (base_facet_type_id == SemIR::ErrorInst::TypeId) {
return SemIR::ErrorInst::ConstantId;
} else {
CARBON_CHECK(base_facet_type_id == SemIR::TypeType::TypeId,
"Unexpected type_id: {0}, inst: {1}", base_facet_type_id,
base_facet_inst);
}
// Add the constraints from the `WhereExpr` instruction into `info`.
if (typed_inst.requirements_id.has_value()) {
auto insts = eval_context.inst_blocks().Get(typed_inst.requirements_id);
for (auto inst_id : insts) {
if (auto rewrite =
eval_context.insts().TryGetAs<SemIR::RequirementRewrite>(
if (auto base =
eval_context.insts().TryGetAs<SemIR::RequirementBaseFacetType>(
inst_id)) {
if (base->base_type_inst_id == SemIR::ErrorInst::TypeInstId) {
return SemIR::ErrorInst::ConstantId;
}
if (auto base_facet_type =
eval_context.insts().TryGetAs<SemIR::FacetType>(
base->base_type_inst_id)) {
const auto& base_info =
eval_context.facet_types().Get(base_facet_type->facet_type_id);
info.extend_constraints.append(base_info.extend_constraints);
info.self_impls_constraints.append(base_info.self_impls_constraints);
info.rewrite_constraints.append(base_info.rewrite_constraints);
info.other_requirements |= base_info.other_requirements;
}
} else if (auto rewrite =
eval_context.insts().TryGetAs<SemIR::RequirementRewrite>(
inst_id)) {
info.rewrite_constraints.push_back(
{.lhs_id = rewrite->lhs_id, .rhs_id = rewrite->rhs_id});
} else if (auto impls =