Change the Destroy blanket impls to be more specific (#6098)

The main direction of this change is the edits to `destroy.carbon`
(matching in both prelude and min_prelude).

Previously there was a no-op blanket impl for `Destroy`, which hid all
missing implementations of `Destroy`. This does a few things:

- Sets up builtin aggregate destruction for struct and tuple types as
before, but also adds C++ class types and array types to the same
handling. (all as a TODO for actual implementation)
- Also maybe-unformed destruction, for now at least. (there's a chance I
may try a different approach on this, but the impl lookup wasn't working
as I'd hope in order to write it in code)
- Adds handlers for simple things that are easy to do in code: `type`,
`bool`, pointers. (because these are no-op destruction)
- Redirect `const T` destruction to `T` destruction.

This leaves as future issues:

- `partial T` destruction. (this can't be done similar to `const`
because it only works for non-`final` class types; I think `class`
definitions should just generate what's needed)
- Destruction of other prelude-provided types. (will probably come up as
we implement class destruction, that the adapted builtin type doesn't
implement `Destroy` -- but may end up special-casing that in a way that
moots it)

This moves the `&` operator from `facet_types.carbon` to
`convert.carbon` because more things need to handle type and now that
we're getting separate copy and destroy interfaces. It should be
low-cost (an interface and builtin) so hopefully this is the right
balance for complexity and re-use.

A few tests are also edited in order to focus them more on what they
intend to test, and avoid a `Destroy` dependency.
This commit is contained in:
Jon Ross-Perkins
2025-09-18 22:10:50 +00:00
committed by GitHub
parent 868c4b768c
commit 9704dc670e
143 changed files with 3271 additions and 2413 deletions
+7 -7
View File
@@ -327,16 +327,16 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) {
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %.4ab: type = cpp_overload_set_type @HasQualifiers.F.1 [concrete]
// CHECK:STDOUT: %empty_struct: %.4ab = struct_value () [concrete]
// CHECK:STDOUT: %const: type = const_type %HasQualifiers [concrete]
// CHECK:STDOUT: %ptr.2cb: type = ptr_type %const [concrete]
// CHECK:STDOUT: %const.2b5: type = const_type %HasQualifiers [concrete]
// CHECK:STDOUT: %ptr.2cb: type = ptr_type %const.2b5 [concrete]
// CHECK:STDOUT: %F__carbon_thunk.type: type = fn_type @F__carbon_thunk [concrete]
// CHECK:STDOUT: %F__carbon_thunk: %F__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %pattern_type.fe8: type = pattern_type %ptr.235 [concrete]
// CHECK:STDOUT: %HasQualifiers.F.type.d208f0.2: type = fn_type @HasQualifiers.F.2 [concrete]
// CHECK:STDOUT: %HasQualifiers.F.efd4e4.2: %HasQualifiers.F.type.d208f0.2 = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.f3e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%ptr.235) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a18: %T.as.Destroy.impl.Op.type.f3e = struct_value () [concrete]
// CHECK:STDOUT: %ptr.as.Destroy.impl.Op.type.142: type = fn_type @ptr.as.Destroy.impl.Op, @ptr.as.Destroy.impl(%i32) [concrete]
// CHECK:STDOUT: %ptr.as.Destroy.impl.Op.c04: %ptr.as.Destroy.impl.Op.type.142 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.5d5: type = ptr_type %ptr.235 [concrete]
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.type.4f9: type = fn_type @Int.as.Destroy.impl.Op, @Int.as.Destroy.impl(%int_32) [concrete]
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.796: %Int.as.Destroy.impl.Op.type.4f9 = struct_value () [concrete]
@@ -395,11 +395,11 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) {
// CHECK:STDOUT: %ptr.loc9: type = ptr_type %i32.loc9 [concrete = constants.%ptr.235]
// CHECK:STDOUT: }
// CHECK:STDOUT: %b: ref %ptr.235 = bind_name b, %b.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %b.var, constants.%T.as.Destroy.impl.Op.a18
// CHECK:STDOUT: %ptr.as.Destroy.impl.Op.bound: <bound method> = bound_method %b.var, constants.%ptr.as.Destroy.impl.Op.c04
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc9_3: <bound method> = bound_method %b.var, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method.loc9_3: <bound method> = bound_method %b.var, %ptr.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc9_3: %ptr.5d5 = addr_of %b.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc9_3(%addr.loc9_3)
// CHECK:STDOUT: %ptr.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc9_3(%addr.loc9_3)
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.bound: <bound method> = bound_method %a.var, constants.%Int.as.Destroy.impl.Op.796
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_3: <bound method> = bound_method %a.var, %Int.as.Destroy.impl.Op.specific_fn