Quellcode durchsuchen

Generate thunks for functions in `impl`s (#5390)

Generate a thunk when a function in an `impl` has a different signature
than the function in the interface. This follows the design in
[#3763](https://docs.carbon-lang.dev/proposals/p3763.html#impl-members-vs-interface-members),
although some of the checks described there are not yet implemented.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Richard Smith vor 1 Jahr
Ursprung
Commit
95903dc624

+ 7 - 17
toolchain/check/BUILD

@@ -44,10 +44,12 @@ cc_library(
         "name_component.cpp",
         "name_lookup.cpp",
         "operator.cpp",
+        "pattern.cpp",
         "pattern_match.cpp",
+        "pointer_dereference.cpp",
         "return.cpp",
-        "subpattern.cpp",
         "subst.cpp",
+        "thunk.cpp",
         "type.cpp",
         "type_completion.cpp",
         "type_structure.cpp",
@@ -86,12 +88,14 @@ cc_library(
         "name_lookup.h",
         "operator.h",
         "param_and_arg_refs_stack.h",
+        "pattern.h",
         "pattern_match.h",
         "pending_block.h",
+        "pointer_dereference.h",
         "region_stack.h",
         "return.h",
-        "subpattern.h",
         "subst.h",
+        "thunk.h",
         "type.h",
         "type_completion.h",
         "type_structure.h",
@@ -100,6 +104,7 @@ cc_library(
         ":node_stack",
         "//common:array_stack",
         "//common:check",
+        "//common:find",
         "//common:map",
         "//common:ostream",
         "//common:raw_string_ostream",
@@ -167,7 +172,6 @@ cc_library(
         ":context",
         ":diagnostic_emitter",
         ":dump",
-        ":pointer_dereference",
         "//common:check",
         "//common:error",
         "//common:find",
@@ -238,20 +242,6 @@ cc_library(
     ],
 )
 
-cc_library(
-    name = "pointer_dereference",
-    srcs = ["pointer_dereference.cpp"],
-    hdrs = ["pointer_dereference.h"],
-    deps = [
-        ":context",
-        "//common:check",
-        "//toolchain/parse:node_kind",
-        "//toolchain/sem_ir:file",
-        "//toolchain/sem_ir:typed_insts",
-        "@llvm-project//llvm:Support",
-    ],
-)
-
 cc_library(
     name = "scope_stack",
     srcs = ["scope_stack.cpp"],

+ 71 - 16
toolchain/check/function.cpp

@@ -4,29 +4,29 @@
 
 #include "toolchain/check/function.h"
 
+#include "common/find.h"
 #include "toolchain/check/merge.h"
 #include "toolchain/check/type_completion.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/pattern.h"
 
 namespace Carbon::Check {
 
-auto CheckFunctionTypeMatches(Context& context,
-                              const SemIR::Function& new_function,
-                              const SemIR::Function& prev_function,
-                              SemIR::SpecificId prev_specific_id,
-                              bool check_syntax, bool check_self) -> bool {
-  // TODO: When check_syntax is false, the functions should be allowed to have
-  // different signatures as long as we can synthesize a suitable thunk. i.e.,
-  // when there's an implicit conversion from the original parameter types to
-  // the overriding parameter types, and from the overriding return type to the
-  // original return type.
-  // Also, build that thunk.
-  if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
-                              DeclParams(prev_function), prev_specific_id,
-                              /*diagnose=*/true, check_syntax, check_self)) {
-    return false;
-  }
+auto FindSelfPattern(Context& context,
+                     SemIR::InstBlockId implicit_param_patterns_id)
+    -> SemIR::InstId {
+  auto implicit_param_patterns =
+      context.inst_blocks().GetOrEmpty(implicit_param_patterns_id);
+  return FindIfOrNone(implicit_param_patterns, [&](auto implicit_param_id) {
+    return SemIR::IsSelfPattern(context.sem_ir(), implicit_param_id);
+  });
+}
 
+auto CheckFunctionReturnTypeMatches(Context& context,
+                                    const SemIR::Function& new_function,
+                                    const SemIR::Function& prev_function,
+                                    SemIR::SpecificId prev_specific_id,
+                                    bool diagnose) -> bool {
   // TODO: Pass a specific ID for `prev_function` instead of substitutions and
   // use it here.
   auto new_return_type_id =
@@ -39,6 +39,10 @@ auto CheckFunctionTypeMatches(Context& context,
   }
   if (!context.types().AreEqualAcrossDeclarations(new_return_type_id,
                                                   prev_return_type_id)) {
+    if (!diagnose) {
+      return false;
+    }
+
     CARBON_DIAGNOSTIC(
         FunctionRedeclReturnTypeDiffers, Error,
         "function redeclaration differs because return type is {0}",
@@ -72,6 +76,21 @@ auto CheckFunctionTypeMatches(Context& context,
   return true;
 }
 
+auto CheckFunctionTypeMatches(Context& context,
+                              const SemIR::Function& new_function,
+                              const SemIR::Function& prev_function,
+                              SemIR::SpecificId prev_specific_id,
+                              bool check_syntax, bool check_self, bool diagnose)
+    -> bool {
+  if (!CheckRedeclParamsMatch(context, DeclParams(new_function),
+                              DeclParams(prev_function), prev_specific_id,
+                              diagnose, check_syntax, check_self)) {
+    return false;
+  }
+  return CheckFunctionReturnTypeMatches(context, new_function, prev_function,
+                                        prev_specific_id, diagnose);
+}
+
 auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
                              const SemIR::Function& function,
                              SemIR::SpecificId specific_id)
@@ -108,4 +127,40 @@ auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
   return return_info;
 }
 
+auto CheckFunctionDefinitionSignature(Context& context,
+                                      SemIR::FunctionId function_id) -> void {
+  auto& function = context.functions().Get(function_id);
+
+  auto params_to_complete =
+      context.inst_blocks().GetOrEmpty(function.call_params_id);
+
+  // Check the return type is complete.
+  if (function.return_slot_pattern_id.has_value()) {
+    CheckFunctionReturnType(context,
+                            SemIR::LocId(function.return_slot_pattern_id),
+                            function, SemIR::SpecificId::None);
+    // Don't re-check the return type below.
+    params_to_complete = params_to_complete.drop_back();
+  }
+
+  // Check the parameter types are complete.
+  for (auto param_ref_id : params_to_complete) {
+    if (param_ref_id == SemIR::ErrorInst::InstId) {
+      continue;
+    }
+
+    // The parameter types need to be complete.
+    RequireCompleteType(
+        context, context.insts().GetAs<SemIR::AnyParam>(param_ref_id).type_id,
+        SemIR::LocId(param_ref_id), [&] {
+          CARBON_DIAGNOSTIC(
+              IncompleteTypeInFunctionParam, Error,
+              "parameter has incomplete type {0} in function definition",
+              TypeOfInstId);
+          return context.emitter().Build(
+              param_ref_id, IncompleteTypeInFunctionParam, param_ref_id);
+        });
+  }
+}
+
 }  // namespace Carbon::Check

+ 24 - 1
toolchain/check/function.h

@@ -26,6 +26,22 @@ struct SuspendedFunction {
   DeclNameStack::SuspendedName saved_name_state;
 };
 
+// Returns the ID of the self parameter pattern, or None.
+// TODO: Do this during initial traversal of implicit params.
+auto FindSelfPattern(Context& context,
+                     SemIR::InstBlockId implicit_param_patterns_id)
+    -> SemIR::InstId;
+
+// Checks that `new_function` has the same return type as `prev_function`, or if
+// `prev_function_id` is specified, a specific version of `prev_function`.
+// Prints a suitable diagnostic and returns false if not. Never checks for a
+// syntactic match.
+auto CheckFunctionReturnTypeMatches(Context& context,
+                                    const SemIR::Function& new_function,
+                                    const SemIR::Function& prev_function,
+                                    SemIR::SpecificId prev_specific_id,
+                                    bool diagnose = true) -> bool;
+
 // Checks that `new_function` has the same parameter types and return type as
 // `prev_function`, or if `prev_function_id` is specified, a specific version of
 // `prev_function`. Prints a suitable diagnostic and returns false if not.
@@ -38,7 +54,8 @@ auto CheckFunctionTypeMatches(Context& context,
                               const SemIR::Function& new_function,
                               const SemIR::Function& prev_function,
                               SemIR::SpecificId prev_specific_id,
-                              bool check_syntax, bool check_self) -> bool;
+                              bool check_syntax, bool check_self,
+                              bool diagnose = true) -> bool;
 
 inline auto CheckFunctionTypeMatches(Context& context,
                                      const SemIR::Function& new_function,
@@ -58,6 +75,12 @@ auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
                              SemIR::SpecificId specific_id)
     -> SemIR::ReturnTypeInfo;
 
+// Checks that a function declaration's signature is suitable to support a
+// function definition. This requires the parameter types to be complete and the
+// return type to be concrete.
+auto CheckFunctionDefinitionSignature(Context& context,
+                                      SemIR::FunctionId function_id) -> void;
+
 }  // namespace Carbon::Check
 
 #endif  // CARBON_TOOLCHAIN_CHECK_FUNCTION_H_

+ 7 - 45
toolchain/check/handle_binding_pattern.cpp

@@ -8,8 +8,8 @@
 #include "toolchain/check/inst.h"
 #include "toolchain/check/interface.h"
 #include "toolchain/check/name_lookup.h"
+#include "toolchain/check/pattern.h"
 #include "toolchain/check/return.h"
-#include "toolchain/check/subpattern.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
 #include "toolchain/diagnostics/format_providers.h"
@@ -51,62 +51,24 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
       context.decl_introducer_state_stack().innermost();
 
   auto make_binding_pattern = [&]() -> SemIR::InstId {
-    // bind_id and entity_name_id are not populated if name_id is Underscore.
-    auto bind_id = SemIR::InstId::None;
     // TODO: Eventually the name will need to support associations with other
     // scopes, but right now we don't support qualified names here.
-    auto entity_name_id = SemIR::EntityNameId::None;
-    entity_name_id = context.entity_names().AddSymbolicBindingName(
-        name_id, context.scope_stack().PeekNameScopeId(),
-        is_generic ? context.scope_stack().AddCompileTimeBinding()
-                   : SemIR::CompileTimeBindIndex::None,
-        is_template);
-    if (is_generic) {
-      bind_id = AddInstInNoBlock(
-          context, name_node,
-          SemIR::BindSymbolicName{.type_id = cast_type_id,
-                                  .entity_name_id = entity_name_id,
-                                  .value_id = SemIR::InstId::None});
-    } else {
-      bind_id =
-          AddInstInNoBlock(context, name_node,
-                           SemIR::BindName{.type_id = cast_type_id,
-                                           .entity_name_id = entity_name_id,
-                                           .value_id = SemIR::InstId::None});
-    }
-
-    auto pattern_type_id = GetPatternType(context, cast_type_id);
-    auto binding_pattern_id = SemIR::InstId::None;
-    if (is_generic) {
-      binding_pattern_id = AddPatternInst<SemIR::SymbolicBindingPattern>(
-          context, name_node,
-          {.type_id = pattern_type_id, .entity_name_id = entity_name_id});
-    } else {
-      binding_pattern_id = AddPatternInst<SemIR::BindingPattern>(
-          context, name_node,
-          {.type_id = pattern_type_id, .entity_name_id = entity_name_id});
-    }
+    auto binding =
+        AddBindingPattern(context, name_node, name_id, cast_type_id,
+                          type_expr_region_id, is_generic, is_template);
 
-    if (is_generic) {
-      context.scope_stack().PushCompileTimeBinding(bind_id);
-    }
     if (name_id != SemIR::NameId::Underscore) {
       // Add name to lookup immediately, so it can be used in the rest of the
       // enclosing pattern.
       auto name_context =
           context.decl_name_stack().MakeUnqualifiedName(name_node, name_id);
       context.decl_name_stack().AddNameOrDiagnose(
-          name_context, bind_id, introducer.modifier_set.GetAccessKind());
+          name_context, binding.bind_id,
+          introducer.modifier_set.GetAccessKind());
       context.full_pattern_stack().AddBindName(name_id);
     }
 
-    bool inserted = context.bind_name_map()
-                        .Insert(binding_pattern_id,
-                                {.bind_name_id = bind_id,
-                                 .type_expr_region_id = type_expr_region_id})
-                        .is_inserted();
-    CARBON_CHECK(inserted);
-    return binding_pattern_id;
+    return binding.pattern_id;
   };
 
   // A `self` binding can only appear in an implicit parameter list.

+ 5 - 53
toolchain/check/handle_function.cpp

@@ -5,7 +5,6 @@
 #include <optional>
 #include <utility>
 
-#include "common/find.h"
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/check/context.h"
 #include "toolchain/check/control_flow.h"
@@ -34,7 +33,6 @@
 #include "toolchain/sem_ir/function.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/inst.h"
-#include "toolchain/sem_ir/pattern.h"
 #include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::Check {
@@ -85,18 +83,6 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
   return true;
 }
 
-// Returns the ID of the self parameter pattern, or None.
-// TODO: Do this during initial traversal of implicit params.
-static auto FindSelfPattern(Context& context,
-                            SemIR::InstBlockId implicit_param_patterns_id)
-    -> SemIR::InstId {
-  auto implicit_param_patterns =
-      context.inst_blocks().GetOrEmpty(implicit_param_patterns_id);
-  return FindIfOrNone(implicit_param_patterns, [&](auto implicit_param_id) {
-    return SemIR::IsSelfPattern(context.sem_ir(), implicit_param_id);
-  });
-}
-
 // Diagnoses issues with the modifiers, removing modifiers that shouldn't be
 // present.
 static auto DiagnoseModifiers(Context& context,
@@ -577,55 +563,20 @@ auto HandleParseNode(Context& context, Parse::FunctionDeclId node_id) -> bool {
   return true;
 }
 
-static auto CheckFunctionDefinitionSignature(Context& context,
-                                             SemIR::Function& function)
-    -> void {
-  auto params_to_complete =
-      context.inst_blocks().GetOrEmpty(function.call_params_id);
-
-  // Check the return type is complete.
-  if (function.return_slot_pattern_id.has_value()) {
-    CheckFunctionReturnType(context,
-                            SemIR::LocId(function.return_slot_pattern_id),
-                            function, SemIR::SpecificId::None);
-    params_to_complete = params_to_complete.drop_back();
-  }
-
-  // Check the parameter types are complete.
-  for (auto param_ref_id : params_to_complete) {
-    if (param_ref_id == SemIR::ErrorInst::InstId) {
-      continue;
-    }
-
-    // The parameter types need to be complete.
-    RequireCompleteType(
-        context, context.insts().GetAs<SemIR::AnyParam>(param_ref_id).type_id,
-        SemIR::LocId(param_ref_id), [&] {
-          CARBON_DIAGNOSTIC(
-              IncompleteTypeInFunctionParam, Error,
-              "parameter has incomplete type {0} in function definition",
-              TypeOfInstId);
-          return context.emitter().Build(
-              param_ref_id, IncompleteTypeInFunctionParam, param_ref_id);
-        });
-  }
-}
-
 // Processes a function definition after a signature for which we have already
 // built a function ID. This logic is shared between processing regular function
 // definitions and delayed parsing of inline method definitions.
 static auto HandleFunctionDefinitionAfterSignature(
     Context& context, Parse::FunctionDefinitionStartId node_id,
     SemIR::FunctionId function_id, SemIR::InstId decl_id) -> void {
-  auto& function = context.functions().Get(function_id);
-
   // Create the function scope and the entry block.
   context.scope_stack().PushForFunctionBody(decl_id);
   context.inst_block_stack().Push();
   context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
-  StartGenericDefinition(context, function.generic_id);
+  StartGenericDefinition(context,
+                         context.functions().Get(function_id).generic_id);
 
-  CheckFunctionDefinitionSignature(context, function);
+  CheckFunctionDefinitionSignature(context, function_id);
 
   context.node_stack().Push(node_id, function_id);
 }
@@ -765,8 +716,9 @@ auto HandleParseNode(Context& context,
 
   auto builtin_kind = LookupBuiltinFunctionKind(context, name_id);
   if (builtin_kind != SemIR::BuiltinFunctionKind::None) {
+    CheckFunctionDefinitionSignature(context, function_id);
+
     auto& function = context.functions().Get(function_id);
-    CheckFunctionDefinitionSignature(context, function);
     if (IsValidBuiltinDeclaration(context, function, builtin_kind)) {
       function.builtin_function_kind = builtin_kind;
       // Build an empty generic definition if this is a generic builtin.

+ 2 - 2
toolchain/check/handle_impl.cpp

@@ -564,9 +564,9 @@ auto HandleParseNode(Context& context, Parse::ImplDefinitionId /*node_id*/)
   auto impl_id =
       context.node_stack().Pop<Parse::NodeKind::ImplDefinitionStart>();
 
+  FinishImplWitness(context, impl_id);
+
   auto& impl_info = context.impls().Get(impl_id);
-  CARBON_CHECK(!impl_info.is_complete());
-  FinishImplWitness(context, impl_info);
   impl_info.defined = true;
   FinishGenericDefinition(context, impl_info.generic_id);
 

+ 1 - 1
toolchain/check/handle_let_and_var.cpp

@@ -14,9 +14,9 @@
 #include "toolchain/check/interface.h"
 #include "toolchain/check/keyword_modifier_set.h"
 #include "toolchain/check/modifiers.h"
+#include "toolchain/check/pattern.h"
 #include "toolchain/check/pattern_match.h"
 #include "toolchain/check/return.h"
-#include "toolchain/check/subpattern.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
 #include "toolchain/diagnostics/format_providers.h"
 #include "toolchain/lex/token_kind.h"

+ 1 - 1
toolchain/check/handle_pattern_list.cpp

@@ -5,7 +5,7 @@
 #include "toolchain/check/context.h"
 #include "toolchain/check/handle.h"
 #include "toolchain/check/inst.h"
-#include "toolchain/check/subpattern.h"
+#include "toolchain/check/pattern.h"
 #include "toolchain/check/type.h"
 
 namespace Carbon::Check {

+ 8 - 9
toolchain/check/impl.cpp

@@ -14,6 +14,7 @@
 #include "toolchain/check/inst.h"
 #include "toolchain/check/interface.h"
 #include "toolchain/check/name_lookup.h"
+#include "toolchain/check/thunk.h"
 #include "toolchain/check/type.h"
 #include "toolchain/check/type_completion.h"
 #include "toolchain/diagnostics/diagnostic_emitter.h"
@@ -76,14 +77,8 @@ static auto CheckAssociatedFunctionImplementation(
               .generic_id,
           impl_enclosing_specific_id, self_type_id, witness_inst_id);
 
-  if (!CheckFunctionTypeMatches(
-          context, context.functions().Get(impl_function_decl->function_id),
-          context.functions().Get(interface_function_type.function_id),
-          interface_function_specific_id, /*check_syntax=*/false,
-          /*check_self=*/true)) {
-    return SemIR::ErrorInst::InstId;
-  }
-  return impl_decl_id;
+  return BuildThunk(context, interface_function_type.function_id,
+                    interface_function_specific_id, impl_decl_id);
 }
 
 // Builds an initial witness from the rewrites in the facet type, if any.
@@ -168,7 +163,11 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
 
 // Adds functions to the witness that the specified impl implements the given
 // interface.
-auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void {
+auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void {
+  // Make a copy of the impl. We're going to reference it a lot, and `impl`s
+  // could get invalidated by some of the things we do.
+  const auto impl = context.impls().Get(impl_id);
+
   CARBON_CHECK(impl.is_being_defined());
   CARBON_CHECK(impl.witness_id.has_value());
   if (impl.witness_id == SemIR::ErrorInst::InstId) {

+ 1 - 1
toolchain/check/impl.h

@@ -21,7 +21,7 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl,
 auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void;
 
 // Adds the function members to the witness for `impl`.
-auto FinishImplWitness(Context& context, SemIR::Impl& impl) -> void;
+auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void;
 
 // Sets all unset members of the witness for `impl` to the error instruction.
 auto FillImplWitnessWithErrors(Context& context, SemIR::Impl& impl) -> void;

+ 5 - 6
toolchain/check/inst.h

@@ -132,12 +132,11 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
 // Convenience for AddPatternInst with typed nodes.
 //
 // As a safety check, prevent use with storage insts (see `AddInstWithCleanup`).
-template <typename InstT>
-  requires(SemIR::Internal::HasNodeId<InstT> && !InstT::Kind.has_cleanup())
-auto AddPatternInst(Context& context,
-                    typename decltype(InstT::Kind)::TypedNodeId node_id,
-                    InstT inst) -> SemIR::InstId {
-  return AddPatternInst(context, SemIR::LocIdAndInst(node_id, inst));
+template <typename InstT, typename LocT>
+  requires(!InstT::Kind.has_cleanup() &&
+           std::convertible_to<LocT, SemIR::LocId>)
+auto AddPatternInst(Context& context, LocT loc, InstT inst) -> SemIR::InstId {
+  return AddPatternInst(context, SemIR::LocIdAndInst(loc, inst));
 }
 
 // Adds an instruction to the current block, returning the produced ID. The

+ 99 - 0
toolchain/check/pattern.cpp

@@ -0,0 +1,99 @@
+// 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
+
+#include "toolchain/check/pattern.h"
+
+#include "toolchain/check/inst.h"
+#include "toolchain/check/type.h"
+
+namespace Carbon::Check {
+
+auto BeginSubpattern(Context& context) -> void {
+  context.inst_block_stack().Push();
+  context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
+}
+
+auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
+    -> SemIR::ExprRegionId {
+  if (context.region_stack().PeekRegion().size() > 1) {
+    // End the exit block with a branch to a successor block, whose contents
+    // will be determined later.
+    AddInst(context,
+            SemIR::LocIdAndInst::NoLoc<SemIR::Branch>(
+                {.target_id = context.inst_blocks().AddPlaceholder()}));
+  } else {
+    // This single-block region will be inserted as a SpliceBlock, so we don't
+    // need control flow out of it.
+  }
+  auto block_id = context.inst_block_stack().Pop();
+  CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
+
+  // TODO: Is it possible to validate that this region is genuinely
+  // single-entry, single-exit?
+  return context.sem_ir().expr_regions().Add(
+      {.block_ids = context.region_stack().PopRegion(),
+       .result_id = result_id});
+}
+
+auto EndSubpatternAsNonExpr(Context& context) -> void {
+  auto block_id = context.inst_block_stack().Pop();
+  CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
+  CARBON_CHECK(context.region_stack().PeekRegion().size() == 1);
+  // TODO: Add `CARBON_CHECK(inst_blocks().Get(block_id).empty())`.
+  // Currently that can fail when ending a tuple pattern in a name binding
+  // decl in a class or interface.
+  context.region_stack().PopAndDiscardRegion();
+}
+
+auto AddBindingPattern(Context& context, SemIR::LocId name_loc,
+                       SemIR::NameId name_id, SemIR::TypeId type_id,
+                       SemIR::ExprRegionId type_region_id, bool is_generic,
+                       bool is_template) -> BindingPatternInfo {
+  auto entity_name_id = context.entity_names().AddSymbolicBindingName(
+      name_id, context.scope_stack().PeekNameScopeId(),
+      is_generic ? context.scope_stack().AddCompileTimeBinding()
+                 : SemIR::CompileTimeBindIndex::None,
+      is_template);
+
+  auto bind_id = SemIR::InstId::None;
+  if (is_generic) {
+    bind_id = AddInstInNoBlock<SemIR::BindSymbolicName>(
+        context, name_loc,
+        {.type_id = type_id,
+         .entity_name_id = entity_name_id,
+         .value_id = SemIR::InstId::None});
+  } else {
+    bind_id =
+        AddInstInNoBlock<SemIR::BindName>(context, name_loc,
+                                          {.type_id = type_id,
+                                           .entity_name_id = entity_name_id,
+                                           .value_id = SemIR::InstId::None});
+  }
+
+  auto pattern_type_id = GetPatternType(context, type_id);
+  auto binding_pattern_id = SemIR::InstId::None;
+  if (is_generic) {
+    binding_pattern_id = AddPatternInst<SemIR::SymbolicBindingPattern>(
+        context, name_loc,
+        {.type_id = pattern_type_id, .entity_name_id = entity_name_id});
+  } else {
+    binding_pattern_id = AddPatternInst<SemIR::BindingPattern>(
+        context, name_loc,
+        {.type_id = pattern_type_id, .entity_name_id = entity_name_id});
+  }
+
+  if (is_generic) {
+    context.scope_stack().PushCompileTimeBinding(bind_id);
+  }
+
+  bool inserted =
+      context.bind_name_map()
+          .Insert(binding_pattern_id, {.bind_name_id = bind_id,
+                                       .type_expr_region_id = type_region_id})
+          .is_inserted();
+  CARBON_CHECK(inserted);
+  return {.pattern_id = binding_pattern_id, .bind_id = bind_id};
+}
+
+}  // namespace Carbon::Check

+ 16 - 3
toolchain/check/subpattern.h → toolchain/check/pattern.h

@@ -2,8 +2,8 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-#ifndef CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
-#define CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
+#ifndef CARBON_TOOLCHAIN_CHECK_PATTERN_H_
+#define CARBON_TOOLCHAIN_CHECK_PATTERN_H_
 
 #include "toolchain/check/context.h"
 #include "toolchain/sem_ir/ids.h"
@@ -27,8 +27,21 @@ auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
 // it had no expression content.
 auto EndSubpatternAsNonExpr(Context& context) -> void;
 
+// Information about a created binding pattern.
+struct BindingPatternInfo {
+  SemIR::InstId pattern_id;
+  SemIR::InstId bind_id;
+};
+
 // TODO: Add EndSubpatternAsPattern, when needed.
 
+// Creates a binding pattern. Returns the binding pattern and the bind name
+// instruction.
+auto AddBindingPattern(Context& context, SemIR::LocId name_loc,
+                       SemIR::NameId name_id, SemIR::TypeId type_id,
+                       SemIR::ExprRegionId type_region_id, bool is_generic,
+                       bool is_template) -> BindingPatternInfo;
+
 }  // namespace Carbon::Check
 
-#endif  // CARBON_TOOLCHAIN_CHECK_SUBPATTERN_H_
+#endif  // CARBON_TOOLCHAIN_CHECK_PATTERN_H_

+ 1 - 1
toolchain/check/pattern_match.cpp

@@ -14,7 +14,7 @@
 #include "toolchain/check/context.h"
 #include "toolchain/check/control_flow.h"
 #include "toolchain/check/convert.h"
-#include "toolchain/check/subpattern.h"
+#include "toolchain/check/pattern.h"
 #include "toolchain/check/type.h"
 #include "toolchain/diagnostics/format_providers.h"
 #include "toolchain/sem_ir/expr_info.h"

+ 3 - 4
toolchain/check/pointer_dereference.cpp

@@ -14,13 +14,12 @@
 namespace Carbon::Check {
 
 auto PerformPointerDereference(
-    Context& context, Parse::AnyPointerDeferenceExprId node_id,
-    SemIR::InstId base_id,
+    Context& context, SemIR::LocId loc_id, SemIR::InstId base_id,
     llvm::function_ref<auto(SemIR::TypeId not_pointer_type_id)->void>
         diagnose_not_pointer) -> SemIR::InstId {
   // TODO: Once we have a finalized design for a pointer interface, use
   //
-  //   HandleUnaryOperator(context, node_id, {"Pointer", "Dereference"});
+  //   HandleUnaryOperator(context, loc_id, {"Pointer", "Dereference"});
   //
   // to convert to a pointer value.
   base_id = ConvertToValueExpr(context, base_id);
@@ -35,7 +34,7 @@ auto PerformPointerDereference(
     diagnose_not_pointer(type_id);
   }
   return AddInst<SemIR::Deref>(
-      context, node_id, {.type_id = result_type_id, .pointer_id = base_id});
+      context, loc_id, {.type_id = result_type_id, .pointer_id = base_id});
 }
 
 }  // namespace Carbon::Check

+ 1 - 2
toolchain/check/pointer_dereference.h

@@ -15,8 +15,7 @@ namespace Carbon::Check {
 // Creates SemIR to perform a pointer dereference with base expression
 // `base_id`. Returns the result of the access.
 auto PerformPointerDereference(
-    Context& context, Parse::AnyPointerDeferenceExprId node_id,
-    SemIR::InstId base_i,
+    Context& context, SemIR::LocId loc_id, SemIR::InstId base_i,
     llvm::function_ref<auto(SemIR::TypeId not_pointer_type_id)->void>
         diagnose_not_pointer) -> SemIR::InstId;
 

+ 9 - 10
toolchain/check/return.cpp

@@ -113,23 +113,22 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
   }
 }
 
-auto BuildReturnWithNoExpr(Context& context, Parse::ReturnStatementId node_id)
-    -> void {
+auto BuildReturnWithNoExpr(Context& context, SemIR::LocId loc_id) -> void {
   const auto& function = GetCurrentFunctionForReturn(context);
   auto return_type_id = function.GetDeclaredReturnType(context.sem_ir());
 
   if (return_type_id.has_value()) {
     CARBON_DIAGNOSTIC(ReturnStatementMissingExpr, Error,
                       "missing return value");
-    auto diag = context.emitter().Build(node_id, ReturnStatementMissingExpr);
+    auto diag = context.emitter().Build(loc_id, ReturnStatementMissingExpr);
     NoteReturnType(context, diag, function);
     diag.Emit();
   }
 
-  AddInst<SemIR::Return>(context, node_id, {});
+  AddInst<SemIR::Return>(context, loc_id, {});
 }
 
-auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
+auto BuildReturnWithExpr(Context& context, SemIR::LocId loc_id,
                          SemIR::InstId expr_id) -> void {
   const auto& function = GetCurrentFunctionForReturn(context);
   auto returned_var_id = GetCurrentReturnedVar(context);
@@ -141,7 +140,7 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
     CARBON_DIAGNOSTIC(
         ReturnStatementDisallowExpr, Error,
         "no return expression should be provided in this context");
-    auto diag = context.emitter().Build(node_id, ReturnStatementDisallowExpr);
+    auto diag = context.emitter().Build(loc_id, ReturnStatementDisallowExpr);
     NoteNoReturnTypeProvided(diag, function);
     diag.Emit();
     expr_id = SemIR::ErrorInst::InstId;
@@ -149,7 +148,7 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
     CARBON_DIAGNOSTIC(
         ReturnExprWithReturnedVar, Error,
         "can only `return var;` in the scope of a `returned var`");
-    auto diag = context.emitter().Build(node_id, ReturnExprWithReturnedVar);
+    auto diag = context.emitter().Build(loc_id, ReturnExprWithReturnedVar);
     NoteReturnedVar(diag, returned_var_id);
     diag.Emit();
     expr_id = SemIR::ErrorInst::InstId;
@@ -161,13 +160,13 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
     return_slot_id = GetCurrentReturnSlot(context);
     CARBON_CHECK(return_slot_id.has_value());
     // Note that this can import a function and invalidate `function`.
-    expr_id = Initialize(context, node_id, return_slot_id, expr_id);
+    expr_id = Initialize(context, loc_id, return_slot_id, expr_id);
   } else {
     expr_id =
-        ConvertToValueOfType(context, node_id, expr_id, return_info.type_id);
+        ConvertToValueOfType(context, loc_id, expr_id, return_info.type_id);
   }
 
-  AddInst<SemIR::ReturnExpr>(context, node_id,
+  AddInst<SemIR::ReturnExpr>(context, loc_id,
                              {.expr_id = expr_id, .dest_id = return_slot_id});
 }
 

+ 2 - 3
toolchain/check/return.h

@@ -25,11 +25,10 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
                          SemIR::InstId bind_id) -> void;
 
 // Checks and builds SemIR for a `return;` statement.
-auto BuildReturnWithNoExpr(Context& context, Parse::ReturnStatementId node_id)
-    -> void;
+auto BuildReturnWithNoExpr(Context& context, SemIR::LocId loc_id) -> void;
 
 // Checks and builds SemIR for a `return <expression>;` statement.
-auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
+auto BuildReturnWithExpr(Context& context, SemIR::LocId loc_id,
                          SemIR::InstId expr_id) -> void;
 
 // Checks and builds SemIR for a `return var;` statement.

+ 0 - 48
toolchain/check/subpattern.cpp

@@ -1,48 +0,0 @@
-// 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
-
-#include "toolchain/check/subpattern.h"
-
-#include "toolchain/check/inst.h"
-
-namespace Carbon::Check {
-
-auto BeginSubpattern(Context& context) -> void {
-  context.inst_block_stack().Push();
-  context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
-}
-
-auto EndSubpatternAsExpr(Context& context, SemIR::InstId result_id)
-    -> SemIR::ExprRegionId {
-  if (context.region_stack().PeekRegion().size() > 1) {
-    // End the exit block with a branch to a successor block, whose contents
-    // will be determined later.
-    AddInst(context,
-            SemIR::LocIdAndInst::NoLoc<SemIR::Branch>(
-                {.target_id = context.inst_blocks().AddPlaceholder()}));
-  } else {
-    // This single-block region will be inserted as a SpliceBlock, so we don't
-    // need control flow out of it.
-  }
-  auto block_id = context.inst_block_stack().Pop();
-  CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
-
-  // TODO: Is it possible to validate that this region is genuinely
-  // single-entry, single-exit?
-  return context.sem_ir().expr_regions().Add(
-      {.block_ids = context.region_stack().PopRegion(),
-       .result_id = result_id});
-}
-
-auto EndSubpatternAsNonExpr(Context& context) -> void {
-  auto block_id = context.inst_block_stack().Pop();
-  CARBON_CHECK(block_id == context.region_stack().PeekRegion().back());
-  CARBON_CHECK(context.region_stack().PeekRegion().size() == 1);
-  // TODO: Add `CARBON_CHECK(inst_blocks().Get(block_id).empty())`.
-  // Currently that can fail when ending a tuple pattern in a name binding
-  // decl in a class or interface.
-  context.region_stack().PopAndDiscardRegion();
-}
-
-}  // namespace Carbon::Check

+ 27 - 7
toolchain/check/testdata/impl/fail_call_invalid.carbon

@@ -32,6 +32,7 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:   %Self.as_type.716: type = facet_access_type %Self.3c9 [symbolic]
 // CHECK:STDOUT:   %pattern_type.f88: type = pattern_type %Self.as_type.716 [symbolic]
 // CHECK:STDOUT:   %G.type.b60: type = fn_type @G.1 [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
 // CHECK:STDOUT:   %G.cb0: %G.type.b60 = struct_value () [concrete]
 // CHECK:STDOUT:   %Simple.assoc_type: type = assoc_entity_type @Simple [concrete]
 // CHECK:STDOUT:   %assoc0.db2: %Simple.assoc_type = assoc_entity element0, @Simple.%G.decl [concrete]
@@ -40,13 +41,15 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:   %Int.generic: %Int.type = struct_value () [concrete]
 // CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
 // CHECK:STDOUT:   %Simple.impl_witness: <witness> = impl_witness file.%Simple.impl_witness_table [concrete]
-// CHECK:STDOUT:   %G.type.c98: type = fn_type @G.2 [concrete]
-// CHECK:STDOUT:   %G.e73: %G.type.c98 = struct_value () [concrete]
+// CHECK:STDOUT:   %G.type.c9825d.1: type = fn_type @G.2 [concrete]
+// CHECK:STDOUT:   %G.e73e91.1: %G.type.c9825d.1 = struct_value () [concrete]
 // CHECK:STDOUT:   %Simple.facet: %Simple.type = facet_value %i32, (%Simple.impl_witness) [concrete]
 // CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
+// CHECK:STDOUT:   %G.type.c9825d.2: type = fn_type @G.3 [concrete]
+// CHECK:STDOUT:   %G.e73e91.2: %G.type.c9825d.2 = struct_value () [concrete]
 // CHECK:STDOUT:   %InstanceCall.type: type = fn_type @InstanceCall [concrete]
 // CHECK:STDOUT:   %InstanceCall: %InstanceCall.type = struct_value () [concrete]
-// CHECK:STDOUT:   %.0aa: type = fn_type_with_self_type %G.type.b60, %Simple.facet [concrete]
+// CHECK:STDOUT:   %.8e6: type = fn_type_with_self_type %G.type.b60, %Simple.facet [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -72,7 +75,7 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     %Simple.ref: type = name_ref Simple, file.%Simple.decl [concrete = constants.%Simple.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Simple.impl_witness_table = impl_witness_table (<error>), @impl.006 [concrete]
+// CHECK:STDOUT:   %Simple.impl_witness_table = impl_witness_table (@impl.006.%G.decl.loc20_27.2), @impl.006 [concrete]
 // CHECK:STDOUT:   %Simple.impl_witness: <witness> = impl_witness %Simple.impl_witness_table [concrete = constants.%Simple.impl_witness]
 // CHECK:STDOUT:   %InstanceCall.decl: %InstanceCall.type = fn_decl @InstanceCall [concrete = constants.%InstanceCall] {
 // CHECK:STDOUT:     %n.patt: %pattern_type.7ce = binding_pattern n [concrete]
@@ -110,7 +113,7 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl.006: %i32 as %Simple.ref {
-// CHECK:STDOUT:   %G.decl: %G.type.c98 = fn_decl @G.2 [concrete = constants.%G.e73] {
+// CHECK:STDOUT:   %G.decl.loc20_27.1: %G.type.c9825d.1 = fn_decl @G.2 [concrete = constants.%G.e73e91.1] {
 // CHECK:STDOUT:     %self.patt: <error> = binding_pattern self [concrete]
 // CHECK:STDOUT:     %self.param_patt: <error> = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:   } {
@@ -118,10 +121,17 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:     %Undeclared.ref: <error> = name_ref Undeclared, <error> [concrete = <error>]
 // CHECK:STDOUT:     %self: <error> = bind_name self, %self.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %G.decl.loc20_27.2: %G.type.c9825d.2 = fn_decl @G.3 [concrete = constants.%G.e73e91.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.7ce = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.7ce = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %i32 = value_param call_param0
+// CHECK:STDOUT:     %self: %i32 = bind_name self, %self.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Undeclared = <poisoned>
-// CHECK:STDOUT:   .G = %G.decl
+// CHECK:STDOUT:   .G = %G.decl.loc20_27.1
 // CHECK:STDOUT:   witness = file.%Simple.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -135,12 +145,22 @@ fn InstanceCall(n: i32) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @G.2(%self.param: <error>);
 // CHECK:STDOUT:
+// CHECK:STDOUT: fn @G.3(%self.param: %i32) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %i32 = name_ref self, %self.param
+// CHECK:STDOUT:   %G.bound: <bound method> = bound_method %self.ref, @impl.006.%G.decl.loc20_27.1
+// CHECK:STDOUT:   %G.call: init %empty_tuple.type = call %G.bound(<error>)
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: fn @InstanceCall(%n.param: %i32) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %n.ref: %i32 = name_ref n, %n
 // CHECK:STDOUT:   %Simple.ref: type = name_ref Simple, file.%Simple.decl [concrete = constants.%Simple.type]
 // CHECK:STDOUT:   %G.ref: %Simple.assoc_type = name_ref G, @Simple.%assoc0 [concrete = constants.%assoc0.db2]
-// CHECK:STDOUT:   %impl.elem0: %.0aa = impl_witness_access constants.%Simple.impl_witness, element0 [concrete = <error>]
+// CHECK:STDOUT:   %impl.elem0: %.8e6 = impl_witness_access constants.%Simple.impl_witness, element0 [concrete = constants.%G.e73e91.2]
+// CHECK:STDOUT:   %bound_method: <bound method> = bound_method %n.ref, %impl.elem0
+// CHECK:STDOUT:   %G.call: init %empty_tuple.type = call %bound_method(%n.ref)
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

Datei-Diff unterdrückt, da er zu groß ist
+ 403 - 236
toolchain/check/testdata/impl/fail_impl_bad_assoc_fn.carbon


+ 86 - 54
toolchain/check/testdata/impl/fail_self_type_mismatch.carbon

@@ -12,6 +12,12 @@ class C[T:! type](X:! T) {}
 
 interface I {
   // Uses of `Self` inside the definition of `I` have type `I`.
+  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+6]]:8: error: cannot implicitly convert expression of type `C(i32 as I)` to `C(i32)` [ConversionFailure]
+  // CHECK:STDERR:   fn F(c: C(Self));
+  // CHECK:STDERR:        ^~~~~~~~~~
+  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+3]]:8: note: type `C(i32 as I)` does not implement interface `Core.ImplicitAs(C(i32))` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   fn F(c: C(Self));
+  // CHECK:STDERR:        ^~~~~~~~~~
   fn F(c: C(Self));
 }
 
@@ -23,12 +29,12 @@ impl bool as I {
 }
 
 impl i32 as I {
-  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+7]]:8: error: type `<pattern for C(i32)>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for C(i32 as I)>` [RedeclParamDiffersType]
+  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE+7]]:8: note: initializing function parameter [InCallToFunctionParam]
   // CHECK:STDERR:   fn F(c: C(i32));
   // CHECK:STDERR:        ^~~~~~~~~
-  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE-14]]:8: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
+  // CHECK:STDERR: fail_self_type_mismatch.carbon:[[@LINE-14]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
   // CHECK:STDERR:   fn F(c: C(Self));
-  // CHECK:STDERR:        ^~~~~~~~~~
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~
   // CHECK:STDERR:
   fn F(c: C(i32));
 }
@@ -39,24 +45,25 @@ impl i32 as I {
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic]
 // CHECK:STDOUT:   %pattern_type.98f: type = pattern_type type [concrete]
 // CHECK:STDOUT:   %X: %T = bind_symbolic_name X, 1 [symbolic]
-// CHECK:STDOUT:   %pattern_type.7dc: type = pattern_type %T [symbolic]
+// CHECK:STDOUT:   %pattern_type.7dcd0a.1: type = pattern_type %T [symbolic]
 // CHECK:STDOUT:   %C.type: type = generic_class_type @C [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
 // CHECK:STDOUT:   %C.generic: %C.type = struct_value () [concrete]
 // CHECK:STDOUT:   %C.b36: type = class_type @C, @C(%T, %X) [symbolic]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
-// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.826: %I.type = bind_symbolic_name Self, 0 [symbolic]
 // CHECK:STDOUT:   %pattern_type.2b5: type = pattern_type %I.type [concrete]
-// CHECK:STDOUT:   %C.dbb: type = class_type @C, @C(%I.type, %Self) [symbolic]
+// CHECK:STDOUT:   %C.dbb: type = class_type @C, @C(%I.type, %Self.826) [symbolic]
 // CHECK:STDOUT:   %pattern_type.4fb: type = pattern_type %C.dbb [symbolic]
 // CHECK:STDOUT:   %F.type.cf0: type = fn_type @F.1 [concrete]
 // CHECK:STDOUT:   %F.bc6: %F.type.cf0 = struct_value () [concrete]
 // CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
-// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
+// CHECK:STDOUT:   %assoc0.82e: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
 // CHECK:STDOUT:   %Bool.type: type = fn_type @Bool [concrete]
 // CHECK:STDOUT:   %Bool: %Bool.type = struct_value () [concrete]
-// CHECK:STDOUT:   %I.impl_witness.c21: <witness> = impl_witness file.%I.impl_witness_table.loc18 [concrete]
+// CHECK:STDOUT:   %I.impl_witness.c21: <witness> = impl_witness file.%I.impl_witness_table.loc24 [concrete]
 // CHECK:STDOUT:   %I.facet.e8a: %I.type = facet_value bool, (%I.impl_witness.c21) [concrete]
 // CHECK:STDOUT:   %C.7db: type = class_type @C, @C(%I.type, %I.facet.e8a) [concrete]
 // CHECK:STDOUT:   %pattern_type.225: type = pattern_type %C.7db [concrete]
@@ -66,25 +73,31 @@ impl i32 as I {
 // CHECK:STDOUT:   %Int.type: type = generic_class_type @Int [concrete]
 // CHECK:STDOUT:   %Int.generic: %Int.type = struct_value () [concrete]
 // CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
-// CHECK:STDOUT:   %I.impl_witness.d39: <witness> = impl_witness file.%I.impl_witness_table.loc25 [concrete]
+// CHECK:STDOUT:   %I.impl_witness.863: <witness> = impl_witness file.%I.impl_witness_table.loc31 [concrete]
 // CHECK:STDOUT:   %C.6fb: type = class_type @C, @C(type, %i32) [concrete]
 // CHECK:STDOUT:   %pattern_type.52b: type = pattern_type %C.6fb [concrete]
-// CHECK:STDOUT:   %F.type.066: type = fn_type @F.3 [concrete]
-// CHECK:STDOUT:   %F.9ec: %F.type.066 = struct_value () [concrete]
-// CHECK:STDOUT:   %I.facet.8b2: %I.type = facet_value %i32, (%I.impl_witness.d39) [concrete]
-// CHECK:STDOUT:   %C.835: type = class_type @C, @C(%I.type, %I.facet.8b2) [concrete]
-// CHECK:STDOUT:   %pattern_type.023: type = pattern_type %C.835 [concrete]
+// CHECK:STDOUT:   %F.type.066a53.1: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.9ec58f.1: %F.type.066a53.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet.118: %I.type = facet_value %i32, (%I.impl_witness.863) [concrete]
+// CHECK:STDOUT:   %C.d88: type = class_type @C, @C(%I.type, %I.facet.118) [concrete]
+// CHECK:STDOUT:   %pattern_type.c65: type = pattern_type %C.d88 [concrete]
+// CHECK:STDOUT:   %F.type.066a53.2: type = fn_type @F.4 [concrete]
+// CHECK:STDOUT:   %F.9ec58f.2: %F.type.066a53.2 = struct_value () [concrete]
+// CHECK:STDOUT:   %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
+// CHECK:STDOUT:   %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [concrete] {
 // CHECK:STDOUT:     .Bool = %Core.Bool
 // CHECK:STDOUT:     .Int = %Core.Int
+// CHECK:STDOUT:     .ImplicitAs = %Core.ImplicitAs
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/...
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.Bool: %Bool.type = import_ref Core//prelude/types/bool, Bool, loaded [concrete = constants.%Bool]
 // CHECK:STDOUT:   %Core.Int: %Int.type = import_ref Core//prelude/types/int, Int, loaded [concrete = constants.%Int.generic]
+// CHECK:STDOUT:   %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/operators/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -96,7 +109,7 @@ impl i32 as I {
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %C.decl: %C.type = class_decl @C [concrete = constants.%C.generic] {
 // CHECK:STDOUT:     %T.patt: %pattern_type.98f = symbolic_binding_pattern T, 0 [concrete]
-// CHECK:STDOUT:     %X.patt: @C.%pattern_type (%pattern_type.7dc) = symbolic_binding_pattern X, 1 [concrete]
+// CHECK:STDOUT:     %X.patt: @C.%pattern_type (%pattern_type.7dcd0a.1) = symbolic_binding_pattern X, 1 [concrete]
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %T.loc11_9.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc11_9.2 (constants.%T)]
 // CHECK:STDOUT:     %T.ref: type = name_ref T, %T.loc11_9.1 [symbolic = %T.loc11_9.2 (constants.%T)]
@@ -105,36 +118,36 @@ impl i32 as I {
 // CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
 // CHECK:STDOUT:   impl_decl @impl.049 [concrete] {} {
 // CHECK:STDOUT:     %bool.make_type: init type = call constants.%Bool() [concrete = bool]
-// CHECK:STDOUT:     %.loc18_6.1: type = value_of_initializer %bool.make_type [concrete = bool]
-// CHECK:STDOUT:     %.loc18_6.2: type = converted %bool.make_type, %.loc18_6.1 [concrete = bool]
+// CHECK:STDOUT:     %.loc24_6.1: type = value_of_initializer %bool.make_type [concrete = bool]
+// CHECK:STDOUT:     %.loc24_6.2: type = converted %bool.make_type, %.loc24_6.1 [concrete = bool]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %I.impl_witness_table.loc18 = impl_witness_table (@impl.049.%F.decl), @impl.049 [concrete]
-// CHECK:STDOUT:   %I.impl_witness.loc18: <witness> = impl_witness %I.impl_witness_table.loc18 [concrete = constants.%I.impl_witness.c21]
+// CHECK:STDOUT:   %I.impl_witness_table.loc24 = impl_witness_table (@impl.049.%F.decl), @impl.049 [concrete]
+// CHECK:STDOUT:   %I.impl_witness.loc24: <witness> = impl_witness %I.impl_witness_table.loc24 [concrete = constants.%I.impl_witness.c21]
 // CHECK:STDOUT:   impl_decl @impl.a9a [concrete] {} {
 // CHECK:STDOUT:     %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %I.impl_witness_table.loc25 = impl_witness_table (<error>), @impl.a9a [concrete]
-// CHECK:STDOUT:   %I.impl_witness.loc25: <witness> = impl_witness %I.impl_witness_table.loc25 [concrete = constants.%I.impl_witness.d39]
+// CHECK:STDOUT:   %I.impl_witness_table.loc31 = impl_witness_table (@impl.a9a.%F.decl.loc39_18.2), @impl.a9a [concrete]
+// CHECK:STDOUT:   %I.impl_witness.loc31: <witness> = impl_witness %I.impl_witness_table.loc31 [concrete = constants.%I.impl_witness.863]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @I {
-// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.826]
 // CHECK:STDOUT:   %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
 // CHECK:STDOUT:     %c.patt: @F.1.%pattern_type (%pattern_type.4fb) = binding_pattern c [concrete]
 // CHECK:STDOUT:     %c.param_patt: @F.1.%pattern_type (%pattern_type.4fb) = value_param_pattern %c.patt, call_param0 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %c.param: @F.1.%C.loc15_17.1 (%C.dbb) = value_param call_param0
-// CHECK:STDOUT:     %.loc15: type = splice_block %C.loc15_17.2 [symbolic = %C.loc15_17.1 (constants.%C.dbb)] {
+// CHECK:STDOUT:     %c.param: @F.1.%C.loc21_17.1 (%C.dbb) = value_param call_param0
+// CHECK:STDOUT:     %.loc21: type = splice_block %C.loc21_17.2 [symbolic = %C.loc21_17.1 (constants.%C.dbb)] {
 // CHECK:STDOUT:       %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
-// CHECK:STDOUT:       %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
-// CHECK:STDOUT:       %C.loc15_17.2: type = class_type @C, @C(constants.%I.type, constants.%Self) [symbolic = %C.loc15_17.1 (constants.%C.dbb)]
+// CHECK:STDOUT:       %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self.826)]
+// CHECK:STDOUT:       %C.loc21_17.2: type = class_type @C, @C(constants.%I.type, constants.%Self.826) [symbolic = %C.loc21_17.1 (constants.%C.dbb)]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %c: @F.1.%C.loc15_17.1 (%C.dbb) = bind_name c, %c.param
+// CHECK:STDOUT:     %c: @F.1.%C.loc21_17.1 (%C.dbb) = bind_name c, %c.param
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0.82e]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -143,18 +156,18 @@ impl i32 as I {
 // CHECK:STDOUT:   witness = (%F.decl)
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.049: %.loc18_6.2 as %I.ref {
+// CHECK:STDOUT: impl @impl.049: %.loc24_6.2 as %I.ref {
 // CHECK:STDOUT:   %F.decl: %F.type.8ba = fn_decl @F.2 [concrete = constants.%F.2cf] {
 // CHECK:STDOUT:     %c.patt: %pattern_type.225 = binding_pattern c [concrete]
 // CHECK:STDOUT:     %c.param_patt: %pattern_type.225 = value_param_pattern %c.patt, call_param0 [concrete]
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %c.param: %C.7db = value_param call_param0
-// CHECK:STDOUT:     %.loc22_22: type = splice_block %C [concrete = constants.%C.7db] {
+// CHECK:STDOUT:     %.loc28_22: type = splice_block %C [concrete = constants.%C.7db] {
 // CHECK:STDOUT:       %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
 // CHECK:STDOUT:       %bool.make_type: init type = call constants.%Bool() [concrete = bool]
 // CHECK:STDOUT:       %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
 // CHECK:STDOUT:       %I.facet: %I.type = facet_value bool, (constants.%I.impl_witness.c21) [concrete = constants.%I.facet.e8a]
-// CHECK:STDOUT:       %.loc22_18: %I.type = converted %bool.make_type, %I.facet [concrete = constants.%I.facet.e8a]
+// CHECK:STDOUT:       %.loc28_18: %I.type = converted %bool.make_type, %I.facet [concrete = constants.%I.facet.e8a]
 // CHECK:STDOUT:       %C: type = class_type @C, @C(constants.%I.type, constants.%I.facet.e8a) [concrete = constants.%C.7db]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %c: %C.7db = bind_name c, %c.param
@@ -164,16 +177,16 @@ impl i32 as I {
 // CHECK:STDOUT:   .C = <poisoned>
 // CHECK:STDOUT:   .I = <poisoned>
 // CHECK:STDOUT:   .F = %F.decl
-// CHECK:STDOUT:   witness = file.%I.impl_witness.loc18
+// CHECK:STDOUT:   witness = file.%I.impl_witness.loc24
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl.a9a: %i32 as %I.ref {
-// CHECK:STDOUT:   %F.decl: %F.type.066 = fn_decl @F.3 [concrete = constants.%F.9ec] {
+// CHECK:STDOUT:   %F.decl.loc39_18.1: %F.type.066a53.1 = fn_decl @F.3 [concrete = constants.%F.9ec58f.1] {
 // CHECK:STDOUT:     %c.patt: %pattern_type.52b = binding_pattern c [concrete]
 // CHECK:STDOUT:     %c.param_patt: %pattern_type.52b = value_param_pattern %c.patt, call_param0 [concrete]
 // CHECK:STDOUT:   } {
 // CHECK:STDOUT:     %c.param: %C.6fb = value_param call_param0
-// CHECK:STDOUT:     %.loc33: type = splice_block %C [concrete = constants.%C.6fb] {
+// CHECK:STDOUT:     %.loc39: type = splice_block %C [concrete = constants.%C.6fb] {
 // CHECK:STDOUT:       %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic]
 // CHECK:STDOUT:       %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:       %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
@@ -181,17 +194,24 @@ impl i32 as I {
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %c: %C.6fb = bind_name c, %c.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc39_18.2: %F.type.066a53.2 = fn_decl @F.4 [concrete = constants.%F.9ec58f.2] {
+// CHECK:STDOUT:     %c.patt: %pattern_type.c65 = binding_pattern c [concrete]
+// CHECK:STDOUT:     %c.param_patt: %pattern_type.c65 = value_param_pattern %c.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %c.param: %C.d88 = value_param call_param0
+// CHECK:STDOUT:     %c: %C.d88 = bind_name c, %c.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .C = <poisoned>
-// CHECK:STDOUT:   .F = %F.decl
-// CHECK:STDOUT:   witness = file.%I.impl_witness.loc25
+// CHECK:STDOUT:   .F = %F.decl.loc39_18.1
+// CHECK:STDOUT:   witness = file.%I.impl_witness.loc31
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic class @C(%T.loc11_9.1: type, %X.loc11_19.1: @C.%T.loc11_9.2 (%T)) {
 // CHECK:STDOUT:   %T.loc11_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc11_9.2 (constants.%T)]
 // CHECK:STDOUT:   %X.loc11_19.2: @C.%T.loc11_9.2 (%T) = bind_symbolic_name X, 1 [symbolic = %X.loc11_19.2 (constants.%X)]
-// CHECK:STDOUT:   %pattern_type: type = pattern_type %T.loc11_9.2 [symbolic = %pattern_type (constants.%pattern_type.7dc)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %T.loc11_9.2 [symbolic = %pattern_type (constants.%pattern_type.7dcd0a.1)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:
@@ -206,32 +226,40 @@ impl i32 as I {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
-// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
-// CHECK:STDOUT:   %C.loc15_17.1: type = class_type @C, @C(constants.%I.type, %Self) [symbolic = %C.loc15_17.1 (constants.%C.dbb)]
-// CHECK:STDOUT:   %pattern_type: type = pattern_type %C.loc15_17.1 [symbolic = %pattern_type (constants.%pattern_type.4fb)]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self.826)]
+// CHECK:STDOUT:   %C.loc21_17.1: type = class_type @C, @C(constants.%I.type, %Self) [symbolic = %C.loc21_17.1 (constants.%C.dbb)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %C.loc21_17.1 [symbolic = %pattern_type (constants.%pattern_type.4fb)]
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn(%c.param: @F.1.%C.loc15_17.1 (%C.dbb));
+// CHECK:STDOUT:   fn(%c.param: @F.1.%C.loc21_17.1 (%C.dbb));
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.2(%c.param: %C.7db);
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F.3(%c.param: %C.6fb);
 // CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.4(%c.param: %C.d88) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %c.ref: %C.d88 = name_ref c, %c.param
+// CHECK:STDOUT:   %.loc21: %C.6fb = converted %c.ref, <error> [concrete = <error>]
+// CHECK:STDOUT:   %F.call: init %empty_tuple.type = call @impl.a9a.%F.decl.loc39_18.1(<error>)
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @C(constants.%T, constants.%X) {
 // CHECK:STDOUT:   %T.loc11_9.2 => constants.%T
 // CHECK:STDOUT:   %X.loc11_19.2 => constants.%X
-// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.7dc
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.7dcd0a.1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @C(constants.%I.type, constants.%Self) {
+// CHECK:STDOUT: specific @C(constants.%I.type, constants.%Self.826) {
 // CHECK:STDOUT:   %T.loc11_9.2 => constants.%I.type
-// CHECK:STDOUT:   %X.loc11_19.2 => constants.%Self
+// CHECK:STDOUT:   %X.loc11_19.2 => constants.%Self.826
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.2b5
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%Self) {
-// CHECK:STDOUT:   %Self => constants.%Self
-// CHECK:STDOUT:   %C.loc15_17.1 => constants.%C.dbb
+// CHECK:STDOUT: specific @F.1(constants.%Self.826) {
+// CHECK:STDOUT:   %Self => constants.%Self.826
+// CHECK:STDOUT:   %C.loc21_17.1 => constants.%C.dbb
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.4fb
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -243,7 +271,7 @@ impl i32 as I {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.1(constants.%I.facet.e8a) {
 // CHECK:STDOUT:   %Self => constants.%I.facet.e8a
-// CHECK:STDOUT:   %C.loc15_17.1 => constants.%C.7db
+// CHECK:STDOUT:   %C.loc21_17.1 => constants.%C.7db
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.225
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -251,17 +279,21 @@ impl i32 as I {
 // CHECK:STDOUT:   %T.loc11_9.2 => type
 // CHECK:STDOUT:   %X.loc11_19.2 => constants.%i32
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.98f
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%I.facet.8b2) {
-// CHECK:STDOUT:   %Self => constants.%I.facet.8b2
-// CHECK:STDOUT:   %C.loc15_17.1 => constants.%C.835
-// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.023
+// CHECK:STDOUT: specific @F.1(constants.%I.facet.118) {
+// CHECK:STDOUT:   %Self => constants.%I.facet.118
+// CHECK:STDOUT:   %C.loc21_17.1 => constants.%C.d88
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c65
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @C(constants.%I.type, constants.%I.facet.8b2) {
+// CHECK:STDOUT: specific @C(constants.%I.type, constants.%I.facet.118) {
 // CHECK:STDOUT:   %T.loc11_9.2 => constants.%I.type
-// CHECK:STDOUT:   %X.loc11_19.2 => constants.%I.facet.8b2
+// CHECK:STDOUT:   %X.loc11_19.2 => constants.%I.facet.118
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.2b5
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1843 - 0
toolchain/check/testdata/impl/no_prelude/impl_thunk.carbon

@@ -0,0 +1,1843 @@
+// 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
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/no_prelude/impl_thunk.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/impl_thunk.carbon
+
+// --- fail_todo_param_name_differs.carbon
+
+library "[[@TEST_NAME]]";
+
+// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+3]]:20: error: parameter has incomplete type `C` in function definition [IncompleteTypeInFunctionParam]
+// CHECK:STDERR: interface I { fn F(x: Self); }
+// CHECK:STDERR:                    ^~~~~~~
+interface I { fn F(x: Self); }
+
+// TODO: This currently uses a thunk due to the parameter name mismatch, but shouldn't!
+// TODO: This then fails because we attempt to build the thunk before `C` is complete.
+// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+3]]:1: note: class is incomplete within its definition [ClassIncompleteWithinDefinition]
+// CHECK:STDERR: class C {
+// CHECK:STDERR: ^~~~~~~~~
+class C {
+  impl as I {
+    // CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+17]]:5: note: while building thunk calling this function [ThunkCallee]
+    // CHECK:STDERR:     fn F(not_x: C);
+    // CHECK:STDERR:     ^~~~~~~~~~~~~~~
+    // CHECK:STDERR:
+    // CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-13]]:20: error: forming value of incomplete type `C` [IncompleteTypeInValueConversion]
+    // CHECK:STDERR: interface I { fn F(x: Self); }
+    // CHECK:STDERR:                    ^~~~~~~
+    // CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-9]]:1: note: class is incomplete within its definition [ClassIncompleteWithinDefinition]
+    // CHECK:STDERR: class C {
+    // CHECK:STDERR: ^~~~~~~~~
+    // CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+7]]:10: note: initializing function parameter [InCallToFunctionParam]
+    // CHECK:STDERR:     fn F(not_x: C);
+    // CHECK:STDERR:          ^~~~~~~~
+    // CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-22]]:15: note: while building thunk to match the signature of this function [ThunkSignature]
+    // CHECK:STDERR: interface I { fn F(x: Self); }
+    // CHECK:STDERR:               ^~~~~~~~~~~~~~
+    // CHECK:STDERR:
+    fn F(not_x: C);
+  }
+}
+
+// --- struct_conversion.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  fn F(x: {.a: (), .b: {}}) -> {.c: (), .d: {}};
+}
+
+impl () as I {
+  fn F(y: {.b: {}, .a: ()}) -> {.d: {}, .c: ()};
+}
+
+// --- inheritance_conversion.carbon
+
+library "[[@TEST_NAME]]";
+
+base class A {}
+base class B { extend base: A; }
+class C { extend base: B; }
+
+interface X {
+  fn F[addr self: Self*](other: Self*) -> Self*;
+}
+
+impl B as X {
+  fn F[addr self: A*](other: A*) -> C*;
+}
+
+// --- inheritance_value_conversion.carbon
+
+library "[[@TEST_NAME]]";
+
+base class A {}
+class B { extend base: A; }
+
+interface X {
+  fn F[self: Self](other: Self);
+}
+
+impl B as X {
+  fn F[self: A](other: A);
+}
+
+// --- inheritance_value_conversion_pointer.carbon
+
+library "[[@TEST_NAME]]";
+
+base class A {}
+base class B { extend base: A; }
+class C { extend base: B; }
+
+interface X {
+  fn F[addr self: Self*](other: Self*) -> Self*;
+}
+
+impl B as X {
+  fn F[addr self: A*](other: A*) -> C*;
+}
+
+// --- fail_inheritance_value_conversion_copy_return.carbon
+
+library "[[@TEST_NAME]]";
+
+base class A {}
+class B { extend base: A; }
+
+interface X {
+  fn F() -> Self;
+}
+
+impl A as X {
+  // CHECK:STDERR: fail_inheritance_value_conversion_copy_return.carbon:[[@LINE+7]]:3: error: cannot copy value of type `A` [CopyOfUncopyableType]
+  // CHECK:STDERR:   fn F() -> B;
+  // CHECK:STDERR:   ^~~~~~~~~~~~
+  // CHECK:STDERR: fail_inheritance_value_conversion_copy_return.carbon:[[@LINE-7]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
+  // CHECK:STDERR:   fn F() -> Self;
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  fn F() -> B;
+}
+
+// --- fail_param_type_mismatch.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  // CHECK:STDERR: fail_param_type_mismatch.carbon:[[@LINE+3]]:8: error: `Core.ImplicitAs` implicitly referenced here, but package `Core` not found [CoreNotFound]
+  // CHECK:STDERR:   fn F(a: Self);
+  // CHECK:STDERR:        ^~~~~~~
+  fn F(a: Self);
+}
+
+class A {}
+class B {}
+
+impl A as I {
+  // CHECK:STDERR: fail_param_type_mismatch.carbon:[[@LINE+7]]:8: note: initializing function parameter [InCallToFunctionParam]
+  // CHECK:STDERR:   fn F(a: B);
+  // CHECK:STDERR:        ^~~~
+  // CHECK:STDERR: fail_param_type_mismatch.carbon:[[@LINE-10]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
+  // CHECK:STDERR:   fn F(a: Self);
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  fn F(a: B);
+}
+
+// --- fail_return_mismatch.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  fn F() -> Self;
+}
+
+class A {}
+class B {}
+
+impl A as I {
+  // CHECK:STDERR: fail_return_mismatch.carbon:[[@LINE+7]]:3: error: `Core.ImplicitAs` implicitly referenced here, but package `Core` not found [CoreNotFound]
+  // CHECK:STDERR:   fn F() -> B;
+  // CHECK:STDERR:   ^~~~~~~~~~~~
+  // CHECK:STDERR: fail_return_mismatch.carbon:[[@LINE-10]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
+  // CHECK:STDERR:   fn F() -> Self;
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  fn F() -> B;
+}
+
+// --- return_empty_tuple_mismatch_allowed.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  fn HasReturn() -> Self;
+  fn NoReturn();
+  fn EmptyTupleReturn() -> ();
+}
+
+impl () as I {
+  // OK, can `return HasReturn();` in thunk.
+  fn HasReturn();
+
+  // OK, exact match.
+  fn NoReturn();
+
+  // OK, same as `HasReturn`.
+  fn EmptyTupleReturn();
+}
+
+// --- fail_return_empty_tuple_mismatch.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  fn NoReturn();
+}
+
+impl () as I {
+  // TODO: The proposal says to reject this. But should we really do so?
+  // CHECK:STDERR: fail_return_empty_tuple_mismatch.carbon:[[@LINE+7]]:3: error: function redeclaration differs because return type is `()` [FunctionRedeclReturnTypeDiffers]
+  // CHECK:STDERR:   fn NoReturn() -> ();
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_return_empty_tuple_mismatch.carbon:[[@LINE-8]]:3: note: previously declared with no return type [FunctionRedeclReturnTypePreviousNoReturn]
+  // CHECK:STDERR:   fn NoReturn();
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  fn NoReturn() -> ();
+}
+
+class C {}
+
+impl C as I {
+  // CHECK:STDERR: fail_return_empty_tuple_mismatch.carbon:[[@LINE+7]]:3: error: function redeclaration differs because return type is `C` [FunctionRedeclReturnTypeDiffers]
+  // CHECK:STDERR:   fn NoReturn() -> C;
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_return_empty_tuple_mismatch.carbon:[[@LINE-21]]:3: note: previously declared with no return type [FunctionRedeclReturnTypePreviousNoReturn]
+  // CHECK:STDERR:   fn NoReturn();
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  fn NoReturn() -> C;
+}
+
+// CHECK:STDOUT: --- fail_todo_param_name_differs.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.6de: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %F.type.cf0: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %F.bc6: %F.type.cf0 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness @C.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.c48: type = pattern_type %C [concrete]
+// CHECK:STDOUT:   %F.type.f3605c.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.4c32b3.1: %F.type.f3605c.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet: %I.type = facet_value %C, (%I.impl_witness) [concrete]
+// CHECK:STDOUT:   %F.type.f3605c.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.4c32b3.2: %F.type.f3605c.2 = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
+// CHECK:STDOUT:     %x.patt: @F.1.%pattern_type (%pattern_type.6de) = binding_pattern x [concrete]
+// CHECK:STDOUT:     %x.param_patt: @F.1.%pattern_type (%pattern_type.6de) = value_param_pattern %x.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %x.param: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type) = value_param call_param0
+// CHECK:STDOUT:     %.loc7_23.1: type = splice_block %.loc7_23.2 [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)] {
+// CHECK:STDOUT:       %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc7_23.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc7_23.2: type = converted %Self.ref, %Self.as_type.loc7_23.2 [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %x: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type) = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %Self.ref as %I.ref {
+// CHECK:STDOUT:   %F.decl.loc33_19.1: %F.type.f3605c.1 = fn_decl @F.2 [concrete = constants.%F.4c32b3.1] {
+// CHECK:STDOUT:     %not_x.patt: %pattern_type.c48 = binding_pattern not_x [concrete]
+// CHECK:STDOUT:     %not_x.param_patt: %pattern_type.c48 = value_param_pattern %not_x.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %not_x.param: %C = value_param call_param0
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %not_x: %C = bind_name not_x, %not_x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc33_19.2: %F.type.f3605c.2 = fn_decl @F.3 [concrete = constants.%F.4c32b3.2] {
+// CHECK:STDOUT:     %x.patt: %pattern_type.c48 = binding_pattern x [concrete]
+// CHECK:STDOUT:     %x.param_patt: %pattern_type.c48 = value_param_pattern %x.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %x.param: %C = value_param call_param0
+// CHECK:STDOUT:     %x: %C = bind_name x, %x.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .C = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc33_19.1
+// CHECK:STDOUT:   witness = @C.%I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%C [concrete = constants.%C]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (@impl.%F.decl.loc33_19.2), @impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .I = <poisoned>
+// CHECK:STDOUT:   .C = <poisoned>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc7_23.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc7_23.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(%x.param: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type));
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%not_x.param: %C);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%x.param: %C) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %C = name_ref x, %x.param
+// CHECK:STDOUT:   %F.call: init %empty_tuple.type = call @impl.%F.decl.loc33_19.1(<error>)
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc7_23.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.6de
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%I.facet) {
+// CHECK:STDOUT:   %Self => constants.%I.facet
+// CHECK:STDOUT:   %Self.as_type.loc7_23.1 => constants.%C
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c48
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- struct_conversion.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %struct_type.a.b.391: type = struct_type {.a: %empty_tuple.type, .b: %empty_struct_type} [concrete]
+// CHECK:STDOUT:   %pattern_type.bec: type = pattern_type %struct_type.a.b.391 [concrete]
+// CHECK:STDOUT:   %struct_type.c.d.15a: type = struct_type {.c: %empty_tuple.type, .d: %empty_struct_type} [concrete]
+// CHECK:STDOUT:   %pattern_type.d63: type = pattern_type %struct_type.c.d.15a [concrete]
+// CHECK:STDOUT:   %F.type.cf0: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.bc6: %F.type.cf0 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness file.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %struct_type.b.a.40c: type = struct_type {.b: %empty_struct_type, .a: %empty_tuple.type} [concrete]
+// CHECK:STDOUT:   %pattern_type.231: type = pattern_type %struct_type.b.a.40c [concrete]
+// CHECK:STDOUT:   %struct_type.d.c.b36: type = struct_type {.d: %empty_struct_type, .c: %empty_tuple.type} [concrete]
+// CHECK:STDOUT:   %pattern_type.844: type = pattern_type %struct_type.d.c.b36 [concrete]
+// CHECK:STDOUT:   %F.type.39e918.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.c04b92.1: %F.type.39e918.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet: %I.type = facet_value %empty_tuple.type, (%I.impl_witness) [concrete]
+// CHECK:STDOUT:   %F.type.39e918.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.c04b92.2: %F.type.39e918.2 = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
+// CHECK:STDOUT:   %struct: %struct_type.c.d.15a = struct_value (%empty_tuple, %empty_struct) [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %.loc8_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc8_7.2: type = converted %.loc8_7.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (@impl.%F.decl.loc9_48.2), @impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
+// CHECK:STDOUT:     %x.patt: %pattern_type.bec = binding_pattern x [concrete]
+// CHECK:STDOUT:     %x.param_patt: %pattern_type.bec = value_param_pattern %x.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.d63 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.d63 = out_param_pattern %return.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc5_38.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc5_38.2: type = converted %.loc5_38.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %.loc5_46.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc5_46.2: type = converted %.loc5_46.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %struct_type.c.d: type = struct_type {.c: %empty_tuple.type, .d: %empty_struct_type} [concrete = constants.%struct_type.c.d.15a]
+// CHECK:STDOUT:     %x.param: %struct_type.a.b.391 = value_param call_param0
+// CHECK:STDOUT:     %.loc5_26: type = splice_block %struct_type.a.b [concrete = constants.%struct_type.a.b.391] {
+// CHECK:STDOUT:       %.loc5_17.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:       %.loc5_17.2: type = converted %.loc5_17.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:       %.loc5_25.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:       %.loc5_25.2: type = converted %.loc5_25.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:       %struct_type.a.b: type = struct_type {.a: %empty_tuple.type, .b: %empty_struct_type} [concrete = constants.%struct_type.a.b.391]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %x: %struct_type.a.b.391 = bind_name x, %x.param
+// CHECK:STDOUT:     %return.param: ref %struct_type.c.d.15a = out_param call_param1
+// CHECK:STDOUT:     %return: ref %struct_type.c.d.15a = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %.loc8_7.2 as %I.ref {
+// CHECK:STDOUT:   %F.decl.loc9_48.1: %F.type.39e918.1 = fn_decl @F.2 [concrete = constants.%F.c04b92.1] {
+// CHECK:STDOUT:     %y.patt: %pattern_type.231 = binding_pattern y [concrete]
+// CHECK:STDOUT:     %y.param_patt: %pattern_type.231 = value_param_pattern %y.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.844 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.844 = out_param_pattern %return.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc9_38.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc9_38.2: type = converted %.loc9_38.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc9_46.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc9_46.2: type = converted %.loc9_46.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %struct_type.d.c: type = struct_type {.d: %empty_struct_type, .c: %empty_tuple.type} [concrete = constants.%struct_type.d.c.b36]
+// CHECK:STDOUT:     %y.param: %struct_type.b.a.40c = value_param call_param0
+// CHECK:STDOUT:     %.loc9_26: type = splice_block %struct_type.b.a [concrete = constants.%struct_type.b.a.40c] {
+// CHECK:STDOUT:       %.loc9_17.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:       %.loc9_17.2: type = converted %.loc9_17.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:       %.loc9_25.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:       %.loc9_25.2: type = converted %.loc9_25.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:       %struct_type.b.a: type = struct_type {.b: %empty_struct_type, .a: %empty_tuple.type} [concrete = constants.%struct_type.b.a.40c]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %y: %struct_type.b.a.40c = bind_name y, %y.param
+// CHECK:STDOUT:     %return.param: ref %struct_type.d.c.b36 = out_param call_param1
+// CHECK:STDOUT:     %return: ref %struct_type.d.c.b36 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc9_48.2: %F.type.39e918.2 = fn_decl @F.3 [concrete = constants.%F.c04b92.2] {
+// CHECK:STDOUT:     %x.patt: %pattern_type.bec = binding_pattern x [concrete]
+// CHECK:STDOUT:     %x.param_patt: %pattern_type.bec = value_param_pattern %x.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.d63 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.d63 = out_param_pattern %return.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %x.param: %struct_type.a.b.391 = value_param call_param0
+// CHECK:STDOUT:     %x: %struct_type.a.b.391 = bind_name x, %x.param
+// CHECK:STDOUT:     %return.param: ref %struct_type.c.d.15a = out_param call_param1
+// CHECK:STDOUT:     %return: ref %struct_type.c.d.15a = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .F = %F.decl.loc9_48.1
+// CHECK:STDOUT:   witness = file.%I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   fn(%x.param: %struct_type.a.b.391) -> %return.param: %struct_type.c.d.15a;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%y.param: %struct_type.b.a.40c) -> %return.param: %struct_type.d.c.b36;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%x.param: %struct_type.a.b.391) -> %return.param: %struct_type.c.d.15a {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %struct_type.a.b.391 = name_ref x, %x.param
+// CHECK:STDOUT:   %.loc9_48.1: ref %struct_type.d.c.b36 = temporary_storage
+// CHECK:STDOUT:   %.loc5_9.1: %empty_struct_type = struct_access %x.ref, element1
+// CHECK:STDOUT:   %.loc5_9.2: %empty_tuple.type = struct_access %x.ref, element0
+// CHECK:STDOUT:   %struct: %struct_type.b.a.40c = struct_value (%.loc5_9.1, %.loc5_9.2)
+// CHECK:STDOUT:   %.loc5_9.3: %struct_type.b.a.40c = converted %x.ref, %struct
+// CHECK:STDOUT:   %F.call: init %struct_type.d.c.b36 = call @impl.%F.decl.loc9_48.1(%.loc5_9.3) to %.loc9_48.1
+// CHECK:STDOUT:   %.loc9_48.2: ref %struct_type.d.c.b36 = temporary %.loc9_48.1, %F.call
+// CHECK:STDOUT:   %.loc9_48.3: ref %empty_tuple.type = struct_access %.loc9_48.2, element1
+// CHECK:STDOUT:   %.loc9_48.4: ref %empty_tuple.type = struct_access %return, element1
+// CHECK:STDOUT:   %.loc9_48.5: init %empty_tuple.type = tuple_init () to %.loc9_48.4 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc9_48.6: init %empty_tuple.type = converted %.loc9_48.3, %.loc9_48.5 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc9_48.7: ref %empty_struct_type = struct_access %.loc9_48.2, element0
+// CHECK:STDOUT:   %.loc9_48.8: ref %empty_struct_type = struct_access %return, element0
+// CHECK:STDOUT:   %.loc9_48.9: init %empty_struct_type = struct_init () to %.loc9_48.8 [concrete = constants.%empty_struct]
+// CHECK:STDOUT:   %.loc9_48.10: init %empty_struct_type = converted %.loc9_48.7, %.loc9_48.9 [concrete = constants.%empty_struct]
+// CHECK:STDOUT:   %.loc9_48.11: init %struct_type.c.d.15a = struct_init (%.loc9_48.6, %.loc9_48.10) to %return [concrete = constants.%struct]
+// CHECK:STDOUT:   %.loc9_48.12: init %struct_type.c.d.15a = converted %F.call, %.loc9_48.11 [concrete = constants.%struct]
+// CHECK:STDOUT:   return %.loc9_48.12 to %return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%I.facet) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- inheritance_conversion.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %B.elem: type = unbound_element_type %B, %A [concrete]
+// CHECK:STDOUT:   %struct_type.base.953: type = struct_type {.base: %A} [concrete]
+// CHECK:STDOUT:   %complete_type.020: <witness> = complete_type_witness %struct_type.base.953 [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %C.elem: type = unbound_element_type %C, %B [concrete]
+// CHECK:STDOUT:   %struct_type.base.0ff: type = struct_type {.base: %B} [concrete]
+// CHECK:STDOUT:   %complete_type.98e: <witness> = complete_type_witness %struct_type.base.0ff [concrete]
+// CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %ptr.d06: type = ptr_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %pattern_type.4c5: type = pattern_type %ptr.d06 [symbolic]
+// CHECK:STDOUT:   %pattern_type.f6d: type = pattern_type auto [concrete]
+// CHECK:STDOUT:   %F.type.594: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.b69: %F.type.594 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.assoc_type: type = assoc_entity_type @X [concrete]
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, @X.%F.decl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness file.%X.impl_witness_table [concrete]
+// CHECK:STDOUT:   %ptr.6db: type = ptr_type %A [concrete]
+// CHECK:STDOUT:   %pattern_type.5f8: type = pattern_type %ptr.6db [concrete]
+// CHECK:STDOUT:   %ptr.019: type = ptr_type %C [concrete]
+// CHECK:STDOUT:   %pattern_type.44a: type = pattern_type %ptr.019 [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.5161e9.1: %F.type.f1b0b1.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.facet: %X.type = facet_value %B, (%X.impl_witness) [concrete]
+// CHECK:STDOUT:   %ptr.e79: type = ptr_type %B [concrete]
+// CHECK:STDOUT:   %pattern_type.960: type = pattern_type %ptr.e79 [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.5161e9.2: %F.type.f1b0b1.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .X = %X.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   %X.decl: type = interface_decl @X [concrete = constants.%X.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %X.impl_witness_table = impl_witness_table (@impl.%F.decl.loc13_39.2), @impl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness %X.impl_witness_table [concrete = constants.%X.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @X {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.594 = fn_decl @F.1 [concrete = constants.%F.b69] {
+// CHECK:STDOUT:     %self.patt: @F.1.%pattern_type (%pattern_type.4c5) = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc9_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: @F.1.%pattern_type (%pattern_type.4c5) = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: @F.1.%pattern_type (%pattern_type.4c5) = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref.loc9_43: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %Self.as_type.loc9_47: type = facet_access_type %Self.ref.loc9_43 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %.loc9_47: type = converted %Self.ref.loc9_43, %Self.as_type.loc9_47 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %ptr.loc9_47: type = ptr_type %.loc9_47 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     %self.param: @F.1.%ptr.loc9_23.1 (%ptr.d06) = value_param call_param0
+// CHECK:STDOUT:     %.loc9_23.1: type = splice_block %ptr.loc9_23.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)] {
+// CHECK:STDOUT:       %Self.ref.loc9_19: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc9_23.2: type = facet_access_type %Self.ref.loc9_19 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc9_23.2: type = converted %Self.ref.loc9_19, %Self.as_type.loc9_23.2 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %ptr.loc9_23.2: type = ptr_type %.loc9_23.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %self: @F.1.%ptr.loc9_23.1 (%ptr.d06) = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: @F.1.%ptr.loc9_23.1 (%ptr.d06) = value_param call_param1
+// CHECK:STDOUT:     %.loc9_37.1: type = splice_block %ptr.loc9_37 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)] {
+// CHECK:STDOUT:       %Self.ref.loc9_33: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc9_37: type = facet_access_type %Self.ref.loc9_33 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc9_37.2: type = converted %Self.ref.loc9_33, %Self.as_type.loc9_37 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %ptr.loc9_37: type = ptr_type %.loc9_37.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %other: @F.1.%ptr.loc9_23.1 (%ptr.d06) = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref @F.1.%ptr.loc9_23.1 (%ptr.d06) = out_param call_param2
+// CHECK:STDOUT:     %return: ref @F.1.%ptr.loc9_23.1 (%ptr.d06) = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %B.ref as %X.ref {
+// CHECK:STDOUT:   %F.decl.loc13_39.1: %F.type.f1b0b1.1 = fn_decl @F.2 [concrete = constants.%F.5161e9.1] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.5f8 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.5f8 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc13_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.5f8 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.5f8 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.44a = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.44a = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %ptr.loc13_38: type = ptr_type %C.ref [concrete = constants.%ptr.019]
+// CHECK:STDOUT:     %self.param: %ptr.6db = value_param call_param0
+// CHECK:STDOUT:     %.loc13_20: type = splice_block %ptr.loc13_20 [concrete = constants.%ptr.6db] {
+// CHECK:STDOUT:       %A.ref.loc13_19: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:       %ptr.loc13_20: type = ptr_type %A.ref.loc13_19 [concrete = constants.%ptr.6db]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %self: %ptr.6db = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %ptr.6db = value_param call_param1
+// CHECK:STDOUT:     %.loc13_31: type = splice_block %ptr.loc13_31 [concrete = constants.%ptr.6db] {
+// CHECK:STDOUT:       %A.ref.loc13_30: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:       %ptr.loc13_31: type = ptr_type %A.ref.loc13_30 [concrete = constants.%ptr.6db]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %other: %ptr.6db = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref %ptr.019 = out_param call_param2
+// CHECK:STDOUT:     %return: ref %ptr.019 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc13_39.2: %F.type.f1b0b1.2 = fn_decl @F.3 [concrete = constants.%F.5161e9.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.960 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.960 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc9_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.960 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.960 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.960 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.960 = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %ptr.e79 = value_param call_param0
+// CHECK:STDOUT:     %self: %ptr.e79 = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %ptr.e79 = value_param call_param1
+// CHECK:STDOUT:     %other: %ptr.e79 = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref %ptr.e79 = out_param call_param2
+// CHECK:STDOUT:     %return: ref %ptr.e79 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .C = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc13_39.1
+// CHECK:STDOUT:   witness = file.%X.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:   %.loc5: %B.elem = base_decl %A.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %A} [concrete = constants.%struct_type.base.953]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.020]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .base = %.loc5
+// CHECK:STDOUT:   extend %A.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:   %.loc6: %C.elem = base_decl %B.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %B} [concrete = constants.%struct_type.base.0ff]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.98e]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .B = <poisoned>
+// CHECK:STDOUT:   .base = %.loc6
+// CHECK:STDOUT:   extend %B.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@X.%Self: %X.type) {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %ptr.loc9_23.1: type = ptr_type %Self.as_type.loc9_23.1 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %ptr.loc9_23.1 [symbolic = %pattern_type (constants.%pattern_type.4c5)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(%self.param: @F.1.%ptr.loc9_23.1 (%ptr.d06), %other.param: @F.1.%ptr.loc9_23.1 (%ptr.d06)) -> @F.1.%ptr.loc9_23.1 (%ptr.d06);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%self.param: %ptr.6db, %other.param: %ptr.6db) -> %ptr.019;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%self.param: %ptr.e79, %other.param: %ptr.e79) -> %ptr.e79 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %ptr.e79 = name_ref self, %self.param
+// CHECK:STDOUT:   %.loc9_17.1: ref %B = deref %self.ref
+// CHECK:STDOUT:   %F.bound: <bound method> = bound_method %.loc9_17.1, @impl.%F.decl.loc13_39.1
+// CHECK:STDOUT:   %other.ref: %ptr.e79 = name_ref other, %other.param
+// CHECK:STDOUT:   %addr.loc9_17.1: %ptr.e79 = addr_of %.loc9_17.1
+// CHECK:STDOUT:   %.loc9_17.2: ref %B = deref %addr.loc9_17.1
+// CHECK:STDOUT:   %.loc9_17.3: ref %A = class_element_access %.loc9_17.2, element0
+// CHECK:STDOUT:   %addr.loc9_17.2: %ptr.6db = addr_of %.loc9_17.3
+// CHECK:STDOUT:   %.loc9_17.4: %ptr.6db = converted %addr.loc9_17.1, %addr.loc9_17.2
+// CHECK:STDOUT:   %.loc9_31.1: ref %B = deref %other.ref
+// CHECK:STDOUT:   %.loc9_31.2: ref %A = class_element_access %.loc9_31.1, element0
+// CHECK:STDOUT:   %addr.loc9_31: %ptr.6db = addr_of %.loc9_31.2
+// CHECK:STDOUT:   %.loc9_31.3: %ptr.6db = converted %other.ref, %addr.loc9_31
+// CHECK:STDOUT:   %F.call: init %ptr.019 = call %F.bound(%.loc9_17.4, %.loc9_31.3)
+// CHECK:STDOUT:   %.loc13_39.1: %ptr.019 = value_of_initializer %F.call
+// CHECK:STDOUT:   %.loc13_39.2: %ptr.019 = converted %F.call, %.loc13_39.1
+// CHECK:STDOUT:   %.loc13_39.3: ref %C = deref %.loc13_39.2
+// CHECK:STDOUT:   %.loc13_39.4: ref %B = class_element_access %.loc13_39.3, element0
+// CHECK:STDOUT:   %addr.loc13: %ptr.e79 = addr_of %.loc13_39.4
+// CHECK:STDOUT:   %.loc13_39.5: %ptr.e79 = converted %F.call, %addr.loc13
+// CHECK:STDOUT:   return %.loc13_39.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %ptr.loc9_23.1 => constants.%ptr.d06
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.4c5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%X.facet) {
+// CHECK:STDOUT:   %Self => constants.%X.facet
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1 => constants.%B
+// CHECK:STDOUT:   %ptr.loc9_23.1 => constants.%ptr.e79
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.960
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- inheritance_value_conversion.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %B.elem: type = unbound_element_type %B, %A [concrete]
+// CHECK:STDOUT:   %struct_type.base.953: type = struct_type {.base: %A} [concrete]
+// CHECK:STDOUT:   %complete_type.020: <witness> = complete_type_witness %struct_type.base.953 [concrete]
+// CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.331: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %F.type.594: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.b69: %F.type.594 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.assoc_type: type = assoc_entity_type @X [concrete]
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, @X.%F.decl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness file.%X.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.c10: type = pattern_type %A [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.5161e9.1: %F.type.f1b0b1.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.facet: %X.type = facet_value %B, (%X.impl_witness) [concrete]
+// CHECK:STDOUT:   %pattern_type.049: type = pattern_type %B [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.5161e9.2: %F.type.f1b0b1.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:     .X = %X.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   %X.decl: type = interface_decl @X [concrete = constants.%X.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %X.impl_witness_table = impl_witness_table (@impl.%F.decl.loc12_26.2), @impl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness %X.impl_witness_table [concrete = constants.%X.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @X {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.594 = fn_decl @F.1 [concrete = constants.%F.b69] {
+// CHECK:STDOUT:     %self.patt: @F.1.%pattern_type (%pattern_type.331) = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: @F.1.%pattern_type (%pattern_type.331) = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %other.patt: @F.1.%pattern_type (%pattern_type.331) = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: @F.1.%pattern_type (%pattern_type.331) = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type) = value_param call_param0
+// CHECK:STDOUT:     %.loc8_14.1: type = splice_block %.loc8_14.2 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)] {
+// CHECK:STDOUT:       %Self.ref.loc8_14: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc8_14.2: type = facet_access_type %Self.ref.loc8_14 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc8_14.2: type = converted %Self.ref.loc8_14, %Self.as_type.loc8_14.2 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %self: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type) = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type) = value_param call_param1
+// CHECK:STDOUT:     %.loc8_27.1: type = splice_block %.loc8_27.2 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)] {
+// CHECK:STDOUT:       %Self.ref.loc8_27: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc8_27: type = facet_access_type %Self.ref.loc8_27 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc8_27.2: type = converted %Self.ref.loc8_27, %Self.as_type.loc8_27 [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %other: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type) = bind_name other, %other.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %B.ref as %X.ref {
+// CHECK:STDOUT:   %F.decl.loc12_26.1: %F.type.f1b0b1.1 = fn_decl @F.2 [concrete = constants.%F.5161e9.1] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.c10 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.c10 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.c10 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.c10 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %A = value_param call_param0
+// CHECK:STDOUT:     %A.ref.loc12_14: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:     %self: %A = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %A = value_param call_param1
+// CHECK:STDOUT:     %A.ref.loc12_24: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:     %other: %A = bind_name other, %other.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc12_26.2: %F.type.f1b0b1.2 = fn_decl @F.3 [concrete = constants.%F.5161e9.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.049 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.049 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.049 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.049 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %B = value_param call_param0
+// CHECK:STDOUT:     %self: %B = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %B = value_param call_param1
+// CHECK:STDOUT:     %other: %B = bind_name other, %other.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc12_26.1
+// CHECK:STDOUT:   witness = file.%X.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:   %.loc5: %B.elem = base_decl %A.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %A} [concrete = constants.%struct_type.base.953]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.020]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .base = %.loc5
+// CHECK:STDOUT:   extend %A.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@X.%Self: %X.type) {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc8_14.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc8_14.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc8_14.1 [symbolic = %pattern_type (constants.%pattern_type.331)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(%self.param: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type), %other.param: @F.1.%Self.as_type.loc8_14.1 (%Self.as_type));
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%self.param: %A, %other.param: %A);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%self.param: %B, %other.param: %B) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %B = name_ref self, %self.param
+// CHECK:STDOUT:   %F.bound: <bound method> = bound_method %self.ref, @impl.%F.decl.loc12_26.1
+// CHECK:STDOUT:   %other.ref: %B = name_ref other, %other.param
+// CHECK:STDOUT:   %.loc8_12.1: ref %A = class_element_access %self.ref, element0
+// CHECK:STDOUT:   %.loc8_12.2: ref %A = converted %self.ref, %.loc8_12.1
+// CHECK:STDOUT:   %.loc8_12.3: %A = bind_value %.loc8_12.2
+// CHECK:STDOUT:   %.loc8_25.1: ref %A = class_element_access %other.ref, element0
+// CHECK:STDOUT:   %.loc8_25.2: ref %A = converted %other.ref, %.loc8_25.1
+// CHECK:STDOUT:   %.loc8_25.3: %A = bind_value %.loc8_25.2
+// CHECK:STDOUT:   %F.call: init %empty_tuple.type = call %F.bound(%.loc8_12.3, %.loc8_25.3)
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc8_14.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.331
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%X.facet) {
+// CHECK:STDOUT:   %Self => constants.%X.facet
+// CHECK:STDOUT:   %Self.as_type.loc8_14.1 => constants.%B
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.049
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- inheritance_value_conversion_pointer.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %B.elem: type = unbound_element_type %B, %A [concrete]
+// CHECK:STDOUT:   %struct_type.base.953: type = struct_type {.base: %A} [concrete]
+// CHECK:STDOUT:   %complete_type.020: <witness> = complete_type_witness %struct_type.base.953 [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %C.elem: type = unbound_element_type %C, %B [concrete]
+// CHECK:STDOUT:   %struct_type.base.0ff: type = struct_type {.base: %B} [concrete]
+// CHECK:STDOUT:   %complete_type.98e: <witness> = complete_type_witness %struct_type.base.0ff [concrete]
+// CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %ptr.d06: type = ptr_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %pattern_type.4c5: type = pattern_type %ptr.d06 [symbolic]
+// CHECK:STDOUT:   %pattern_type.f6d: type = pattern_type auto [concrete]
+// CHECK:STDOUT:   %F.type.594: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.b69: %F.type.594 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.assoc_type: type = assoc_entity_type @X [concrete]
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, @X.%F.decl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness file.%X.impl_witness_table [concrete]
+// CHECK:STDOUT:   %ptr.6db: type = ptr_type %A [concrete]
+// CHECK:STDOUT:   %pattern_type.5f8: type = pattern_type %ptr.6db [concrete]
+// CHECK:STDOUT:   %ptr.019: type = ptr_type %C [concrete]
+// CHECK:STDOUT:   %pattern_type.44a: type = pattern_type %ptr.019 [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.5161e9.1: %F.type.f1b0b1.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.facet: %X.type = facet_value %B, (%X.impl_witness) [concrete]
+// CHECK:STDOUT:   %ptr.e79: type = ptr_type %B [concrete]
+// CHECK:STDOUT:   %pattern_type.960: type = pattern_type %ptr.e79 [concrete]
+// CHECK:STDOUT:   %F.type.f1b0b1.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.5161e9.2: %F.type.f1b0b1.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:     .X = %X.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   %X.decl: type = interface_decl @X [concrete = constants.%X.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %X.impl_witness_table = impl_witness_table (@impl.%F.decl.loc13_39.2), @impl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness %X.impl_witness_table [concrete = constants.%X.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @X {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.594 = fn_decl @F.1 [concrete = constants.%F.b69] {
+// CHECK:STDOUT:     %self.patt: @F.1.%pattern_type (%pattern_type.4c5) = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc9_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: @F.1.%pattern_type (%pattern_type.4c5) = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: @F.1.%pattern_type (%pattern_type.4c5) = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: @F.1.%pattern_type (%pattern_type.4c5) = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref.loc9_43: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %Self.as_type.loc9_47: type = facet_access_type %Self.ref.loc9_43 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %.loc9_47: type = converted %Self.ref.loc9_43, %Self.as_type.loc9_47 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %ptr.loc9_47: type = ptr_type %.loc9_47 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     %self.param: @F.1.%ptr.loc9_23.1 (%ptr.d06) = value_param call_param0
+// CHECK:STDOUT:     %.loc9_23.1: type = splice_block %ptr.loc9_23.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)] {
+// CHECK:STDOUT:       %Self.ref.loc9_19: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc9_23.2: type = facet_access_type %Self.ref.loc9_19 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc9_23.2: type = converted %Self.ref.loc9_19, %Self.as_type.loc9_23.2 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %ptr.loc9_23.2: type = ptr_type %.loc9_23.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %self: @F.1.%ptr.loc9_23.1 (%ptr.d06) = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: @F.1.%ptr.loc9_23.1 (%ptr.d06) = value_param call_param1
+// CHECK:STDOUT:     %.loc9_37.1: type = splice_block %ptr.loc9_37 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)] {
+// CHECK:STDOUT:       %Self.ref.loc9_33: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc9_37: type = facet_access_type %Self.ref.loc9_33 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc9_37.2: type = converted %Self.ref.loc9_33, %Self.as_type.loc9_37 [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %ptr.loc9_37: type = ptr_type %.loc9_37.2 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %other: @F.1.%ptr.loc9_23.1 (%ptr.d06) = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref @F.1.%ptr.loc9_23.1 (%ptr.d06) = out_param call_param2
+// CHECK:STDOUT:     %return: ref @F.1.%ptr.loc9_23.1 (%ptr.d06) = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %B.ref as %X.ref {
+// CHECK:STDOUT:   %F.decl.loc13_39.1: %F.type.f1b0b1.1 = fn_decl @F.2 [concrete = constants.%F.5161e9.1] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.5f8 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.5f8 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc13_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.5f8 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.5f8 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.44a = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.44a = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %ptr.loc13_38: type = ptr_type %C.ref [concrete = constants.%ptr.019]
+// CHECK:STDOUT:     %self.param: %ptr.6db = value_param call_param0
+// CHECK:STDOUT:     %.loc13_20: type = splice_block %ptr.loc13_20 [concrete = constants.%ptr.6db] {
+// CHECK:STDOUT:       %A.ref.loc13_19: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:       %ptr.loc13_20: type = ptr_type %A.ref.loc13_19 [concrete = constants.%ptr.6db]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %self: %ptr.6db = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %ptr.6db = value_param call_param1
+// CHECK:STDOUT:     %.loc13_31: type = splice_block %ptr.loc13_31 [concrete = constants.%ptr.6db] {
+// CHECK:STDOUT:       %A.ref.loc13_30: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:       %ptr.loc13_31: type = ptr_type %A.ref.loc13_30 [concrete = constants.%ptr.6db]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %other: %ptr.6db = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref %ptr.019 = out_param call_param2
+// CHECK:STDOUT:     %return: ref %ptr.019 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc13_39.2: %F.type.f1b0b1.2 = fn_decl @F.3 [concrete = constants.%F.5161e9.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.960 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.960 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.loc9_8: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT:     %other.patt: %pattern_type.960 = binding_pattern other [concrete]
+// CHECK:STDOUT:     %other.param_patt: %pattern_type.960 = value_param_pattern %other.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.960 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.960 = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %ptr.e79 = value_param call_param0
+// CHECK:STDOUT:     %self: %ptr.e79 = bind_name self, %self.param
+// CHECK:STDOUT:     %other.param: %ptr.e79 = value_param call_param1
+// CHECK:STDOUT:     %other: %ptr.e79 = bind_name other, %other.param
+// CHECK:STDOUT:     %return.param: ref %ptr.e79 = out_param call_param2
+// CHECK:STDOUT:     %return: ref %ptr.e79 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .C = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc13_39.1
+// CHECK:STDOUT:   witness = file.%X.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:   %.loc5: %B.elem = base_decl %A.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %A} [concrete = constants.%struct_type.base.953]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.020]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .base = %.loc5
+// CHECK:STDOUT:   extend %A.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:   %.loc6: %C.elem = base_decl %B.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %B} [concrete = constants.%struct_type.base.0ff]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.98e]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .B = <poisoned>
+// CHECK:STDOUT:   .base = %.loc6
+// CHECK:STDOUT:   extend %B.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@X.%Self: %X.type) {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc9_23.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %ptr.loc9_23.1: type = ptr_type %Self.as_type.loc9_23.1 [symbolic = %ptr.loc9_23.1 (constants.%ptr.d06)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %ptr.loc9_23.1 [symbolic = %pattern_type (constants.%pattern_type.4c5)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(%self.param: @F.1.%ptr.loc9_23.1 (%ptr.d06), %other.param: @F.1.%ptr.loc9_23.1 (%ptr.d06)) -> @F.1.%ptr.loc9_23.1 (%ptr.d06);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%self.param: %ptr.6db, %other.param: %ptr.6db) -> %ptr.019;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%self.param: %ptr.e79, %other.param: %ptr.e79) -> %ptr.e79 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %ptr.e79 = name_ref self, %self.param
+// CHECK:STDOUT:   %.loc9_17.1: ref %B = deref %self.ref
+// CHECK:STDOUT:   %F.bound: <bound method> = bound_method %.loc9_17.1, @impl.%F.decl.loc13_39.1
+// CHECK:STDOUT:   %other.ref: %ptr.e79 = name_ref other, %other.param
+// CHECK:STDOUT:   %addr.loc9_17.1: %ptr.e79 = addr_of %.loc9_17.1
+// CHECK:STDOUT:   %.loc9_17.2: ref %B = deref %addr.loc9_17.1
+// CHECK:STDOUT:   %.loc9_17.3: ref %A = class_element_access %.loc9_17.2, element0
+// CHECK:STDOUT:   %addr.loc9_17.2: %ptr.6db = addr_of %.loc9_17.3
+// CHECK:STDOUT:   %.loc9_17.4: %ptr.6db = converted %addr.loc9_17.1, %addr.loc9_17.2
+// CHECK:STDOUT:   %.loc9_31.1: ref %B = deref %other.ref
+// CHECK:STDOUT:   %.loc9_31.2: ref %A = class_element_access %.loc9_31.1, element0
+// CHECK:STDOUT:   %addr.loc9_31: %ptr.6db = addr_of %.loc9_31.2
+// CHECK:STDOUT:   %.loc9_31.3: %ptr.6db = converted %other.ref, %addr.loc9_31
+// CHECK:STDOUT:   %F.call: init %ptr.019 = call %F.bound(%.loc9_17.4, %.loc9_31.3)
+// CHECK:STDOUT:   %.loc13_39.1: %ptr.019 = value_of_initializer %F.call
+// CHECK:STDOUT:   %.loc13_39.2: %ptr.019 = converted %F.call, %.loc13_39.1
+// CHECK:STDOUT:   %.loc13_39.3: ref %C = deref %.loc13_39.2
+// CHECK:STDOUT:   %.loc13_39.4: ref %B = class_element_access %.loc13_39.3, element0
+// CHECK:STDOUT:   %addr.loc13: %ptr.e79 = addr_of %.loc13_39.4
+// CHECK:STDOUT:   %.loc13_39.5: %ptr.e79 = converted %F.call, %addr.loc13
+// CHECK:STDOUT:   return %.loc13_39.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %ptr.loc9_23.1 => constants.%ptr.d06
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.4c5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%X.facet) {
+// CHECK:STDOUT:   %Self => constants.%X.facet
+// CHECK:STDOUT:   %Self.as_type.loc9_23.1 => constants.%B
+// CHECK:STDOUT:   %ptr.loc9_23.1 => constants.%ptr.e79
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.960
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_inheritance_value_conversion_copy_return.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %B.elem: type = unbound_element_type %B, %A [concrete]
+// CHECK:STDOUT:   %struct_type.base.953: type = struct_type {.base: %A} [concrete]
+// CHECK:STDOUT:   %complete_type.020: <witness> = complete_type_witness %struct_type.base.953 [concrete]
+// CHECK:STDOUT:   %X.type: type = facet_type <@X> [concrete]
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.331: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %F.type.594: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.b69: %F.type.594 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.assoc_type: type = assoc_entity_type @X [concrete]
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, @X.%F.decl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness file.%X.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.049: type = pattern_type %B [concrete]
+// CHECK:STDOUT:   %F.type.b24d6f.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.77e9d5.1: %F.type.b24d6f.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %X.facet: %X.type = facet_value %A, (%X.impl_witness) [concrete]
+// CHECK:STDOUT:   %pattern_type.c10: type = pattern_type %A [concrete]
+// CHECK:STDOUT:   %F.type.b24d6f.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.77e9d5.2: %F.type.b24d6f.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:     .X = %X.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   %X.decl: type = interface_decl @X [concrete = constants.%X.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:     %X.ref: type = name_ref X, file.%X.decl [concrete = constants.%X.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %X.impl_witness_table = impl_witness_table (@impl.%F.decl.loc19_14.2), @impl [concrete]
+// CHECK:STDOUT:   %X.impl_witness: <witness> = impl_witness %X.impl_witness_table [concrete = constants.%X.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @X {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.594 = fn_decl @F.1 [concrete = constants.%F.b69] {
+// CHECK:STDOUT:     %return.patt: @F.1.%pattern_type (%pattern_type.331) = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: @F.1.%pattern_type (%pattern_type.331) = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref: %X.type = name_ref Self, @X.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %Self.as_type.loc8_13.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc8_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %.loc8: type = converted %Self.ref, %Self.as_type.loc8_13.2 [symbolic = %Self.as_type.loc8_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %return.param: ref @F.1.%Self.as_type.loc8_13.1 (%Self.as_type) = out_param call_param0
+// CHECK:STDOUT:     %return: ref @F.1.%Self.as_type.loc8_13.1 (%Self.as_type) = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %X.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %A.ref as %X.ref {
+// CHECK:STDOUT:   %F.decl.loc19_14.1: %F.type.b24d6f.1 = fn_decl @F.2 [concrete = constants.%F.77e9d5.1] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.049 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.049 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %return.param: ref %B = out_param call_param0
+// CHECK:STDOUT:     %return: ref %B = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc19_14.2: %F.type.b24d6f.2 = fn_decl @F.3 [concrete = constants.%F.77e9d5.2] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.c10 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c10 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %return.param: ref %A = out_param call_param0
+// CHECK:STDOUT:     %return: ref %A = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .B = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc19_14.1
+// CHECK:STDOUT:   witness = file.%X.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:   %.loc5: %B.elem = base_decl %A.ref, element0 [concrete]
+// CHECK:STDOUT:   %struct_type.base: type = struct_type {.base: %A} [concrete = constants.%struct_type.base.953]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.base [concrete = constants.%complete_type.020]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT:   .A = <poisoned>
+// CHECK:STDOUT:   .base = %.loc5
+// CHECK:STDOUT:   extend %A.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@X.%Self: %X.type) {
+// CHECK:STDOUT:   %Self: %X.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc8_13.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc8_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc8_13.1 [symbolic = %pattern_type (constants.%pattern_type.331)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() -> @F.1.%Self.as_type.loc8_13.1 (%Self.as_type);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2() -> %return.param: %B;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3() -> %return.param: %A {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc19_14.1: ref %B = temporary_storage
+// CHECK:STDOUT:   %F.call: init %B = call @impl.%F.decl.loc19_14.1() to %.loc19_14.1
+// CHECK:STDOUT:   %.loc19_14.2: ref %B = temporary %.loc19_14.1, %F.call
+// CHECK:STDOUT:   %.loc19_14.3: ref %A = class_element_access %.loc19_14.2, element0
+// CHECK:STDOUT:   %.loc19_14.4: ref %A = converted %F.call, %.loc19_14.3
+// CHECK:STDOUT:   %.loc19_14.5: %A = bind_value %.loc19_14.4
+// CHECK:STDOUT:   return <error> to %return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc8_13.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.331
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%X.facet) {
+// CHECK:STDOUT:   %Self => constants.%X.facet
+// CHECK:STDOUT:   %Self.as_type.loc8_13.1 => constants.%A
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_param_type_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.6de: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %F.type.cf0: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %F.bc6: %F.type.cf0 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness file.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.049: type = pattern_type %B [concrete]
+// CHECK:STDOUT:   %F.type.2ae1ef.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.2a7aab.1: %F.type.2ae1ef.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet: %I.type = facet_value %A, (%I.impl_witness) [concrete]
+// CHECK:STDOUT:   %pattern_type.c10: type = pattern_type %A [concrete]
+// CHECK:STDOUT:   %F.type.2ae1ef.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.2a7aab.2: %F.type.2ae1ef.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (@impl.%F.decl.loc22_13.2), @impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
+// CHECK:STDOUT:     %a.patt: @F.1.%pattern_type (%pattern_type.6de) = binding_pattern a [concrete]
+// CHECK:STDOUT:     %a.param_patt: @F.1.%pattern_type (%pattern_type.6de) = value_param_pattern %a.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %a.param: @F.1.%Self.as_type.loc8_11.1 (%Self.as_type) = value_param call_param0
+// CHECK:STDOUT:     %.loc8_11.1: type = splice_block %.loc8_11.2 [symbolic = %Self.as_type.loc8_11.1 (constants.%Self.as_type)] {
+// CHECK:STDOUT:       %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:       %Self.as_type.loc8_11.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc8_11.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:       %.loc8_11.2: type = converted %Self.ref, %Self.as_type.loc8_11.2 [symbolic = %Self.as_type.loc8_11.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %a: @F.1.%Self.as_type.loc8_11.1 (%Self.as_type) = bind_name a, %a.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %A.ref as %I.ref {
+// CHECK:STDOUT:   %F.decl.loc22_13.1: %F.type.2ae1ef.1 = fn_decl @F.2 [concrete = constants.%F.2a7aab.1] {
+// CHECK:STDOUT:     %a.patt: %pattern_type.049 = binding_pattern a [concrete]
+// CHECK:STDOUT:     %a.param_patt: %pattern_type.049 = value_param_pattern %a.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %a.param: %B = value_param call_param0
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %a: %B = bind_name a, %a.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc22_13.2: %F.type.2ae1ef.2 = fn_decl @F.3 [concrete = constants.%F.2a7aab.2] {
+// CHECK:STDOUT:     %a.patt: %pattern_type.c10 = binding_pattern a [concrete]
+// CHECK:STDOUT:     %a.param_patt: %pattern_type.c10 = value_param_pattern %a.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %a.param: %A = value_param call_param0
+// CHECK:STDOUT:     %a: %A = bind_name a, %a.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .B = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc22_13.1
+// CHECK:STDOUT:   witness = file.%I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc8_11.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc8_11.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc8_11.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(%a.param: @F.1.%Self.as_type.loc8_11.1 (%Self.as_type));
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2(%a.param: %B);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%a.param: %A) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %A = name_ref a, %a.param
+// CHECK:STDOUT:   %.loc8: %B = converted %a.ref, <error> [concrete = <error>]
+// CHECK:STDOUT:   %F.call: init %empty_tuple.type = call @impl.%F.decl.loc22_13.1(<error>)
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc8_11.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.6de
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%I.facet) {
+// CHECK:STDOUT:   %Self => constants.%I.facet
+// CHECK:STDOUT:   %Self.as_type.loc8_11.1 => constants.%A
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_return_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.6de: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %F.type.cf0: type = fn_type @F.1 [concrete]
+// CHECK:STDOUT:   %F.bc6: %F.type.cf0 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %B: type = class_type @B [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness file.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %pattern_type.049: type = pattern_type %B [concrete]
+// CHECK:STDOUT:   %F.type.2ae1ef.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.2a7aab.1: %F.type.2ae1ef.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet: %I.type = facet_value %A, (%I.impl_witness) [concrete]
+// CHECK:STDOUT:   %pattern_type.c10: type = pattern_type %A [concrete]
+// CHECK:STDOUT:   %F.type.2ae1ef.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.2a7aab.2: %F.type.2ae1ef.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .A = %A.decl
+// CHECK:STDOUT:     .B = %B.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
+// CHECK:STDOUT:   %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (@impl.%F.decl.loc19_14.2), @impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F.decl: %F.type.cf0 = fn_decl @F.1 [concrete = constants.%F.bc6] {
+// CHECK:STDOUT:     %return.patt: @F.1.%pattern_type (%pattern_type.6de) = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: @F.1.%pattern_type (%pattern_type.6de) = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %Self.as_type.loc5_13.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc5_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %.loc5: type = converted %Self.ref, %Self.as_type.loc5_13.2 [symbolic = %Self.as_type.loc5_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %return.param: ref @F.1.%Self.as_type.loc5_13.1 (%Self.as_type) = out_param call_param0
+// CHECK:STDOUT:     %return: ref @F.1.%Self.as_type.loc5_13.1 (%Self.as_type) = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %assoc0
+// CHECK:STDOUT:   witness = (%F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %A.ref as %I.ref {
+// CHECK:STDOUT:   %F.decl.loc19_14.1: %F.type.2ae1ef.1 = fn_decl @F.2 [concrete = constants.%F.2a7aab.1] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.049 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.049 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B]
+// CHECK:STDOUT:     %return.param: ref %B = out_param call_param0
+// CHECK:STDOUT:     %return: ref %B = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc19_14.2: %F.type.2ae1ef.2 = fn_decl @F.3 [concrete = constants.%F.2a7aab.2] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.c10 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c10 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %return.param: ref %A = out_param call_param0
+// CHECK:STDOUT:     %return: ref %A = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .B = <poisoned>
+// CHECK:STDOUT:   .F = %F.decl.loc19_14.1
+// CHECK:STDOUT:   witness = file.%I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%A
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @B {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%B
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc5_13.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc5_13.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc5_13.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() -> @F.1.%Self.as_type.loc5_13.1 (%Self.as_type);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.2() -> %return.param: %B;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3() -> %return.param: %A {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc19_14.1: ref %B = temporary_storage
+// CHECK:STDOUT:   %F.call: init %B = call @impl.%F.decl.loc19_14.1() to %.loc19_14.1
+// CHECK:STDOUT:   %.loc19_14.2: %A = converted %F.call, <error> [concrete = <error>]
+// CHECK:STDOUT:   return <error> to %return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc5_13.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.6de
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F.1(constants.%I.facet) {
+// CHECK:STDOUT:   %Self => constants.%I.facet
+// CHECK:STDOUT:   %Self.as_type.loc5_13.1 => constants.%A
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.c10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- return_empty_tuple_mismatch_allowed.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %Self.as_type: type = facet_access_type %Self [symbolic]
+// CHECK:STDOUT:   %pattern_type.6de: type = pattern_type %Self.as_type [symbolic]
+// CHECK:STDOUT:   %HasReturn.type.bf9: type = fn_type @HasReturn.1 [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %HasReturn.dcf: %HasReturn.type.bf9 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%HasReturn.decl [concrete]
+// CHECK:STDOUT:   %NoReturn.type.7ff: type = fn_type @NoReturn.1 [concrete]
+// CHECK:STDOUT:   %NoReturn.7fd: %NoReturn.type.7ff = struct_value () [concrete]
+// CHECK:STDOUT:   %assoc1: %I.assoc_type = assoc_entity element1, @I.%NoReturn.decl [concrete]
+// CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.type.1cb: type = fn_type @EmptyTupleReturn.1 [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.c56: %EmptyTupleReturn.type.1cb = struct_value () [concrete]
+// CHECK:STDOUT:   %assoc2: %I.assoc_type = assoc_entity element2, @I.%EmptyTupleReturn.decl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness file.%I.impl_witness_table [concrete]
+// CHECK:STDOUT:   %HasReturn.type.c73908.1: type = fn_type @HasReturn.2 [concrete]
+// CHECK:STDOUT:   %HasReturn.424378.1: %HasReturn.type.c73908.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %NoReturn.type.948: type = fn_type @NoReturn.2 [concrete]
+// CHECK:STDOUT:   %NoReturn.9fa: %NoReturn.type.948 = struct_value () [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.type.9ea74f.1: type = fn_type @EmptyTupleReturn.2 [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.282179.1: %EmptyTupleReturn.type.9ea74f.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet: %I.type = facet_value %empty_tuple.type, (%I.impl_witness) [concrete]
+// CHECK:STDOUT:   %HasReturn.type.c73908.2: type = fn_type @HasReturn.3 [concrete]
+// CHECK:STDOUT:   %HasReturn.424378.2: %HasReturn.type.c73908.2 = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.type.9ea74f.2: type = fn_type @EmptyTupleReturn.3 [concrete]
+// CHECK:STDOUT:   %EmptyTupleReturn.282179.2: %EmptyTupleReturn.type.9ea74f.2 = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl [concrete] {} {
+// CHECK:STDOUT:     %.loc10_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_7.2: type = converted %.loc10_7.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table = impl_witness_table (@impl.%HasReturn.decl.loc12_17.2, @impl.%NoReturn.decl, @impl.%EmptyTupleReturn.decl.loc18_24.2), @impl [concrete]
+// CHECK:STDOUT:   %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %HasReturn.decl: %HasReturn.type.bf9 = fn_decl @HasReturn.1 [concrete = constants.%HasReturn.dcf] {
+// CHECK:STDOUT:     %return.patt: @HasReturn.1.%pattern_type (%pattern_type.6de) = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: @HasReturn.1.%pattern_type (%pattern_type.6de) = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:     %Self.as_type.loc5_21.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc5_21.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %.loc5: type = converted %Self.ref, %Self.as_type.loc5_21.2 [symbolic = %Self.as_type.loc5_21.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:     %return.param: ref @HasReturn.1.%Self.as_type.loc5_21.1 (%Self.as_type) = out_param call_param0
+// CHECK:STDOUT:     %return: ref @HasReturn.1.%Self.as_type.loc5_21.1 (%Self.as_type) = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %HasReturn.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:   %NoReturn.decl: %NoReturn.type.7ff = fn_decl @NoReturn.1 [concrete = constants.%NoReturn.7fd] {} {}
+// CHECK:STDOUT:   %assoc1: %I.assoc_type = assoc_entity element1, %NoReturn.decl [concrete = constants.%assoc1]
+// CHECK:STDOUT:   %EmptyTupleReturn.decl: %EmptyTupleReturn.type.1cb = fn_decl @EmptyTupleReturn.1 [concrete = constants.%EmptyTupleReturn.c56] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc7_29.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc7_29.2: type = converted %.loc7_29.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param0
+// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %assoc2: %I.assoc_type = assoc_entity element2, %EmptyTupleReturn.decl [concrete = constants.%assoc2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .HasReturn = %assoc0
+// CHECK:STDOUT:   .NoReturn = %assoc1
+// CHECK:STDOUT:   .EmptyTupleReturn = %assoc2
+// CHECK:STDOUT:   witness = (%HasReturn.decl, %NoReturn.decl, %EmptyTupleReturn.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl: %.loc10_7.2 as %I.ref {
+// CHECK:STDOUT:   %HasReturn.decl.loc12_17.1: %HasReturn.type.c73908.1 = fn_decl @HasReturn.2 [concrete = constants.%HasReturn.424378.1] {} {}
+// CHECK:STDOUT:   %NoReturn.decl: %NoReturn.type.948 = fn_decl @NoReturn.2 [concrete = constants.%NoReturn.9fa] {} {}
+// CHECK:STDOUT:   %EmptyTupleReturn.decl.loc18_24.1: %EmptyTupleReturn.type.9ea74f.1 = fn_decl @EmptyTupleReturn.2 [concrete = constants.%EmptyTupleReturn.282179.1] {} {}
+// CHECK:STDOUT:   %HasReturn.decl.loc12_17.2: %HasReturn.type.c73908.2 = fn_decl @HasReturn.3 [concrete = constants.%HasReturn.424378.2] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param0
+// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %EmptyTupleReturn.decl.loc18_24.2: %EmptyTupleReturn.type.9ea74f.2 = fn_decl @EmptyTupleReturn.3 [concrete = constants.%EmptyTupleReturn.282179.2] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param0
+// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .HasReturn = %HasReturn.decl.loc12_17.1
+// CHECK:STDOUT:   .NoReturn = %NoReturn.decl
+// CHECK:STDOUT:   .EmptyTupleReturn = %EmptyTupleReturn.decl.loc18_24.1
+// CHECK:STDOUT:   witness = file.%I.impl_witness
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @HasReturn.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
+// CHECK:STDOUT:   %Self.as_type.loc5_21.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc5_21.1 (constants.%Self.as_type)]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %Self.as_type.loc5_21.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() -> @HasReturn.1.%Self.as_type.loc5_21.1 (%Self.as_type);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @NoReturn.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @EmptyTupleReturn.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   fn() -> %empty_tuple.type;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @HasReturn.2();
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @NoReturn.2();
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @EmptyTupleReturn.2();
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @HasReturn.3() -> %empty_tuple.type {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %HasReturn.call: init %empty_tuple.type = call @impl.%HasReturn.decl.loc12_17.1()
+// CHECK:STDOUT:   %.loc12_17.1: ref %empty_tuple.type = temporary_storage
+// CHECK:STDOUT:   %.loc12_17.2: ref %empty_tuple.type = temporary %.loc12_17.1, %HasReturn.call
+// CHECK:STDOUT:   %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc12_17.3: %empty_tuple.type = converted %HasReturn.call, %tuple [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   return %.loc12_17.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @EmptyTupleReturn.3() -> %empty_tuple.type {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %EmptyTupleReturn.call: init %empty_tuple.type = call @impl.%EmptyTupleReturn.decl.loc18_24.1()
+// CHECK:STDOUT:   %.loc18_24.1: ref %empty_tuple.type = temporary_storage
+// CHECK:STDOUT:   %.loc18_24.2: ref %empty_tuple.type = temporary %.loc18_24.1, %EmptyTupleReturn.call
+// CHECK:STDOUT:   %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   %.loc18_24.3: %empty_tuple.type = converted %EmptyTupleReturn.call, %tuple [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   return %.loc18_24.3
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasReturn.1(constants.%Self) {
+// CHECK:STDOUT:   %Self => constants.%Self
+// CHECK:STDOUT:   %Self.as_type.loc5_21.1 => constants.%Self.as_type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.6de
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @NoReturn.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @EmptyTupleReturn.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @HasReturn.1(constants.%I.facet) {
+// CHECK:STDOUT:   %Self => constants.%I.facet
+// CHECK:STDOUT:   %Self.as_type.loc5_21.1 => constants.%empty_tuple.type
+// CHECK:STDOUT:   %pattern_type => constants.%pattern_type.cb1
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @NoReturn.1(constants.%I.facet) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @EmptyTupleReturn.1(constants.%I.facet) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_return_empty_tuple_mismatch.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
+// CHECK:STDOUT:   %NoReturn.type.7ff: type = fn_type @NoReturn.1 [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %NoReturn.7fd: %NoReturn.type.7ff = struct_value () [concrete]
+// CHECK:STDOUT:   %I.assoc_type: type = assoc_entity_type @I [concrete]
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%NoReturn.decl [concrete]
+// CHECK:STDOUT:   %I.impl_witness.c4e: <witness> = impl_witness file.%I.impl_witness_table.loc8 [concrete]
+// CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
+// CHECK:STDOUT:   %NoReturn.type.948: type = fn_type @NoReturn.2 [concrete]
+// CHECK:STDOUT:   %NoReturn.9fa: %NoReturn.type.948 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet.372: %I.type = facet_value %empty_tuple.type, (%I.impl_witness.c4e) [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
+// CHECK:STDOUT:   %I.impl_witness.464: <witness> = impl_witness file.%I.impl_witness_table.loc22 [concrete]
+// CHECK:STDOUT:   %pattern_type.c48: type = pattern_type %C [concrete]
+// CHECK:STDOUT:   %NoReturn.type.930: type = fn_type @NoReturn.3 [concrete]
+// CHECK:STDOUT:   %NoReturn.ac0: %NoReturn.type.930 = struct_value () [concrete]
+// CHECK:STDOUT:   %I.facet.be9: %I.type = facet_value %C, (%I.impl_witness.464) [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [concrete] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
+// CHECK:STDOUT:   impl_decl @impl.4ab [concrete] {} {
+// CHECK:STDOUT:     %.loc8_7.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc8_7.2: type = converted %.loc8_7.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table.loc8 = impl_witness_table (<error>), @impl.4ab [concrete]
+// CHECK:STDOUT:   %I.impl_witness.loc8: <witness> = impl_witness %I.impl_witness_table.loc8 [concrete = constants.%I.impl_witness.c4e]
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
+// CHECK:STDOUT:   impl_decl @impl.770 [concrete] {} {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.impl_witness_table.loc22 = impl_witness_table (<error>), @impl.770 [concrete]
+// CHECK:STDOUT:   %I.impl_witness.loc22: <witness> = impl_witness %I.impl_witness_table.loc22 [concrete = constants.%I.impl_witness.464]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %NoReturn.decl: %NoReturn.type.7ff = fn_decl @NoReturn.1 [concrete = constants.%NoReturn.7fd] {} {}
+// CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, %NoReturn.decl [concrete = constants.%assoc0]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .NoReturn = %assoc0
+// CHECK:STDOUT:   witness = (%NoReturn.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.4ab: %.loc8_7.2 as %I.ref {
+// CHECK:STDOUT:   %NoReturn.decl: %NoReturn.type.948 = fn_decl @NoReturn.2 [concrete = constants.%NoReturn.9fa] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.cb1 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.cb1 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc17_21.1: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc17_21.2: type = converted %.loc17_21.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:     %return.param: ref %empty_tuple.type = out_param call_param0
+// CHECK:STDOUT:     %return: ref %empty_tuple.type = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .NoReturn = %NoReturn.decl
+// CHECK:STDOUT:   witness = file.%I.impl_witness.loc8
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: impl @impl.770: %C.ref as %I.ref {
+// CHECK:STDOUT:   %NoReturn.decl: %NoReturn.type.930 = fn_decl @NoReturn.3 [concrete = constants.%NoReturn.ac0] {
+// CHECK:STDOUT:     %return.patt: %pattern_type.c48 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.c48 = out_param_pattern %return.patt, call_param0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
+// CHECK:STDOUT:     %return.param: ref %C = out_param call_param0
+// CHECK:STDOUT:     %return: ref %C = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .C = <poisoned>
+// CHECK:STDOUT:   .NoReturn = %NoReturn.decl
+// CHECK:STDOUT:   witness = file.%I.impl_witness.loc22
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
+// CHECK:STDOUT:   complete_type_witness = %complete_type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @NoReturn.1(@I.%Self: %I.type) {
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @NoReturn.2() -> %empty_tuple.type;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @NoReturn.3() -> %C;
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @NoReturn.1(constants.%Self) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @NoReturn.1(constants.%I.facet.372) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @NoReturn.1(constants.%I.facet.be9) {}
+// CHECK:STDOUT:

+ 157 - 60
toolchain/check/testdata/impl/use_assoc_const.carbon

@@ -189,6 +189,13 @@ interface J2 {
 }
 
 impl () as J2 where .U2 = {} {
+  // CHECK:STDERR: fail_todo_self_period_associated_type.carbon:[[@LINE+7]]:3: error: expression cannot be used as a value [UseOfNonExprAsValue]
+  // CHECK:STDERR:   fn F[self: Self](z: {}) -> {} { return z; }
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_todo_self_period_associated_type.carbon:[[@LINE-7]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
+  // CHECK:STDERR:   fn F[self: Self](z: Self.U2) -> Self.U2;
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
   fn F[self: Self](z: {}) -> {} { return z; }
 }
 
@@ -210,12 +217,12 @@ interface K {
 }
 
 impl () as K where .V = {.a: ()} {
-  // CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:20: error: type `<pattern for {.x: ()}>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for {.a: ()}>` [RedeclParamDiffersType]
+  // CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:3: error: expression cannot be used as a value [UseOfNonExprAsValue]
   // CHECK:STDERR:   fn F[self: Self](v: {.x: ()}) -> {.x: ()} { return v; }
-  // CHECK:STDERR:                    ^~~~~~~~~~~
-  // CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE-7]]:20: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE-7]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
   // CHECK:STDERR:   fn F[self: Self](v: V) -> V;
-  // CHECK:STDERR:                    ^~~~
+  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:
   fn F[self: Self](v: {.x: ()}) -> {.x: ()} { return v; }
 }
@@ -2256,10 +2263,12 @@ fn F() {
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness @E.%J.impl_witness_table [concrete]
 // CHECK:STDOUT:   %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
 // CHECK:STDOUT:   %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
-// CHECK:STDOUT:   %F.type.b84: type = fn_type @F.2 [concrete]
-// CHECK:STDOUT:   %F.b07: %F.type.b84 = struct_value () [concrete]
-// CHECK:STDOUT:   %J.facet.bd9: %J.type = facet_value %E, (%J.impl_witness) [concrete]
+// CHECK:STDOUT:   %F.type.b842fd.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.b07d12.1: %F.type.b842fd.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %J.facet.f43: %J.type = facet_value %E, (%J.impl_witness) [concrete]
 // CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
+// CHECK:STDOUT:   %F.type.b842fd.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.b07d12.2: %F.type.b842fd.2 = struct_value () [concrete]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %complete_type.357: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete]
@@ -2326,7 +2335,7 @@ fn F() {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %Self.ref as %.loc9_20 {
-// CHECK:STDOUT:   %F.decl: %F.type.b84 = fn_decl @F.2 [concrete = constants.%F.b07] {
+// CHECK:STDOUT:   %F.decl.loc24_21.1: %F.type.b842fd.1 = fn_decl @F.2 [concrete = constants.%F.b07d12.1] {
 // CHECK:STDOUT:     %u.patt: <error> = binding_pattern u [concrete]
 // CHECK:STDOUT:     %u.param_patt: <error> = value_param_pattern %u.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %return.patt: <error> = return_slot_pattern [concrete]
@@ -2343,10 +2352,21 @@ fn F() {
 // CHECK:STDOUT:     %return.param: ref <error> = out_param call_param1
 // CHECK:STDOUT:     %return: ref <error> = return_slot %return.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc24_21.2: %F.type.b842fd.2 = fn_decl @F.3 [concrete = constants.%F.b07d12.2] {
+// CHECK:STDOUT:     %u.patt: %pattern_type.7ce = binding_pattern u [concrete]
+// CHECK:STDOUT:     %u.param_patt: %pattern_type.7ce = value_param_pattern %u.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.7ce = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %u.param: %i32 = value_param call_param0
+// CHECK:STDOUT:     %u: %i32 = bind_name u, %u.param
+// CHECK:STDOUT:     %return.param: ref %i32 = out_param call_param1
+// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .U = <poisoned>
-// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .F = %F.decl.loc24_21.1
 // CHECK:STDOUT:   witness = @E.%J.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -2366,7 +2386,7 @@ fn F() {
 // CHECK:STDOUT:       requirement_rewrite %impl.elem0, %i32
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, <error>), @impl [concrete]
+// CHECK:STDOUT:   %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @impl.%F.decl.loc24_21.2), @impl [concrete]
 // CHECK:STDOUT:   %J.impl_witness: <witness> = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness]
 // CHECK:STDOUT:   %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%i32 [concrete = constants.%i32]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
@@ -2397,6 +2417,13 @@ fn F() {
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%u.param: %i32) -> %i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %u.ref: %i32 = name_ref u, %u.param
+// CHECK:STDOUT:   %F.call: init <error> = call @impl.%F.decl.loc24_21.1(<error>)
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @U(constants.%Self.ccd) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @U(constants.%J.facet.521) {}
@@ -2410,8 +2437,8 @@ fn F() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @U(constants.%J.facet.330) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%J.facet.bd9) {
-// CHECK:STDOUT:   %Self => constants.%J.facet.bd9
+// CHECK:STDOUT: specific @F.1(constants.%J.facet.f43) {
+// CHECK:STDOUT:   %Self => constants.%J.facet.f43
 // CHECK:STDOUT:   %J.lookup_impl_witness => constants.%J.impl_witness
 // CHECK:STDOUT:   %impl.elem0.loc5_11.1 => constants.%i32
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.7ce
@@ -2437,20 +2464,24 @@ fn F() {
 // CHECK:STDOUT:   %impl.elem0: type = impl_witness_access %J2.lookup_impl_witness, element0 [symbolic_self]
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %J2_where.type.9e1: type = facet_type <@J2 where %impl.elem0 = %empty_struct_type> [concrete]
-// CHECK:STDOUT:   %J2.impl_witness.1aa: <witness> = impl_witness file.%J2.impl_witness_table.loc22 [concrete]
+// CHECK:STDOUT:   %J2.impl_witness.6a9: <witness> = impl_witness file.%J2.impl_witness_table.loc22 [concrete]
 // CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
 // CHECK:STDOUT:   %pattern_type.a96: type = pattern_type %empty_struct_type [concrete]
-// CHECK:STDOUT:   %F.type.f40: type = fn_type @F.2 [concrete]
-// CHECK:STDOUT:   %F.214: %F.type.f40 = struct_value () [concrete]
-// CHECK:STDOUT:   %J2.facet.af8: %J2.type = facet_value %empty_tuple.type, (%J2.impl_witness.1aa) [concrete]
+// CHECK:STDOUT:   %F.type.f405c5.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.214a71.1: %F.type.f405c5.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %J2.facet.86f: %J2.type = facet_value %empty_tuple.type, (%J2.impl_witness.6a9) [concrete]
+// CHECK:STDOUT:   %F.type.f405c5.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.214a71.2: %F.type.f405c5.2 = struct_value () [concrete]
 // CHECK:STDOUT:   %C2: type = class_type @C2 [concrete]
 // CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
 // CHECK:STDOUT:   %J2_where.type.df9: type = facet_type <@J2 where %impl.elem0 = %C2> [concrete]
-// CHECK:STDOUT:   %J2.impl_witness.774: <witness> = impl_witness file.%J2.impl_witness_table.loc31 [concrete]
+// CHECK:STDOUT:   %J2.impl_witness.267: <witness> = impl_witness file.%J2.impl_witness_table.loc38 [concrete]
 // CHECK:STDOUT:   %pattern_type.838: type = pattern_type %C2 [concrete]
-// CHECK:STDOUT:   %F.type.05d: type = fn_type @F.3 [concrete]
-// CHECK:STDOUT:   %F.bfa: %F.type.05d = struct_value () [concrete]
-// CHECK:STDOUT:   %J2.facet.eed: %J2.type = facet_value %C2, (%J2.impl_witness.774) [concrete]
+// CHECK:STDOUT:   %F.type.05d6a0.1: type = fn_type @F.4 [concrete]
+// CHECK:STDOUT:   %F.bfa759.1: %F.type.05d6a0.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %J2.facet.c3f: %J2.type = facet_value %C2, (%J2.impl_witness.267) [concrete]
+// CHECK:STDOUT:   %F.type.05d6a0.2: type = fn_type @F.5 [concrete]
+// CHECK:STDOUT:   %F.bfa759.2: %F.type.05d6a0.2 = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -2484,27 +2515,27 @@ fn F() {
 // CHECK:STDOUT:       requirement_rewrite %impl.elem0, %.loc22_28.2
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %J2.impl_witness_table.loc22 = impl_witness_table (%impl_witness_assoc_constant.loc22, <error>), @impl.4e9 [concrete]
-// CHECK:STDOUT:   %J2.impl_witness.loc22: <witness> = impl_witness %J2.impl_witness_table.loc22 [concrete = constants.%J2.impl_witness.1aa]
+// CHECK:STDOUT:   %J2.impl_witness_table.loc22 = impl_witness_table (%impl_witness_assoc_constant.loc22, @impl.4e9.%F.decl.loc30_33.2), @impl.4e9 [concrete]
+// CHECK:STDOUT:   %J2.impl_witness.loc22: <witness> = impl_witness %J2.impl_witness_table.loc22 [concrete = constants.%J2.impl_witness.6a9]
 // CHECK:STDOUT:   %impl_witness_assoc_constant.loc22: type = impl_witness_assoc_constant constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:   %C2.decl: type = class_decl @C2 [concrete = constants.%C2] {} {}
 // CHECK:STDOUT:   impl_decl @impl.8b3 [concrete] {} {
-// CHECK:STDOUT:     %C2.ref.loc31_6: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
+// CHECK:STDOUT:     %C2.ref.loc38_6: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
 // CHECK:STDOUT:     %J2.ref: type = name_ref J2, file.%J2.decl [concrete = constants.%J2.type]
 // CHECK:STDOUT:     %.Self: %J2.type = bind_symbolic_name .Self [symbolic_self = constants.%.Self]
 // CHECK:STDOUT:     %.Self.ref: %J2.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
 // CHECK:STDOUT:     %U2.ref: %J2.assoc_type = name_ref U2, @U2.%assoc0 [concrete = constants.%assoc0]
 // CHECK:STDOUT:     %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type]
-// CHECK:STDOUT:     %.loc31_21: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
+// CHECK:STDOUT:     %.loc38_21: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
 // CHECK:STDOUT:     %impl.elem0: type = impl_witness_access constants.%J2.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0]
-// CHECK:STDOUT:     %C2.ref.loc31_27: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
-// CHECK:STDOUT:     %.loc31_15: type = where_expr %.Self [concrete = constants.%J2_where.type.df9] {
-// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %C2.ref.loc31_27
+// CHECK:STDOUT:     %C2.ref.loc38_27: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
+// CHECK:STDOUT:     %.loc38_15: type = where_expr %.Self [concrete = constants.%J2_where.type.df9] {
+// CHECK:STDOUT:       requirement_rewrite %impl.elem0, %C2.ref.loc38_27
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %J2.impl_witness_table.loc31 = impl_witness_table (%impl_witness_assoc_constant.loc31, <error>), @impl.8b3 [concrete]
-// CHECK:STDOUT:   %J2.impl_witness.loc31: <witness> = impl_witness %J2.impl_witness_table.loc31 [concrete = constants.%J2.impl_witness.774]
-// CHECK:STDOUT:   %impl_witness_assoc_constant.loc31: type = impl_witness_assoc_constant constants.%C2 [concrete = constants.%C2]
+// CHECK:STDOUT:   %J2.impl_witness_table.loc38 = impl_witness_table (%impl_witness_assoc_constant.loc38, @impl.8b3.%F.decl.loc39_33.2), @impl.8b3 [concrete]
+// CHECK:STDOUT:   %J2.impl_witness.loc38: <witness> = impl_witness %J2.impl_witness_table.loc38 [concrete = constants.%J2.impl_witness.267]
+// CHECK:STDOUT:   %impl_witness_assoc_constant.loc38: type = impl_witness_assoc_constant constants.%C2 [concrete = constants.%C2]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @J2 {
@@ -2548,7 +2579,7 @@ fn F() {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl.4e9: %.loc22_7.2 as %.loc22_15 {
-// CHECK:STDOUT:   %F.decl: %F.type.f40 = fn_decl @F.2 [concrete = constants.%F.214] {
+// CHECK:STDOUT:   %F.decl.loc30_33.1: %F.type.f405c5.1 = fn_decl @F.2 [concrete = constants.%F.214a71.1] {
 // CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
 // CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %z.patt: %pattern_type.a96 = binding_pattern z [concrete]
@@ -2556,28 +2587,41 @@ fn F() {
 // CHECK:STDOUT:     %return.patt: %pattern_type.a96 = return_slot_pattern [concrete]
 // CHECK:STDOUT:     %return.param_patt: %pattern_type.a96 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %.loc23_31.1: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:     %.loc23_31.2: type = converted %.loc23_31.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc30_31.1: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:     %.loc30_31.2: type = converted %.loc30_31.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:     %self.param: %empty_tuple.type = value_param call_param0
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, @impl.4e9.%.loc22_7.2 [concrete = constants.%empty_tuple.type]
 // CHECK:STDOUT:     %self: %empty_tuple.type = bind_name self, %self.param
 // CHECK:STDOUT:     %z.param: %empty_struct_type = value_param call_param1
-// CHECK:STDOUT:     %.loc23_24.1: type = splice_block %.loc23_24.3 [concrete = constants.%empty_struct_type] {
-// CHECK:STDOUT:       %.loc23_24.2: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:       %.loc23_24.3: type = converted %.loc23_24.2, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:     %.loc30_24.1: type = splice_block %.loc30_24.3 [concrete = constants.%empty_struct_type] {
+// CHECK:STDOUT:       %.loc30_24.2: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:       %.loc30_24.3: type = converted %.loc30_24.2, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     %z: %empty_struct_type = bind_name z, %z.param
 // CHECK:STDOUT:     %return.param: ref %empty_struct_type = out_param call_param2
 // CHECK:STDOUT:     %return: ref %empty_struct_type = return_slot %return.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc30_33.2: %F.type.f405c5.2 = fn_decl @F.3 [concrete = constants.%F.214a71.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.param_patt: <error> = value_param_pattern <error>, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: <error> = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: <error> = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %empty_tuple.type = value_param call_param0
+// CHECK:STDOUT:     %self: %empty_tuple.type = bind_name self, %self.param
+// CHECK:STDOUT:     %.param: <error> = value_param call_param1
+// CHECK:STDOUT:     %return.param: ref <error> = out_param call_param2
+// CHECK:STDOUT:     %return: ref <error> = return_slot %return.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .F = %F.decl.loc30_33.1
 // CHECK:STDOUT:   witness = file.%J2.impl_witness.loc22
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl @impl.8b3: %C2.ref.loc31_6 as %.loc31_15 {
-// CHECK:STDOUT:   %F.decl: %F.type.05d = fn_decl @F.3 [concrete = constants.%F.bfa] {
+// CHECK:STDOUT: impl @impl.8b3: %C2.ref.loc38_6 as %.loc38_15 {
+// CHECK:STDOUT:   %F.decl.loc39_33.1: %F.type.05d6a0.1 = fn_decl @F.4 [concrete = constants.%F.bfa759.1] {
 // CHECK:STDOUT:     %self.patt: %pattern_type.838 = binding_pattern self [concrete]
 // CHECK:STDOUT:     %self.param_patt: %pattern_type.838 = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %z.patt: %pattern_type.838 = binding_pattern z [concrete]
@@ -2585,27 +2629,40 @@ fn F() {
 // CHECK:STDOUT:     %return.patt: %pattern_type.838 = return_slot_pattern [concrete]
 // CHECK:STDOUT:     %return.param_patt: %pattern_type.838 = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %C2.ref.loc32_30: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
+// CHECK:STDOUT:     %C2.ref.loc39_30: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
 // CHECK:STDOUT:     %self.param: %C2 = value_param call_param0
-// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @impl.8b3.%C2.ref.loc31_6 [concrete = constants.%C2]
+// CHECK:STDOUT:     %Self.ref: type = name_ref Self, @impl.8b3.%C2.ref.loc38_6 [concrete = constants.%C2]
 // CHECK:STDOUT:     %self: %C2 = bind_name self, %self.param
 // CHECK:STDOUT:     %z.param: %C2 = value_param call_param1
-// CHECK:STDOUT:     %C2.ref.loc32_23: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
+// CHECK:STDOUT:     %C2.ref.loc39_23: type = name_ref C2, file.%C2.decl [concrete = constants.%C2]
 // CHECK:STDOUT:     %z: %C2 = bind_name z, %z.param
 // CHECK:STDOUT:     %return.param: ref %C2 = out_param call_param2
 // CHECK:STDOUT:     %return: ref %C2 = return_slot %return.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc39_33.2: %F.type.05d6a0.2 = fn_decl @F.5 [concrete = constants.%F.bfa759.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.838 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.838 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %.param_patt: <error> = value_param_pattern <error>, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: <error> = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: <error> = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %C2 = value_param call_param0
+// CHECK:STDOUT:     %self: %C2 = bind_name self, %self.param
+// CHECK:STDOUT:     %.param: <error> = value_param call_param1
+// CHECK:STDOUT:     %return.param: ref <error> = out_param call_param2
+// CHECK:STDOUT:     %return: ref <error> = return_slot %return.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .C2 = <poisoned>
-// CHECK:STDOUT:   .F = %F.decl
-// CHECK:STDOUT:   witness = file.%J2.impl_witness.loc31
+// CHECK:STDOUT:   .F = %F.decl.loc39_33.1
+// CHECK:STDOUT:   witness = file.%J2.impl_witness.loc38
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C2 {
-// CHECK:STDOUT:   %.loc28_10: %empty_struct_type = struct_literal ()
-// CHECK:STDOUT:   %.loc28_11: type = converted %.loc28_10, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
-// CHECK:STDOUT:   adapt_decl %.loc28_11 [concrete]
+// CHECK:STDOUT:   %.loc35_10: %empty_struct_type = struct_literal ()
+// CHECK:STDOUT:   %.loc35_11: type = converted %.loc35_10, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
+// CHECK:STDOUT:   adapt_decl %.loc35_11 [concrete]
 // CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
 // CHECK:STDOUT:   complete_type_witness = %complete_type
 // CHECK:STDOUT:
@@ -2627,12 +2684,28 @@ fn F() {
 // CHECK:STDOUT:   return %z.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F.3(%self.param: %C2, %z.param: %C2) -> %C2 {
+// CHECK:STDOUT: fn @F.3(%self.param: %empty_tuple.type, %.param: <error>) -> <error> {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %empty_tuple.type = name_ref self, %self.param
+// CHECK:STDOUT:   %.ref: <error> = name_ref <none>, %.param [concrete = <error>]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.4(%self.param: %C2, %z.param: %C2) -> %C2 {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %self.ref: %C2 = name_ref self, %self
 // CHECK:STDOUT:   return %self.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.5(%self.param: %C2, %.param: <error>) -> <error> {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %C2 = name_ref self, %self.param
+// CHECK:STDOUT:   %F.bound: <bound method> = bound_method %self.ref, @impl.8b3.%F.decl.loc39_33.1
+// CHECK:STDOUT:   %.ref: <error> = name_ref <none>, %.param [concrete = <error>]
+// CHECK:STDOUT:   %F.call: init %C2 = call %F.bound(%self.ref, <error>)
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @U2(constants.%Self) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @F.1(constants.%Self) {
@@ -2643,14 +2716,14 @@ fn F() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @U2(constants.%J2.facet.e30) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%J2.facet.af8) {
-// CHECK:STDOUT:   %Self => constants.%J2.facet.af8
+// CHECK:STDOUT: specific @F.1(constants.%J2.facet.86f) {
+// CHECK:STDOUT:   %Self => constants.%J2.facet.86f
 // CHECK:STDOUT:   %Self.as_type.loc19_14.1 => constants.%empty_tuple.type
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.cb1
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%J2.facet.eed) {
-// CHECK:STDOUT:   %Self => constants.%J2.facet.eed
+// CHECK:STDOUT: specific @F.1(constants.%J2.facet.c3f) {
+// CHECK:STDOUT:   %Self => constants.%J2.facet.c3f
 // CHECK:STDOUT:   %Self.as_type.loc19_14.1 => constants.%C2
 // CHECK:STDOUT:   %pattern_type => constants.%pattern_type.838
 // CHECK:STDOUT: }
@@ -2683,10 +2756,12 @@ fn F() {
 // CHECK:STDOUT:   %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete]
 // CHECK:STDOUT:   %struct_type.x: type = struct_type {.x: %empty_tuple.type} [concrete]
 // CHECK:STDOUT:   %pattern_type.414: type = pattern_type %struct_type.x [concrete]
-// CHECK:STDOUT:   %F.type.c52: type = fn_type @F.2 [concrete]
-// CHECK:STDOUT:   %F.5eb: %F.type.c52 = struct_value () [concrete]
-// CHECK:STDOUT:   %K.facet.77f: %K.type = facet_value %empty_tuple.type, (%K.impl_witness) [concrete]
+// CHECK:STDOUT:   %F.type.c5249c.1: type = fn_type @F.2 [concrete]
+// CHECK:STDOUT:   %F.5eb4dd.1: %F.type.c5249c.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %K.facet.e32: %K.type = facet_value %empty_tuple.type, (%K.impl_witness) [concrete]
 // CHECK:STDOUT:   %pattern_type.e85: type = pattern_type %struct_type.a [concrete]
+// CHECK:STDOUT:   %F.type.c5249c.2: type = fn_type @F.3 [concrete]
+// CHECK:STDOUT:   %F.5eb4dd.2: %F.type.c5249c.2 = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -2720,7 +2795,7 @@ fn F() {
 // CHECK:STDOUT:       requirement_rewrite %impl.elem0, %struct_type.a
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %K.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, <error>), @impl [concrete]
+// CHECK:STDOUT:   %K.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @impl.%F.decl.loc16_45.2), @impl [concrete]
 // CHECK:STDOUT:   %K.impl_witness: <witness> = impl_witness %K.impl_witness_table [concrete = constants.%K.impl_witness]
 // CHECK:STDOUT:   %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%struct_type.a [concrete = constants.%struct_type.a]
 // CHECK:STDOUT: }
@@ -2770,7 +2845,7 @@ fn F() {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: impl @impl: %.loc8_7.2 as %.loc8_14 {
-// CHECK:STDOUT:   %F.decl: %F.type.c52 = fn_decl @F.2 [concrete = constants.%F.5eb] {
+// CHECK:STDOUT:   %F.decl.loc16_45.1: %F.type.c5249c.1 = fn_decl @F.2 [concrete = constants.%F.5eb4dd.1] {
 // CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
 // CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %v.patt: %pattern_type.414 = binding_pattern v [concrete]
@@ -2794,9 +2869,24 @@ fn F() {
 // CHECK:STDOUT:     %return.param: ref %struct_type.x = out_param call_param2
 // CHECK:STDOUT:     %return: ref %struct_type.x = return_slot %return.param
 // CHECK:STDOUT:   }
+// CHECK:STDOUT:   %F.decl.loc16_45.2: %F.type.c5249c.2 = fn_decl @F.3 [concrete = constants.%F.5eb4dd.2] {
+// CHECK:STDOUT:     %self.patt: %pattern_type.cb1 = binding_pattern self [concrete]
+// CHECK:STDOUT:     %self.param_patt: %pattern_type.cb1 = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT:     %v.patt: %pattern_type.e85 = binding_pattern v [concrete]
+// CHECK:STDOUT:     %v.param_patt: %pattern_type.e85 = value_param_pattern %v.patt, call_param1 [concrete]
+// CHECK:STDOUT:     %return.patt: %pattern_type.e85 = return_slot_pattern [concrete]
+// CHECK:STDOUT:     %return.param_patt: %pattern_type.e85 = out_param_pattern %return.patt, call_param2 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %self.param: %empty_tuple.type = value_param call_param0
+// CHECK:STDOUT:     %self: %empty_tuple.type = bind_name self, %self.param
+// CHECK:STDOUT:     %v.param: %struct_type.a = value_param call_param1
+// CHECK:STDOUT:     %v: %struct_type.a = bind_name v, %v.param
+// CHECK:STDOUT:     %return.param: ref %struct_type.a = out_param call_param2
+// CHECK:STDOUT:     %return: ref %struct_type.a = return_slot %return.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
-// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .F = %F.decl.loc16_45.1
 // CHECK:STDOUT:   witness = file.%K.impl_witness
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -2817,6 +2907,13 @@ fn F() {
 // CHECK:STDOUT:   return %v.ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: fn @F.3(%self.param: %empty_tuple.type, %v.param: %struct_type.a) -> %struct_type.a {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %self.ref: %empty_tuple.type = name_ref self, %self.param
+// CHECK:STDOUT:   %v.ref: %struct_type.a = name_ref v, %v.param
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: specific @V(constants.%Self) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @V(constants.%K.facet.589) {}
@@ -2832,8 +2929,8 @@ fn F() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @V(constants.%K.facet.b09) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @F.1(constants.%K.facet.77f) {
-// CHECK:STDOUT:   %Self => constants.%K.facet.77f
+// CHECK:STDOUT: specific @F.1(constants.%K.facet.e32) {
+// CHECK:STDOUT:   %Self => constants.%K.facet.e32
 // CHECK:STDOUT:   %Self.as_type.loc5_14.1 => constants.%empty_tuple.type
 // CHECK:STDOUT:   %pattern_type.loc5_8 => constants.%pattern_type.cb1
 // CHECK:STDOUT:   %K.lookup_impl_witness => constants.%K.impl_witness

+ 410 - 0
toolchain/check/thunk.cpp

@@ -0,0 +1,410 @@
+// 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
+
+#include "toolchain/check/thunk.h"
+
+#include "toolchain/base/kind_switch.h"
+#include "toolchain/check/call.h"
+#include "toolchain/check/diagnostic_helpers.h"
+#include "toolchain/check/function.h"
+#include "toolchain/check/generic.h"
+#include "toolchain/check/inst.h"
+#include "toolchain/check/member_access.h"
+#include "toolchain/check/pattern.h"
+#include "toolchain/check/pattern_match.h"
+#include "toolchain/check/pointer_dereference.h"
+#include "toolchain/check/return.h"
+#include "toolchain/check/type.h"
+#include "toolchain/diagnostics/diagnostic.h"
+#include "toolchain/sem_ir/function.h"
+#include "toolchain/sem_ir/generic.h"
+#include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/inst.h"
+#include "toolchain/sem_ir/pattern.h"
+#include "toolchain/sem_ir/typed_insts.h"
+
+namespace Carbon::Check {
+
+// Adds a pattern instruction for a thunk, copying the location from an existing
+// instruction.
+static auto RebuildPatternInst(Context& context, SemIR::InstId orig_inst_id,
+                               SemIR::Inst new_inst) -> SemIR::InstId {
+  // Ensure we built the same kind of instruction. In particular, this ensures
+  // that the location of the old instruction can be reused for the new one.
+  CARBON_CHECK(context.insts().Get(orig_inst_id).kind() == new_inst.kind(),
+               "Rebuilt pattern with the wrong kind: {0} -> {1}",
+               context.insts().Get(orig_inst_id), new_inst);
+  return AddPatternInst(context, SemIR::LocIdAndInst::UncheckedLoc(
+                                     SemIR::LocId(orig_inst_id), new_inst));
+}
+
+// Wrapper to allow the type to be specified as a template argument for API
+// consistency with `AddInst`.
+template <typename InstT>
+static auto RebuildPatternInst(Context& context, SemIR::InstId orig_inst_id,
+                               InstT new_inst) -> SemIR::InstId {
+  return RebuildPatternInst(context, orig_inst_id, SemIR::Inst(new_inst));
+}
+
+// Makes a copy of the given binding pattern, with its type adjusted to be
+// `new_pattern_type_id`.
+static auto CloneBindingPattern(Context& context, SemIR::InstId pattern_id,
+                                SemIR::AnyBindingPattern pattern,
+                                SemIR::TypeId new_pattern_type_id)
+    -> SemIR::InstId {
+  bool is_generic = pattern.kind == SemIR::SymbolicBindingPattern::Kind;
+  auto entity_name = context.entity_names().Get(pattern.entity_name_id);
+  CARBON_CHECK(is_generic == entity_name.bind_index().has_value());
+
+  // Get the transformed type of the binding.
+  if (new_pattern_type_id == SemIR::ErrorInst::TypeId) {
+    return SemIR::ErrorInst::InstId;
+  }
+  auto type_inst_id = context.types()
+                          .GetAs<SemIR::PatternType>(new_pattern_type_id)
+                          .scrutinee_type_inst_id;
+  auto type_id = context.types().GetTypeIdForTypeInstId(type_inst_id);
+  auto type_expr_region_id = context.sem_ir().expr_regions().Add(
+      {.block_ids = {SemIR::InstBlockId::Empty}, .result_id = type_inst_id});
+
+  // Rebuild the binding pattern.
+  return AddBindingPattern(context, SemIR::LocId(pattern_id),
+                           entity_name.name_id, type_id, type_expr_region_id,
+                           is_generic, entity_name.is_template)
+      .pattern_id;
+}
+
+// Makes a copy of the given pattern instruction, substituting values from a
+// specific as needed. The resulting pattern behaves like a newly-created
+// pattern, so is suitable for running `CalleePatternMatch` against.
+static auto ClonePattern(Context& context, SemIR::SpecificId specific_id,
+                         SemIR::InstId pattern_id) -> SemIR::InstId {
+  if (!pattern_id.has_value()) {
+    return SemIR::InstId::None;
+  }
+
+  auto get_type = [&](SemIR::InstId inst_id) -> SemIR::TypeId {
+    return SemIR::GetTypeOfInstInSpecific(context.sem_ir(), specific_id,
+                                          inst_id);
+  };
+
+  auto pattern = context.insts().Get(pattern_id);
+
+  // Decompose the pattern. The forms we allow for patterns in a function
+  // parameter list are currently fairly restrictive.
+
+  // Optional `addr`, only for `self`.
+  auto [addr, addr_id] = context.insts().TryUnwrap(
+      pattern, pattern_id, &SemIR::AddrPattern::inner_id);
+
+  // Optional parameter pattern.
+  auto [param, param_id] = context.insts().TryUnwrap(
+      pattern, pattern_id, &SemIR::AnyParamPattern::subpattern_id);
+
+  // Finally, either a binding pattern or a return slot pattern.
+  auto new_pattern_id = SemIR::InstId::None;
+  if (auto binding = pattern.TryAs<SemIR::AnyBindingPattern>()) {
+    new_pattern_id = CloneBindingPattern(context, pattern_id, *binding,
+                                         get_type(pattern_id));
+  } else if (auto return_slot = pattern.TryAs<SemIR::ReturnSlotPattern>()) {
+    new_pattern_id = RebuildPatternInst<SemIR::ReturnSlotPattern>(
+        context, pattern_id,
+        {.type_id = get_type(pattern_id),
+         .type_inst_id = SemIR::TypeInstId::None});
+  } else {
+    CARBON_CHECK(pattern.Is<SemIR::ErrorInst>(),
+                 "Unexpected pattern {0} in function signature", pattern);
+    return SemIR::ErrorInst::InstId;
+  }
+
+  // Rebuild parameter.
+  if (param) {
+    new_pattern_id = RebuildPatternInst<SemIR::AnyParamPattern>(
+        context, param_id,
+        {.kind = param->kind,
+         .type_id = get_type(param_id),
+         .subpattern_id = new_pattern_id,
+         .index = SemIR::CallParamIndex::None});
+  }
+
+  // Rebuild `addr`.
+  if (addr) {
+    new_pattern_id = RebuildPatternInst<SemIR::AddrPattern>(
+        context, addr_id,
+        {.type_id = get_type(addr_id), .inner_id = new_pattern_id});
+  }
+
+  return new_pattern_id;
+}
+
+static auto ClonePatternBlock(Context& context, SemIR::SpecificId specific_id,
+                              SemIR::InstBlockId inst_block_id)
+    -> SemIR::InstBlockId {
+  if (!inst_block_id.has_value()) {
+    return SemIR::InstBlockId::None;
+  }
+  return context.inst_blocks().Transform(
+      inst_block_id, [&](SemIR::InstId inst_id) {
+        return ClonePattern(context, specific_id, inst_id);
+      });
+}
+
+static auto CloneFunctionDecl(Context& context, SemIR::LocId loc_id,
+                              SemIR::FunctionId signature_id,
+                              SemIR::SpecificId signature_specific_id,
+                              SemIR::FunctionId callee_id)
+    -> std::pair<SemIR::FunctionId, SemIR::InstId> {
+  StartGenericDecl(context);
+
+  // Clone the signature. Note that we re-get the function after each of these,
+  // because they might trigger imports that invalidate the function.
+  context.pattern_block_stack().Push();
+  auto implicit_param_patterns_id = ClonePatternBlock(
+      context, signature_specific_id,
+      context.functions().Get(signature_id).implicit_param_patterns_id);
+  auto param_patterns_id = ClonePatternBlock(
+      context, signature_specific_id,
+      context.functions().Get(signature_id).param_patterns_id);
+  auto return_slot_pattern_id = ClonePattern(
+      context, signature_specific_id,
+      context.functions().Get(signature_id).return_slot_pattern_id);
+  auto self_param_id = FindSelfPattern(context, implicit_param_patterns_id);
+  auto pattern_block_id = context.pattern_block_stack().Pop();
+
+  // Perform callee-side pattern matching to rebuild the parameter list.
+  context.inst_block_stack().Push();
+  auto call_params_id =
+      CalleePatternMatch(context, implicit_param_patterns_id, param_patterns_id,
+                         return_slot_pattern_id);
+  auto decl_block_id = context.inst_block_stack().Pop();
+
+  // Create the `FunctionDecl` instruction.
+  SemIR::FunctionDecl function_decl = {SemIR::TypeId::None,
+                                       SemIR::FunctionId::None, decl_block_id};
+  auto decl_id = AddPlaceholderInst(
+      context, SemIR::LocIdAndInst::UncheckedLoc(loc_id, function_decl));
+  auto generic_id = BuildGenericDecl(context, decl_id);
+
+  // Create the `Function` object.
+  auto& signature = context.functions().Get(signature_id);
+  auto& callee = context.functions().Get(callee_id);
+  function_decl.function_id = context.functions().Add(
+      SemIR::Function{{.name_id = signature.name_id,
+                       .parent_scope_id = callee.parent_scope_id,
+                       .generic_id = generic_id,
+                       .first_param_node_id = signature.first_param_node_id,
+                       .last_param_node_id = signature.last_param_node_id,
+                       .pattern_block_id = pattern_block_id,
+                       .implicit_param_patterns_id = implicit_param_patterns_id,
+                       .param_patterns_id = param_patterns_id,
+                       .is_extern = false,
+                       .extern_library_id = SemIR::LibraryNameId::None,
+                       .non_owning_decl_id = SemIR::InstId::None,
+                       .first_owning_decl_id = decl_id,
+                       .definition_id = decl_id},
+                      {.call_params_id = call_params_id,
+                       .return_slot_pattern_id = return_slot_pattern_id,
+                       .virtual_modifier = callee.virtual_modifier,
+                       .virtual_index = callee.virtual_index,
+                       .self_param_id = self_param_id}});
+  function_decl.type_id =
+      GetFunctionType(context, function_decl.function_id,
+                      context.scope_stack().PeekSpecificId());
+  ReplaceInstBeforeConstantUse(context, decl_id, function_decl);
+  return {function_decl.function_id, decl_id};
+}
+
+// Build an expression that names the value matched by a pattern.
+static auto BuildPatternRef(Context& context, SemIR::FunctionId function_id,
+                            SemIR::InstId pattern_id) -> SemIR::InstId {
+  auto pattern = context.insts().Get(pattern_id);
+
+  auto addr = context.insts()
+                  .TryUnwrap(pattern, pattern_id, &SemIR::AddrPattern::inner_id)
+                  .first;
+
+  auto pattern_ref_id = SemIR::InstId::None;
+  if (auto value_param = pattern.TryAs<SemIR::ValueParamPattern>()) {
+    // Build a reference to this parameter.
+    auto call_param_id = context.inst_blocks().Get(
+        context.functions()
+            .Get(function_id)
+            .call_params_id)[value_param->index.index];
+    // Use a pretty name for the `name_ref`. While it's suspicious to use a
+    // pretty name in the IR like this, the only reason we include a name at
+    // all here is to make the formatted SemIR more readable.
+    pattern_ref_id = AddInst<SemIR::NameRef>(
+        context, SemIR::LocId(pattern_id),
+        {.type_id = context.insts().Get(call_param_id).type_id(),
+         .name_id = SemIR::GetPrettyNameFromPatternId(
+             context.sem_ir(), value_param->subpattern_id),
+         .value_id = call_param_id});
+  } else {
+    if (pattern_id != SemIR::ErrorInst::InstId) {
+      context.TODO(
+          pattern_id,
+          "don't know how to build reference to this pattern in thunk");
+    }
+    return SemIR::ErrorInst::InstId;
+  }
+
+  if (addr) {
+    pattern_ref_id = PerformPointerDereference(
+        context, SemIR::LocId(pattern_id), pattern_ref_id, [](SemIR::TypeId) {
+          CARBON_FATAL("addr subpattern is not a pointer");
+        });
+  }
+
+  return pattern_ref_id;
+}
+
+// Build a call to a function that forwards the arguments of the enclosing
+// function, for use when constructing a thunk.
+static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
+                           SemIR::InstId callee_id) -> SemIR::InstId {
+  auto loc_id = SemIR::LocId(callee_id);
+  auto& function = context.functions().Get(function_id);
+
+  // If we have a self parameter, form `self.<callee_id>`.
+  if (function.self_param_id.has_value()) {
+    callee_id = PerformCompoundMemberAccess(
+        context, loc_id,
+        BuildPatternRef(context, function_id, function.self_param_id),
+        callee_id);
+  }
+
+  // Form an argument list.
+  llvm::SmallVector<SemIR::InstId> args;
+  for (auto pattern_id :
+       context.inst_blocks().Get(function.param_patterns_id)) {
+    args.push_back(BuildPatternRef(context, function_id, pattern_id));
+  }
+
+  return PerformCall(context, loc_id, callee_id, args);
+}
+
+static auto HasDeclaredReturnType(Context& context,
+                                  SemIR::FunctionId function_id) -> bool {
+  return context.functions()
+      .Get(function_id)
+      .return_slot_pattern_id.has_value();
+}
+
+// Given a declaration of a thunk and the function that it should call, build
+// the thunk body.
+static auto BuildThunkDefinition(Context& context,
+                                 SemIR::FunctionId signature_id,
+                                 SemIR::FunctionId function_id,
+                                 SemIR::InstId thunk_id,
+                                 SemIR::InstId callee_id) {
+  // TODO: Improve the diagnostics produced here. Specifically, it would likely
+  // be better for the primary error message to be that we tried to produce a
+  // thunk because of a type mismatch, but couldn't, with notes explaining
+  // why, rather than the primary error message being whatever went wrong
+  // building the thunk.
+
+  {
+    // The check below produces diagnostics referring to the signature, so also
+    // note the callee.
+    Diagnostics::AnnotationScope annot_scope(
+        &context.emitter(), [&](DiagnosticBuilder& builder) {
+          CARBON_DIAGNOSTIC(ThunkCallee, Note,
+                            "while building thunk calling this function");
+          builder.Note(callee_id, ThunkCallee);
+        });
+
+    CheckFunctionDefinitionSignature(context, function_id);
+  }
+
+  // TODO: This duplicates much of the handling for FunctionDefinitionStart and
+  // FunctionDefinition parse nodes. Consider refactoring.
+  context.scope_stack().PushForFunctionBody(thunk_id);
+  context.inst_block_stack().Push();
+  context.region_stack().PushRegion(context.inst_block_stack().PeekOrAdd());
+  StartGenericDefinition(context,
+                         context.functions().Get(function_id).generic_id);
+
+  // The checks below produce diagnostics pointing at the callee, so also note
+  // the signature.
+  Diagnostics::AnnotationScope annot_scope(
+      &context.emitter(), [&](DiagnosticBuilder& builder) {
+        CARBON_DIAGNOSTIC(
+            ThunkSignature, Note,
+            "while building thunk to match the signature of this function");
+        builder.Note(context.functions().Get(signature_id).first_owning_decl_id,
+                     ThunkSignature);
+      });
+
+  auto call_id = BuildThunkCall(context, function_id, callee_id);
+  if (HasDeclaredReturnType(context, function_id)) {
+    BuildReturnWithExpr(context, SemIR::LocId(callee_id), call_id);
+  } else {
+    BuildReturnWithNoExpr(context, SemIR::LocId(callee_id));
+  }
+
+  context.inst_block_stack().Pop();
+  context.scope_stack().Pop();
+
+  auto& function = context.functions().Get(function_id);
+  function.body_block_ids = context.region_stack().PopRegion();
+  FinishGenericDefinition(context, function.generic_id);
+}
+
+auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
+                SemIR::SpecificId signature_specific_id,
+                SemIR::InstId callee_id) -> SemIR::InstId {
+  auto callee = SemIR::GetCalleeFunction(context.sem_ir(), callee_id);
+
+  // Check whether we can use the given function without a thunk.
+  // TODO: For virtual functions, we want different rules for checking `self`.
+  // TODO: This is too strict; for example, we should not compare parameter
+  // names here.
+  if (CheckFunctionTypeMatches(
+          context, context.functions().Get(callee.function_id),
+          context.functions().Get(signature_id), signature_specific_id,
+          /*check_syntax=*/false, /*check_self=*/true, /*diagnose=*/false)) {
+    return callee_id;
+  }
+
+  // From P3763:
+  //   If the function in the interface does not have a return type, the
+  //   program is invalid if the function in the impl specifies a return type.
+  //
+  // Call into the redeclaration checking logic to produce a suitable error.
+  //
+  // TODO: Consider a different rule: always use an explicit return type for the
+  // thunk, and always convert the result of the wrapped call to the return type
+  // of the thunk.
+  if (!HasDeclaredReturnType(context, signature_id) &&
+      HasDeclaredReturnType(context, callee.function_id)) {
+    bool success = CheckFunctionReturnTypeMatches(
+        context, context.functions().Get(callee.function_id),
+        context.functions().Get(signature_id), signature_specific_id);
+    CARBON_CHECK(!success, "Return type unexpectedly matches");
+    return SemIR::ErrorInst::InstId;
+  }
+
+  // Create a scope for the function's parameters and generic parameters.
+  context.scope_stack().PushForDeclName();
+
+  // We can't use the function directly. Build a thunk.
+  // TODO: Check for and diagnose obvious reasons why this will fail, such as
+  // arity mismatch, before trying to build the thunk.
+  auto [function_id, thunk_id] =
+      CloneFunctionDecl(context, SemIR::LocId(callee_id), signature_id,
+                        signature_specific_id, callee.function_id);
+
+  // Define the thunk.
+  // TODO: We should delay doing this until we get to the end of the enclosing
+  // deferred definition scope, if there is one. For example, an `impl` inside a
+  // `class` definition should have its thunks defined at the end of the class,
+  // like they would be if they were defined inline.
+  BuildThunkDefinition(context, signature_id, function_id, thunk_id, callee_id);
+
+  context.scope_stack().Pop();
+
+  return thunk_id;
+}
+
+}  // namespace Carbon::Check

+ 22 - 0
toolchain/check/thunk.h

@@ -0,0 +1,22 @@
+// 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
+
+#ifndef CARBON_TOOLCHAIN_CHECK_THUNK_H_
+#define CARBON_TOOLCHAIN_CHECK_THUNK_H_
+
+#include "toolchain/check/context.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::Check {
+
+// Given a function signature and a callee function, build a thunk that matches
+// the given signature and calls the specified callee. Returns the callee
+// unchanged if it can be used directly.
+auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
+                SemIR::SpecificId signature_specific_id,
+                SemIR::InstId callee_id) -> SemIR::InstId;
+
+}  // namespace Carbon::Check
+
+#endif  // CARBON_TOOLCHAIN_CHECK_THUNK_H_

+ 2 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -240,6 +240,8 @@ CARBON_DIAGNOSTIC_KIND(InvalidMainRunSignature)
 CARBON_DIAGNOSTIC_KIND(MissingReturnStatement)
 CARBON_DIAGNOSTIC_KIND(UnknownBuiltinFunctionName)
 CARBON_DIAGNOSTIC_KIND(InvalidBuiltinSignature)
+CARBON_DIAGNOSTIC_KIND(ThunkSignature)
+CARBON_DIAGNOSTIC_KIND(ThunkCallee)
 
 CARBON_DIAGNOSTIC_KIND(DestroyFunctionOutsideClass)
 CARBON_DIAGNOSTIC_KIND(DestroyFunctionMissingSelf)

+ 8 - 0
toolchain/sem_ir/block_value_store.h

@@ -57,6 +57,14 @@ class BlockValueStore : public Yaml::Printable<BlockValueStore<IdT>> {
     return values_.Get(id);
   }
 
+  // Returns a new block formed by applying `transform(elem_id)` to each element
+  // in the specified block.
+  template <typename TransformFnT>
+  auto Transform(IdT id, TransformFnT transform) -> IdT {
+    llvm::SmallVector<ElementType> block(llvm::map_range(Get(id), transform));
+    return Add(block);
+  }
+
   // Adds a block or finds an existing canonical block with the given content,
   // and returns an ID to reference it.
   auto AddCanonical(llvm::ArrayRef<ElementType> content) -> IdT {

+ 5 - 12
toolchain/sem_ir/function.cpp

@@ -70,23 +70,16 @@ auto Function::GetParamPatternInfoFromPatternId(const File& sem_ir,
   auto inst_id = pattern_id;
   auto inst = sem_ir.insts().Get(inst_id);
 
-  if (auto addr_pattern = inst.TryAs<AddrPattern>()) {
-    inst_id = addr_pattern->inner_id;
-    inst = sem_ir.insts().Get(inst_id);
-  }
-
-  auto param_pattern_inst = inst.TryAs<AnyParamPattern>();
-  if (!param_pattern_inst) {
+  sem_ir.insts().TryUnwrap(inst, inst_id, &AddrPattern::inner_id);
+  auto [param_pattern, param_pattern_id] =
+      sem_ir.insts().TryUnwrap(inst, inst_id, &AnyParamPattern::subpattern_id);
+  if (!param_pattern) {
     return std::nullopt;
   }
-  auto param_pattern_id = inst_id;
-
-  inst_id = param_pattern_inst->subpattern_id;
-  inst = sem_ir.insts().Get(inst_id);
 
   auto binding_pattern = inst.As<AnyBindingPattern>();
   return {{.inst_id = param_pattern_id,
-           .inst = *param_pattern_inst,
+           .inst = *param_pattern,
            .entity_name_id = binding_pattern.entity_name_id}};
 }
 

+ 17 - 0
toolchain/sem_ir/inst.h

@@ -451,6 +451,23 @@ class InstStore {
     return TryGetAs<InstT>(inst_id);
   }
 
+  // Attempts to convert the given instruction to the type that contains
+  // `member`. If it can be converted, the instruction ID and instruction are
+  // replaced by the unwrapped value of that member, and the converted wrapper
+  // instruction and its ID are returned. Otherwise returns {nullopt, None}.
+  template <typename InstT, typename InstIdT>
+    requires std::derived_from<InstIdT, InstId>
+  auto TryUnwrap(Inst& inst, InstId& inst_id, InstIdT InstT::*member) const
+      -> std::pair<std::optional<InstT>, InstId> {
+    if (auto wrapped_inst = inst.TryAs<InstT>()) {
+      auto wrapped_inst_id = inst_id;
+      inst_id = (*wrapped_inst).*member;
+      inst = Get(inst_id);
+      return {wrapped_inst, wrapped_inst_id};
+    }
+    return {std::nullopt, InstId::None};
+  }
+
   // Returns a resolved LocId, which will point to a parse node, an import, or
   // be None.
   //

+ 8 - 11
toolchain/sem_ir/typed_insts.h

@@ -1393,23 +1393,20 @@ struct RequireCompleteType {
 };
 
 struct Return {
-  static constexpr auto Kind =
-      InstKind::Return.Define<Parse::NodeIdOneOf<Parse::FunctionDefinitionId,
-                                                 Parse::ReturnStatementId>>(
-          {.ir_name = "return",
-           .constant_kind = InstConstantKind::Never,
-           .terminator_kind = TerminatorKind::Terminator});
+  static constexpr auto Kind = InstKind::Return.Define<Parse::NodeId>(
+      {.ir_name = "return",
+       .constant_kind = InstConstantKind::Never,
+       .terminator_kind = TerminatorKind::Terminator});
 
   // This is a statement, so has no type.
 };
 
 // A `return expr;` statement.
 struct ReturnExpr {
-  static constexpr auto Kind =
-      InstKind::ReturnExpr.Define<Parse::ReturnStatementId>(
-          {.ir_name = "return",
-           .constant_kind = InstConstantKind::Never,
-           .terminator_kind = TerminatorKind::Terminator});
+  static constexpr auto Kind = InstKind::ReturnExpr.Define<Parse::NodeId>(
+      {.ir_name = "return",
+       .constant_kind = InstConstantKind::Never,
+       .terminator_kind = TerminatorKind::Terminator});
 
   // This is a statement, so has no type.
   InstId expr_id;

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.