From b6a55c0818b118d49d2aad1525a7e72a7fe8a228 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 10 May 2025 13:36:28 -0400 Subject: [PATCH] Diagnose impls that are fully overlapped by a final impl (#5417) Such impls will never be used, so they should not exist. And test that a final impl partially overlapping a non-final impl is accepted. There is a question about a final impl partially overlapping a final impl that is part of https://github.com/carbon-language/carbon-lang/pull/5337 --- toolchain/check/check_unit.cpp | 180 ++++++++++----- toolchain/check/check_unit.h | 4 - toolchain/check/impl_lookup.cpp | 13 ++ toolchain/check/impl_lookup.h | 8 + .../impl/lookup/min_prelude/impl_cycle.carbon | 8 +- .../min_prelude/specialization_poison.carbon | 102 +++++++-- .../min_prelude/generic_redeclaration.carbon | 207 +++++++++--------- toolchain/diagnostics/diagnostic_kind.def | 6 +- 8 files changed, 350 insertions(+), 178 deletions(-) diff --git a/toolchain/check/check_unit.cpp b/toolchain/check/check_unit.cpp index f3cc33bb881f..05c6ba2f6335 100644 --- a/toolchain/check/check_unit.cpp +++ b/toolchain/check/check_unit.cpp @@ -5,6 +5,7 @@ #include "toolchain/check/check_unit.h" #include +#include #include #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -570,24 +571,143 @@ auto CheckUnit::CheckPoisonedConcreteImplLookupQueries() -> void { context_.inst_block_stack().PopAndDiscard(); } +// Check for invalid overlap between impls, given the set of all impls for a +// single interface. +static auto CheckOverlappingImplsForInterface( + Context& context, + llvm::ArrayRef> + impls_and_interface) -> void { + // Range over `SemIR::ImplId` only. It'd be nice to make this the function + // parameter but we don't have a concept to express that outside the (banned) + // std::ranges. + auto impl_ids = llvm::map_range( + impls_and_interface, + [=](std::pair pair) { + auto [impl_id, _] = pair; + return impl_id; + }); + + // Avoid holding a reference into the ImplStore, as the diagnostic checks + // below can invalidate the reference. We copy out the part of the `Impl` we + // need. + struct ImplInfo { + bool is_final; + SemIR::InstId witness_id; + SemIR::TypeInstId self_id; + SemIR::InstId latest_decl_id; + SemIR::SpecificInterface interface; + }; + auto get_impl_info = [&](SemIR::ImplId impl_id) -> ImplInfo { + const auto& impl = context.impls().Get(impl_id); + return {.is_final = impl.is_final, + .witness_id = impl.witness_id, + .self_id = impl.self_id, + .latest_decl_id = impl.latest_decl_id(), + .interface = impl.interface}; + }; + + // TODO: We should revisit this and look for a way to do these checks in less + // than quadratic time. From @zygoloid: Possibly by converting the set of + // impls into a decision tree. + for (auto [index_a, impl_a_id] : llvm::enumerate(impl_ids)) { + auto impl_a = get_impl_info(impl_a_id); + if (impl_a.witness_id == SemIR::ErrorInst::InstId) { + continue; + } + auto type_structure = + BuildTypeStructure(context, impl_a.self_id, impl_a.interface); + + for (auto impl_b_id : llvm::drop_begin(impl_ids, index_a + 1)) { + auto impl_b = get_impl_info(impl_b_id); + if (impl_b.witness_id == SemIR::ErrorInst::InstId) { + continue; + } + + // The type structure each non-final `impl` must differ from all other + // non-final `impl` for the same interface visible from the file. + if (!impl_a.is_final && !impl_b.is_final) { + auto type_structure2 = + BuildTypeStructure(context, impl_b.self_id, impl_b.interface); + if (type_structure == type_structure2) { + CARBON_DIAGNOSTIC(ImplNonFinalSameTypeStructure, Error, + "found non-final `impl` with the same type " + "structure as another non-final `impl`"); + auto builder = context.emitter().Build(impl_b.latest_decl_id, + ImplNonFinalSameTypeStructure); + CARBON_DIAGNOSTIC(ImplNonFinalSameTypeStructureNote, Note, + "other `impl` here"); + builder.Note(impl_a.latest_decl_id, + ImplNonFinalSameTypeStructureNote); + builder.Emit(); + break; + } + } else { + CARBON_CHECK(impl_a.is_final || impl_b.is_final); + + auto diagnose = [&](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)) { + CARBON_DIAGNOSTIC(ImplFinalOverlapsNonFinal, Error, + "`impl` will never be used"); + auto builder = context.emitter().Build(query_impl.latest_decl_id, + ImplFinalOverlapsNonFinal); + CARBON_DIAGNOSTIC( + ImplFinalOverlapsNonFinalNote, Note, + "`final impl` declared here would always be used instead"); + builder.Note(final_impl.latest_decl_id, + ImplFinalOverlapsNonFinalNote); + builder.Emit(); + return true; + } + return false; + }; + + bool did_diagnose = false; + if (impl_a.is_final) { + did_diagnose = diagnose(impl_b, impl_a_id, impl_a); + } + if (impl_b.is_final && !did_diagnose) { + diagnose(impl_a, impl_b_id, impl_b); + } + } + } + + // TODO: The self + constraint of a `impl` must not match against (be + // fully subsumed by) any final `impl` visible from the file. Do a + // final-only query for all non-final impls? + } +} + auto CheckUnit::CheckOverlappingImpls() -> void { // Collect all of the impls sorted into contiguous segments by their // interface. We only need to compare impls within each such segment. - llvm::SmallVector impls_by_interface( - context_.impls().array_ref()); + // + // 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> + impl_ids_by_interface(llvm::map_range( + context_.impls().enumerate(), + [](std::pair pair) { + return std::make_pair(pair.first, pair.second.interface); + })); llvm::stable_sort( - impls_by_interface, [](const SemIR::Impl& a, const SemIR::Impl& b) { - return a.interface.interface_id.index < b.interface.interface_id.index; + impl_ids_by_interface, + [](std::pair a, + std::pair b) { + return a.second.interface_id.index < b.second.interface_id.index; }); - const auto* it = impls_by_interface.begin(); - while (it != impls_by_interface.end()) { + const auto* it = impl_ids_by_interface.begin(); + while (it != impl_ids_by_interface.end()) { const auto* segment_begin = it; do { ++it; - } while (it != impls_by_interface.end() && - it->interface.interface_id == - segment_begin->interface.interface_id); + } while (it != impl_ids_by_interface.end() && + it->second.interface_id == segment_begin->second.interface_id); const auto* segment_end = it; if (std::distance(segment_begin, segment_end) == 1) { @@ -596,47 +716,7 @@ auto CheckUnit::CheckOverlappingImpls() -> void { } CheckOverlappingImplsForInterface( - llvm::ArrayRef(segment_begin, segment_end)); - } -} - -auto CheckUnit::CheckOverlappingImplsForInterface( - llvm::ArrayRef impls) -> void { - for (auto [index_a, impl_a] : llvm::enumerate(impls)) { - if (impl_a.witness_id == SemIR::ErrorInst::InstId) { - continue; - } - auto impl_a_type_structure = - BuildTypeStructure(context_, impl_a.self_id, impl_a.interface); - - for (const auto& impl_b : impls.drop_front(index_a + 1)) { - if (impl_b.witness_id == SemIR::ErrorInst::InstId) { - continue; - } - - // The type structure each non-final `impl` must differ from all other - // non-final `impl` for the same interface visible from the file. - if (!impl_a.is_final && !impl_b.is_final) { - auto impl_b_type_structure = - BuildTypeStructure(context_, impl_b.self_id, impl_b.interface); - if (impl_a_type_structure == impl_b_type_structure) { - CARBON_DIAGNOSTIC(ImplFullyOverlapNonFinal, Error, - "found non-final `impl` that fully overlaps " - "previous non-final `impl`"); - auto builder = - emitter_.Build(impl_b.latest_decl_id(), ImplFullyOverlapNonFinal); - CARBON_DIAGNOSTIC(ImplFullyOverlapNonFinalNote, Note, - "fully overlaps `impl` here"); - builder.Note(impl_a.latest_decl_id(), ImplFullyOverlapNonFinalNote); - builder.Emit(); - break; - } - } - } - - // TODO: The self + constraint of a `impl` must not match against (be - // fully subsumed by) any final `impl` visible from the file. Do a - // final-only query for all non-final impls? + context_, llvm::ArrayRef(segment_begin, segment_end)); } } diff --git a/toolchain/check/check_unit.h b/toolchain/check/check_unit.h index 9420769d0872..4be9d19af0f9 100644 --- a/toolchain/check/check_unit.h +++ b/toolchain/check/check_unit.h @@ -176,10 +176,6 @@ class CheckUnit { // - The type structure each non-final `impl` must differ from every other // non-final `impl` for the same interface visible from the file. auto CheckOverlappingImpls() -> void; - // Check for invalid overlap between impls, given the set of all impls for a - // single interface. - auto CheckOverlappingImplsForInterface(llvm::ArrayRef impls) - -> void; // Does work after processing the parse tree, such as finishing the IR and // checking for missing contents. diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index d2f28b7d6203..3096956f6553 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -690,4 +690,17 @@ auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id, return EvalImplLookupResult::MakeNone(); } +auto LookupMatchesImpl(Context& context, SemIR::LocId loc_id, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterface query_specific_interface, + SemIR::ImplId target_impl) -> bool { + if (query_self_const_id == SemIR::ErrorInst::ConstantId) { + return false; + } + auto result = GetWitnessIdForImpl( + context, loc_id, /*query_is_concrete=*/false, query_self_const_id, + query_specific_interface, target_impl); + return result.has_value(); +} + } // namespace Carbon::Check diff --git a/toolchain/check/impl_lookup.h b/toolchain/check/impl_lookup.h index b32387f70c21..8323354a58af 100644 --- a/toolchain/check/impl_lookup.h +++ b/toolchain/check/impl_lookup.h @@ -39,6 +39,14 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_facet_type_const_id) -> SemIR::InstBlockIdOrError; +// Returns whether the query matches against the given impl. This is like a +// `LookupImplWitness` operation but for a single interface, and against only +// the single impl. +auto LookupMatchesImpl(Context& context, SemIR::LocId loc_id, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterface query_specific_interface, + SemIR::ImplId target_impl) -> bool; + // The result of EvalLookupSingleImplWitness(). It can be one of: // - No value. Lookup failed to find an impl declaration. // - A concrete value. Lookup found a concrete impl declaration that can be diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon index 0c4fc854abe8..f2cf7b7ece68 100644 --- a/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon +++ b/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon @@ -269,19 +269,19 @@ impl C as ComparableTo(D) {} // T is always ComparableWith(T). impl forall [T:! type] T as ComparableWith(T) {} // If U is ComparableTo(T), U is ComparableWith(T). -// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! type, U:! ComparableTo(T)] U as ComparableWith(T) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE-5]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE-5]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! type] T as ComparableWith(T) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: impl forall [T:! type, U:! ComparableTo(T)] U as ComparableWith(T) {} // If U is ComparableTo(T), T is ComparableWith(U). -// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! type, U:! ComparableTo(T)] T as ComparableWith(U) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE-5]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_todo_impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon:[[@LINE-5]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! type, U:! ComparableTo(T)] U as ComparableWith(T) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/specialization_poison.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/specialization_poison.carbon index eef60e194135..ae7a4fb141d2 100644 --- a/toolchain/check/testdata/impl/lookup/min_prelude/specialization_poison.carbon +++ b/toolchain/check/testdata/impl/lookup/min_prelude/specialization_poison.carbon @@ -170,49 +170,77 @@ final impl forall [V:! type] V* as I where .T = V { fn F[self: Self]() -> V { return *self; } } -// --- todo_final_overlaps_earlier_non_final_impl.carbon +// --- fail_final_overlaps_earlier_non_final_impl.carbon library "[[@TEST_NAME]]"; interface Z(T:! type) {} interface Y {} -impl forall [T:! Y] T as Z(T) {} +// CHECK:STDERR: fail_final_overlaps_earlier_non_final_impl.carbon:[[@LINE+3]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal] +// CHECK:STDERR: impl () as Z(()) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ +impl () as Z(()) {} -// TODO: Diagnose overlap with previous impl (query of this matches that). +// CHECK:STDERR: fail_final_overlaps_earlier_non_final_impl.carbon:[[@LINE+4]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote] +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} -// --- todo_final_overlaps_later_non_final_impl.carbon +// --- fail_final_overlaps_later_non_final_impl.carbon library "[[@TEST_NAME]]"; interface Z(T:! type) {} interface Y {} -// TODO: Diagnose overlap with next impl (query of this matches that). final impl forall [T:! type] T as Z(T) {} -impl forall [T:! Y] T as Z(T) {} +// CHECK:STDERR: fail_final_overlaps_later_non_final_impl.carbon:[[@LINE+7]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal] +// CHECK:STDERR: impl () as Z(()) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_final_overlaps_later_non_final_impl.carbon:[[@LINE-5]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote] +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +impl () as Z(()) {} -// --- todo_final_overlaps_earlier_final_impl.carbon +// --- fail_final_overlaps_earlier_final_impl.carbon library "[[@TEST_NAME]]"; interface Z(T:! type) {} interface Y {} -final impl forall [T:! Y] T as Z(T) {} +class C; -// TODO: Diagnose overlap with previous impl (query of this matches that). +// CHECK:STDERR: fail_final_overlaps_earlier_final_impl.carbon:[[@LINE+3]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal] +// CHECK:STDERR: final impl C as Z(C) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ +final impl C as Z(C) {} + +// CHECK:STDERR: fail_final_overlaps_earlier_final_impl.carbon:[[@LINE+4]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote] +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} -// --- todo_final_overlaps_later_final_impl.carbon +// --- fail_final_overlaps_later_final_impl.carbon library "[[@TEST_NAME]]"; interface Z(T:! type) {} interface Y {} -// TODO: Diagnose overlap with next impl (query of this matches that) +class C; + final impl forall [T:! type] T as Z(T) {} -final impl forall [T:! Y] T as Z(T) {} +// CHECK:STDERR: fail_final_overlaps_later_final_impl.carbon:[[@LINE+7]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal] +// CHECK:STDERR: final impl C as Z(C) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_final_overlaps_later_final_impl.carbon:[[@LINE-5]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote] +// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +final impl C as Z(C) {} // --- fail_non_final_overlaps_non_final_impl.carbon library "[[@TEST_NAME]]"; @@ -222,14 +250,15 @@ interface Y {} impl forall [T:! Y] T as Z(T) {} -class C(T:! type) {} +class C(T:! type); + // No diagnosis here as the type structure is unique. impl forall [T:! type] T as Z(C(T)) {} -// CHECK:STDERR: fail_non_final_overlaps_non_final_impl.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_non_final_overlaps_non_final_impl.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! type] T as Z(T) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_non_final_overlaps_non_final_impl.carbon:[[@LINE-9]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_non_final_overlaps_non_final_impl.carbon:[[@LINE-10]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! Y] T as Z(T) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: @@ -245,3 +274,46 @@ class D; impl C as Z {} impl D as Z {} + +// --- final_partial_overlaps_non_final_impl.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y {} + +class C; + +impl forall [T:! type] T as Z(T) {} + +// Partially overlaps the previous impl, which is fine. +final impl C as Z(C) {} + +// --- todo_final_partial_overlaps_final_impl_in_self_type.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y {} + +class C(T:! type, U:! type); + +final impl forall [T:! type] C(T, ()) as Z {} + +// TODO: Partially overlaps the previous impl, which may or may not be fine outside of +// a `match_first`, depending how +// https://github.com/carbon-language/carbon-lang/pull/5337 turns out. +final impl forall [U:! type] C((), U) as Z {} + +// --- todo_final_partial_overlaps_final_impl_in_interface.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type, U:! type) {} +interface Y {} + +class C; + +final impl forall [T:! type] C as Z(T, ()) {} + +// TODO: Partially overlaps the previous impl, which may or may not be fine outside of +// a `match_first`, depending how +// https://github.com/carbon-language/carbon-lang/pull/5337 turns out. +final impl forall [U:! type] C as Z((), U) {} diff --git a/toolchain/check/testdata/impl/min_prelude/generic_redeclaration.carbon b/toolchain/check/testdata/impl/min_prelude/generic_redeclaration.carbon index 888f31ad123c..37fc991161ec 100644 --- a/toolchain/check/testdata/impl/min_prelude/generic_redeclaration.carbon +++ b/toolchain/check/testdata/impl/min_prelude/generic_redeclaration.carbon @@ -11,7 +11,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/min_prelude/generic_redeclaration.carbon -// --- fail_same_self_and_interface.carbon +// --- fail_todo_same_self_and_interface.carbon library "[[@TEST_NAME]]"; @@ -22,6 +22,7 @@ interface J {} interface K {} interface L {} +// TODO: Put these in a match_first so the test will pass again. impl forall [T:! I] T as Interface; impl forall [T:! J] T as Interface; impl forall [T:! K] T as Interface; @@ -30,26 +31,26 @@ impl forall [T:! L] T as Interface; // These are different impls, so they are not redefinitions, even though the // self type and constraint type are the same. impl forall [T:! I] T as Interface {} -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! J] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE-4]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE-4]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! I] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: impl forall [T:! J] T as Interface {} -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! K] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE-4]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE-4]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! J] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: impl forall [T:! K] T as Interface {} -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl forall [T:! L] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_same_self_and_interface.carbon:[[@LINE-4]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_todo_same_self_and_interface.carbon:[[@LINE-4]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl forall [T:! K] T as Interface {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: @@ -82,10 +83,10 @@ interface I {} // Since the spelling is different, it's not caught as a redefinition, but it // is diagnosed as an overlapping impl without using a `match_first` block. impl C as I {} -// CHECK:STDERR: fail_same_type_different_spelling.carbon:[[@LINE+7]]:1: error: found non-final `impl` that fully overlaps previous non-final `impl` [ImplFullyOverlapNonFinal] +// CHECK:STDERR: fail_same_type_different_spelling.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure] // CHECK:STDERR: impl (C, C).0 as I {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: fail_same_type_different_spelling.carbon:[[@LINE-4]]:1: note: fully overlaps `impl` here [ImplFullyOverlapNonFinalNote] +// CHECK:STDERR: fail_same_type_different_spelling.carbon:[[@LINE-4]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote] // CHECK:STDERR: impl C as I {} // CHECK:STDERR: ^~~~~~~~~~~~~ // CHECK:STDERR: @@ -116,7 +117,7 @@ impl forall [T:! type] T as I { } } -// CHECK:STDOUT: --- fail_same_self_and_interface.carbon +// CHECK:STDOUT: --- fail_todo_same_self_and_interface.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Interface.type: type = facet_type <@Interface> [concrete] @@ -132,19 +133,19 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: %T.826: %I.type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %pattern_type.2b5: type = pattern_type %I.type [concrete] // CHECK:STDOUT: %T.as_type.b70: type = facet_access_type %T.826 [symbolic] -// CHECK:STDOUT: %Interface.impl_witness.a14: = impl_witness file.%Interface.impl_witness_table.loc11, @impl.c3d(%T.826) [symbolic] +// CHECK:STDOUT: %Interface.impl_witness.a14: = impl_witness file.%Interface.impl_witness_table.loc12, @impl.c3d(%T.826) [symbolic] // CHECK:STDOUT: %T.ccd: %J.type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %pattern_type.28e: type = pattern_type %J.type [concrete] // CHECK:STDOUT: %T.as_type.3df: type = facet_access_type %T.ccd [symbolic] -// CHECK:STDOUT: %Interface.impl_witness.608: = impl_witness file.%Interface.impl_witness_table.loc12, @impl.793(%T.ccd) [symbolic] +// CHECK:STDOUT: %Interface.impl_witness.608: = impl_witness file.%Interface.impl_witness_table.loc13, @impl.793(%T.ccd) [symbolic] // CHECK:STDOUT: %T.09f: %K.type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %pattern_type.4a6: type = pattern_type %K.type [concrete] // CHECK:STDOUT: %T.as_type.037: type = facet_access_type %T.09f [symbolic] -// CHECK:STDOUT: %Interface.impl_witness.b9e: = impl_witness file.%Interface.impl_witness_table.loc13, @impl.c93(%T.09f) [symbolic] +// CHECK:STDOUT: %Interface.impl_witness.b9e: = impl_witness file.%Interface.impl_witness_table.loc14, @impl.c93(%T.09f) [symbolic] // CHECK:STDOUT: %T.1d2: %L.type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %pattern_type.86b: type = pattern_type %L.type [concrete] // CHECK:STDOUT: %T.as_type.0ed: type = facet_access_type %T.1d2 [symbolic] -// CHECK:STDOUT: %Interface.impl_witness.e9d: = impl_witness file.%Interface.impl_witness_table.loc14, @impl.9e6(%T.1d2) [symbolic] +// CHECK:STDOUT: %Interface.impl_witness.e9d: = impl_witness file.%Interface.impl_witness_table.loc15, @impl.9e6(%T.1d2) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -171,90 +172,90 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: impl_decl @impl.c3d [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.2b5 = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc11: %I.type = name_ref T, %T.loc11_14.1 [symbolic = %T.loc11_14.2 (constants.%T.826)] -// CHECK:STDOUT: %T.as_type.loc11_21.1: type = facet_access_type %T.ref.loc11 [symbolic = %T.as_type.loc11_21.2 (constants.%T.as_type.b70)] -// CHECK:STDOUT: %.loc11: type = converted %T.ref.loc11, %T.as_type.loc11_21.1 [symbolic = %T.as_type.loc11_21.2 (constants.%T.as_type.b70)] -// CHECK:STDOUT: %Interface.ref.loc11: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %I.ref.loc11: type = name_ref I, file.%I.decl [concrete = constants.%I.type] -// CHECK:STDOUT: %T.loc11_14.1: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc11_14.2 (constants.%T.826)] +// CHECK:STDOUT: %T.ref.loc12: %I.type = name_ref T, %T.loc12_14.1 [symbolic = %T.loc12_14.2 (constants.%T.826)] +// CHECK:STDOUT: %T.as_type.loc12_21.1: type = facet_access_type %T.ref.loc12 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.b70)] +// CHECK:STDOUT: %.loc12: type = converted %T.ref.loc12, %T.as_type.loc12_21.1 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.b70)] +// CHECK:STDOUT: %Interface.ref.loc12: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %I.ref.loc12: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: %T.loc12_14.1: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.826)] // CHECK:STDOUT: } -// CHECK:STDOUT: %Interface.impl_witness_table.loc11 = impl_witness_table (), @impl.c3d [concrete] -// CHECK:STDOUT: %Interface.impl_witness.loc11: = impl_witness %Interface.impl_witness_table.loc11, @impl.c3d(constants.%T.826) [symbolic = @impl.c3d.%Interface.impl_witness (constants.%Interface.impl_witness.a14)] +// CHECK:STDOUT: %Interface.impl_witness_table.loc12 = impl_witness_table (), @impl.c3d [concrete] +// CHECK:STDOUT: %Interface.impl_witness.loc12: = impl_witness %Interface.impl_witness_table.loc12, @impl.c3d(constants.%T.826) [symbolic = @impl.c3d.%Interface.impl_witness (constants.%Interface.impl_witness.a14)] // CHECK:STDOUT: impl_decl @impl.793 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.28e = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc12: %J.type = name_ref T, %T.loc12_14.1 [symbolic = %T.loc12_14.2 (constants.%T.ccd)] -// CHECK:STDOUT: %T.as_type.loc12_21.1: type = facet_access_type %T.ref.loc12 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.3df)] -// CHECK:STDOUT: %.loc12: type = converted %T.ref.loc12, %T.as_type.loc12_21.1 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.3df)] -// CHECK:STDOUT: %Interface.ref.loc12: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %J.ref.loc12: type = name_ref J, file.%J.decl [concrete = constants.%J.type] -// CHECK:STDOUT: %T.loc12_14.1: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.ccd)] +// CHECK:STDOUT: %T.ref.loc13: %J.type = name_ref T, %T.loc13_14.1 [symbolic = %T.loc13_14.2 (constants.%T.ccd)] +// CHECK:STDOUT: %T.as_type.loc13_21.1: type = facet_access_type %T.ref.loc13 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.3df)] +// CHECK:STDOUT: %.loc13: type = converted %T.ref.loc13, %T.as_type.loc13_21.1 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.3df)] +// CHECK:STDOUT: %Interface.ref.loc13: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %J.ref.loc13: type = name_ref J, file.%J.decl [concrete = constants.%J.type] +// CHECK:STDOUT: %T.loc13_14.1: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.ccd)] // CHECK:STDOUT: } -// CHECK:STDOUT: %Interface.impl_witness_table.loc12 = impl_witness_table (), @impl.793 [concrete] -// CHECK:STDOUT: %Interface.impl_witness.loc12: = impl_witness %Interface.impl_witness_table.loc12, @impl.793(constants.%T.ccd) [symbolic = @impl.793.%Interface.impl_witness (constants.%Interface.impl_witness.608)] +// CHECK:STDOUT: %Interface.impl_witness_table.loc13 = impl_witness_table (), @impl.793 [concrete] +// CHECK:STDOUT: %Interface.impl_witness.loc13: = impl_witness %Interface.impl_witness_table.loc13, @impl.793(constants.%T.ccd) [symbolic = @impl.793.%Interface.impl_witness (constants.%Interface.impl_witness.608)] // CHECK:STDOUT: impl_decl @impl.c93 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.4a6 = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc13: %K.type = name_ref T, %T.loc13_14.1 [symbolic = %T.loc13_14.2 (constants.%T.09f)] -// CHECK:STDOUT: %T.as_type.loc13_21.1: type = facet_access_type %T.ref.loc13 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.037)] -// CHECK:STDOUT: %.loc13: type = converted %T.ref.loc13, %T.as_type.loc13_21.1 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.037)] -// CHECK:STDOUT: %Interface.ref.loc13: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %K.ref.loc13: type = name_ref K, file.%K.decl [concrete = constants.%K.type] -// CHECK:STDOUT: %T.loc13_14.1: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.09f)] +// CHECK:STDOUT: %T.ref.loc14: %K.type = name_ref T, %T.loc14_14.1 [symbolic = %T.loc14_14.2 (constants.%T.09f)] +// CHECK:STDOUT: %T.as_type.loc14_21.1: type = facet_access_type %T.ref.loc14 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.037)] +// CHECK:STDOUT: %.loc14: type = converted %T.ref.loc14, %T.as_type.loc14_21.1 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.037)] +// CHECK:STDOUT: %Interface.ref.loc14: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %K.ref.loc14: type = name_ref K, file.%K.decl [concrete = constants.%K.type] +// CHECK:STDOUT: %T.loc14_14.1: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.09f)] // CHECK:STDOUT: } -// CHECK:STDOUT: %Interface.impl_witness_table.loc13 = impl_witness_table (), @impl.c93 [concrete] -// CHECK:STDOUT: %Interface.impl_witness.loc13: = impl_witness %Interface.impl_witness_table.loc13, @impl.c93(constants.%T.09f) [symbolic = @impl.c93.%Interface.impl_witness (constants.%Interface.impl_witness.b9e)] +// CHECK:STDOUT: %Interface.impl_witness_table.loc14 = impl_witness_table (), @impl.c93 [concrete] +// CHECK:STDOUT: %Interface.impl_witness.loc14: = impl_witness %Interface.impl_witness_table.loc14, @impl.c93(constants.%T.09f) [symbolic = @impl.c93.%Interface.impl_witness (constants.%Interface.impl_witness.b9e)] // CHECK:STDOUT: impl_decl @impl.9e6 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.86b = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc14: %L.type = name_ref T, %T.loc14_14.1 [symbolic = %T.loc14_14.2 (constants.%T.1d2)] -// CHECK:STDOUT: %T.as_type.loc14_21.1: type = facet_access_type %T.ref.loc14 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.0ed)] -// CHECK:STDOUT: %.loc14: type = converted %T.ref.loc14, %T.as_type.loc14_21.1 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.0ed)] -// CHECK:STDOUT: %Interface.ref.loc14: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %L.ref.loc14: type = name_ref L, file.%L.decl [concrete = constants.%L.type] -// CHECK:STDOUT: %T.loc14_14.1: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.1d2)] +// CHECK:STDOUT: %T.ref.loc15: %L.type = name_ref T, %T.loc15_14.1 [symbolic = %T.loc15_14.2 (constants.%T.1d2)] +// CHECK:STDOUT: %T.as_type.loc15_21.1: type = facet_access_type %T.ref.loc15 [symbolic = %T.as_type.loc15_21.2 (constants.%T.as_type.0ed)] +// CHECK:STDOUT: %.loc15: type = converted %T.ref.loc15, %T.as_type.loc15_21.1 [symbolic = %T.as_type.loc15_21.2 (constants.%T.as_type.0ed)] +// CHECK:STDOUT: %Interface.ref.loc15: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %L.ref.loc15: type = name_ref L, file.%L.decl [concrete = constants.%L.type] +// CHECK:STDOUT: %T.loc15_14.1: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc15_14.2 (constants.%T.1d2)] // CHECK:STDOUT: } -// CHECK:STDOUT: %Interface.impl_witness_table.loc14 = impl_witness_table (), @impl.9e6 [concrete] -// CHECK:STDOUT: %Interface.impl_witness.loc14: = impl_witness %Interface.impl_witness_table.loc14, @impl.9e6(constants.%T.1d2) [symbolic = @impl.9e6.%Interface.impl_witness (constants.%Interface.impl_witness.e9d)] +// CHECK:STDOUT: %Interface.impl_witness_table.loc15 = impl_witness_table (), @impl.9e6 [concrete] +// CHECK:STDOUT: %Interface.impl_witness.loc15: = impl_witness %Interface.impl_witness_table.loc15, @impl.9e6(constants.%T.1d2) [symbolic = @impl.9e6.%Interface.impl_witness (constants.%Interface.impl_witness.e9d)] // CHECK:STDOUT: impl_decl @impl.c3d [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.2b5 = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc18: %I.type = name_ref T, %T.loc18 [symbolic = %T.loc11_14.2 (constants.%T.826)] -// CHECK:STDOUT: %T.as_type.loc18: type = facet_access_type %T.ref.loc18 [symbolic = %T.as_type.loc11_21.2 (constants.%T.as_type.b70)] -// CHECK:STDOUT: %.loc18: type = converted %T.ref.loc18, %T.as_type.loc18 [symbolic = %T.as_type.loc11_21.2 (constants.%T.as_type.b70)] -// CHECK:STDOUT: %Interface.ref.loc18: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %I.ref.loc18: type = name_ref I, file.%I.decl [concrete = constants.%I.type] -// CHECK:STDOUT: %T.loc18: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc11_14.2 (constants.%T.826)] +// CHECK:STDOUT: %T.ref.loc19: %I.type = name_ref T, %T.loc19 [symbolic = %T.loc12_14.2 (constants.%T.826)] +// CHECK:STDOUT: %T.as_type.loc19: type = facet_access_type %T.ref.loc19 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.b70)] +// CHECK:STDOUT: %.loc19: type = converted %T.ref.loc19, %T.as_type.loc19 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.b70)] +// CHECK:STDOUT: %Interface.ref.loc19: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %I.ref.loc19: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: %T.loc19: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.826)] // CHECK:STDOUT: } // CHECK:STDOUT: impl_decl @impl.793 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.28e = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc26: %J.type = name_ref T, %T.loc26 [symbolic = %T.loc12_14.2 (constants.%T.ccd)] -// CHECK:STDOUT: %T.as_type.loc26: type = facet_access_type %T.ref.loc26 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.3df)] -// CHECK:STDOUT: %.loc26: type = converted %T.ref.loc26, %T.as_type.loc26 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.3df)] -// CHECK:STDOUT: %Interface.ref.loc26: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %J.ref.loc26: type = name_ref J, file.%J.decl [concrete = constants.%J.type] -// CHECK:STDOUT: %T.loc26: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.ccd)] +// CHECK:STDOUT: %T.ref.loc27: %J.type = name_ref T, %T.loc27 [symbolic = %T.loc13_14.2 (constants.%T.ccd)] +// CHECK:STDOUT: %T.as_type.loc27: type = facet_access_type %T.ref.loc27 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.3df)] +// CHECK:STDOUT: %.loc27: type = converted %T.ref.loc27, %T.as_type.loc27 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.3df)] +// CHECK:STDOUT: %Interface.ref.loc27: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %J.ref.loc27: type = name_ref J, file.%J.decl [concrete = constants.%J.type] +// CHECK:STDOUT: %T.loc27: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.ccd)] // CHECK:STDOUT: } // CHECK:STDOUT: impl_decl @impl.c93 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.4a6 = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc34: %K.type = name_ref T, %T.loc34 [symbolic = %T.loc13_14.2 (constants.%T.09f)] -// CHECK:STDOUT: %T.as_type.loc34: type = facet_access_type %T.ref.loc34 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.037)] -// CHECK:STDOUT: %.loc34: type = converted %T.ref.loc34, %T.as_type.loc34 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.037)] -// CHECK:STDOUT: %Interface.ref.loc34: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %K.ref.loc34: type = name_ref K, file.%K.decl [concrete = constants.%K.type] -// CHECK:STDOUT: %T.loc34: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.09f)] +// CHECK:STDOUT: %T.ref.loc35: %K.type = name_ref T, %T.loc35 [symbolic = %T.loc14_14.2 (constants.%T.09f)] +// CHECK:STDOUT: %T.as_type.loc35: type = facet_access_type %T.ref.loc35 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.037)] +// CHECK:STDOUT: %.loc35: type = converted %T.ref.loc35, %T.as_type.loc35 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.037)] +// CHECK:STDOUT: %Interface.ref.loc35: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %K.ref.loc35: type = name_ref K, file.%K.decl [concrete = constants.%K.type] +// CHECK:STDOUT: %T.loc35: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.09f)] // CHECK:STDOUT: } // CHECK:STDOUT: impl_decl @impl.9e6 [concrete] { // CHECK:STDOUT: %T.patt: %pattern_type.86b = symbolic_binding_pattern T, 0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %T.ref.loc42: %L.type = name_ref T, %T.loc42 [symbolic = %T.loc14_14.2 (constants.%T.1d2)] -// CHECK:STDOUT: %T.as_type.loc42: type = facet_access_type %T.ref.loc42 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.0ed)] -// CHECK:STDOUT: %.loc42: type = converted %T.ref.loc42, %T.as_type.loc42 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.0ed)] -// CHECK:STDOUT: %Interface.ref.loc42: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] -// CHECK:STDOUT: %L.ref.loc42: type = name_ref L, file.%L.decl [concrete = constants.%L.type] -// CHECK:STDOUT: %T.loc42: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.1d2)] +// CHECK:STDOUT: %T.ref.loc43: %L.type = name_ref T, %T.loc43 [symbolic = %T.loc15_14.2 (constants.%T.1d2)] +// CHECK:STDOUT: %T.as_type.loc43: type = facet_access_type %T.ref.loc43 [symbolic = %T.as_type.loc15_21.2 (constants.%T.as_type.0ed)] +// CHECK:STDOUT: %.loc43: type = converted %T.ref.loc43, %T.as_type.loc43 [symbolic = %T.as_type.loc15_21.2 (constants.%T.as_type.0ed)] +// CHECK:STDOUT: %Interface.ref.loc43: type = name_ref Interface, file.%Interface.decl [concrete = constants.%Interface.type] +// CHECK:STDOUT: %L.ref.loc43: type = name_ref L, file.%L.decl [concrete = constants.%L.type] +// CHECK:STDOUT: %T.loc43: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc15_14.2 (constants.%T.1d2)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -298,23 +299,10 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: witness = () // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic impl @impl.c3d(%T.loc11_14.1: %I.type) { -// CHECK:STDOUT: %T.loc11_14.2: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc11_14.2 (constants.%T.826)] -// CHECK:STDOUT: %T.as_type.loc11_21.2: type = facet_access_type %T.loc11_14.2 [symbolic = %T.as_type.loc11_21.2 (constants.%T.as_type.b70)] -// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc11, @impl.c3d(%T.loc11_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.a14)] -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: -// CHECK:STDOUT: -// CHECK:STDOUT: impl: %.loc11 as %Interface.ref.loc11 { -// CHECK:STDOUT: !members: -// CHECK:STDOUT: witness = file.%Interface.impl_witness.loc11 -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: generic impl @impl.793(%T.loc12_14.1: %J.type) { -// CHECK:STDOUT: %T.loc12_14.2: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.ccd)] -// CHECK:STDOUT: %T.as_type.loc12_21.2: type = facet_access_type %T.loc12_14.2 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.3df)] -// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc12, @impl.793(%T.loc12_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.608)] +// CHECK:STDOUT: generic impl @impl.c3d(%T.loc12_14.1: %I.type) { +// CHECK:STDOUT: %T.loc12_14.2: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc12_14.2 (constants.%T.826)] +// CHECK:STDOUT: %T.as_type.loc12_21.2: type = facet_access_type %T.loc12_14.2 [symbolic = %T.as_type.loc12_21.2 (constants.%T.as_type.b70)] +// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc12, @impl.c3d(%T.loc12_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.a14)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -324,10 +312,10 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic impl @impl.c93(%T.loc13_14.1: %K.type) { -// CHECK:STDOUT: %T.loc13_14.2: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.09f)] -// CHECK:STDOUT: %T.as_type.loc13_21.2: type = facet_access_type %T.loc13_14.2 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.037)] -// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc13, @impl.c93(%T.loc13_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.b9e)] +// CHECK:STDOUT: generic impl @impl.793(%T.loc13_14.1: %J.type) { +// CHECK:STDOUT: %T.loc13_14.2: %J.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_14.2 (constants.%T.ccd)] +// CHECK:STDOUT: %T.as_type.loc13_21.2: type = facet_access_type %T.loc13_14.2 [symbolic = %T.as_type.loc13_21.2 (constants.%T.as_type.3df)] +// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc13, @impl.793(%T.loc13_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.608)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -337,10 +325,10 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic impl @impl.9e6(%T.loc14_14.1: %L.type) { -// CHECK:STDOUT: %T.loc14_14.2: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.1d2)] -// CHECK:STDOUT: %T.as_type.loc14_21.2: type = facet_access_type %T.loc14_14.2 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.0ed)] -// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc14, @impl.9e6(%T.loc14_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.e9d)] +// CHECK:STDOUT: generic impl @impl.c93(%T.loc14_14.1: %K.type) { +// CHECK:STDOUT: %T.loc14_14.2: %K.type = bind_symbolic_name T, 0 [symbolic = %T.loc14_14.2 (constants.%T.09f)] +// CHECK:STDOUT: %T.as_type.loc14_21.2: type = facet_access_type %T.loc14_14.2 [symbolic = %T.as_type.loc14_21.2 (constants.%T.as_type.037)] +// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc14, @impl.c93(%T.loc14_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.b9e)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -350,27 +338,40 @@ impl forall [T:! type] T as I { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: generic impl @impl.9e6(%T.loc15_14.1: %L.type) { +// CHECK:STDOUT: %T.loc15_14.2: %L.type = bind_symbolic_name T, 0 [symbolic = %T.loc15_14.2 (constants.%T.1d2)] +// CHECK:STDOUT: %T.as_type.loc15_21.2: type = facet_access_type %T.loc15_14.2 [symbolic = %T.as_type.loc15_21.2 (constants.%T.as_type.0ed)] +// CHECK:STDOUT: %Interface.impl_witness: = impl_witness file.%Interface.impl_witness_table.loc15, @impl.9e6(%T.loc15_14.2) [symbolic = %Interface.impl_witness (constants.%Interface.impl_witness.e9d)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: impl: %.loc15 as %Interface.ref.loc15 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%Interface.impl_witness.loc15 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: specific @impl.c3d(constants.%T.826) { -// CHECK:STDOUT: %T.loc11_14.2 => constants.%T.826 -// CHECK:STDOUT: %T.as_type.loc11_21.2 => constants.%T.as_type.b70 +// CHECK:STDOUT: %T.loc12_14.2 => constants.%T.826 +// CHECK:STDOUT: %T.as_type.loc12_21.2 => constants.%T.as_type.b70 // CHECK:STDOUT: %Interface.impl_witness => constants.%Interface.impl_witness.a14 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @impl.793(constants.%T.ccd) { -// CHECK:STDOUT: %T.loc12_14.2 => constants.%T.ccd -// CHECK:STDOUT: %T.as_type.loc12_21.2 => constants.%T.as_type.3df +// CHECK:STDOUT: %T.loc13_14.2 => constants.%T.ccd +// CHECK:STDOUT: %T.as_type.loc13_21.2 => constants.%T.as_type.3df // CHECK:STDOUT: %Interface.impl_witness => constants.%Interface.impl_witness.608 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @impl.c93(constants.%T.09f) { -// CHECK:STDOUT: %T.loc13_14.2 => constants.%T.09f -// CHECK:STDOUT: %T.as_type.loc13_21.2 => constants.%T.as_type.037 +// CHECK:STDOUT: %T.loc14_14.2 => constants.%T.09f +// CHECK:STDOUT: %T.as_type.loc14_21.2 => constants.%T.as_type.037 // CHECK:STDOUT: %Interface.impl_witness => constants.%Interface.impl_witness.b9e // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @impl.9e6(constants.%T.1d2) { -// CHECK:STDOUT: %T.loc14_14.2 => constants.%T.1d2 -// CHECK:STDOUT: %T.as_type.loc14_21.2 => constants.%T.as_type.0ed +// CHECK:STDOUT: %T.loc15_14.2 => constants.%T.1d2 +// CHECK:STDOUT: %T.as_type.loc15_21.2 => constants.%T.as_type.0ed // CHECK:STDOUT: %Interface.impl_witness => constants.%Interface.impl_witness.e9d // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index ea8930af8145..5af5afc86ba6 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -316,8 +316,10 @@ CARBON_DIAGNOSTIC_KIND(ImplUnusedBinding) CARBON_DIAGNOSTIC_KIND(PoisonedImplLookupConcreteResult) CARBON_DIAGNOSTIC_KIND(PoisonedImplLookupConcreteResultNoteBadImpl) CARBON_DIAGNOSTIC_KIND(PoisonedImplLookupConcreteResultNotePreviousImpl) -CARBON_DIAGNOSTIC_KIND(ImplFullyOverlapNonFinal) -CARBON_DIAGNOSTIC_KIND(ImplFullyOverlapNonFinalNote) +CARBON_DIAGNOSTIC_KIND(ImplFinalOverlapsNonFinal) +CARBON_DIAGNOSTIC_KIND(ImplFinalOverlapsNonFinalNote) +CARBON_DIAGNOSTIC_KIND(ImplNonFinalSameTypeStructure) +CARBON_DIAGNOSTIC_KIND(ImplNonFinalSameTypeStructureNote) // Impl lookup. CARBON_DIAGNOSTIC_KIND(MissingImplInMemberAccess)