mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:54:41 +01:00
Fearlessly hold references into ValueStore again (#5589)
Undo changes that were meant to prevent use of a reference into `ValueStore` after being invalidated. After #5576, the `ValueStore` makes such references stable, so there's no need to worry about invalidation.
This commit is contained in:
@@ -22,15 +22,9 @@ namespace Carbon::Check {
|
||||
|
||||
namespace {
|
||||
|
||||
struct ImplAndInterface {
|
||||
SemIR::ImplId impl_id;
|
||||
SemIR::SpecificInterface interface;
|
||||
};
|
||||
|
||||
// We avoid holding a reference into the ImplStore, as the act of verifying the
|
||||
// diagnostic checks can invalidate such a reference. We collect what we need to
|
||||
// know about the the `Impl` for validation into this struct.
|
||||
// All information about a `SemIR::Impl` needed for validation.
|
||||
struct ImplInfo {
|
||||
SemIR::ImplId impl_id;
|
||||
bool is_final;
|
||||
SemIR::InstId witness_id;
|
||||
SemIR::TypeInstId self_id;
|
||||
@@ -56,7 +50,8 @@ static auto GetIRId(Context& context, SemIR::InstId owning_inst_id)
|
||||
auto GetImplInfo(Context& context, SemIR::ImplId impl_id) -> ImplInfo {
|
||||
const auto& impl = context.impls().Get(impl_id);
|
||||
auto ir_id = GetIRId(context, impl.first_owning_decl_id);
|
||||
return {.is_final = impl.is_final,
|
||||
return {.impl_id = impl_id,
|
||||
.is_final = impl.is_final,
|
||||
.witness_id = impl.witness_id,
|
||||
.self_id = impl.self_id,
|
||||
.latest_decl_id = impl.latest_decl_id(),
|
||||
@@ -146,15 +141,15 @@ static auto DiagnoseNonFinalImplsWithSameTypeStructure(Context& context,
|
||||
// final impl.
|
||||
//
|
||||
// Returns true if an error was diagnosed.
|
||||
static auto DiagnoseUnmatchableNonFinalImplWithFinalImpl(
|
||||
Context& context, SemIR::ImplId impl_a_id, const ImplInfo& impl_a,
|
||||
SemIR::ImplId impl_b_id, const ImplInfo& impl_b) -> bool {
|
||||
static auto DiagnoseUnmatchableNonFinalImplWithFinalImpl(Context& context,
|
||||
const ImplInfo& impl_a,
|
||||
const ImplInfo& impl_b)
|
||||
-> bool {
|
||||
auto diagnose_unmatchable_impl = [&](const ImplInfo& query_impl,
|
||||
SemIR::ImplId final_impl_id,
|
||||
const ImplInfo& final_impl) -> bool {
|
||||
if (LookupMatchesImpl(context, SemIR::LocId(query_impl.latest_decl_id),
|
||||
context.constant_values().Get(query_impl.self_id),
|
||||
query_impl.interface, final_impl_id)) {
|
||||
query_impl.interface, final_impl.impl_id)) {
|
||||
CARBON_DIAGNOSTIC(ImplFinalOverlapsNonFinal, Error,
|
||||
"`impl` will never be used");
|
||||
auto builder = context.emitter().Build(query_impl.latest_decl_id,
|
||||
@@ -172,9 +167,9 @@ static auto DiagnoseUnmatchableNonFinalImplWithFinalImpl(
|
||||
CARBON_CHECK(impl_a.is_final || impl_b.is_final);
|
||||
|
||||
if (impl_b.is_final) {
|
||||
return diagnose_unmatchable_impl(impl_a, impl_b_id, impl_b);
|
||||
return diagnose_unmatchable_impl(impl_a, impl_b);
|
||||
} else {
|
||||
return diagnose_unmatchable_impl(impl_b, impl_a_id, impl_a);
|
||||
return diagnose_unmatchable_impl(impl_b, impl_a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,27 +231,17 @@ static auto DiagnoseFinalImplsOverlapOutsideMatchFirst(Context& context,
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto ValidateImplsForInterface(
|
||||
Context& context, llvm::ArrayRef<ImplAndInterface> impls_and_interface)
|
||||
-> void {
|
||||
// Range over `SemIR::ImplId` only. Caller has ensured all of these are
|
||||
// for the same interface.
|
||||
auto impl_ids = llvm::map_range(impls_and_interface,
|
||||
[=](ImplAndInterface impl_and_interface) {
|
||||
return impl_and_interface.impl_id;
|
||||
});
|
||||
|
||||
static auto ValidateImplsForInterface(Context& context,
|
||||
llvm::ArrayRef<ImplInfo> impls) -> void {
|
||||
// All `impl`s we look at here have the same `InterfaceId` (though different
|
||||
// `SpecificId`s in their `SpecificInterface`s). So we can grab the
|
||||
// `ImportIRId` for the interface a single time up front.
|
||||
auto interface_decl_id =
|
||||
context.interfaces()
|
||||
.Get(impls_and_interface[0].interface.interface_id)
|
||||
.first_owning_decl_id;
|
||||
auto interface_decl_id = context.interfaces()
|
||||
.Get(impls[0].interface.interface_id)
|
||||
.first_owning_decl_id;
|
||||
auto interface_ir_id = GetIRId(context, interface_decl_id);
|
||||
|
||||
for (auto impl_id : impl_ids) {
|
||||
auto impl = GetImplInfo(context, impl_id);
|
||||
for (const auto& impl : impls) {
|
||||
if (impl.is_final && impl.is_local) {
|
||||
// =======================================================================
|
||||
/// Rules for an individual final impl.
|
||||
@@ -273,11 +258,8 @@ static auto ValidateImplsForInterface(
|
||||
// For each impl, we compare it pair-wise which each impl found before it, so
|
||||
// that diagnostics are attached to the later impl, as the earlier impl on its
|
||||
// own does not generate a diagnostic.
|
||||
size_t num_impl_ids = impls_and_interface.size();
|
||||
for (auto [split_point, impl_b_id] :
|
||||
llvm::drop_begin(llvm::enumerate(impl_ids))) {
|
||||
auto impl_b = GetImplInfo(context, impl_b_id);
|
||||
|
||||
size_t num_impls = impls.size();
|
||||
for (auto [split_point, impl_b] : llvm::drop_begin(llvm::enumerate(impls))) {
|
||||
// Prevent diagnosing the same error multiple times for the same `impl_b`
|
||||
// against different impls before it. But still ensure we do give one of
|
||||
// each diagnostic when they are different errors.
|
||||
@@ -286,10 +268,8 @@ static auto ValidateImplsForInterface(
|
||||
bool did_diagnose_final_impls_overlap_in_different_files = false;
|
||||
bool did_diagnose_final_impls_overlap_outside_match_first = false;
|
||||
|
||||
auto impls_before = llvm::drop_end(impl_ids, num_impl_ids - split_point);
|
||||
for (auto impl_a_id : impls_before) {
|
||||
auto impl_a = GetImplInfo(context, impl_a_id);
|
||||
|
||||
auto impls_before = llvm::drop_end(impls, num_impls - split_point);
|
||||
for (const auto& impl_a : impls_before) {
|
||||
// Only enforce rules when at least one of the impls was written in this
|
||||
// file.
|
||||
if (!impl_a.is_local && !impl_b.is_local) {
|
||||
@@ -318,8 +298,8 @@ static auto ValidateImplsForInterface(
|
||||
// Rules between final impl and non-final impl.
|
||||
// =====================================================================
|
||||
if (!did_diagnose_unmatchable_non_final_impl_with_final_impl) {
|
||||
if (DiagnoseUnmatchableNonFinalImplWithFinalImpl(
|
||||
context, impl_a_id, impl_a, impl_b_id, impl_b)) {
|
||||
if (DiagnoseUnmatchableNonFinalImplWithFinalImpl(context, impl_a,
|
||||
impl_b)) {
|
||||
did_diagnose_unmatchable_non_final_impl_with_final_impl = true;
|
||||
}
|
||||
}
|
||||
@@ -432,23 +412,18 @@ auto ValidateImplsInFile(Context& context) -> void {
|
||||
// about them anyhow. We also verify the impl has an `InterfaceId` since it
|
||||
// can be missing, in which case a diagnostic would have been generated
|
||||
// already as well.
|
||||
//
|
||||
// Don't hold Impl pointers here because the process of looking for
|
||||
// diagnostics may cause imports and may invalidate pointers into the
|
||||
// ImplStore.
|
||||
llvm::SmallVector<ImplAndInterface> impl_ids_by_interface(llvm::map_range(
|
||||
llvm::SmallVector<ImplInfo> impl_ids_by_interface(llvm::map_range(
|
||||
llvm::make_filter_range(
|
||||
context.impls().enumerate(),
|
||||
[](std::pair<SemIR::ImplId, const SemIR::Impl&> pair) {
|
||||
return pair.second.witness_id != SemIR::ErrorInst::InstId &&
|
||||
pair.second.interface.interface_id.has_value();
|
||||
}),
|
||||
[](std::pair<SemIR::ImplId, const SemIR::Impl&> pair) {
|
||||
return ImplAndInterface{.impl_id = pair.first,
|
||||
.interface = pair.second.interface};
|
||||
[&](std::pair<SemIR::ImplId, const SemIR::Impl&> pair) {
|
||||
return GetImplInfo(context, pair.first);
|
||||
}));
|
||||
llvm::stable_sort(impl_ids_by_interface, [](const ImplAndInterface& lhs,
|
||||
const ImplAndInterface& rhs) {
|
||||
llvm::stable_sort(impl_ids_by_interface, [](const ImplInfo& lhs,
|
||||
const ImplInfo& rhs) {
|
||||
return lhs.interface.interface_id.index < rhs.interface.interface_id.index;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user