Support accessing associated functions by member access into facets (#4872)

For an expression such as `(Type as Interface).AssocFn()`, track the
`Self` type `Type` in the result of the member access so that it's
available when checking the function call.

This introduces a new kind of type, `ImplFunctionType`, that represents
the type of a function that is expected within an impl, modeled as the
type of the function within the interface plus a value to use as `Self`.
Calls to values of this type behave like calls to the underlying
function except that the `Self` parameter is pre-bound to the self type
from the facet.

In order to support this, fix an issue where the imported list of
generic bindings lost their association with their enclosing generic.
This adds a little complexity to `import_ref`, including a new recursive
cycle that I intend to address in a follow-up PR.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2025-02-04 22:38:38 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent dcfccd3187
commit fcfb1345d5
234 changed files with 4213 additions and 2531 deletions
+14 -8
View File
@@ -785,10 +785,13 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %tuple.type.f94: type = tuple_type (Core.IntLiteral, Core.IntLiteral) [template]
// CHECK:STDOUT: %tuple.type.4c8: type = tuple_type (Core.IntLiteral, %i32) [template]
// CHECK:STDOUT: %TupleParam.specific_fn: <specific function> = specific_function %TupleParam, @TupleParam(Core.IntLiteral) [template]
// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [template]
// CHECK:STDOUT: %Convert.type.1b6: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.d39: <witness> = impl_witness (imports.%Core.import_ref.a5b), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.035: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.956: %Convert.type.035 = struct_value () [template]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, %impl_witness.d39 [template]
// CHECK:STDOUT: %.a0b: type = fn_type_with_self_type %Convert.type.1b6, %ImplicitAs.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2.ecc, %Convert.956 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_2.ef8: %i32 = int_value 2 [template]
@@ -854,10 +857,10 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.ecc]
// CHECK:STDOUT: %.loc7_19.1: %tuple.type.f94 = tuple_literal (%int_1, %int_2)
// CHECK:STDOUT: %TupleParam.specific_fn: <specific function> = specific_function %TupleParam.ref, @TupleParam(Core.IntLiteral) [template = constants.%TupleParam.specific_fn]
// CHECK:STDOUT: %impl.elem0: %Convert.type.1b6 = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_2) [template = constants.%int_2.ef8]
// CHECK:STDOUT: %impl.elem0: %.a0b = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_2) [template = constants.%int_2.ef8]
// CHECK:STDOUT: %.loc7_19.2: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_2.ef8]
// CHECK:STDOUT: %.loc7_19.3: %i32 = converted %int_2, %.loc7_19.2 [template = constants.%int_2.ef8]
// CHECK:STDOUT: %tuple: %tuple.type.4c8 = tuple_value (%int_1, %.loc7_19.3) [template = constants.%tuple]
@@ -900,10 +903,13 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %struct_type.a.b.cfd: type = struct_type {.a: Core.IntLiteral, .b: Core.IntLiteral} [template]
// CHECK:STDOUT: %struct_type.a.b.a13: type = struct_type {.a: Core.IntLiteral, .b: %i32} [template]
// CHECK:STDOUT: %StructParam.specific_fn: <specific function> = specific_function %StructParam, @StructParam(Core.IntLiteral) [template]
// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [template]
// CHECK:STDOUT: %Convert.type.1b6: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.d39: <witness> = impl_witness (imports.%Core.import_ref.a5b), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.035: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.956: %Convert.type.035 = struct_value () [template]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, %impl_witness.d39 [template]
// CHECK:STDOUT: %.a0b: type = fn_type_with_self_type %Convert.type.1b6, %ImplicitAs.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2.ecc, %Convert.956 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_2.ef8: %i32 = int_value 2 [template]
@@ -968,10 +974,10 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.ecc]
// CHECK:STDOUT: %.loc7_30.1: %struct_type.a.b.cfd = struct_literal (%int_1, %int_2)
// CHECK:STDOUT: %StructParam.specific_fn: <specific function> = specific_function %StructParam.ref, @StructParam(Core.IntLiteral) [template = constants.%StructParam.specific_fn]
// CHECK:STDOUT: %impl.elem0: %Convert.type.1b6 = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_2) [template = constants.%int_2.ef8]
// CHECK:STDOUT: %impl.elem0: %.a0b = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_2) [template = constants.%int_2.ef8]
// CHECK:STDOUT: %.loc7_30.2: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_2.ef8]
// CHECK:STDOUT: %.loc7_30.3: %i32 = converted %int_2, %.loc7_30.2 [template = constants.%int_2.ef8]
// CHECK:STDOUT: %struct: %struct_type.a.b.a13 = struct_value (%int_1, %.loc7_30.3) [template = constants.%struct]
@@ -122,8 +122,8 @@ fn H() {
// CHECK:STDOUT: %H: %H.type = struct_value () [template]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %F.specific_fn.04a: <specific function> = specific_function %F, @F(%C) [template]
// CHECK:STDOUT: %G.type: type = fn_type @G [template]
// CHECK:STDOUT: %G: %G.type = struct_value () [template]
@@ -134,6 +134,8 @@ fn H() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.F: %F.type = import_ref Main//library, F, loaded [template = constants.%F]
// CHECK:STDOUT: %Main.G: %G.type = import_ref Main//library, G, loaded [template = constants.%G]
// CHECK:STDOUT: %Main.import_ref.f6b058.1: type = import_ref Main//library, loc4_6, loaded [symbolic = @F.%T (constants.%T)]
// CHECK:STDOUT: %Main.import_ref.f6b058.2: type = import_ref Main//library, loc7_6, loaded [symbolic = @G.%T (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -169,7 +171,7 @@ fn H() {
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F(constants.%T: type) [from "library.carbon"] {
// CHECK:STDOUT: generic fn @F(imports.%Main.import_ref.f6b058.1: type) [from "library.carbon"] {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
// CHECK:STDOUT:
@@ -178,7 +180,7 @@ fn H() {
// CHECK:STDOUT: fn(%T.param_patt: type);
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @G(constants.%T: type) [from "library.carbon"] {
// CHECK:STDOUT: generic fn @G(imports.%Main.import_ref.f6b058.2: type) [from "library.carbon"] {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
// CHECK:STDOUT:
@@ -17,10 +17,13 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [template]
// CHECK:STDOUT: %N.51e: %i32 = bind_symbolic_name N, 0 [symbolic]
// CHECK:STDOUT: %N.patt.8e2: %i32 = symbolic_binding_pattern N, 0 [symbolic]
// CHECK:STDOUT: %ImplicitAs.type.2fd: type = facet_type <@ImplicitAs, @ImplicitAs(Core.IntLiteral)> [template]
// CHECK:STDOUT: %Convert.type.71e: type = fn_type @Convert.1, @ImplicitAs(Core.IntLiteral) [template]
// CHECK:STDOUT: %impl_witness.023: <witness> = impl_witness (imports.%Core.import_ref.85c), @impl.2(%int_32) [template]
// CHECK:STDOUT: %Convert.type.4ad: type = fn_type @Convert.3, @impl.2(%int_32) [template]
// CHECK:STDOUT: %Convert.960: %Convert.type.4ad = struct_value () [template]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.2fd = facet_value %i32, %impl_witness.023 [template]
// CHECK:STDOUT: %.10e: type = fn_type_with_self_type %Convert.type.71e, %ImplicitAs.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %N.51e, %Convert.960 [symbolic]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.3(%int_32) [symbolic]
// CHECK:STDOUT: %int.convert_checked: init Core.IntLiteral = call %Convert.specific_fn(%N.51e) [symbolic]
@@ -62,10 +65,10 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: %int_32.loc11_19: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc11_19: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %N.ref: %i32 = name_ref N, %N.loc11_6.1 [symbolic = %N.loc11_6.2 (constants.%N.51e)]
// CHECK:STDOUT: %impl.elem0: %Convert.type.71e = impl_witness_access constants.%impl_witness.023, element0 [template = constants.%Convert.960]
// CHECK:STDOUT: %Convert.bound.loc11_24.1: <bound method> = bound_method %N.ref, %impl.elem0 [symbolic = %Convert.bound.loc11_24.2 (constants.%Convert.bound)]
// CHECK:STDOUT: %Convert.specific_fn.loc11_24.1: <specific function> = specific_function %Convert.bound.loc11_24.1, @Convert.3(constants.%int_32) [symbolic = %Convert.specific_fn.loc11_24.2 (constants.%Convert.specific_fn)]
// CHECK:STDOUT: %int.convert_checked.loc11_24.1: init Core.IntLiteral = call %Convert.specific_fn.loc11_24.1(%N.ref) [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %impl.elem0: %.10e = impl_witness_access constants.%impl_witness.023, element0 [template = constants.%Convert.960]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %N.ref, %impl.elem0 [symbolic = %Convert.bound (constants.%Convert.bound)]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.3(constants.%int_32) [symbolic = %Convert.specific_fn (constants.%Convert.specific_fn)]
// CHECK:STDOUT: %int.convert_checked.loc11_24.1: init Core.IntLiteral = call %specific_fn(%N.ref) [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %.loc11_24.1: Core.IntLiteral = value_of_initializer %int.convert_checked.loc11_24.1 [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %.loc11_24.2: Core.IntLiteral = converted %N.ref, %.loc11_24.1 [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %array_type.loc11_25.1: type = array_type %.loc11_24.2, %i32 [symbolic = %array_type.loc11_25.2 (constants.%array_type)]
@@ -78,9 +81,9 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: generic fn @F(%N.loc11_6.1: %i32) {
// CHECK:STDOUT: %N.loc11_6.2: %i32 = bind_symbolic_name N, 0 [symbolic = %N.loc11_6.2 (constants.%N.51e)]
// CHECK:STDOUT: %N.patt.loc11_6.2: %i32 = symbolic_binding_pattern N, 0 [symbolic = %N.patt.loc11_6.2 (constants.%N.patt.8e2)]
// CHECK:STDOUT: %Convert.bound.loc11_24.2: <bound method> = bound_method %N.loc11_6.2, constants.%Convert.960 [symbolic = %Convert.bound.loc11_24.2 (constants.%Convert.bound)]
// CHECK:STDOUT: %Convert.specific_fn.loc11_24.2: <specific function> = specific_function %Convert.bound.loc11_24.2, @Convert.3(constants.%int_32) [symbolic = %Convert.specific_fn.loc11_24.2 (constants.%Convert.specific_fn)]
// CHECK:STDOUT: %int.convert_checked.loc11_24.2: init Core.IntLiteral = call %Convert.specific_fn.loc11_24.2(%N.loc11_6.2) [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %N.loc11_6.2, constants.%Convert.960 [symbolic = %Convert.bound (constants.%Convert.bound)]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.3(constants.%int_32) [symbolic = %Convert.specific_fn (constants.%Convert.specific_fn)]
// CHECK:STDOUT: %int.convert_checked.loc11_24.2: init Core.IntLiteral = call %Convert.specific_fn(%N.loc11_6.2) [symbolic = %int.convert_checked.loc11_24.2 (constants.%int.convert_checked)]
// CHECK:STDOUT: %array_type.loc11_25.2: type = array_type %int.convert_checked.loc11_24.2, %i32 [symbolic = %array_type.loc11_25.2 (constants.%array_type)]
// CHECK:STDOUT: %ptr.loc11_26.2: type = ptr_type @F.%array_type.loc11_25.2 (%array_type) [symbolic = %ptr.loc11_26.2 (constants.%ptr)]
// CHECK:STDOUT:
@@ -90,8 +93,8 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: specific @F(constants.%N.51e) {
// CHECK:STDOUT: %N.loc11_6.2 => constants.%N.51e
// CHECK:STDOUT: %N.patt.loc11_6.2 => constants.%N.51e
// CHECK:STDOUT: %Convert.bound.loc11_24.2 => constants.%Convert.bound
// CHECK:STDOUT: %Convert.specific_fn.loc11_24.2 => constants.%Convert.specific_fn
// CHECK:STDOUT: %Convert.bound => constants.%Convert.bound
// CHECK:STDOUT: %Convert.specific_fn => constants.%Convert.specific_fn
// CHECK:STDOUT: %int.convert_checked.loc11_24.2 => constants.%int.convert_checked
// CHECK:STDOUT: %array_type.loc11_25.2 => constants.%array_type
// CHECK:STDOUT: %ptr.loc11_26.2 => constants.%ptr
+21 -12
View File
@@ -66,10 +66,13 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [template]
// CHECK:STDOUT: %complete_type.f8a: <witness> = complete_type_witness %i32.builtin [template]
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [template]
// CHECK:STDOUT: %Convert.type.99b: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.882: <witness> = impl_witness (imports.%Core.import_ref.78a), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.4fd: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.197: %Convert.type.4fd = struct_value () [template]
// CHECK:STDOUT: %As.facet: %As.type.fd4 = facet_value Core.IntLiteral, %impl_witness.882 [template]
// CHECK:STDOUT: %.214: type = fn_type_with_self_type %Convert.type.99b, %As.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.5c6, %Convert.197 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [template]
@@ -140,10 +143,10 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.5c6]
// CHECK:STDOUT: %int_32.loc9: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc9: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.99b = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %impl.elem0: %.214 = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc9_20.1: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc9_20.2: %i32 = converted %int_0, %.loc9_20.1 [template = constants.%int_0.6a9]
// CHECK:STDOUT: %Defined.specific_fn: <specific function> = specific_function %Defined.ref, @Defined(constants.%i32) [template = constants.%Defined.specific_fn]
@@ -180,10 +183,13 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [template]
// CHECK:STDOUT: %complete_type.f8a: <witness> = complete_type_witness %i32.builtin [template]
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [template]
// CHECK:STDOUT: %Convert.type.99b: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.882: <witness> = impl_witness (imports.%Core.import_ref.78a), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.4fd: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.197: %Convert.type.4fd = struct_value () [template]
// CHECK:STDOUT: %As.facet: %As.type.fd4 = facet_value Core.IntLiteral, %impl_witness.882 [template]
// CHECK:STDOUT: %.214: type = fn_type_with_self_type %Convert.type.99b, %As.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.5c6, %Convert.197 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [template]
@@ -272,10 +278,10 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.5c6]
// CHECK:STDOUT: %int_32.loc7: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc7: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.99b = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %impl.elem0: %.214 = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc7_20.1: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc7_20.2: %i32 = converted %int_0, %.loc7_20.1 [template = constants.%int_0.6a9]
// CHECK:STDOUT: %Defined.specific_fn: <specific function> = specific_function %Defined.ref, @Defined(constants.%i32) [template = constants.%Defined.specific_fn]
@@ -310,10 +316,13 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %CallUndefined.type: type = fn_type @CallUndefined [template]
// CHECK:STDOUT: %CallUndefined: %CallUndefined.type = struct_value () [template]
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [template]
// CHECK:STDOUT: %Convert.type.99b: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.882: <witness> = impl_witness (imports.%Core.import_ref.78a), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.4fd: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.197: %Convert.type.4fd = struct_value () [template]
// CHECK:STDOUT: %As.facet: %As.type.fd4 = facet_value Core.IntLiteral, %impl_witness.882 [template]
// CHECK:STDOUT: %.214: type = fn_type_with_self_type %Convert.type.99b, %As.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.5c6, %Convert.197 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [template]
@@ -377,10 +386,10 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.5c6]
// CHECK:STDOUT: %int_32.loc14: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc14: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.99b = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %impl.elem0: %.214 = impl_witness_access constants.%impl_witness.882, element0 [template = constants.%Convert.197]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_0) [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc14_22.1: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc14_22.2: %i32 = converted %int_0, %.loc14_22.1 [template = constants.%int_0.6a9]
// CHECK:STDOUT: %Undefined.specific_fn: <specific function> = specific_function %Undefined.ref, @Undefined(constants.%i32) [template = constants.%Undefined.specific_fn]