Handle destruction for return statements (#5785)

This just catches uses equivalent to `return;` and `return <expr>;`.
Note it's just extending the current implicit return logic, not really
adding much unique here.

I'm still delaying break and continue because those require partial
destruction, which is more work and I want to be careful to get it
right.
This commit is contained in:
Jon Ross-Perkins
2025-07-10 16:32:39 +00:00
committed by GitHub
parent a5ddc3e3cd
commit 6a53947c5c
65 changed files with 3313 additions and 684 deletions
+49 -14
View File
@@ -24,6 +24,7 @@ fn F() -> i32 {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
@@ -46,14 +47,33 @@ fn F() -> i32 {
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.956, @Convert.2(%int_32) [concrete]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0.5c6, %Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete]
// CHECK:STDOUT: %ptr: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %pattern_type.fe8: type = pattern_type %ptr [concrete]
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
// CHECK:STDOUT: %pattern_type.fe8: type = pattern_type %ptr.235 [concrete]
// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete]
// CHECK:STDOUT: %Op.type.bae: type = fn_type @Op.2 [concrete]
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %Op.type.bc9: type = fn_type @Op.3, @impl.49c(%T) [symbolic]
// CHECK:STDOUT: %Op.46f: %Op.type.bc9 = struct_value () [symbolic]
// CHECK:STDOUT: %Destroy.impl_witness.711: <witness> = impl_witness imports.%Destroy.impl_witness_table, @impl.49c(%ptr.235) [concrete]
// CHECK:STDOUT: %Op.type.ba2: type = fn_type @Op.3, @impl.49c(%ptr.235) [concrete]
// CHECK:STDOUT: %Op.649: %Op.type.ba2 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.5d5: type = ptr_type %ptr.235 [concrete]
// CHECK:STDOUT: %Destroy.facet.2bf: %Destroy.type = facet_value %ptr.235, (%Destroy.impl_witness.711) [concrete]
// CHECK:STDOUT: %.a79: type = fn_type_with_self_type %Op.type.bae, %Destroy.facet.2bf [concrete]
// CHECK:STDOUT: %Op.specific_fn.829: <specific function> = specific_function %Op.649, @Op.3(%ptr.235) [concrete]
// CHECK:STDOUT: %Destroy.impl_witness.64e: <witness> = impl_witness imports.%Destroy.impl_witness_table, @impl.49c(%i32) [concrete]
// CHECK:STDOUT: %Op.type.a17: type = fn_type @Op.3, @impl.49c(%i32) [concrete]
// CHECK:STDOUT: %Op.e6a: %Op.type.a17 = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.facet.5f7: %Destroy.type = facet_value %i32, (%Destroy.impl_witness.64e) [concrete]
// CHECK:STDOUT: %.ab7: type = fn_type_with_self_type %Op.type.bae, %Destroy.facet.5f7 [concrete]
// CHECK:STDOUT: %Op.specific_fn.014: <specific function> = specific_function %Op.e6a, @Op.3(%i32) [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
// CHECK:STDOUT: .Destroy = %Core.Destroy
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
@@ -61,6 +81,9 @@ fn F() -> i32 {
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
// CHECK:STDOUT: %Core.import_ref.a5b: @impl.4f9.%Convert.type (%Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @impl.4f9.%Convert (constants.%Convert.f06)]
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @impl.4f9 [concrete]
// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type]
// CHECK:STDOUT: %Core.import_ref.0b9: @impl.49c.%Op.type (%Op.type.bc9) = import_ref Core//prelude/parts/destroy, loc8_29, loaded [symbolic = @impl.49c.%Op (constants.%Op.46f)]
// CHECK:STDOUT: %Destroy.impl_witness_table = impl_witness_table (%Core.import_ref.0b9), @impl.49c [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -88,10 +111,10 @@ fn F() -> i32 {
// CHECK:STDOUT: }
// CHECK:STDOUT: %n.var: ref %i32 = var %n.var_patt
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Convert.956]
// CHECK:STDOUT: %bound_method.loc16_3.1: <bound method> = bound_method %int_0, %impl.elem0 [concrete = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Convert.2(constants.%int_32) [concrete = constants.%Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc16_3.2: <bound method> = bound_method %int_0, %specific_fn [concrete = constants.%bound_method]
// CHECK:STDOUT: %impl.elem0.loc16_3.1: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Convert.956]
// CHECK:STDOUT: %bound_method.loc16_3.1: <bound method> = bound_method %int_0, %impl.elem0.loc16_3.1 [concrete = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn.loc16_3.1: <specific function> = specific_function %impl.elem0.loc16_3.1, @Convert.2(constants.%int_32) [concrete = constants.%Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc16_3.2: <bound method> = bound_method %int_0, %specific_fn.loc16_3.1 [concrete = constants.%bound_method]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %bound_method.loc16_3.2(%int_0) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc16_3: init %i32 = converted %int_0, %int.convert_checked [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign %n.var, %.loc16_3
@@ -104,20 +127,32 @@ fn F() -> i32 {
// CHECK:STDOUT: %p.patt: %pattern_type.fe8 = binding_pattern p [concrete]
// CHECK:STDOUT: %p.var_patt: %pattern_type.fe8 = var_pattern %p.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %p.var: ref %ptr = var %p.var_patt
// CHECK:STDOUT: %p.var: ref %ptr.235 = var %p.var_patt
// CHECK:STDOUT: %n.ref: ref %i32 = name_ref n, %n
// CHECK:STDOUT: %addr: %ptr = addr_of %n.ref
// CHECK:STDOUT: assign %p.var, %addr
// CHECK:STDOUT: %.loc17: type = splice_block %ptr [concrete = constants.%ptr] {
// CHECK:STDOUT: %addr.loc17_17: %ptr.235 = addr_of %n.ref
// CHECK:STDOUT: assign %p.var, %addr.loc17_17
// CHECK:STDOUT: %.loc17: type = splice_block %ptr [concrete = constants.%ptr.235] {
// CHECK:STDOUT: %int_32.loc17: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
// CHECK:STDOUT: %i32.loc17: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc17 [concrete = constants.%ptr]
// CHECK:STDOUT: %ptr: type = ptr_type %i32.loc17 [concrete = constants.%ptr.235]
// CHECK:STDOUT: }
// CHECK:STDOUT: %p: ref %ptr = bind_name p, %p.var
// CHECK:STDOUT: %p.ref: ref %ptr = name_ref p, %p
// CHECK:STDOUT: %.loc19_11: %ptr = bind_value %p.ref
// CHECK:STDOUT: %p: ref %ptr.235 = bind_name p, %p.var
// CHECK:STDOUT: %p.ref: ref %ptr.235 = name_ref p, %p
// CHECK:STDOUT: %.loc19_11: %ptr.235 = bind_value %p.ref
// CHECK:STDOUT: %.loc19_10.1: ref %i32 = deref %.loc19_11
// CHECK:STDOUT: %.loc19_10.2: %i32 = bind_value %.loc19_10.1
// CHECK:STDOUT: %impl.elem0.loc17: %.a79 = impl_witness_access constants.%Destroy.impl_witness.711, element0 [concrete = constants.%Op.649]
// CHECK:STDOUT: %bound_method.loc17_3.1: <bound method> = bound_method %p.var, %impl.elem0.loc17
// CHECK:STDOUT: %specific_fn.loc17: <specific function> = specific_function %impl.elem0.loc17, @Op.3(constants.%ptr.235) [concrete = constants.%Op.specific_fn.829]
// CHECK:STDOUT: %bound_method.loc17_3.2: <bound method> = bound_method %p.var, %specific_fn.loc17
// CHECK:STDOUT: %addr.loc17_3: %ptr.5d5 = addr_of %p.var
// CHECK:STDOUT: %no_op.loc17: init %empty_tuple.type = call %bound_method.loc17_3.2(%addr.loc17_3)
// CHECK:STDOUT: %impl.elem0.loc16_3.2: %.ab7 = impl_witness_access constants.%Destroy.impl_witness.64e, element0 [concrete = constants.%Op.e6a]
// CHECK:STDOUT: %bound_method.loc16_3.3: <bound method> = bound_method %n.var, %impl.elem0.loc16_3.2
// CHECK:STDOUT: %specific_fn.loc16_3.2: <specific function> = specific_function %impl.elem0.loc16_3.2, @Op.3(constants.%i32) [concrete = constants.%Op.specific_fn.014]
// CHECK:STDOUT: %bound_method.loc16_3.4: <bound method> = bound_method %n.var, %specific_fn.loc16_3.2
// CHECK:STDOUT: %addr.loc16: %ptr.235 = addr_of %n.var
// CHECK:STDOUT: %no_op.loc16: init %empty_tuple.type = call %bound_method.loc16_3.4(%addr.loc16)
// CHECK:STDOUT: return %.loc19_10.2
// CHECK:STDOUT: }
// CHECK:STDOUT: