Fix SemIR for derived-to-base conversion and lowering crash. (#7783)

We use the same conversion codepath to handle both qualification
conversions and derived-to-base conversions, because we allow both to be
performed at once. However, we were previously modeling the
qualification conversion as happening *first*, and producing a result
whose type is the target type of the overall conversion (that is, the
base class type). That led to bogus SemIR, where a `Derived` -> `const
Base` conversion would first have a "compatible" conversion from
`Derived` to `const Base`, *then* an access of the base subobject (of
type `const Base`, within an object of type `const Base`).

We now reverse the order: first we do a derived-to-base conversion,
which already has logic to preserve qualifiers, and then we do any
necessary qualification conversions on the result to reach the overall
target type.

In passing, we now skip forming the `as_compatible` instruction at all
for a pure derived-to-base conversion that has no qualification
conversion, simplifying the SemIR by one instruction in the common case.
This commit is contained in:
Richard Smith
2026-09-15 23:11:51 +00:00
committed by GitHub
parent 64ce58dd64
commit d8c4fc51cd
22 changed files with 351 additions and 315 deletions
@@ -1692,13 +1692,12 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %instance_data.ref: %NonFunctionMemberPublic.elem = name_ref instance_data, @NonFunctionMemberPublic.%field_decl [concrete = @NonFunctionMemberPublic.%field_decl]
// CHECK:STDOUT: %.loc12_36.1: %NonFunctionMemberPublic = as_compatible %d.ref
// CHECK:STDOUT: %.loc12_36.2: ref %NonFunctionMemberPublic = class_element_access %.loc12_36.1, element0
// CHECK:STDOUT: %.loc12_36.3: ref %NonFunctionMemberPublic = converted %d.ref, %.loc12_36.2
// CHECK:STDOUT: %.loc12_36.4: ref %i32 = class_element_access %.loc12_36.3, element0
// CHECK:STDOUT: %.loc12_36.5: %i32 = acquire_value %.loc12_36.4
// CHECK:STDOUT: %.loc12_36.1: ref %NonFunctionMemberPublic = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc12_36.2: ref %NonFunctionMemberPublic = converted %d.ref, %.loc12_36.1
// CHECK:STDOUT: %.loc12_36.3: ref %i32 = class_element_access %.loc12_36.2, element0
// CHECK:STDOUT: %.loc12_36.4: %i32 = acquire_value %.loc12_36.3
// CHECK:STDOUT: %i32.loc12: type = type_literal constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %instance_data: %i32 = wrapper_binding instance_data, %.loc12_36.5
// CHECK:STDOUT: %instance_data: %i32 = wrapper_binding instance_data, %.loc12_36.4
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %instance_data.patt: %pattern_type.6b6 = value_binding_pattern instance_data [concrete = constants.%instance_data.patt]
// CHECK:STDOUT: }
@@ -1760,13 +1759,12 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: %Derived = name_ref self, %self
// CHECK:STDOUT: %instance_data.ref: %NonFunctionMemberProtected.elem = name_ref instance_data, @NonFunctionMemberProtected.%field_decl [concrete = @NonFunctionMemberProtected.%field_decl]
// CHECK:STDOUT: %.loc10_41.1: %NonFunctionMemberProtected = as_compatible %self.ref
// CHECK:STDOUT: %.loc10_41.2: ref %NonFunctionMemberProtected = class_element_access %.loc10_41.1, element0
// CHECK:STDOUT: %.loc10_41.3: ref %NonFunctionMemberProtected = converted %self.ref, %.loc10_41.2
// CHECK:STDOUT: %.loc10_41.4: ref %i32 = class_element_access %.loc10_41.3, element0
// CHECK:STDOUT: %.loc10_41.5: %i32 = acquire_value %.loc10_41.4
// CHECK:STDOUT: %.loc10_41.1: ref %NonFunctionMemberProtected = class_element_access %self.ref, element0
// CHECK:STDOUT: %.loc10_41.2: ref %NonFunctionMemberProtected = converted %self.ref, %.loc10_41.1
// CHECK:STDOUT: %.loc10_41.3: ref %i32 = class_element_access %.loc10_41.2, element0
// CHECK:STDOUT: %.loc10_41.4: %i32 = acquire_value %.loc10_41.3
// CHECK:STDOUT: %i32.loc10: type = type_literal constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %instance_data: %i32 = wrapper_binding instance_data, %.loc10_41.5
// CHECK:STDOUT: %instance_data: %i32 = wrapper_binding instance_data, %.loc10_41.4
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %instance_data.patt: %pattern_type.6b6 = value_binding_pattern instance_data [concrete = constants.%instance_data.patt]
// CHECK:STDOUT: }
@@ -2598,17 +2596,15 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: %instance.ref.loc24: ref %Public = name_ref instance, %instance
// CHECK:STDOUT: %PublicInstance.ref: %Public.PublicInstance.cpp_overload_set.type = name_ref PublicInstance, imports.%Public.PublicInstance.cpp_overload_set.value [concrete = constants.%Public.PublicInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc24: <bound method> = bound_method %instance.ref.loc24, %PublicInstance.ref
// CHECK:STDOUT: %.loc24_5.1: ref %Base = as_compatible %instance.ref.loc24
// CHECK:STDOUT: %.loc24_5.2: ref %Base = class_element_access %.loc24_5.1, element0
// CHECK:STDOUT: %.loc24_5.3: ref %Base = converted %instance.ref.loc24, %.loc24_5.2
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.3)
// CHECK:STDOUT: %.loc24_5.1: ref %Base = class_element_access %instance.ref.loc24, element0
// CHECK:STDOUT: %.loc24_5.2: ref %Base = converted %instance.ref.loc24, %.loc24_5.1
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.2)
// CHECK:STDOUT: %instance.ref.loc26: ref %Public = name_ref instance, %instance
// CHECK:STDOUT: %ProtectedInstance.ref: %Public.ProtectedInstance.cpp_overload_set.type = name_ref ProtectedInstance, imports.%Public.ProtectedInstance.cpp_overload_set.value [concrete = constants.%Public.ProtectedInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc26: <bound method> = bound_method %instance.ref.loc26, %ProtectedInstance.ref
// CHECK:STDOUT: %.loc26_5.1: ref %Base = as_compatible %instance.ref.loc26
// CHECK:STDOUT: %.loc26_5.2: ref %Base = class_element_access %.loc26_5.1, element0
// CHECK:STDOUT: %.loc26_5.3: ref %Base = converted %instance.ref.loc26, %.loc26_5.2
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.3)
// CHECK:STDOUT: %.loc26_5.1: ref %Base = class_element_access %instance.ref.loc26, element0
// CHECK:STDOUT: %.loc26_5.2: ref %Base = converted %instance.ref.loc26, %.loc26_5.1
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.2)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -2624,17 +2620,15 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: %instance.ref.loc36: ref %Public = name_ref instance, %instance
// CHECK:STDOUT: %PublicInstance.ref.loc36: %Public.PublicInstance.cpp_overload_set.type = name_ref PublicInstance, imports.%Public.PublicInstance.cpp_overload_set.value [concrete = constants.%Public.PublicInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc36: <bound method> = bound_method %instance.ref.loc36, %PublicInstance.ref.loc36
// CHECK:STDOUT: %.loc36_3.1: ref %Base = as_compatible %instance.ref.loc36
// CHECK:STDOUT: %.loc36_3.2: ref %Base = class_element_access %.loc36_3.1, element0
// CHECK:STDOUT: %.loc36_3.3: ref %Base = converted %instance.ref.loc36, %.loc36_3.2
// CHECK:STDOUT: %Base.PublicInstance.call.loc36: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc36_3.3)
// CHECK:STDOUT: %.loc36_3.1: ref %Base = class_element_access %instance.ref.loc36, element0
// CHECK:STDOUT: %.loc36_3.2: ref %Base = converted %instance.ref.loc36, %.loc36_3.1
// CHECK:STDOUT: %Base.PublicInstance.call.loc36: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc36_3.2)
// CHECK:STDOUT: %instance.ref.loc37: ref %Public = name_ref instance, %instance
// CHECK:STDOUT: %PublicInstance.ref.loc37: %Public.PublicInstance.cpp_overload_set.type = name_ref PublicInstance, imports.%Public.PublicInstance.cpp_overload_set.value [concrete = constants.%Public.PublicInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc37: <bound method> = bound_method %instance.ref.loc37, %PublicInstance.ref.loc37
// CHECK:STDOUT: %.loc37_3.1: ref %Base = as_compatible %instance.ref.loc37
// CHECK:STDOUT: %.loc37_3.2: ref %Base = class_element_access %.loc37_3.1, element0
// CHECK:STDOUT: %.loc37_3.3: ref %Base = converted %instance.ref.loc37, %.loc37_3.2
// CHECK:STDOUT: %Base.PublicInstance.call.loc37: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc37_3.3)
// CHECK:STDOUT: %.loc37_3.1: ref %Base = class_element_access %instance.ref.loc37, element0
// CHECK:STDOUT: %.loc37_3.2: ref %Base = converted %instance.ref.loc37, %.loc37_3.1
// CHECK:STDOUT: %Base.PublicInstance.call.loc37: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc37_3.2)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -2753,17 +2747,15 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: %instance.ref.loc24: ref %Protected = name_ref instance, %instance
// CHECK:STDOUT: %PublicInstance.ref: %Protected.PublicInstance.cpp_overload_set.type = name_ref PublicInstance, imports.%Protected.PublicInstance.cpp_overload_set.value [concrete = constants.%Protected.PublicInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc24: <bound method> = bound_method %instance.ref.loc24, %PublicInstance.ref
// CHECK:STDOUT: %.loc24_5.1: ref %Base = as_compatible %instance.ref.loc24
// CHECK:STDOUT: %.loc24_5.2: ref %Base = class_element_access %.loc24_5.1, element0
// CHECK:STDOUT: %.loc24_5.3: ref %Base = converted %instance.ref.loc24, %.loc24_5.2
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.3)
// CHECK:STDOUT: %.loc24_5.1: ref %Base = class_element_access %instance.ref.loc24, element0
// CHECK:STDOUT: %.loc24_5.2: ref %Base = converted %instance.ref.loc24, %.loc24_5.1
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.2)
// CHECK:STDOUT: %instance.ref.loc26: ref %Protected = name_ref instance, %instance
// CHECK:STDOUT: %ProtectedInstance.ref: %Protected.ProtectedInstance.cpp_overload_set.type = name_ref ProtectedInstance, imports.%Protected.ProtectedInstance.cpp_overload_set.value [concrete = constants.%Protected.ProtectedInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc26: <bound method> = bound_method %instance.ref.loc26, %ProtectedInstance.ref
// CHECK:STDOUT: %.loc26_5.1: ref %Base = as_compatible %instance.ref.loc26
// CHECK:STDOUT: %.loc26_5.2: ref %Base = class_element_access %.loc26_5.1, element0
// CHECK:STDOUT: %.loc26_5.3: ref %Base = converted %instance.ref.loc26, %.loc26_5.2
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.3)
// CHECK:STDOUT: %.loc26_5.1: ref %Base = class_element_access %instance.ref.loc26, element0
// CHECK:STDOUT: %.loc26_5.2: ref %Base = converted %instance.ref.loc26, %.loc26_5.1
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.2)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -2855,19 +2847,17 @@ fn Call(var instance: Cpp.PublicPrivate) {
// CHECK:STDOUT: %instance.ref.loc24: ref %PublicProtected = name_ref instance, %instance
// CHECK:STDOUT: %PublicInstance.ref: %PublicProtected.PublicInstance.cpp_overload_set.type = name_ref PublicInstance, imports.%PublicProtected.PublicInstance.cpp_overload_set.value [concrete = constants.%PublicProtected.PublicInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc24: <bound method> = bound_method %instance.ref.loc24, %PublicInstance.ref
// CHECK:STDOUT: %.loc24_5.1: ref %Base = as_compatible %instance.ref.loc24
// CHECK:STDOUT: %.loc24_5.2: ref %Protected = class_element_access %.loc24_5.1, element0
// CHECK:STDOUT: %.loc24_5.3: ref %Base = class_element_access %.loc24_5.2, element0
// CHECK:STDOUT: %.loc24_5.4: ref %Base = converted %instance.ref.loc24, %.loc24_5.3
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.4)
// CHECK:STDOUT: %.loc24_5.1: ref %Protected = class_element_access %instance.ref.loc24, element0
// CHECK:STDOUT: %.loc24_5.2: ref %Base = class_element_access %.loc24_5.1, element0
// CHECK:STDOUT: %.loc24_5.3: ref %Base = converted %instance.ref.loc24, %.loc24_5.2
// CHECK:STDOUT: %Base.PublicInstance.call: init %empty_tuple.type = call imports.%Base.PublicInstance.decl(%.loc24_5.3)
// CHECK:STDOUT: %instance.ref.loc26: ref %PublicProtected = name_ref instance, %instance
// CHECK:STDOUT: %ProtectedInstance.ref: %PublicProtected.ProtectedInstance.cpp_overload_set.type = name_ref ProtectedInstance, imports.%PublicProtected.ProtectedInstance.cpp_overload_set.value [concrete = constants.%PublicProtected.ProtectedInstance.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc26: <bound method> = bound_method %instance.ref.loc26, %ProtectedInstance.ref
// CHECK:STDOUT: %.loc26_5.1: ref %Base = as_compatible %instance.ref.loc26
// CHECK:STDOUT: %.loc26_5.2: ref %Protected = class_element_access %.loc26_5.1, element0
// CHECK:STDOUT: %.loc26_5.3: ref %Base = class_element_access %.loc26_5.2, element0
// CHECK:STDOUT: %.loc26_5.4: ref %Base = converted %instance.ref.loc26, %.loc26_5.3
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.4)
// CHECK:STDOUT: %.loc26_5.1: ref %Protected = class_element_access %instance.ref.loc26, element0
// CHECK:STDOUT: %.loc26_5.2: ref %Base = class_element_access %.loc26_5.1, element0
// CHECK:STDOUT: %.loc26_5.3: ref %Base = converted %instance.ref.loc26, %.loc26_5.2
// CHECK:STDOUT: %Base.ProtectedInstance.call: init %empty_tuple.type = call imports.%Base.ProtectedInstance.decl(%.loc26_5.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
+30 -36
View File
@@ -568,11 +568,10 @@ class V {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %AcceptVal.ref: %AcceptVal.type = name_ref AcceptVal, file.%AcceptVal.decl [concrete = constants.%AcceptVal]
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %.loc16_13.1: %Base = as_compatible %d.ref
// CHECK:STDOUT: %.loc16_13.2: ref %Base = class_element_access %.loc16_13.1, element0
// CHECK:STDOUT: %.loc16_13.3: ref %Base = converted %d.ref, %.loc16_13.2
// CHECK:STDOUT: %.loc16_13.4: %Base = acquire_value %.loc16_13.3
// CHECK:STDOUT: %AcceptVal.call: init %empty_tuple.type = call %AcceptVal.ref(%.loc16_13.4)
// CHECK:STDOUT: %.loc16_13.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc16_13.2: ref %Base = converted %d.ref, %.loc16_13.1
// CHECK:STDOUT: %.loc16_13.3: %Base = acquire_value %.loc16_13.2
// CHECK:STDOUT: %AcceptVal.call: init %empty_tuple.type = call %AcceptVal.ref(%.loc16_13.3)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -663,16 +662,15 @@ class V {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %FieldDerived = name_ref d, %d
// CHECK:STDOUT: %a.ref: %FieldBase.elem = name_ref a, @FieldBase.%field_decl.1 [concrete = @FieldBase.%field_decl.1]
// CHECK:STDOUT: %.loc8_11.1: %FieldBase = as_compatible %d.ref
// CHECK:STDOUT: %.loc8_11.2: ref %FieldBase = class_element_access %.loc8_11.1, element0
// CHECK:STDOUT: %.loc8_11.3: ref %FieldBase = converted %d.ref, %.loc8_11.2
// CHECK:STDOUT: %.loc8_11.4: ref %i32 = class_element_access %.loc8_11.3, element0
// CHECK:STDOUT: %.loc8_11.5: %i32 = acquire_value %.loc8_11.4
// CHECK:STDOUT: %.loc8_11.1: ref %FieldBase = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc8_11.2: ref %FieldBase = converted %d.ref, %.loc8_11.1
// CHECK:STDOUT: %.loc8_11.3: ref %i32 = class_element_access %.loc8_11.2, element0
// CHECK:STDOUT: %.loc8_11.4: %i32 = acquire_value %.loc8_11.3
// CHECK:STDOUT: %impl.elem0: %.737 = impl_witness_access constants.%Copy.impl_witness.b51, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6]
// CHECK:STDOUT: %bound_method.loc8_11.1: <bound method> = bound_method %.loc8_11.5, %impl.elem0
// CHECK:STDOUT: %bound_method.loc8_11.1: <bound method> = bound_method %.loc8_11.4, %impl.elem0
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
// CHECK:STDOUT: %bound_method.loc8_11.2: <bound method> = bound_method %.loc8_11.5, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc8_11.2(%.loc8_11.5)
// CHECK:STDOUT: %bound_method.loc8_11.2: <bound method> = bound_method %.loc8_11.4, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc8_11.2(%.loc8_11.4)
// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -682,16 +680,15 @@ class V {
// CHECK:STDOUT: %Cpp.ref.loc14: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %FieldBase.ref: type = name_ref FieldBase, imports.%FieldBase.decl [concrete = constants.%FieldBase]
// CHECK:STDOUT: %b.ref: %FieldBase.elem = name_ref b, @FieldBase.%field_decl.2 [concrete = @FieldBase.%field_decl.2]
// CHECK:STDOUT: %.loc14_11.1: %FieldBase = as_compatible %d.ref
// CHECK:STDOUT: %.loc14_11.2: ref %FieldBase = class_element_access %.loc14_11.1, element0
// CHECK:STDOUT: %.loc14_11.3: ref %FieldBase = converted %d.ref, %.loc14_11.2
// CHECK:STDOUT: %.loc14_11.4: ref %i32 = class_element_access %.loc14_11.3, element1
// CHECK:STDOUT: %.loc14_11.5: %i32 = acquire_value %.loc14_11.4
// CHECK:STDOUT: %.loc14_11.1: ref %FieldBase = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc14_11.2: ref %FieldBase = converted %d.ref, %.loc14_11.1
// CHECK:STDOUT: %.loc14_11.3: ref %i32 = class_element_access %.loc14_11.2, element1
// CHECK:STDOUT: %.loc14_11.4: %i32 = acquire_value %.loc14_11.3
// CHECK:STDOUT: %impl.elem0: %.737 = impl_witness_access constants.%Copy.impl_witness.b51, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6]
// CHECK:STDOUT: %bound_method.loc14_11.1: <bound method> = bound_method %.loc14_11.5, %impl.elem0
// CHECK:STDOUT: %bound_method.loc14_11.1: <bound method> = bound_method %.loc14_11.4, %impl.elem0
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
// CHECK:STDOUT: %bound_method.loc14_11.2: <bound method> = bound_method %.loc14_11.5, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc14_11.2(%.loc14_11.5)
// CHECK:STDOUT: %bound_method.loc14_11.2: <bound method> = bound_method %.loc14_11.4, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc14_11.2(%.loc14_11.4)
// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -738,11 +735,10 @@ class V {
// CHECK:STDOUT: %d.ref: %MethodDerived = name_ref d, %d
// CHECK:STDOUT: %f.ref: %MethodDerived.f.cpp_overload_set.type = name_ref f, imports.%MethodDerived.f.cpp_overload_set.value [concrete = constants.%MethodDerived.f.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %d.ref, %f.ref
// CHECK:STDOUT: %.loc8_3.1: %MethodBase = as_compatible %d.ref
// CHECK:STDOUT: %.loc8_3.2: ref %MethodBase = class_element_access %.loc8_3.1, element0
// CHECK:STDOUT: %.loc8_3.3: ref %MethodBase = converted %d.ref, %.loc8_3.2
// CHECK:STDOUT: %.loc8_3.4: %MethodBase = acquire_value %.loc8_3.3
// CHECK:STDOUT: %f__carbon_thunk.call: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc8_3.4)
// CHECK:STDOUT: %.loc8_3.1: ref %MethodBase = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc8_3.2: ref %MethodBase = converted %d.ref, %.loc8_3.1
// CHECK:STDOUT: %.loc8_3.3: %MethodBase = acquire_value %.loc8_3.2
// CHECK:STDOUT: %f__carbon_thunk.call: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc8_3.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -753,11 +749,10 @@ class V {
// CHECK:STDOUT: %MethodBase.ref: type = name_ref MethodBase, imports.%MethodBase.decl [concrete = constants.%MethodBase]
// CHECK:STDOUT: %g.ref: %MethodBase.g.cpp_overload_set.type = name_ref g, imports.%MethodBase.g.cpp_overload_set.value [concrete = constants.%MethodBase.g.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %d.ref, %g.ref
// CHECK:STDOUT: %.loc14_3.1: %MethodBase = as_compatible %d.ref
// CHECK:STDOUT: %.loc14_3.2: ref %MethodBase = class_element_access %.loc14_3.1, element0
// CHECK:STDOUT: %.loc14_3.3: ref %MethodBase = converted %d.ref, %.loc14_3.2
// CHECK:STDOUT: %.loc14_3.4: %MethodBase = acquire_value %.loc14_3.3
// CHECK:STDOUT: %g__carbon_thunk.call: init %empty_tuple.type = call imports.%g__carbon_thunk.decl(%.loc14_3.4)
// CHECK:STDOUT: %.loc14_3.1: ref %MethodBase = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc14_3.2: ref %MethodBase = converted %d.ref, %.loc14_3.1
// CHECK:STDOUT: %.loc14_3.3: %MethodBase = acquire_value %.loc14_3.2
// CHECK:STDOUT: %g__carbon_thunk.call: init %empty_tuple.type = call imports.%g__carbon_thunk.decl(%.loc14_3.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -768,11 +763,10 @@ class V {
// CHECK:STDOUT: %MethodDerived.ref.loc23: type = name_ref MethodDerived, imports.%MethodDerived.decl [concrete = constants.%MethodDerived]
// CHECK:STDOUT: %f.ref.loc23: %MethodDerived.f.cpp_overload_set.type = name_ref f, imports.%MethodDerived.f.cpp_overload_set.value [concrete = constants.%MethodDerived.f.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc23: <bound method> = bound_method %d.ref, %f.ref.loc23
// CHECK:STDOUT: %.loc23_3.1: %MethodBase = as_compatible %d.ref
// CHECK:STDOUT: %.loc23_3.2: ref %MethodBase = class_element_access %.loc23_3.1, element0
// CHECK:STDOUT: %.loc23_3.3: ref %MethodBase = converted %d.ref, %.loc23_3.2
// CHECK:STDOUT: %.loc23_3.4: %MethodBase = acquire_value %.loc23_3.3
// CHECK:STDOUT: %f__carbon_thunk.call.loc23: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc23_3.4)
// CHECK:STDOUT: %.loc23_3.1: ref %MethodBase = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc23_3.2: ref %MethodBase = converted %d.ref, %.loc23_3.1
// CHECK:STDOUT: %.loc23_3.3: %MethodBase = acquire_value %.loc23_3.2
// CHECK:STDOUT: %f__carbon_thunk.call.loc23: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc23_3.3)
// CHECK:STDOUT: %b.ref: %MethodBase = name_ref b, %b
// CHECK:STDOUT: %Cpp.ref.loc24: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %MethodDerived.ref.loc24: type = name_ref MethodDerived, imports.%MethodDerived.decl [concrete = constants.%MethodDerived]