Canonicalize generated functions for Core witnesses (#7729)

Use a single `SemIR::Function` per `Core` interface method, whether it's
generated locally or imported. This prevents generating duplicate
functions, which lead to different types when the witness appears in a
`FacetValue` as part of a specific for a class.

We use a `CanonicalValueStore` of `GeneratedFunction` objects that allow
finding an existing FunctionId for a `Generated` special function before
(re-)generating it. Mangling for `Generated` functions is also moved to
use the values from the `GeneratedFunction`'s canonicalization key, so
that we have a consistent source of truth for the unique ID of a
`Generated` function across all files.

New tests are in
`toolchain/check/testdata/impl/custom_witness/destroy.carbon`.
This commit is contained in:
Dana Jansens
2026-09-15 16:02:13 +00:00
committed by GitHub
parent db2e26ba86
commit 4416f3525b
278 changed files with 5941 additions and 5506 deletions
@@ -110,9 +110,9 @@ fn F() {
// CHECK:STDOUT: %initializer_list.initializer_list.0db5f6.2: %initializer_list.initializer_list.type.0fbcd7.2 = struct_value () [concrete]
// CHECK:STDOUT: %initializer_list.cpp_destructor.type: type = fn_type @initializer_list.cpp_destructor [concrete]
// CHECK:STDOUT: %initializer_list.cpp_destructor: %initializer_list.cpp_destructor.type = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.Op.type.1d8f74.4: type = fn_type @Destroy.Op.loc10_23.3 [concrete]
// CHECK:STDOUT: %Destroy.Op.1a2547.4: %Destroy.Op.type.1d8f74.4 = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.Op.bound: <bound method> = bound_method %.981, %Destroy.Op.1a2547.4 [concrete]
// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.4: type = fn_type @Destroy.WithSelf.Op.loc10_23.3 [concrete]
// CHECK:STDOUT: %Destroy.WithSelf.Op.403171.4: %Destroy.WithSelf.Op.type.ef016f.4 = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.WithSelf.Op.bound: <bound method> = bound_method %.981, %Destroy.WithSelf.Op.403171.4 [concrete]
// CHECK:STDOUT: %InitListConstructor: type = class_type @InitListConstructor [concrete]
// CHECK:STDOUT: %pattern_type.ed6: type = pattern_type %InitListConstructor [concrete]
// CHECK:STDOUT: %_.patt.100: %pattern_type.ed6 = value_binding_pattern _ [concrete]
@@ -298,7 +298,7 @@ fn F() {
// CHECK:STDOUT: %Consume__carbon_thunk.call: init %empty_tuple.type = call imports.%Consume__carbon_thunk.decl(%addr.loc10)
// CHECK:STDOUT: %initializer_list.cpp_destructor.bound.loc10: <bound method> = bound_method %.loc10_23.19, constants.%initializer_list.cpp_destructor
// CHECK:STDOUT: %initializer_list.cpp_destructor.call.loc10: init %empty_tuple.type = call %initializer_list.cpp_destructor.bound.loc10(%.loc10_23.19)
// CHECK:STDOUT: %Destroy.Op.call.loc10: init %empty_tuple.type = call constants.%Destroy.Op.bound(constants.%.981)
// CHECK:STDOUT: %Destroy.WithSelf.Op.call.loc10: init %empty_tuple.type = call constants.%Destroy.WithSelf.Op.bound(constants.%.981)
// CHECK:STDOUT: %int_1.loc12_37: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
// CHECK:STDOUT: %int_2.loc12_40: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc]
// CHECK:STDOUT: %int_3.loc12_43: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
@@ -365,10 +365,10 @@ fn F() {
// CHECK:STDOUT: %InitListConstructor.cpp_destructor.call: init %empty_tuple.type = call %InitListConstructor.cpp_destructor.bound(%.loc12_44.25)
// CHECK:STDOUT: %initializer_list.cpp_destructor.bound.loc12: <bound method> = bound_method %.loc12_44.20, constants.%initializer_list.cpp_destructor
// CHECK:STDOUT: %initializer_list.cpp_destructor.call.loc12: init %empty_tuple.type = call %initializer_list.cpp_destructor.bound.loc12(%.loc12_44.20)
// CHECK:STDOUT: %Destroy.Op.call.loc12: init %empty_tuple.type = call constants.%Destroy.Op.bound(constants.%.981)
// CHECK:STDOUT: %Destroy.WithSelf.Op.call.loc12: init %empty_tuple.type = call constants.%Destroy.WithSelf.Op.bound(constants.%.981)
// CHECK:STDOUT: %initializer_list.cpp_destructor.bound.loc8: <bound method> = bound_method %.loc8_50.19, constants.%initializer_list.cpp_destructor
// CHECK:STDOUT: %initializer_list.cpp_destructor.call.loc8: init %empty_tuple.type = call %initializer_list.cpp_destructor.bound.loc8(%.loc8_50.19)
// CHECK:STDOUT: %Destroy.Op.call.loc8: init %empty_tuple.type = call constants.%Destroy.Op.bound(constants.%.981)
// CHECK:STDOUT: %Destroy.WithSelf.Op.call.loc8: init %empty_tuple.type = call constants.%Destroy.WithSelf.Op.bound(constants.%.981)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -376,14 +376,14 @@ fn F() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @initializer_list.initializer_list.loc10(%_.param: %array_type) -> out %return.param: %initializer_list = "cpp.std.initializer_list.make";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc10_23.1(%self.param: ref %i32.builtin) = "no_op";
// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc10_23.1(%self.param: ref %i32.builtin) = "no_op";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc10_23.2(%self.param: ref %i32) {
// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc10_23.2(%self.param: ref %i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc10_23.3(%self.param: ref %array_type) {
// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc10_23.3(%self.param: ref %array_type) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }