Resolve nested accesses in rewrite constraints (#5872)

A rewrite constraint like `.X = .Y.Z and .Y = .Self and .Z = ()` has a
nested `ImplWitnessAccess` `.Y.Z` (technically `(.Self.Y).Z`). The inner
access `.Self.Y` needs to be resolved (in this case to `.Self`) before
the outer `???.Z` can be resolved as `.Self.Z` which is `()`.
This commit is contained in:
Dana Jansens
2025-07-30 14:34:24 +00:00
committed by GitHub
parent f0cff612eb
commit 105618ecb1
6 changed files with 156 additions and 34 deletions
+22 -12
View File
@@ -312,26 +312,33 @@ auto SubstInst(Context& context, SemIR::InstId inst_id,
while (index != -1) {
auto& item = worklist[index];
if (item.is_repeated) {
// Pop the copy of the repeated item when we get back to the repeated
// item, and steal any work that was done there so we don't have to
// Subst() the repeated item again. The pop does not reallocate the
// worklist so does not invalidate `item`.
item.inst_id = worklist.Pop();
}
if (item.is_expanded) {
// Rebuild this item if necessary. Note that this might pop items from the
// worklist but does not reallocate, so does not invalidate `item`.
item.inst_id = Rebuild(context, worklist, item.inst_id, callbacks);
index = item.next_index;
continue;
auto old_inst_id = std::exchange(
item.inst_id, Rebuild(context, worklist, item.inst_id, callbacks));
if (item.is_repeated && old_inst_id != item.inst_id) {
// SubstOperandsAndRetry was returned for the item, and the instruction
// was rebuilt from new operands, so go through Subst() again. Note that
// we've already called Rebuild so we don't want to leave this item as
// repeated, and call back to ReuseUnchanged for it again later unless
// the next call to Subst() asks for that.
item.is_expanded = false;
item.is_repeated = false;
} else {
index = item.next_index;
continue;
}
}
if (item.is_repeated) {
// SubstAgain was returned for the item, and the result of that Subst() is
// at the back of the worklist, which we pop. Note that popping from the
// worklist does not reallocate, so does not invalidate `item`.
//
// When Subst returns SubstAgain, we must call back to Rebuild or
// ReuseUnchanged for that work item.
item.inst_id = callbacks.ReuseUnchanged(item.inst_id);
item.inst_id = callbacks.ReuseUnchanged(worklist.Pop());
index = item.next_index;
continue;
}
@@ -357,6 +364,9 @@ auto SubstInst(Context& context, SemIR::InstId inst_id,
}
case SubstInstCallbacks::SubstResult::SubstOperands:
break;
case SubstInstCallbacks::SubstResult::SubstOperandsAndRetry:
item.is_repeated = true;
break;
}
// Extract the operands of this item into the worklist. Note that this