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
+78 -45
View File
@@ -524,8 +524,10 @@ fn F() {
// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete]
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.610: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.22a: %T.as.Destroy.impl.Op.type.610 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.981: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.4aa: %AggregateT.as_type.as.Destroy.impl.Op.type.981 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -558,11 +560,13 @@ fn F() {
// CHECK:STDOUT: %.loc8_14.3: ref %U = value_as_ref %.loc8_14.2
// CHECK:STDOUT: %addr.loc8_22: %ptr.86f = addr_of %.loc8_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.22a
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc8_12.5: %type_where = converted constants.%U, %facet_value [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.4aa
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_12: %ptr.86f = addr_of %.loc8_12.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -639,8 +643,10 @@ fn F() {
// CHECK:STDOUT: %ptr.87e: type = ptr_type %U [concrete]
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.8a5: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.831: %T.as.Destroy.impl.Op.type.8a5 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.f0f: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.2bd: %AggregateT.as_type.as.Destroy.impl.Op.type.f0f = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -683,22 +689,26 @@ fn F() {
// CHECK:STDOUT: %x.var_patt: %pattern_type.eb9 = var_pattern %x.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref %U = var %x.var_patt
// CHECK:STDOUT: %.loc10: type = splice_block %U.ref.loc10 [concrete = constants.%U] {
// CHECK:STDOUT: %.loc10_15: type = splice_block %U.ref.loc10 [concrete = constants.%U] {
// CHECK:STDOUT: %Cpp.ref.loc10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N.ref.loc10: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %U.ref.loc10: type = name_ref U, imports.%U.decl [concrete = constants.%U]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %U = bind_name x, %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc10: <bound method> = bound_method %x.var, constants.%T.as.Destroy.impl.Op.831
// CHECK:STDOUT: %facet_value.loc10: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc10_3: %type_where = converted constants.%U, %facet_value.loc10 [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound.loc10: <bound method> = bound_method %x.var, constants.%AggregateT.as_type.as.Destroy.impl.Op.2bd
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc10: <bound method> = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %bound_method.loc10: <bound method> = bound_method %x.var, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc10: %ptr.87e = addr_of %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.831
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10)
// CHECK:STDOUT: %facet_value.loc8: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc8_12.5: %type_where = converted constants.%U, %facet_value.loc8 [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.2bd
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_12: %ptr.87e = addr_of %.loc8_12.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -714,8 +724,10 @@ fn F() {
// CHECK:STDOUT: %ptr.8c1: type = ptr_type %U [concrete]
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.081: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.b68: %T.as.Destroy.impl.Op.type.081 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.da5: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.941: %AggregateT.as_type.as.Destroy.impl.Op.type.da5 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -759,11 +771,13 @@ fn F() {
// CHECK:STDOUT: %.loc8_17.3: ref %U = value_as_ref %.loc8_17.2
// CHECK:STDOUT: %addr.loc8_31: %ptr.8c1 = addr_of %.loc8_17.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_15.4, constants.%T.as.Destroy.impl.Op.b68
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc8_15.5: %type_where = converted constants.%U, %facet_value [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_15.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.941
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_15.4, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_15.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_15: %ptr.8c1 = addr_of %.loc8_15.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_15)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_15)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -781,11 +795,14 @@ fn F() {
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.9f7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%O) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.273: %T.as.Destroy.impl.Op.type.9f7 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value.568: %type_where = facet_value %O, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.a17: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value.568) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.c17: %AggregateT.as_type.as.Destroy.impl.Op.type.a17 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.3f8: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.6fd: %T.as.Destroy.impl.Op.type.3f8 = struct_value () [concrete]
// CHECK:STDOUT: %facet_value.f72: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.b0e: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value.f72) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bcd: %AggregateT.as_type.as.Destroy.impl.Op.type.b0e = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -825,21 +842,25 @@ fn F() {
// CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref %O = var %x.var_patt
// CHECK:STDOUT: %.loc9: type = splice_block %O.ref.loc9 [concrete = constants.%O] {
// CHECK:STDOUT: %.loc9_13: type = splice_block %O.ref.loc9 [concrete = constants.%O] {
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %O.ref.loc9: type = name_ref O, imports.%O.decl [concrete = constants.%O]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %O = bind_name x, %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9: <bound method> = bound_method %x.var, constants.%T.as.Destroy.impl.Op.273
// CHECK:STDOUT: %facet_value.loc9: %type_where = facet_value constants.%O, () [concrete = constants.%facet_value.568]
// CHECK:STDOUT: %.loc9_3: %type_where = converted constants.%O, %facet_value.loc9 [concrete = constants.%facet_value.568]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound.loc9: <bound method> = bound_method %x.var, constants.%AggregateT.as_type.as.Destroy.impl.Op.c17
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc9: <bound method> = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %bound_method.loc9: <bound method> = bound_method %x.var, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.6fd
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9)
// CHECK:STDOUT: %facet_value.loc8: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value.f72]
// CHECK:STDOUT: %.loc8_12.5: %type_where = converted constants.%U, %facet_value.loc8 [concrete = constants.%facet_value.f72]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.bcd
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_12: %ptr.a6c = addr_of %.loc8_12.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -859,8 +880,10 @@ fn F() {
// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete]
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.610: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.22a: %T.as.Destroy.impl.Op.type.610 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.981: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.4aa: %AggregateT.as_type.as.Destroy.impl.Op.type.981 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -899,11 +922,13 @@ fn F() {
// CHECK:STDOUT: %.loc9_14.3: ref %U = value_as_ref %.loc9_14.2
// CHECK:STDOUT: %addr.loc9_22: %ptr.86f = addr_of %.loc9_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc9_12.4, constants.%T.as.Destroy.impl.Op.22a
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc9_12.5: %type_where = converted constants.%U, %facet_value [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc9_12.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.4aa
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc9_12.4, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc9_12.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc9_12: %ptr.86f = addr_of %.loc9_12.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc9_12)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc9_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -923,8 +948,10 @@ fn F() {
// CHECK:STDOUT: %empty_struct.e6c: %.372 = struct_value () [concrete]
// CHECK:STDOUT: %U.bar.type: type = fn_type @U.bar [concrete]
// CHECK:STDOUT: %U.bar: %U.bar.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.610: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.22a: %T.as.Destroy.impl.Op.type.610 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.981: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.4aa: %AggregateT.as_type.as.Destroy.impl.Op.type.981 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -963,11 +990,13 @@ fn F() {
// CHECK:STDOUT: %U.ref.loc9: type = name_ref U, imports.%U.decl [concrete = constants.%U]
// CHECK:STDOUT: %bar.ref: %.372 = name_ref bar, imports.%.a8c [concrete = constants.%empty_struct.e6c]
// CHECK:STDOUT: %U.bar.call: init %empty_tuple.type = call imports.%U.bar.decl()
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.22a
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc8_12.5: %type_where = converted constants.%U, %facet_value [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%AggregateT.as_type.as.Destroy.impl.Op.4aa
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_12: %ptr.86f = addr_of %.loc8_12.4
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -1053,8 +1082,10 @@ fn F() {
// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete]
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.610: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.22a: %T.as.Destroy.impl.Op.type.610 = struct_value () [concrete]
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanAggregateDestroy>> [concrete]
// CHECK:STDOUT: %facet_value: %type_where = facet_value %U, () [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.type.981: type = fn_type @AggregateT.as_type.as.Destroy.impl.Op, @AggregateT.as_type.as.Destroy.impl(%facet_value) [concrete]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.4aa: %AggregateT.as_type.as.Destroy.impl.Op.type.981 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -1079,11 +1110,13 @@ fn F() {
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_11.1)
// CHECK:STDOUT: %.loc8_11.2: init %U = in_place_init %foo__carbon_thunk.call, %.loc8_11.1
// CHECK:STDOUT: %.loc8_11.3: ref %U = temporary %.loc8_11.1, %.loc8_11.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_11.3, constants.%T.as.Destroy.impl.Op.22a
// CHECK:STDOUT: %facet_value: %type_where = facet_value constants.%U, () [concrete = constants.%facet_value]
// CHECK:STDOUT: %.loc8_11.4: %type_where = converted constants.%U, %facet_value [concrete = constants.%facet_value]
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_11.3, constants.%AggregateT.as_type.as.Destroy.impl.Op.4aa
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_11.3, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_11.3, %AggregateT.as_type.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_11.2: %ptr.86f = addr_of %.loc8_11.3
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_11.2)
// CHECK:STDOUT: %AggregateT.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_11.2)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: