Repository: carbon-language/carbon-lang
File: toolchain/lower/file_context.cpp (C++)

Code before:
          // multiple times, so we don't delete replaced specifics until the
          // end.
          visited_equivalent_specifics.ForEach(
              [&](std::pair<SemIR::SpecificId, SemIR::SpecificId>
                      equivalent_entry) {
                CARBON_VLOG("Found equivalent specifics: {0}, {1}",
                            equivalent_entry.first, equivalent_entry.second);
                ProcessSpecificEquivalence(equivalent_entry);
              });

          // Removed the replaced specific from the list of emitted specifics.
          // Only the top level, since the others are somewhere else in the
          // vector, they will be found and removed during processing.
          specifics_to_delete.push_back(specifics[j]);
          specifics[j] = specifics[specifics.size() - 1];
          specifics.pop_back();
          --j;
        } else {
          // Only mark non-equivalence based on state for starting specifics.
          InsertPair(specifics[i], specifics[j], non_equivalent_specifics_);
        }
      }
    }

    // Update equivalent specific llvm::Functions, once all equivalences are
    // found and the algorithm has converged on a canonical specific.
    for (auto specific_id : specifics_to_delete) {
      UpdateEquivalentSpecific(specific_id);
      UpdateAndDeleteLLVMFunction(specific_id);
    }
  }
}

auto FileContext::ProcessSpecificEquivalence(
    std::pair<SemIR::SpecificId, SemIR::SpecificId> pair) -> void {
  auto [specific_id1, specific_id2] = pair;
  CARBON_CHECK(specific_id1.has_value() && specific_id2.has_value(),
               "Expected values in equivalence check");

  auto get_canon = [&](SemIR::SpecificId specific_id) {
    return equivalent_specifics_.Get(specific_id).has_value()
               ? equivalent_specifics_.Get(specific_id)
               : specific_id;
  };
  auto canon_id1 = get_canon(specific_id1);
  auto canon_id2 = get_canon(specific_id2);

  if (canon_id1 == canon_id2) {
    // Already equivalent, there was a previous replacement.
    return;
  }

Review comment (suggestion):
Given that this is now per-generic, and a generic may have multiple canonical specifics, suggesting a slightly different comment:

```suggestion
    // Once all equivalences are found for a generic, update and delete up
    // equivalent specifics.
```

Code after:
          // multiple times, so we don't delete replaced specifics until the
          // end.
          visited_equivalent_specifics.ForEach(
              [&](std::pair<SemIR::SpecificId, SemIR::SpecificId>
                      equivalent_entry) {
                CARBON_VLOG("Found equivalent specifics: {0}, {1}",
                            equivalent_entry.first, equivalent_entry.second);
                ProcessSpecificEquivalence(equivalent_entry);
              });

          // Removed the replaced specific from the list of emitted specifics.
          // Only the top level, since the others are somewhere else in the
          // vector, they will be found and removed during processing.
          specifics_to_delete.push_back(specifics[j]);
          specifics[j] = specifics[specifics.size() - 1];
          specifics.pop_back();
          --j;
        } else {
          // Only mark non-equivalence based on state for starting specifics.
          InsertPair(specifics[i], specifics[j], non_equivalent_specifics_);
        }
      }
    }

    // Once all equivalences are found for a generic, update and delete up
    // equivalent specifics.
    for (auto specific_id : specifics_to_delete) {
      UpdateAndDeleteLLVMFunction(specific_id);
    }
  }
}

auto FileContext::ProcessSpecificEquivalence(
    std::pair<SemIR::SpecificId, SemIR::SpecificId> pair) -> void {
  auto [specific_id1, specific_id2] = pair;
  CARBON_CHECK(specific_id1.has_value() && specific_id2.has_value(),
               "Expected values in equivalence check");

  auto get_canon = [&](SemIR::SpecificId specific_id) {
    auto equiv_id = equivalent_specifics_.Get(specific_id);
    return equiv_id.has_value() ? equiv_id : specific_id;
  };
  auto canon_id1 = get_canon(specific_id1);
  auto canon_id2 = get_canon(specific_id2);

  if (canon_id1 == canon_id2) {
    // Already equivalent, there was a previous replacement.
    return;
  }

  if (canon_id1.index >= canon_id2.index) {