Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop merging invalid impl redefinitions #4798

Merged
merged 3 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions toolchain/check/handle_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,22 @@ static auto IsValidImplRedecl(Context& context, SemIR::Impl& new_impl,
return false;
}

if (prev_impl.has_definition_started()) {
// Impls aren't merged in order to avoid generic region lookup into a
// mismatching table.
CARBON_DIAGNOSTIC(ImplRedefinition, Error,
"redefinition of `impl {0} as {1}`", InstIdAsRawType,
InstIdAsRawType);
CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
"previous definition was here");
context.emitter()
.Build(new_impl.latest_decl_id(), ImplRedefinition, new_impl.self_id,
new_impl.constraint_id)
.Note(prev_impl.definition_id, ImplPreviousDefinition)
.Emit();
return false;
}

// TODO: Only allow redeclaration in a match_first/impl_priority block.

// TODO: Merge information from the new declaration into the old one as
Expand Down Expand Up @@ -427,23 +443,11 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionStartId node_id)
BuildImplDecl(context, node_id, /*is_definition=*/true);
auto& impl_info = context.impls().Get(impl_id);

if (impl_info.has_definition_started()) {
CARBON_DIAGNOSTIC(ImplRedefinition, Error,
"redefinition of `impl {0} as {1}`", InstIdAsRawType,
InstIdAsRawType);
CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
"previous definition was here");
context.emitter()
.Build(node_id, ImplRedefinition, impl_info.self_id,
impl_info.constraint_id)
.Note(impl_info.definition_id, ImplPreviousDefinition)
.Emit();
} else {
impl_info.definition_id = impl_decl_id;
impl_info.scope_id = context.name_scopes().Add(
impl_decl_id, SemIR::NameId::Invalid,
context.decl_name_stack().PeekParentScopeId());
}
CARBON_CHECK(!impl_info.has_definition_started());
impl_info.definition_id = impl_decl_id;
impl_info.scope_id =
context.name_scopes().Add(impl_decl_id, SemIR::NameId::Invalid,
context.decl_name_stack().PeekParentScopeId());

context.scope_stack().Push(
impl_decl_id, impl_info.scope_id,
Expand Down
28 changes: 17 additions & 11 deletions toolchain/check/testdata/impl/fail_redefinition.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,18 @@ impl i32 as I {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {}
// CHECK:STDOUT: impl_decl @impl [template] {} {
// CHECK:STDOUT: %int_32.loc13: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc13: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %I.ref.loc13: type = name_ref I, file.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: impl_decl @impl.1 [template] {} {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: impl_decl @impl [template] {} {
// CHECK:STDOUT: %int_32.loc21: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc21: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %I.ref.loc21: type = name_ref I, file.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: %impl_witness.loc13: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: impl_decl @impl.2 [template] {} {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %impl_witness.loc21: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
Expand All @@ -66,8 +67,13 @@ impl i32 as I {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: %i32.loc13 as %I.ref.loc13 {
// CHECK:STDOUT: impl @impl.1: %i32 as %I.ref {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = file.%impl_witness
// CHECK:STDOUT: witness = file.%impl_witness.loc13
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.2: %i32 as %I.ref {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = file.%impl_witness.loc21
// CHECK:STDOUT: }
// CHECK:STDOUT:
24 changes: 15 additions & 9 deletions toolchain/check/testdata/impl/no_prelude/fail_alias.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,16 @@ impl AC as AI {}
// CHECK:STDOUT: %AI: type = bind_alias AI, %I.decl [template = constants.%I.type]
// CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %AC: type = bind_alias AC, %C.decl [template = constants.%C]
// CHECK:STDOUT: impl_decl @impl [template] {} {
// CHECK:STDOUT: %AC.ref.loc17: type = name_ref AC, file.%AC [template = constants.%C]
// CHECK:STDOUT: %AI.ref.loc17: type = name_ref AI, file.%AI [template = constants.%I.type]
// CHECK:STDOUT: impl_decl @impl.1 [template] {} {
// CHECK:STDOUT: %AC.ref: type = name_ref AC, file.%AC [template = constants.%C]
// CHECK:STDOUT: %AI.ref: type = name_ref AI, file.%AI [template = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: impl_decl @impl [template] {} {
// CHECK:STDOUT: %AC.ref.loc25: type = name_ref AC, file.%AC [template = constants.%C]
// CHECK:STDOUT: %AI.ref.loc25: type = name_ref AI, file.%AI [template = constants.%I.type]
// CHECK:STDOUT: %impl_witness.loc17: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: impl_decl @impl.2 [template] {} {
// CHECK:STDOUT: %AC.ref: type = name_ref AC, file.%AC [template = constants.%C]
// CHECK:STDOUT: %AI.ref: type = name_ref AI, file.%AI [template = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %impl_witness.loc25: <witness> = impl_witness () [template = constants.%impl_witness]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
Expand All @@ -67,9 +68,14 @@ impl AC as AI {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: %AC.ref.loc17 as %AI.ref.loc17 {
// CHECK:STDOUT: impl @impl.1: %AC.ref as %AI.ref {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = file.%impl_witness
// CHECK:STDOUT: witness = file.%impl_witness.loc17
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.2: %AC.ref as %AI.ref {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = file.%impl_witness.loc25
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
Expand Down
Loading
Loading