diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 977d4b03c3df..3dcdf61c2cae 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -78,9 +78,6 @@ static auto BuildInterfaceDecl(Context& context, auto existing_interface_decl = existing_decl->As(); interface_decl.interface_id = existing_interface_decl.interface_id; interface_decl.type_id = existing_interface_decl.type_id; - // TODO: If the new declaration is a definition, keep its parameter - // and implicit parameter lists rather than the ones from the - // previous declaration. auto prev_decl_generic_id = context.interfaces().Get(interface_decl.interface_id).generic_id; diff --git a/toolchain/check/interface.cpp b/toolchain/check/interface.cpp index 2931474e72bf..ca153ee083dd 100644 --- a/toolchain/check/interface.cpp +++ b/toolchain/check/interface.cpp @@ -6,8 +6,11 @@ #include #include +#include +#include #include "common/concepts.h" +#include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/core_identifier.h" #include "toolchain/check/eval.h" @@ -153,28 +156,6 @@ auto AddSelfSymbolicBindingToScope(Context& context, return self_param_inst_id; } -template - requires std::same_as -static auto TryGetEntity(Context& context, SemIR::Inst inst) - -> const SemIR::EntityWithParamsBase* { - if (auto decl = inst.TryAs()) { - return &context.interfaces().Get(decl->interface_id); - } else { - return nullptr; - } -} - -template - requires std::same_as -static auto TryGetEntity(Context& context, SemIR::Inst inst) - -> const SemIR::EntityWithParamsBase* { - if (auto decl = inst.TryAs()) { - return &context.named_constraints().Get(decl->named_constraint_id); - } else { - return nullptr; - } -} - template requires std::same_as static constexpr auto DeclTokenKind() -> Lex::TokenKind { @@ -193,6 +174,11 @@ auto TryGetExistingDecl(Context& context, const NameComponent& name, SemIR::ScopeLookupResult lookup_result, const EntityT& entity, bool is_definition) -> std::optional { + using EntityIdT = + std::conditional_t, + SemIR::InterfaceId, SemIR::NamedConstraintId>; + constexpr bool IsInterface = std::is_same_v; + if (lookup_result.is_poisoned()) { // This is a declaration of a poisoned name. DiagnosePoisonedName(context, name.name_id, @@ -204,39 +190,100 @@ auto TryGetExistingDecl(Context& context, const NameComponent& name, return std::nullopt; } - SemIR::InstId existing_id = lookup_result.target_inst_id(); - SemIR::Inst existing_decl_inst = context.insts().Get(existing_id); - const auto* existing_decl_entity = - TryGetEntity(context, existing_decl_inst); - if (!existing_decl_entity) { + auto prev_id = lookup_result.target_inst_id(); + auto prev = context.insts().Get(prev_id); + + auto prev_entity_id = EntityIdT::None; + auto prev_import_ir_id = SemIR::ImportIRId::None; + auto existing_decl_id = SemIR::InstId::None; + CARBON_KIND_SWITCH(prev) { + case CARBON_KIND(SemIR::InterfaceDecl interface_decl): { + if constexpr (IsInterface) { + prev_entity_id = interface_decl.interface_id; + existing_decl_id = prev_id; + } + break; + } + case CARBON_KIND(SemIR::NamedConstraintDecl named_constraint_decl): { + if constexpr (!IsInterface) { + prev_entity_id = named_constraint_decl.named_constraint_id; + existing_decl_id = prev_id; + } + break; + } + case CARBON_KIND(SemIR::ImportRefLoaded import_ref): { + auto import_ir_inst = + context.import_ir_insts().Get(import_ref.import_ir_inst_id); + + // Verify the decl so that things like aliases are name conflicts. + const auto* import_ir = + context.import_irs().Get(import_ir_inst.ir_id()).sem_ir; + if constexpr (IsInterface) { + if (!import_ir->insts().Is( + import_ir_inst.inst_id())) { + break; + } + } else { + if (!import_ir->insts().Is( + import_ir_inst.inst_id())) { + break; + } + } + + // Use the constant value to get the ID. + auto decl_value = context.insts().Get( + context.constant_values().GetConstantInstId(prev_id)); + if (auto facet_type = decl_value.TryAs()) { + auto declared_facet_type = context.declared_facet_types().Get( + facet_type->declared_facet_type_id); + if constexpr (IsInterface) { + prev_entity_id = + declared_facet_type.extend_constraints[0].interface_id; + } else { + prev_entity_id = declared_facet_type.extend_named_constraints[0] + .named_constraint_id; + } + prev_import_ir_id = import_ir_inst.ir_id(); + } + break; + } + default: + break; + } + + if (!prev_entity_id.has_value()) { // This is a redeclaration with a different entity kind. DiagnoseDuplicateName(context, name.name_id, name.name_loc_id, - SemIR::LocId(existing_id)); + SemIR::LocId(prev_id)); return std::nullopt; } + auto& prev_entity = [&]() -> EntityT& { + if constexpr (IsInterface) { + return context.interfaces().Get(prev_entity_id); + } else { + return context.named_constraints().Get(prev_entity_id); + } + }(); + if (!CheckRedeclParamsMatch( context, DeclParams(SemIR::LocId(entity.latest_decl_id()), name.first_param_node_id, name.last_param_node_id, name.implicit_param_patterns_id, name.param_patterns_id), - DeclParams(*existing_decl_entity))) { + DeclParams(prev_entity))) { // Mismatch is diagnosed already if found. return std::nullopt; } - // TODO: This should be refactored a little, particularly for - // prev_import_ir_id. See similar logic for classes and functions, which - // might also be refactored to merge. DiagnoseIfInvalidRedecl( - context, DeclTokenKind(), existing_decl_entity->name_id, + context, DeclTokenKind(), prev_entity.name_id, RedeclInfo(entity, SemIR::LocId(entity.latest_decl_id()), is_definition), - RedeclInfo(*existing_decl_entity, - SemIR::LocId(existing_decl_entity->latest_decl_id()), - existing_decl_entity->has_definition_started()), - /*prev_import_ir_id=*/SemIR::ImportIRId::None); + RedeclInfo(prev_entity, SemIR::LocId(prev_entity.latest_decl_id()), + prev_entity.has_definition_started()), + prev_import_ir_id); - if (is_definition && existing_decl_entity->has_definition_started()) { + if (is_definition && prev_entity.has_definition_started()) { // DiagnoseIfInvalidRedecl would diagnose an error in this case, since we'd // have two definitions. Given the declaration parts of the definitions // match, we would be able to use the prior declaration for error recovery, @@ -246,8 +293,19 @@ auto TryGetExistingDecl(Context& context, const NameComponent& name, return std::nullopt; } + if (is_definition) { + prev_entity.MergeDefinition(entity); + } + + if (prev_import_ir_id.has_value()) { + prev_entity.first_owning_decl_id = entity.first_owning_decl_id; + ReplacePrevInstForMerge(context, entity.parent_scope_id, + prev_entity.name_id, entity.first_owning_decl_id); + } + // This is a matching redeclaration of an existing entity of the same type. - return existing_decl_inst; + return existing_decl_id.has_value() ? std::optional(prev) + : std::nullopt; } template auto TryGetExistingDecl(Context& context, const NameComponent& name, diff --git a/toolchain/check/testdata/class/no_definition_in_impl_file.carbon b/toolchain/check/testdata/class/no_definition_in_impl_file.carbon index f8f535e595d5..ba7d2a13aa4c 100644 --- a/toolchain/check/testdata/class/no_definition_in_impl_file.carbon +++ b/toolchain/check/testdata/class/no_definition_in_impl_file.carbon @@ -18,10 +18,11 @@ library "[[@TEST_NAME]]"; class A; -// --- decl_in_api_definition_in_impl.impl.carbon +// --- todo_fail_decl_in_api_definition_in_impl.impl.carbon impl library "[[@TEST_NAME]]"; +// TODO: This should be diagnosed per #3762: A declaration should always add new information. class A; class A {} @@ -91,7 +92,7 @@ class D; // CHECK:STDOUT: // CHECK:STDOUT: class @A; // CHECK:STDOUT: -// CHECK:STDOUT: --- decl_in_api_definition_in_impl.impl.carbon +// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %A: type = class_type @A [concrete] @@ -101,12 +102,12 @@ class D; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [concrete] { -// CHECK:STDOUT: .A = %A.decl.loc4 +// CHECK:STDOUT: .A = %A.decl.loc5 // CHECK:STDOUT: } // CHECK:STDOUT: %default.import.loc2_46.1 = import // CHECK:STDOUT: %default.import.loc2_46.2 = import -// CHECK:STDOUT: %A.decl.loc4: type = class_decl @A [concrete = constants.%A] {} {} -// CHECK:STDOUT: %A.decl.loc6: type = class_decl @A [concrete = constants.%A] {} {} +// CHECK:STDOUT: %A.decl.loc5: type = class_decl @A [concrete = constants.%A] {} {} +// CHECK:STDOUT: %A.decl.loc7: type = class_decl @A [concrete = constants.%A] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @A { diff --git a/toolchain/check/testdata/function/declaration/no_definition_in_impl_file.carbon b/toolchain/check/testdata/function/declaration/no_definition_in_impl_file.carbon index 056c39a48fac..83f36903551e 100644 --- a/toolchain/check/testdata/function/declaration/no_definition_in_impl_file.carbon +++ b/toolchain/check/testdata/function/declaration/no_definition_in_impl_file.carbon @@ -18,10 +18,11 @@ library "[[@TEST_NAME]]"; fn A(); -// --- decl_in_api_definition_in_impl.impl.carbon +// --- todo_fail_decl_in_api_definition_in_impl.impl.carbon impl library "[[@TEST_NAME]]"; +// TODO: This should be diagnosed per #3762: A declaration should always add new information. fn A(); fn A() {} @@ -92,7 +93,7 @@ fn D(); // CHECK:STDOUT: // CHECK:STDOUT: fn @A(); // CHECK:STDOUT: -// CHECK:STDOUT: --- decl_in_api_definition_in_impl.impl.carbon +// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %A.type: type = fn_type @A [concrete] @@ -101,12 +102,12 @@ fn D(); // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [concrete] { -// CHECK:STDOUT: .A = %A.decl.loc4 +// CHECK:STDOUT: .A = %A.decl.loc5 // CHECK:STDOUT: } // CHECK:STDOUT: %default.import.loc2_46.1 = import // CHECK:STDOUT: %default.import.loc2_46.2 = import -// CHECK:STDOUT: %A.decl.loc4: %A.type = fn_decl @A [concrete = constants.%A] {} {} -// CHECK:STDOUT: %A.decl.loc6: %A.type = fn_decl @A [concrete = constants.%A] {} {} +// CHECK:STDOUT: %A.decl.loc5: %A.type = fn_decl @A [concrete = constants.%A] {} {} +// CHECK:STDOUT: %A.decl.loc7: %A.type = fn_decl @A [concrete = constants.%A] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @A() [from "decl_in_api_definition_in_impl.carbon"] { diff --git a/toolchain/check/testdata/interface/fail_definition_imported.carbon b/toolchain/check/testdata/interface/fail_definition_imported.carbon index bf0c31c0ac0d..2bcffd10ce66 100644 --- a/toolchain/check/testdata/interface/fail_definition_imported.carbon +++ b/toolchain/check/testdata/interface/fail_definition_imported.carbon @@ -23,11 +23,12 @@ interface I; library "[[@TEST_NAME]]"; import library "a"; -// CHECK:STDERR: fail_b.carbon:[[@LINE+8]]:11: error: duplicate name `I` being declared in the same scope [NameDeclDuplicate] +// TODO: Replace this diagnostic with one that better describes the error, such as 'DeclaredInMultipleLibraries'. +// CHECK:STDERR: fail_b.carbon:[[@LINE+8]]:1: error: redeclaration of `interface I` is redundant [RedeclRedundant] // CHECK:STDERR: interface I {} -// CHECK:STDERR: ^ -// CHECK:STDERR: fail_b.carbon:[[@LINE-5]]:1: in import [InImport] -// CHECK:STDERR: a.carbon:4:1: note: name is previously declared here [NameDeclPrevious] +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: fail_b.carbon:[[@LINE-6]]:1: in import [InImport] +// CHECK:STDERR: a.carbon:4:1: note: previously declared here [RedeclPrevDecl] // CHECK:STDERR: interface I; // CHECK:STDERR: ^~~~~~~~~~~~ // CHECK:STDERR: @@ -51,28 +52,23 @@ interface I {} // CHECK:STDOUT: --- fail_b.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %I.type.8e70aa.1: type = facet_type <@I.1> [concrete] -// CHECK:STDOUT: %I.type.8e70aa.2: type = facet_type <@I.loc13> [concrete] +// CHECK:STDOUT: %I.type.8e70aa.2: type = facet_type <@I.loc14_13.2> [concrete] // CHECK:STDOUT: %Self: %I.type.8e70aa.2 = symbolic_binding Self, 0 [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Main.I: type = import_ref Main//a, I, loaded [concrete = constants.%I.type.8e70aa.1] -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [concrete] { -// CHECK:STDOUT: .I = imports.%Main.I +// CHECK:STDOUT: .I = %I.decl // CHECK:STDOUT: } // CHECK:STDOUT: %default.import = import -// CHECK:STDOUT: %I.decl: type = interface_decl @I.loc13 [concrete = constants.%I.type.8e70aa.2] {} {} +// CHECK:STDOUT: %I.decl: type = interface_decl @I.loc14_13.2 [concrete = constants.%I.type.8e70aa.2] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: interface @I.1 [from "a.carbon"]; +// CHECK:STDOUT: interface @I.loc14_13.1; // CHECK:STDOUT: -// CHECK:STDOUT: interface @I.loc13 { +// CHECK:STDOUT: interface @I.loc14_13.2 { // CHECK:STDOUT: %Self: %I.type.8e70aa.2 = symbolic_binding Self, 0 [symbolic = constants.%Self] -// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I.loc13 [concrete] +// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I.loc14_13.2 [concrete] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self diff --git a/toolchain/check/testdata/interface/no_definition_in_impl_file.carbon b/toolchain/check/testdata/interface/no_definition_in_impl_file.carbon new file mode 100644 index 000000000000..360f3377d067 --- /dev/null +++ b/toolchain/check/testdata/interface/no_definition_in_impl_file.carbon @@ -0,0 +1,224 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon +// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only". +// EXTRA-ARGS: --dump-sem-ir-ranges=if-present +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_definition_in_impl_file.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_definition_in_impl_file.carbon + +// --- decl_in_api_definition_in_impl.carbon + +library "[[@TEST_NAME]]"; + +interface A; + +// --- todo_fail_decl_in_api_definition_in_impl.impl.carbon + +impl library "[[@TEST_NAME]]"; + +// TODO: This should be diagnosed per #3762: A declaration should always add new information. +interface A; + +interface A {} + +// --- use_decl_in_api.carbon + +library "[[@TEST_NAME]]"; + +// --- use_decl_in_api.impl.carbon + +impl library "[[@TEST_NAME]]"; + +import library "decl_in_api_definition_in_impl"; + +// --- decl_only_in_api.carbon + +library "[[@TEST_NAME]]"; + +interface B; + +// --- decl_only_in_api.impl.carbon + +impl library "[[@TEST_NAME]]"; + +// --- decl_in_api_decl_in_impl.carbon + +library "[[@TEST_NAME]]"; + +interface C; + +// --- todo_fail_decl_in_api_decl_in_impl.impl.carbon + +impl library "[[@TEST_NAME]]"; + +interface C; + +// --- decl_only_in_impl.carbon + +library "[[@TEST_NAME]]"; + +// --- todo_fail_decl_only_in_impl.impl.carbon + +impl library "[[@TEST_NAME]]"; + +interface D; + +// CHECK:STDOUT: --- decl_in_api_definition_in_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A.type: type = facet_type <@A> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: type = interface_decl @A [concrete = constants.%A.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @A; +// CHECK:STDOUT: +// CHECK:STDOUT: --- todo_fail_decl_in_api_definition_in_impl.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A.type.3138d6.2: type = facet_type <@A.loc7> [concrete] +// CHECK:STDOUT: %Self: %A.type.3138d6.2 = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .A = %A.decl.loc5 +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import.loc2_46.1 = import +// CHECK:STDOUT: %default.import.loc2_46.2 = import +// CHECK:STDOUT: %A.decl.loc5: type = interface_decl @A.loc7 [concrete = constants.%A.type.3138d6.2] {} {} +// CHECK:STDOUT: %A.decl.loc7: type = interface_decl @A.loc7 [concrete = constants.%A.type.3138d6.2] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @A.loc5; +// CHECK:STDOUT: +// CHECK:STDOUT: interface @A.loc7 { +// CHECK:STDOUT: %Self: %A.type.3138d6.2 = symbolic_binding Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %A.WithSelf.decl = interface_with_self_decl @A.loc7 [concrete] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @A.WithSelf(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: --- use_decl_in_api.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- use_decl_in_api.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.A = import_ref Main//decl_in_api_definition_in_impl, A, unloaded +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .A = imports.%Main.A +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import.loc2_31.1 = import +// CHECK:STDOUT: %default.import.loc2_31.2 = import +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- decl_only_in_api.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %B.type: type = facet_type <@B> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .B = %B.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %B.decl: type = interface_decl @B [concrete = constants.%B.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @B; +// CHECK:STDOUT: +// CHECK:STDOUT: --- decl_only_in_api.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.B = import_ref Main//decl_only_in_api, B, unloaded +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .B = imports.%Main.B +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import.loc2_32.1 = import +// CHECK:STDOUT: %default.import.loc2_32.2 = import +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- decl_in_api_decl_in_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C.type: type = facet_type <@C> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = interface_decl @C [concrete = constants.%C.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @C; +// CHECK:STDOUT: +// CHECK:STDOUT: --- todo_fail_decl_in_api_decl_in_impl.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C.type.709119.2: type = facet_type <@C.loc4_12.2> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import.loc2_40.1 = import +// CHECK:STDOUT: %default.import.loc2_40.2 = import +// CHECK:STDOUT: %C.decl: type = interface_decl @C.loc4_12.2 [concrete = constants.%C.type.709119.2] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @C.loc4_12.1; +// CHECK:STDOUT: +// CHECK:STDOUT: interface @C.loc4_12.2; +// CHECK:STDOUT: +// CHECK:STDOUT: --- decl_only_in_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- todo_fail_decl_only_in_impl.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %D.type: type = facet_type <@D> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .D = %D.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %default.import.loc2_33.1 = import +// CHECK:STDOUT: %default.import.loc2_33.2 = import +// CHECK:STDOUT: %D.decl: type = interface_decl @D [concrete = constants.%D.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @D; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/syntactic_merge.carbon b/toolchain/check/testdata/interface/syntactic_merge.carbon index 514b863fe584..dd0570fadff6 100644 --- a/toolchain/check/testdata/interface/syntactic_merge.carbon +++ b/toolchain/check/testdata/interface/syntactic_merge.carbon @@ -229,7 +229,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [concrete = constants.%C] // CHECK:STDOUT: %D: type = alias_binding D, %C.ref [concrete = constants.%C] // CHECK:STDOUT: %Foo.decl.loc7: %Foo.type.bc6 = interface_decl @Foo [concrete = constants.%Foo.generic] { -// CHECK:STDOUT: %a.patt.loc7_16.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc8: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc7: type = splice_block %C.ref.loc7 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc7: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -238,7 +238,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: %a.loc7_16.2: %C = symbolic_binding a, 0 [symbolic = %a.loc7_16.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %Foo.decl.loc8: %Foo.type.bc6 = interface_decl @Foo [concrete = constants.%Foo.generic] { -// CHECK:STDOUT: %a.patt.loc7_16.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc8: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc8: type = splice_block %C.ref.loc8 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc8: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -247,7 +247,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: %a.loc8: %C = symbolic_binding a, 0 [symbolic = %a.loc7_16.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %Bar.decl.loc10: %Bar.type.3f0 = interface_decl @Bar [concrete = constants.%Bar.generic] { -// CHECK:STDOUT: %a.patt.loc10_16.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc11: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc10: type = splice_block %D.ref.loc10 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc10: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -256,7 +256,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: %a.loc10_16.2: %C = symbolic_binding a, 0 [symbolic = %a.loc10_16.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %Bar.decl.loc11: %Bar.type.3f0 = interface_decl @Bar [concrete = constants.%Bar.generic] { -// CHECK:STDOUT: %a.patt.loc10_16.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc11: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc11: type = splice_block %D.ref.loc11 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc11: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -267,7 +267,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic interface @Foo(%a.loc7_16.2: %C) { -// CHECK:STDOUT: %a.patt.loc7_16.2: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc7: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc7 (constants.%a.patt)] // CHECK:STDOUT: %a.loc7_16.1: %C = symbolic_binding a, 0 [symbolic = %a.loc7_16.1 (constants.%a)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -287,7 +287,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic interface @Bar(%a.loc10_16.2: %C) { -// CHECK:STDOUT: %a.patt.loc10_16.2: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10_16.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc10: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc10 (constants.%a.patt)] // CHECK:STDOUT: %a.loc10_16.1: %C = symbolic_binding a, 0 [symbolic = %a.loc10_16.1 (constants.%a)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -315,14 +315,14 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Foo(constants.%a) { -// CHECK:STDOUT: %a.patt.loc7_16.2 => constants.%a.patt +// CHECK:STDOUT: %a.patt.loc7 => constants.%a.patt // CHECK:STDOUT: %a.loc7_16.1 => constants.%a // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Foo.WithSelf(constants.%a, constants.%Self.a95) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @Bar(constants.%a) { -// CHECK:STDOUT: %a.patt.loc10_16.2 => constants.%a.patt +// CHECK:STDOUT: %a.patt.loc10 => constants.%a.patt // CHECK:STDOUT: %a.loc10_16.1 => constants.%a // CHECK:STDOUT: } // CHECK:STDOUT: @@ -352,7 +352,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} // CHECK:STDOUT: %Foo.decl.loc6: %Foo.type.bc6 = interface_decl @Foo [concrete = constants.%Foo.generic] { -// CHECK:STDOUT: %a.patt.loc6_23.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6_23.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc7: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc6: type = splice_block %C.ref.loc6 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc6: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -361,7 +361,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: %a.loc6_23.2: %C = symbolic_binding a, 0 [symbolic = %a.loc6_23.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %Foo.decl.loc7: %Foo.type.bc6 = interface_decl @Foo [concrete = constants.%Foo.generic] { -// CHECK:STDOUT: %a.patt.loc6_23.1: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6_23.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc7: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6 (constants.%a.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc7: type = splice_block %C.ref.loc7 [concrete = constants.%C] { // CHECK:STDOUT: %.Self.frozen.loc7: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -372,7 +372,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic interface @Foo(%a.loc6_23.2: %C) { -// CHECK:STDOUT: %a.patt.loc6_23.2: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6_23.2 (constants.%a.patt)] +// CHECK:STDOUT: %a.patt.loc6: %pattern_type = symbolic_binding_pattern a, 0 [symbolic = %a.patt.loc6 (constants.%a.patt)] // CHECK:STDOUT: %a.loc6_23.1: %C = symbolic_binding a, 0 [symbolic = %a.loc6_23.1 (constants.%a)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -400,7 +400,7 @@ interface Foo(a: const (const C)) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Foo(constants.%a) { -// CHECK:STDOUT: %a.patt.loc6_23.2 => constants.%a.patt +// CHECK:STDOUT: %a.patt.loc6 => constants.%a.patt // CHECK:STDOUT: %a.loc6_23.1 => constants.%a // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/named_constraint/generic.carbon b/toolchain/check/testdata/named_constraint/generic.carbon index 00f1a1fa82bd..9395a5e2037a 100644 --- a/toolchain/check/testdata/named_constraint/generic.carbon +++ b/toolchain/check/testdata/named_constraint/generic.carbon @@ -129,7 +129,7 @@ fn F(unused generic T: Generic((), ())) {} // CHECK:STDOUT: %U.loc7_22.2: %Z.type = symbolic_binding U, 0 [symbolic = %U.loc7_22.1 (constants.%U)] // CHECK:STDOUT: } // CHECK:STDOUT: %ForwardDeclaredGeneric.decl.loc9: %ForwardDeclaredGeneric.type.650 = constraint_decl @ForwardDeclaredGeneric [concrete = constants.%empty_struct.43d] { -// CHECK:STDOUT: %T.patt.loc9_36.1: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9_36.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc10: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9 (constants.%T.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc9_38.1: type = splice_block %.loc9_38.2 [concrete = type] { // CHECK:STDOUT: %.Self.frozen.loc9: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -138,7 +138,7 @@ fn F(unused generic T: Generic((), ())) {} // CHECK:STDOUT: %T.loc9_36.2: type = symbolic_binding T, 0 [symbolic = %T.loc9_36.1 (constants.%T)] // CHECK:STDOUT: } // CHECK:STDOUT: %ForwardDeclaredGeneric.decl.loc10: %ForwardDeclaredGeneric.type.650 = constraint_decl @ForwardDeclaredGeneric [concrete = constants.%empty_struct.43d] { -// CHECK:STDOUT: %T.patt.loc9_36.1: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9_36.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc10: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9 (constants.%T.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %.loc10_38.1: type = splice_block %.loc10_38.2 [concrete = type] { // CHECK:STDOUT: %.Self.frozen.loc10: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] @@ -198,7 +198,7 @@ fn F(unused generic T: Generic((), ())) {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic constraint @ForwardDeclaredGeneric(%T.loc9_36.2: type) { -// CHECK:STDOUT: %T.patt.loc9_36.2: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9_36.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc9: %pattern_type.98f = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc9 (constants.%T.patt)] // CHECK:STDOUT: %T.loc9_36.1: type = symbolic_binding T, 0 [symbolic = %T.loc9_36.1 (constants.%T)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -233,7 +233,7 @@ fn F(unused generic T: Generic((), ())) {} // CHECK:STDOUT: specific @GenericZ.WithSelf(constants.%U, constants.%Self.22bbf7.2) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @ForwardDeclaredGeneric(constants.%T) { -// CHECK:STDOUT: %T.patt.loc9_36.2 => constants.%T.patt +// CHECK:STDOUT: %T.patt.loc9 => constants.%T.patt // CHECK:STDOUT: %T.loc9_36.1 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/sem_ir/interface.h b/toolchain/sem_ir/interface.h index eba5edb46ed7..ca1663727e67 100644 --- a/toolchain/sem_ir/interface.h +++ b/toolchain/sem_ir/interface.h @@ -68,6 +68,21 @@ struct Interface : public EntityWithParamsBase, auto is_being_defined() const -> bool { return has_definition_started() && !is_complete(); } + + // When merging a declaration and definition, prefer things which would point + // at the definition for diagnostics. + auto MergeDefinition(const Interface& definition) -> void { + EntityWithParamsBase::MergeBaseDefinition(definition); + scope_with_self_id = definition.scope_with_self_id; + scope_without_self_id = definition.scope_without_self_id; + body_block_without_self_id = definition.body_block_without_self_id; + body_block_with_self_id = definition.body_block_with_self_id; + self_param_id = definition.self_param_id; + core_interface = definition.core_interface; + require_impls_block_id = definition.require_impls_block_id; + observe_block_id = definition.observe_block_id; + associated_entities_id = definition.associated_entities_id; + } }; using InterfaceStore = ValueStore>; diff --git a/toolchain/sem_ir/named_constraint.h b/toolchain/sem_ir/named_constraint.h index 94fbf112bfc8..966865cd5f13 100644 --- a/toolchain/sem_ir/named_constraint.h +++ b/toolchain/sem_ir/named_constraint.h @@ -57,6 +57,19 @@ struct NamedConstraint : public EntityWithParamsBase, auto is_being_defined() const -> bool { return has_definition_started() && !is_complete(); } + + // When merging a declaration and definition, prefer things which would point + // at the definition for diagnostics. + auto MergeDefinition(const NamedConstraint& definition) -> void { + EntityWithParamsBase::MergeBaseDefinition(definition); + scope_with_self_id = definition.scope_with_self_id; + scope_without_self_id = definition.scope_without_self_id; + body_block_without_self_id = definition.body_block_without_self_id; + body_block_with_self_id = definition.body_block_with_self_id; + self_param_id = definition.self_param_id; + require_impls_block_id = definition.require_impls_block_id; + complete = definition.complete; + } }; using NamedConstraintStore =