Use early rewrites in compound member access (#7207)

We replace the non-canonical ImplWitnessAccess instruction with an
ImplWitnessAccessSubstituted instruction containing the RHS of a prior
rewrite constraint in the same facet type when possible, in order to
access the value of the prior constraint. We were doing this only in the
designator access path though, not in the compound member access. Join
these two code paths when they construct the ImplWitnessAccess, and
perform the early access there for both.
This commit is contained in:
Dana Jansens
2026-05-14 16:37:50 +00:00
committed by GitHub
parent d010d52f37
commit 417531f484
2 changed files with 51 additions and 22 deletions
+30 -22
View File
@@ -178,6 +178,26 @@ static auto ScopeNeedsImplLookup(Context& context,
return true;
}
static auto PerformImplWitnessAccessAndSubstitute(
Context& context, SemIR::LocId loc_id, SemIR::ImplWitnessAccess access)
-> SemIR::InstId {
auto access_id =
GetOrAddInst<SemIR::ImplWitnessAccess>(context, loc_id, access);
if (!context.rewrites_stack().empty()) {
if (auto result = context.rewrites_stack().back().Lookup(
context.constant_values().Get(access_id))) {
return GetOrAddInst<SemIR::ImplWitnessAccessSubstituted>(
context, loc_id,
{.type_id = access.type_id,
.impl_witness_access_id = access_id,
.value_id = result.value()});
}
}
return access_id;
}
static auto AccessMemberOfImplWitness(
Context& context, SemIR::LocId loc_id, SemIR::InstId witness_id,
SemIR::SpecificId interface_with_self_specific_id, SemIR::InstId member_id)
@@ -203,10 +223,11 @@ static auto AccessMemberOfImplWitness(
auto assoc_type_id = GetTypeForSpecificAssociatedEntity(
context, interface_with_self_specific_id, assoc_entity->decl_id);
return GetOrAddInst<SemIR::ImplWitnessAccess>(context, loc_id,
{.type_id = assoc_type_id,
.witness_id = witness_id,
.index = assoc_entity->index});
return PerformImplWitnessAccessAndSubstitute(
context, loc_id,
SemIR::ImplWitnessAccess{.type_id = assoc_type_id,
.witness_id = witness_id,
.index = assoc_entity->index});
}
// For an impl lookup query with a single interface in it, we can convert the
@@ -356,20 +377,6 @@ static auto LookupMemberNameInScope(Context& context, SemIR::LocId loc_id,
}
}
if (!context.rewrites_stack().empty()) {
if (auto access =
context.insts().TryGetAs<SemIR::ImplWitnessAccess>(member_id)) {
if (auto result = context.rewrites_stack().back().Lookup(
context.constant_values().Get(member_id))) {
return GetOrAddInst<SemIR::ImplWitnessAccessSubstituted>(
context, loc_id,
{.type_id = access->type_id,
.impl_witness_access_id = member_id,
.value_id = result.value()});
}
}
}
return member_id;
}
@@ -715,10 +722,11 @@ static auto GetAssociatedValueImpl(Context& context, SemIR::LocId loc_id,
context, interface_with_self_specific_id, assoc_entity.decl_id);
// Now that we have the witness, an index into it, and the type of the
// result, return the element of the witness.
return GetOrAddInst<SemIR::ImplWitnessAccess>(context, loc_id,
{.type_id = assoc_type_id,
.witness_id = witness_id,
.index = assoc_entity.index});
return PerformImplWitnessAccessAndSubstitute(
context, loc_id,
SemIR::ImplWitnessAccess{.type_id = assoc_type_id,
.witness_id = witness_id,
.index = assoc_entity.index});
}
auto GetAssociatedValue(Context& context, SemIR::LocId loc_id,
+21
View File
@@ -323,6 +323,27 @@ fn G(T:! J where .J1 = D) {
F(T);
}
// --- early_rewrite_of_compound_access.carbon
library "[[@TEST_NAME]]";
interface Z {
let Z1:! type;
let Z2:! type;
}
interface Y {}
class NeedY(T:! Y) {}
impl () as Y {}
// These are written differently but should behave the same.
// Designator access of `.Z1`.
fn F(_:! Z where .Z1 = () and .Z2 = NeedY(.Z1)) {}
// Compound member access of `.Z1`.
fn G(_:! Z where .Z1 = () and .Z2 = NeedY(.Self.(Z.Z1))) {}
// --- fail_todo_resolved_constraint_visible_in_type_parameter.carbon
library "[[@TEST_NAME]]";