mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 15:41:04 +01:00
Add builtin functions for destroy, with special requirements in facet types (#6035)
This is in support of a goal of changing the blanket `destroy` impl to
use (roughly):
```
private fn CanAggregateDestroy() -> type = "type.can_aggregate_destroy";
// Handles aggregate type destruction.
impl forall [AggregateDestroyT:! CanAggregateDestroy()] AggregateDestroyT as Destroy {
fn Op[addr self: Self*]() = "type.aggregate_destroy";
}
```
That isn't done here because there's still other issues that migrating
raises. What this *does* do is add the builtin functions, and in
particular, support to `FacetTypeInfo` to make `CanAggregateDestroy`
work.
The "special requirement" approach in `FacetTypeInfo` allows us to
support restricting a blanket impl under the current approach of impls.
Maybe we'll find a cleaner approach that can work in the future, but
this fits into the current model by propagating similar to other
requirements. I'm using an enum mask because we have a number of similar
things to add (e.g. copy, move) but I'm not sure we need a full vector.
A few alternatives considered were:
- Supporting syntax more like `where .Self impls
TypeCanAggregateDestroy(.Self, SupportedInterface,
UnsupportedInterface)`. I think it'd be a little cleaner, but requires
better compile-time evaluation in order to assess the type of the call.
Right now it's expected to be a `FacetType` too early to make this work,
and I was concerned about pouring too much more time down this route.
- Providing an actual interface, in particular doing name lookup back
into `Core.` for an interface. This would've added name lookup overhead,
and the question of whether an `impl` exists.
- Generating an interface. This avoids the name lookup, but would still
raise the question of whether an `impl` should also be generated. Work
I've previously done generating interfaces for class destruction also
feels complex to both write and understand (an unfortunate issue).
- Still modeling as an `ImplsConstraint`, for example by defining a
special `InterfaceId::CanAggregateDestroy = -2` similar to what we do on
other ids. I was hesitant because of how this expands the number of
modes of `InterfaceId`, and things for consuming code to watch out for,
for what feels like a relatively niche set of use-cases that are only
interface-like.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
This commit is contained in:
co-authored by
Dana Jansens
parent
3ec0bcb4fd
commit
5e3bb523f8
+28
-28
@@ -536,8 +536,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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.140: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4e: %T.as.Destroy.impl.Op.type.140 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.37e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a28: %T.as.Destroy.impl.Op.type.37e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -570,7 +570,7 @@ fn F() {
|
||||
// CHECK:STDOUT: %.loc8_14.3: ref %C = value_as_ref %.loc8_14.2
|
||||
// CHECK:STDOUT: %addr.loc8_22: %ptr.d9e = 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.d4e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.a28
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc8_12: %ptr.d9e = addr_of %.loc8_12.4
|
||||
@@ -589,8 +589,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %C.val: %C = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.140: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4e: %T.as.Destroy.impl.Op.type.140 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.37e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a28: %T.as.Destroy.impl.Op.type.37e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -622,7 +622,7 @@ fn F() {
|
||||
// CHECK:STDOUT: %.loc24_14.1: ref %C = converted %.loc24_12.1, %.loc24_12.4
|
||||
// CHECK:STDOUT: %.loc24_14.2: %C = bind_value %.loc24_14.1
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call imports.%foo.decl(%.loc24_14.2)
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc24_12.4, constants.%T.as.Destroy.impl.Op.d4e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc24_12.4, constants.%T.as.Destroy.impl.Op.a28
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc24_12.4, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc24_12.4
|
||||
@@ -725,8 +725,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %ptr.838: type = ptr_type %C [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.054: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.2bd: %T.as.Destroy.impl.Op.type.054 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.679: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.b3e: %T.as.Destroy.impl.Op.type.679 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -775,12 +775,12 @@ fn F() {
|
||||
// CHECK:STDOUT: %C.ref.loc10: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %x: ref %C = 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.2bd
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc10: <bound method> = bound_method %x.var, constants.%T.as.Destroy.impl.Op.b3e
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc10: <bound method> = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1
|
||||
// CHECK:STDOUT: %addr.loc10: %ptr.838 = 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.2bd
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.b3e
|
||||
// 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: %addr.loc8_12: %ptr.838 = addr_of %.loc8_12.4
|
||||
@@ -800,8 +800,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %ptr.c0c: type = ptr_type %C [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.357: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.21e: %T.as.Destroy.impl.Op.type.357 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.6f2: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.c3d: %T.as.Destroy.impl.Op.type.6f2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -845,7 +845,7 @@ fn F() {
|
||||
// CHECK:STDOUT: %.loc8_17.3: ref %C = value_as_ref %.loc8_17.2
|
||||
// CHECK:STDOUT: %addr.loc8_31: %ptr.c0c = 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.21e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_15.4, constants.%T.as.Destroy.impl.Op.c3d
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_15.4, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc8_15: %ptr.c0c = addr_of %.loc8_15.4
|
||||
@@ -867,11 +867,11 @@ 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.a33: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%O) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.b71: %T.as.Destroy.impl.Op.type.a33 = struct_value () [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: %ptr.820: type = ptr_type %O [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.637: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.8d0: %T.as.Destroy.impl.Op.type.637 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.29b: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.49f: %T.as.Destroy.impl.Op.type.29b = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -916,12 +916,12 @@ fn F() {
|
||||
// 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.b71
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9: <bound method> = bound_method %x.var, constants.%T.as.Destroy.impl.Op.273
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method.loc9: <bound method> = bound_method %x.var, %T.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.8d0
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.49f
|
||||
// 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: %addr.loc8_12: %ptr.de2 = addr_of %.loc8_12.4
|
||||
@@ -945,8 +945,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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.140: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4e: %T.as.Destroy.impl.Op.type.140 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.37e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a28: %T.as.Destroy.impl.Op.type.37e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -985,7 +985,7 @@ fn F() {
|
||||
// CHECK:STDOUT: %.loc9_14.3: ref %C = value_as_ref %.loc9_14.2
|
||||
// CHECK:STDOUT: %addr.loc9_22: %ptr.d9e = 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.d4e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc9_12.4, constants.%T.as.Destroy.impl.Op.a28
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc9_12.4, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc9_12: %ptr.d9e = addr_of %.loc9_12.4
|
||||
@@ -1009,8 +1009,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %empty_struct.87a: %.442 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %C.bar.type: type = fn_type @C.bar [concrete]
|
||||
// CHECK:STDOUT: %C.bar: %C.bar.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.140: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4e: %T.as.Destroy.impl.Op.type.140 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.37e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a28: %T.as.Destroy.impl.Op.type.37e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -1049,7 +1049,7 @@ fn F() {
|
||||
// CHECK:STDOUT: %C.ref.loc9: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %bar.ref: %.442 = name_ref bar, imports.%.4a4 [concrete = constants.%empty_struct.87a]
|
||||
// CHECK:STDOUT: %C.bar.call: init %empty_tuple.type = call imports.%C.bar.decl()
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.d4e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.4, constants.%T.as.Destroy.impl.Op.a28
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.4, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc8_12: %ptr.d9e = addr_of %.loc8_12.4
|
||||
@@ -1139,8 +1139,8 @@ fn F() {
|
||||
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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.140: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4e: %T.as.Destroy.impl.Op.type.140 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.37e: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.a28: %T.as.Destroy.impl.Op.type.37e = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
@@ -1165,7 +1165,7 @@ 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 %C = in_place_init %foo__carbon_thunk.call, %.loc8_11.1
|
||||
// CHECK:STDOUT: %.loc8_11.3: ref %C = 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.d4e
|
||||
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_11.3, constants.%T.as.Destroy.impl.Op.a28
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_11.3, %T.as.Destroy.impl.Op.specific_fn
|
||||
// CHECK:STDOUT: %addr.loc8_11.2: %ptr.d9e = addr_of %.loc8_11.3
|
||||
|
||||
Reference in New Issue
Block a user