mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:54:41 +01:00
Use match_first to prioritize impls (#7492)
Allow (don't diagnose) impls that have the same type structure if they are associated with the same match_first block. Similarly, allow final impls (made final by their enclosing match_first block) that overlap in type structure when they are associated with the same match_first block. If the type structures are the same, choose the first impl from the match_first block.same. If the type structures overlap but are not the same, and share a match_first block, then we should choose the first overlapping impl from the match_first block. This is true both for final and non-final impls. See https://github.com/carbon-language/carbon-lang/blob/de8b03faa3178ae683d8e7124fbcba81eb88e00c/proposals/p005337-interface-extension-and-final-impl-update.md#impl-selection-algorithm But in the non-final case if there is an overlapping impl outside the match_first, it can win if it's more specific.
This commit is contained in:
@@ -31,6 +31,7 @@ struct ImplInfo {
|
||||
SemIR::TypeInstId self_id;
|
||||
SemIR::InstId latest_decl_id;
|
||||
SemIR::SpecificInterface interface;
|
||||
SemIR::InstId match_first_id;
|
||||
// Whether the `impl` decl was imported or from the local file.
|
||||
bool is_local;
|
||||
// If imported, the IR from which the `impl` decl was imported.
|
||||
@@ -90,6 +91,7 @@ static auto GetImplInfo(Context& context, SemIR::ImplId impl_id) -> ImplInfo {
|
||||
.self_id = impl.self_id,
|
||||
.latest_decl_id = impl.latest_decl_id(),
|
||||
.interface = impl.interface,
|
||||
.match_first_id = impl.match_first_id,
|
||||
.is_local = !ir_id.has_value(),
|
||||
.ir_id = ir_id,
|
||||
.library_id = library_id,
|
||||
@@ -236,14 +238,16 @@ static auto DiagnoseOrphanImpl(Context& context, const ImplInfo& impl,
|
||||
}
|
||||
|
||||
// The type structure each non-final `impl` must differ from all other non-final
|
||||
// `impl` for the same interface visible from the file.
|
||||
// `impl` for the same interface visible from the file. However, if the `impl`s
|
||||
// are associated with the same match_first block, then they are allowed to have
|
||||
// the same type structure.
|
||||
//
|
||||
// Returns true if an error was diagnosed.
|
||||
static auto DiagnoseNonFinalImplsWithSameTypeStructure(Context& context,
|
||||
const ImplInfo& impl_a,
|
||||
const ImplInfo& impl_b)
|
||||
-> bool {
|
||||
if (impl_a.type_structure == impl_b.type_structure) {
|
||||
static auto DiagnoseNonFinalImplsWithSameTypeStructureOutsideMatchFirst(
|
||||
Context& context, const ImplInfo& impl_a, const ImplInfo& impl_b) -> bool {
|
||||
if (impl_a.type_structure == impl_b.type_structure &&
|
||||
!(impl_a.match_first_id.has_value() &&
|
||||
impl_a.match_first_id == impl_b.match_first_id)) {
|
||||
CARBON_DIAGNOSTIC(ImplNonFinalSameTypeStructure, Error,
|
||||
"found non-final `impl` with the same type "
|
||||
"structure as another non-final `impl`");
|
||||
@@ -330,15 +334,14 @@ static auto DiagnoseFinalImplsOverlapInDifferentFiles(Context& context,
|
||||
// Two final impls in the same file can not overlap in their type
|
||||
// structure if they are not in the same match_first block.
|
||||
//
|
||||
// TODO: Support for match_first needed here when they exist in the
|
||||
// toolchain.
|
||||
//
|
||||
// Returns true if an error was diagnosed.
|
||||
static auto DiagnoseFinalImplsOverlapOutsideMatchFirst(Context& context,
|
||||
const ImplInfo& impl_a,
|
||||
const ImplInfo& impl_b)
|
||||
-> bool {
|
||||
if (impl_a.is_local && impl_b.is_local) {
|
||||
if (impl_a.is_local && impl_b.is_local &&
|
||||
!(impl_a.match_first_id.has_value() &&
|
||||
impl_a.match_first_id == impl_b.match_first_id)) {
|
||||
CARBON_DIAGNOSTIC(FinalImplOverlapsSameFile, Error,
|
||||
"`final impl` overlaps with `final impl` from same file "
|
||||
"outside a `match_first` block");
|
||||
@@ -417,8 +420,8 @@ static auto ValidateImplsForInterface(Context& context,
|
||||
// but possibly different files, if one is in the api and one in the
|
||||
// impl file.
|
||||
if (impl_a.library_id == impl_b.library_id) {
|
||||
if (DiagnoseNonFinalImplsWithSameTypeStructure(context, impl_a,
|
||||
impl_b)) {
|
||||
if (DiagnoseNonFinalImplsWithSameTypeStructureOutsideMatchFirst(
|
||||
context, impl_a, impl_b)) {
|
||||
// The same final `impl_a` may overlap with multiple `impl_b`s,
|
||||
// and we want to diagnose each `impl_b`.
|
||||
did_diagnose_non_final_impls_with_same_type_structure = true;
|
||||
|
||||
Reference in New Issue
Block a user