diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index cfc2a59d16c76..80456092cb3fd 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -43,8 +43,13 @@ auto HandleTypeImplAs(Context& context, Parse::TypeImplAsId node_id) -> bool { auto [self_node, self_id] = context.node_stack().PopExprWithNodeId(); auto self_type_id = ExprAsType(context, self_node, self_id); context.node_stack().Push(node_id, self_type_id); - // TODO: `Self` should come into scope here, at least if it's not already in - // scope. Check the design for the latter case. + + // Introduce `Self`. Note that we add this name lexically rather than adding + // to the `NameScopeId` of the `impl`, because this happens before we enter + // the `impl` scope or even identify which `impl` we're declaring. + // TODO: Revisit this once #3714 is resolved. + context.AddNameToLookup(SemIR::NameId::SelfType, + context.types().GetInstId(self_type_id)); return true; } @@ -85,6 +90,8 @@ auto HandleDefaultSelfImplAs(Context& context, self_type_id = SemIR::TypeId::Error; } + // There's no need to push `Self` into scope here, because we can find it in + // the enclosing class scope. context.node_stack().Push(node_id, self_type_id); return true; } diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index bb440f166f771..c7454921cb875 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -81,7 +81,6 @@ static auto BuildInterfaceDecl(Context& context, // there was an error in the qualifier, we will have lost track of the // interface name here. We should keep track of it even if the name is // invalid. - // TODO: should have a `Self` type id member interface_decl.interface_id = context.interfaces().Add( {.name_id = name_context.name_id_for_new_inst(), .enclosing_scope_id = name_context.enclosing_scope_id_for_new_inst(), diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index ae3d06caff249..ab3a4274d669e 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -47,10 +47,9 @@ static auto CheckAssociatedFunctionImplementation( return SemIR::InstId::BuiltinError; } - // TODO: Substitute the `Self` from the `impl` into the type in the interface - // before checking. Also, this should be a semantic check rather than a - // syntactic one. The functions should be allowed to have different signatures - // as long as we can synthesize a suitable thunk. + // TODO: This should be a semantic check rather than a syntactic one. The + // functions should be allowed to have different signatures as long as we can + // synthesize a suitable thunk. if (!CheckFunctionTypeMatches(context, impl_function_decl->function_id, interface_function_id, substitutions)) { return SemIR::InstId::BuiltinError; diff --git a/toolchain/check/testdata/function/builtin/call_from_operator.carbon b/toolchain/check/testdata/function/builtin/call_from_operator.carbon index bd1eb42a35d57..ff25113ae7c9e 100644 --- a/toolchain/check/testdata/function/builtin/call_from_operator.carbon +++ b/toolchain/check/testdata/function/builtin/call_from_operator.carbon @@ -19,7 +19,7 @@ import Core; // TODO: This should be in `Core`, but currently impl lookup only looks in the // current file. impl i32 as Core.Add { - fn Op[self: i32](other: i32) -> i32 = "int.add"; + fn Op[self: Self](other: Self) -> Self = "int.add"; } var arr: [i32; 1 + 2] = (3, 4, 3 + 4); @@ -125,10 +125,13 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: // CHECK:STDOUT: impl @impl: i32 as Add { // CHECK:STDOUT: %Op: = fn_decl @Op.1 [template] { +// CHECK:STDOUT: %Self.ref.loc7_15: type = name_ref Self, i32 [template = i32] // CHECK:STDOUT: %self.loc7_9.1: i32 = param self // CHECK:STDOUT: %self.loc7_9.2: i32 = bind_name self, %self.loc7_9.1 -// CHECK:STDOUT: %other.loc7_20.1: i32 = param other -// CHECK:STDOUT: %other.loc7_20.2: i32 = bind_name other, %other.loc7_20.1 +// CHECK:STDOUT: %Self.ref.loc7_28: type = name_ref Self, i32 [template = i32] +// CHECK:STDOUT: %other.loc7_21.1: i32 = param other +// CHECK:STDOUT: %other.loc7_21.2: i32 = bind_name other, %other.loc7_21.1 +// CHECK:STDOUT: %Self.ref.loc7_37: type = name_ref Self, i32 [template = i32] // CHECK:STDOUT: %return.var: ref i32 = var // CHECK:STDOUT: } // CHECK:STDOUT: %.1: = interface_witness (%Op) [template = constants.%.2] @@ -138,7 +141,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.1[@impl.%self.loc7_9.2: i32](@impl.%other.loc7_20.2: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Op.1[@impl.%self.loc7_9.2: i32](@impl.%other.loc7_21.2: i32) -> i32 = "int.add"; // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/self_in_class.carbon b/toolchain/check/testdata/impl/self_in_class.carbon new file mode 100644 index 0000000000000..149886edc3aa7 --- /dev/null +++ b/toolchain/check/testdata/impl/self_in_class.carbon @@ -0,0 +1,84 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +interface DefaultConstructible { + fn Make() -> Self; +} + +class A { + impl i32 as DefaultConstructible { + // `Self` here refers to `i32`, not `A`. + // TODO: Revisit this once #3714 is resolved. + fn Make() -> Self { return 0; } + } +} + +// CHECK:STDOUT: --- self_in_class.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @DefaultConstructible [template] +// CHECK:STDOUT: %.2: type = assoc_entity_type @DefaultConstructible, [template] +// CHECK:STDOUT: %.3: in DefaultConstructible> = assoc_entity element0, @DefaultConstructible.%Make [template] +// CHECK:STDOUT: %A: type = class_type @A [template] +// CHECK:STDOUT: %.4: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.5: = interface_witness (@impl.%Make) [template] +// CHECK:STDOUT: %.6: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .DefaultConstructible = %DefaultConstructible.decl +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %DefaultConstructible.decl: type = interface_decl @DefaultConstructible [template = constants.%.1] {} +// CHECK:STDOUT: %A.decl: type = class_decl @A [template = constants.%A] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @DefaultConstructible { +// CHECK:STDOUT: %Self: DefaultConstructible = bind_symbolic_name Self [symbolic] +// CHECK:STDOUT: %Make: = fn_decl @Make.1 [template] { +// CHECK:STDOUT: %Self.ref: DefaultConstructible = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc8_16.1: type = facet_type_access %Self.ref [symbolic = %Self] +// CHECK:STDOUT: %.loc8_16.2: type = converted %Self.ref, %.loc8_16.1 [symbolic = %Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_20: in DefaultConstructible> = assoc_entity element0, %Make [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Make = %.loc8_20 +// CHECK:STDOUT: witness = (%Make) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: i32 as DefaultConstructible { +// CHECK:STDOUT: %Make: = fn_decl @Make.2 [template] { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, i32 [template = i32] +// CHECK:STDOUT: %return.var: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%Make) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Make = %Make +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @A { +// CHECK:STDOUT: impl_decl @impl { +// CHECK:STDOUT: %DefaultConstructible.ref: type = name_ref DefaultConstructible, file.%DefaultConstructible.decl [template = constants.%.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%A +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Make.1() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Make.2() -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc15: i32 = int_literal 0 [template = constants.%.4] +// CHECK:STDOUT: return %.loc15 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/self_in_signature.carbon b/toolchain/check/testdata/impl/self_in_signature.carbon index a87608e298b1a..3d8ea947687ab 100644 --- a/toolchain/check/testdata/impl/self_in_signature.carbon +++ b/toolchain/check/testdata/impl/self_in_signature.carbon @@ -10,11 +10,16 @@ interface UseSelf { class C {} +class D {} + impl C as UseSelf { - // TODO: Use `Self` below once it's supported. fn F[self: C](x: C) -> C { return {}; } } +impl D as UseSelf { + fn F[self: Self](x: Self) -> Self { return {}; } +} + interface SelfNested { fn F(x: (Self*, {.x: Self, .y: i32})); } @@ -23,6 +28,10 @@ impl C as SelfNested { fn F(x: (C*, {.x: C, .y: i32})); } +impl D as SelfNested { + fn F(x: (Self*, {.x: Self, .y: i32})); +} + // CHECK:STDOUT: --- self_in_signature.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -31,39 +40,56 @@ impl C as SelfNested { // CHECK:STDOUT: %.3: in UseSelf> = assoc_entity element0, @UseSelf.%F [template] // CHECK:STDOUT: %C: type = class_type @C [template] // CHECK:STDOUT: %.4: type = struct_type {} [template] +// CHECK:STDOUT: %D: type = class_type @D [template] // CHECK:STDOUT: %.5: type = tuple_type () [template] // CHECK:STDOUT: %.6: type = ptr_type {} [template] // CHECK:STDOUT: %.7: C = struct_value () [template] // CHECK:STDOUT: %.8: = interface_witness (@impl.1.%F) [template] -// CHECK:STDOUT: %.9: type = interface_type @SelfNested [template] -// CHECK:STDOUT: %.10: type = ptr_type Self [symbolic] -// CHECK:STDOUT: %.11: type = struct_type {.x: Self, .y: i32} [symbolic] -// CHECK:STDOUT: %.12: type = tuple_type (type, type) [template] -// CHECK:STDOUT: %.13: type = tuple_type (Self*, {.x: Self, .y: i32}) [symbolic] -// CHECK:STDOUT: %.14: type = assoc_entity_type @SelfNested, [template] -// CHECK:STDOUT: %.15: in SelfNested> = assoc_entity element0, @SelfNested.%F [template] -// CHECK:STDOUT: %.16: type = ptr_type C [template] -// CHECK:STDOUT: %.17: type = struct_type {.x: C, .y: i32} [template] -// CHECK:STDOUT: %.18: type = tuple_type (C*, {.x: C, .y: i32}) [template] -// CHECK:STDOUT: %.19: = interface_witness (@impl.2.%F) [template] +// CHECK:STDOUT: %.9: D = struct_value () [template] +// CHECK:STDOUT: %.10: = interface_witness (@impl.2.%F) [template] +// CHECK:STDOUT: %.11: type = interface_type @SelfNested [template] +// CHECK:STDOUT: %.12: type = ptr_type Self [symbolic] +// CHECK:STDOUT: %.13: type = struct_type {.x: Self, .y: i32} [symbolic] +// CHECK:STDOUT: %.14: type = tuple_type (type, type) [template] +// CHECK:STDOUT: %.15: type = tuple_type (Self*, {.x: Self, .y: i32}) [symbolic] +// CHECK:STDOUT: %.16: type = assoc_entity_type @SelfNested, [template] +// CHECK:STDOUT: %.17: in SelfNested> = assoc_entity element0, @SelfNested.%F [template] +// CHECK:STDOUT: %.18: type = ptr_type C [template] +// CHECK:STDOUT: %.19: type = struct_type {.x: C, .y: i32} [template] +// CHECK:STDOUT: %.20: type = tuple_type (C*, {.x: C, .y: i32}) [template] +// CHECK:STDOUT: %.21: = interface_witness (@impl.3.%F) [template] +// CHECK:STDOUT: %.22: type = ptr_type D [template] +// CHECK:STDOUT: %.23: type = struct_type {.x: D, .y: i32} [template] +// CHECK:STDOUT: %.24: type = tuple_type (D*, {.x: D, .y: i32}) [template] +// CHECK:STDOUT: %.25: = interface_witness (@impl.4.%F) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .UseSelf = %UseSelf.decl // CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .D = %D.decl // CHECK:STDOUT: .SelfNested = %SelfNested.decl // CHECK:STDOUT: } // CHECK:STDOUT: %UseSelf.decl: type = interface_decl @UseSelf [template = constants.%.1] {} // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %D.decl: type = class_decl @D [template = constants.%D] {} // CHECK:STDOUT: impl_decl @impl.1 { -// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C] -// CHECK:STDOUT: %UseSelf.ref: type = name_ref UseSelf, %UseSelf.decl [template = constants.%.1] +// CHECK:STDOUT: %C.ref.loc15: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %UseSelf.ref.loc15: type = name_ref UseSelf, %UseSelf.decl [template = constants.%.1] // CHECK:STDOUT: } -// CHECK:STDOUT: %SelfNested.decl: type = interface_decl @SelfNested [template = constants.%.9] {} // CHECK:STDOUT: impl_decl @impl.2 { -// CHECK:STDOUT: %C.ref.loc22: type = name_ref C, %C.decl [template = constants.%C] -// CHECK:STDOUT: %SelfNested.ref: type = name_ref SelfNested, %SelfNested.decl [template = constants.%.9] +// CHECK:STDOUT: %D.ref.loc19: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %UseSelf.ref.loc19: type = name_ref UseSelf, %UseSelf.decl [template = constants.%.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %SelfNested.decl: type = interface_decl @SelfNested [template = constants.%.11] {} +// CHECK:STDOUT: impl_decl @impl.3 { +// CHECK:STDOUT: %C.ref.loc27: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %SelfNested.ref.loc27: type = name_ref SelfNested, %SelfNested.decl [template = constants.%.11] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.4 { +// CHECK:STDOUT: %D.ref.loc31: type = name_ref D, %D.decl [template = constants.%D] +// CHECK:STDOUT: %SelfNested.ref.loc31: type = name_ref SelfNested, %SelfNested.decl [template = constants.%.11] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -95,37 +121,37 @@ impl C as SelfNested { // CHECK:STDOUT: // CHECK:STDOUT: interface @SelfNested { // CHECK:STDOUT: %Self: SelfNested = bind_symbolic_name Self [symbolic] -// CHECK:STDOUT: %F: = fn_decl @F.3 [template] { -// CHECK:STDOUT: %Self.ref.loc19_12: SelfNested = name_ref Self, %Self [symbolic = %Self] -// CHECK:STDOUT: %.loc19_16.1: type = facet_type_access %Self.ref.loc19_12 [symbolic = %Self] -// CHECK:STDOUT: %.loc19_12: type = converted %Self.ref.loc19_12, %.loc19_16.1 [symbolic = %Self] -// CHECK:STDOUT: %.loc19_16.2: type = ptr_type Self [symbolic = constants.%.10] -// CHECK:STDOUT: %Self.ref.loc19_24: SelfNested = name_ref Self, %Self [symbolic = %Self] -// CHECK:STDOUT: %.loc19_24.1: type = facet_type_access %Self.ref.loc19_24 [symbolic = %Self] -// CHECK:STDOUT: %.loc19_24.2: type = converted %Self.ref.loc19_24, %.loc19_24.1 [symbolic = %Self] -// CHECK:STDOUT: %.loc19_37: type = struct_type {.x: Self, .y: i32} [symbolic = constants.%.11] -// CHECK:STDOUT: %.loc19_38.1: (type, type) = tuple_literal (%.loc19_16.2, %.loc19_37) -// CHECK:STDOUT: %.loc19_38.2: type = converted %.loc19_38.1, constants.%.13 [symbolic = constants.%.13] -// CHECK:STDOUT: %x.loc19_8.1: (Self*, {.x: Self, .y: i32}) = param x -// CHECK:STDOUT: %x.loc19_8.2: (Self*, {.x: Self, .y: i32}) = bind_name x, %x.loc19_8.1 +// CHECK:STDOUT: %F: = fn_decl @F.4 [template] { +// CHECK:STDOUT: %Self.ref.loc24_12: SelfNested = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc24_16.1: type = facet_type_access %Self.ref.loc24_12 [symbolic = %Self] +// CHECK:STDOUT: %.loc24_12: type = converted %Self.ref.loc24_12, %.loc24_16.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc24_16.2: type = ptr_type Self [symbolic = constants.%.12] +// CHECK:STDOUT: %Self.ref.loc24_24: SelfNested = name_ref Self, %Self [symbolic = %Self] +// CHECK:STDOUT: %.loc24_24.1: type = facet_type_access %Self.ref.loc24_24 [symbolic = %Self] +// CHECK:STDOUT: %.loc24_24.2: type = converted %Self.ref.loc24_24, %.loc24_24.1 [symbolic = %Self] +// CHECK:STDOUT: %.loc24_37: type = struct_type {.x: Self, .y: i32} [symbolic = constants.%.13] +// CHECK:STDOUT: %.loc24_38.1: (type, type) = tuple_literal (%.loc24_16.2, %.loc24_37) +// CHECK:STDOUT: %.loc24_38.2: type = converted %.loc24_38.1, constants.%.15 [symbolic = constants.%.15] +// CHECK:STDOUT: %x.loc24_8.1: (Self*, {.x: Self, .y: i32}) = param x +// CHECK:STDOUT: %x.loc24_8.2: (Self*, {.x: Self, .y: i32}) = bind_name x, %x.loc24_8.1 // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc19_40: in SelfNested> = assoc_entity element0, %F [template = constants.%.15] +// CHECK:STDOUT: %.loc24_40: in SelfNested> = assoc_entity element0, %F [template = constants.%.17] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: .F = %.loc19_40 +// CHECK:STDOUT: .F = %.loc24_40 // CHECK:STDOUT: witness = (%F) // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: impl @impl.1: C as UseSelf { // CHECK:STDOUT: %F: = fn_decl @F.2 [template] { -// CHECK:STDOUT: %C.ref.loc15_14: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %self.loc15_8.1: C = param self -// CHECK:STDOUT: %self.loc15_8.2: C = bind_name self, %self.loc15_8.1 -// CHECK:STDOUT: %C.ref.loc15_20: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %x.loc15_17.1: C = param x -// CHECK:STDOUT: %x.loc15_17.2: C = bind_name x, %x.loc15_17.1 -// CHECK:STDOUT: %C.ref.loc15_26: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %C.ref.loc16_14: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %self.loc16_8.1: C = param self +// CHECK:STDOUT: %self.loc16_8.2: C = bind_name self, %self.loc16_8.1 +// CHECK:STDOUT: %C.ref.loc16_20: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %x.loc16_17.1: C = param x +// CHECK:STDOUT: %x.loc16_17.2: C = bind_name x, %x.loc16_17.1 +// CHECK:STDOUT: %C.ref.loc16_26: type = name_ref C, file.%C.decl [template = constants.%C] // CHECK:STDOUT: %return.var: ref C = var // CHECK:STDOUT: } // CHECK:STDOUT: %.1: = interface_witness (%F) [template = constants.%.8] @@ -135,18 +161,54 @@ impl C as SelfNested { // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl.2: C as SelfNested { -// CHECK:STDOUT: %F: = fn_decl @F.4 [template] { -// CHECK:STDOUT: %C.ref.loc23_12: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc23_13: type = ptr_type C [template = constants.%.16] -// CHECK:STDOUT: %C.ref.loc23_21: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc23_31: type = struct_type {.x: C, .y: i32} [template = constants.%.17] -// CHECK:STDOUT: %.loc23_32.1: (type, type) = tuple_literal (%.loc23_13, %.loc23_31) -// CHECK:STDOUT: %.loc23_32.2: type = converted %.loc23_32.1, constants.%.18 [template = constants.%.18] -// CHECK:STDOUT: %x.loc23_8.1: (C*, {.x: C, .y: i32}) = param x -// CHECK:STDOUT: %x.loc23_8.2: (C*, {.x: C, .y: i32}) = bind_name x, %x.loc23_8.1 +// CHECK:STDOUT: impl @impl.2: D as UseSelf { +// CHECK:STDOUT: %F: = fn_decl @F.3 [template] { +// CHECK:STDOUT: %Self.ref.loc20_14: type = name_ref Self, constants.%D [template = constants.%D] +// CHECK:STDOUT: %self.loc20_8.1: D = param self +// CHECK:STDOUT: %self.loc20_8.2: D = bind_name self, %self.loc20_8.1 +// CHECK:STDOUT: %Self.ref.loc20_23: type = name_ref Self, constants.%D [template = constants.%D] +// CHECK:STDOUT: %x.loc20_20.1: D = param x +// CHECK:STDOUT: %x.loc20_20.2: D = bind_name x, %x.loc20_20.1 +// CHECK:STDOUT: %Self.ref.loc20_32: type = name_ref Self, constants.%D [template = constants.%D] +// CHECK:STDOUT: %return.var: ref D = var // CHECK:STDOUT: } -// CHECK:STDOUT: %.1: = interface_witness (%F) [template = constants.%.19] +// CHECK:STDOUT: %.1: = interface_witness (%F) [template = constants.%.10] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.3: C as SelfNested { +// CHECK:STDOUT: %F: = fn_decl @F.5 [template] { +// CHECK:STDOUT: %C.ref.loc28_12: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc28_13: type = ptr_type C [template = constants.%.18] +// CHECK:STDOUT: %C.ref.loc28_21: type = name_ref C, file.%C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc28_31: type = struct_type {.x: C, .y: i32} [template = constants.%.19] +// CHECK:STDOUT: %.loc28_32.1: (type, type) = tuple_literal (%.loc28_13, %.loc28_31) +// CHECK:STDOUT: %.loc28_32.2: type = converted %.loc28_32.1, constants.%.20 [template = constants.%.20] +// CHECK:STDOUT: %x.loc28_8.1: (C*, {.x: C, .y: i32}) = param x +// CHECK:STDOUT: %x.loc28_8.2: (C*, {.x: C, .y: i32}) = bind_name x, %x.loc28_8.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%F) [template = constants.%.21] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: witness = %.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.4: D as SelfNested { +// CHECK:STDOUT: %F: = fn_decl @F.6 [template] { +// CHECK:STDOUT: %Self.ref.loc32_12: type = name_ref Self, constants.%D [template = constants.%D] +// CHECK:STDOUT: %.loc32_16: type = ptr_type D [template = constants.%.22] +// CHECK:STDOUT: %Self.ref.loc32_24: type = name_ref Self, constants.%D [template = constants.%D] +// CHECK:STDOUT: %.loc32_37: type = struct_type {.x: D, .y: i32} [template = constants.%.23] +// CHECK:STDOUT: %.loc32_38.1: (type, type) = tuple_literal (%.loc32_16, %.loc32_37) +// CHECK:STDOUT: %.loc32_38.2: type = converted %.loc32_38.1, constants.%.24 [template = constants.%.24] +// CHECK:STDOUT: %x.loc32_8.1: (D*, {.x: D, .y: i32}) = param x +// CHECK:STDOUT: %x.loc32_8.2: (D*, {.x: D, .y: i32}) = bind_name x, %x.loc32_8.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.1: = interface_witness (%F) [template = constants.%.25] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .F = %F @@ -158,17 +220,32 @@ impl C as SelfNested { // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: class @D { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: fn @F.1[@UseSelf.%self.loc8_8.2: Self](@UseSelf.%x.loc8_20.2: Self) -> Self; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2[@impl.1.%self.loc15_8.2: C](@impl.1.%x.loc15_17.2: C) -> @impl.1.%return.var: C { +// CHECK:STDOUT: fn @F.2[@impl.1.%self.loc16_8.2: C](@impl.1.%x.loc16_17.2: C) -> @impl.1.%return.var: C { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc15_38.1: {} = struct_literal () -// CHECK:STDOUT: %.loc15_38.2: init C = class_init (), @impl.1.%return.var [template = constants.%.7] -// CHECK:STDOUT: %.loc15_38.3: init C = converted %.loc15_38.1, %.loc15_38.2 [template = constants.%.7] -// CHECK:STDOUT: return %.loc15_38.3 +// CHECK:STDOUT: %.loc16_38.1: {} = struct_literal () +// CHECK:STDOUT: %.loc16_38.2: init C = class_init (), @impl.1.%return.var [template = constants.%.7] +// CHECK:STDOUT: %.loc16_38.3: init C = converted %.loc16_38.1, %.loc16_38.2 [template = constants.%.7] +// CHECK:STDOUT: return %.loc16_38.3 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.3(@SelfNested.%x.loc19_8.2: (Self*, {.x: Self, .y: i32})); +// CHECK:STDOUT: fn @F.3[@impl.2.%self.loc20_8.2: D](@impl.2.%x.loc20_20.2: D) -> @impl.2.%return.var: D { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc20_47.1: {} = struct_literal () +// CHECK:STDOUT: %.loc20_47.2: init D = class_init (), @impl.2.%return.var [template = constants.%.9] +// CHECK:STDOUT: %.loc20_47.3: init D = converted %.loc20_47.1, %.loc20_47.2 [template = constants.%.9] +// CHECK:STDOUT: return %.loc20_47.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.4(@SelfNested.%x.loc24_8.2: (Self*, {.x: Self, .y: i32})); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.5(@impl.3.%x.loc28_8.2: (C*, {.x: C, .y: i32})); // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.4(@impl.2.%x.loc23_8.2: (C*, {.x: C, .y: i32})); +// CHECK:STDOUT: fn @F.6(@impl.4.%x.loc32_8.2: (D*, {.x: D, .y: i32})); // CHECK:STDOUT: