Pārlūkot izejas kodu

Disallow compile time bindings where they aren't clearly supported. (#4338)

This is resolving a fuzz-discovered crash related to function suspends
and compile time bind indices. Although the crash originally came from
clearly invalid syntax (missing the `=` inside a `class` decl), the
syntax with a value should also be valid but has the same crash.

This approach disallows compile-time bindings in contexts that can
create ambiguous results, particularly class declarations. These are an
issue because a suspended function can have let declarations after it.
I'm allowing them in function bodies and interface scopes.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Jon Ross-Perkins 1 gadu atpakaļ
vecāks
revīzija
87678cc374

+ 17 - 3
toolchain/check/handle_binding_pattern.cpp

@@ -32,6 +32,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
         inst_id.is_valid() && context.insts().Is<SemIR::InterfaceDecl>(inst_id);
   }
 
+  bool needs_compile_time_binding = is_generic && !is_associated_constant;
+
   // Create the appropriate kind of binding for this pattern.
   auto make_bind_name = [&](SemIR::TypeId type_id,
                             SemIR::InstId value_id) -> SemIR::LocIdAndInst {
@@ -42,7 +44,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
          .parent_scope_id = context.scope_stack().PeekNameScopeId(),
          // TODO: Don't allocate a compile-time binding index for an associated
          // constant declaration.
-         .bind_index = is_generic && !is_associated_constant
+         .bind_index = needs_compile_time_binding
                            ? context.scope_stack().AddCompileTimeBinding()
                            : SemIR::CompileTimeBindIndex::Invalid});
     if (is_generic) {
@@ -63,7 +65,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
   // stack.
   auto push_bind_name = [&](SemIR::InstId bind_id) {
     context.node_stack().Push(node_id, bind_id);
-    if (is_generic && !is_associated_constant) {
+    if (needs_compile_time_binding) {
       context.scope_stack().PushCompileTimeBinding(bind_id);
     }
   };
@@ -200,7 +202,19 @@ auto HandleParseNode(Context& context, Parse::BindingPatternId node_id)
 
 auto HandleParseNode(Context& context,
                      Parse::CompileTimeBindingPatternId node_id) -> bool {
-  return HandleAnyBindingPattern(context, node_id, /*is_generic=*/true);
+  bool is_generic = true;
+  if (context.decl_introducer_state_stack().innermost().kind ==
+      Lex::TokenKind::Let) {
+    auto scope_inst = context.insts().Get(context.scope_stack().PeekInstId());
+    if (!scope_inst.Is<SemIR::InterfaceDecl>() &&
+        !scope_inst.Is<SemIR::FunctionDecl>()) {
+      context.TODO(node_id,
+                   "`let` compile time binding outside function or interface");
+      is_generic = false;
+    }
+  }
+
+  return HandleAnyBindingPattern(context, node_id, is_generic);
 }
 
 auto HandleParseNode(Context& context, Parse::AddrId node_id) -> bool {

+ 16 - 14
toolchain/check/scope_stack.cpp

@@ -13,6 +13,18 @@ auto ScopeStack::VerifyOnFinish() -> void {
   CARBON_CHECK(scope_stack_.empty(), "{0}", scope_stack_.size());
 }
 
+auto ScopeStack::VerifyNextCompileTimeBindIndex(llvm::StringLiteral label,
+                                                const ScopeStackEntry& scope)
+    -> void {
+  CARBON_CHECK(
+      static_cast<int32_t>(compile_time_binding_stack_.all_values_size()) ==
+          scope.next_compile_time_bind_index.index,
+      "Wrong number of entries in compile-time binding stack after {0}: have "
+      "{1}, expected {2}",
+      label, compile_time_binding_stack_.all_values_size(),
+      scope.next_compile_time_bind_index.index);
+}
+
 auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
                       SemIR::SpecificId specific_id,
                       bool lexical_lookup_has_load_error) -> void {
@@ -49,6 +61,8 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
   CARBON_CHECK(next_scope_index_.index != std::numeric_limits<int32_t>::max(),
                "Ran out of scopes");
   ++next_scope_index_.index;
+
+  VerifyNextCompileTimeBindIndex("Push", scope_stack_.back());
 }
 
 auto ScopeStack::Pop() -> void {
@@ -72,13 +86,7 @@ auto ScopeStack::Pop() -> void {
     return_scope_stack_.back().returned_var = SemIR::InstId::Invalid;
   }
 
-  CARBON_CHECK(
-      scope.next_compile_time_bind_index.index ==
-          static_cast<int32_t>(compile_time_binding_stack_.all_values_size()),
-      "Wrong number of entries in compile-time binding stack, have {0}, "
-      "expected {1}",
-      compile_time_binding_stack_.all_values_size(),
-      scope.next_compile_time_bind_index.index);
+  VerifyNextCompileTimeBindIndex("Pop", scope);
   compile_time_binding_stack_.PopArray();
 }
 
@@ -216,13 +224,7 @@ auto ScopeStack::Restore(SuspendedScope scope) -> void {
     }
   }
 
-  CARBON_CHECK(
-      scope.entry.next_compile_time_bind_index.index ==
-          static_cast<int32_t>(compile_time_binding_stack_.all_values_size()),
-      "Wrong number of entries in compile-time binding stack when restoring, "
-      "have {0}, expected {1}",
-      compile_time_binding_stack_.all_values_size(),
-      scope.entry.next_compile_time_bind_index.index);
+  VerifyNextCompileTimeBindIndex("Restore", scope.entry);
 
   if (scope.entry.scope_id.is_valid()) {
     non_lexical_scope_stack_.push_back(

+ 7 - 0
toolchain/check/scope_stack.h

@@ -212,6 +212,13 @@ class ScopeStack {
            scope_stack_.back().lexical_lookup_has_load_error;
   }
 
+  // Checks that the provided scope's `next_compile_time_bind_index` matches the
+  // full size of the current `compile_time_binding_stack_`. The values should
+  // always match, and this is used to validate the correspondence during
+  // significant changes.
+  auto VerifyNextCompileTimeBindIndex(llvm::StringLiteral label,
+                                      const ScopeStackEntry& scope) -> void;
+
   // A stack of scopes from which we can `return`.
   llvm::SmallVector<ReturnScope> return_scope_stack_;
 

+ 822 - 0
toolchain/check/testdata/let/compile_time_bindings.carbon

@@ -0,0 +1,822 @@
+
+// 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
+//
+// This is mostly checking against crashes for compile time bindings in
+// difficult contexts.
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/let/compile_time_bindings.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/let/compile_time_bindings.carbon
+
+// --- fail_let_after.carbon
+
+library "[[@TEST_NAME]]";
+
+class C {
+  fn F() -> () { return x; }
+  // CHECK:STDERR: fail_let_after.carbon:[[@LINE+4]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let x:! () = ();
+  // CHECK:STDERR:       ^~~~~~
+  // CHECK:STDERR:
+  let x:! () = ();
+}
+
+// --- fail_let_before.carbon
+
+library "[[@TEST_NAME]]";
+
+class C {
+  // CHECK:STDERR: fail_let_before.carbon:[[@LINE+4]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let x:! () = ();
+  // CHECK:STDERR:       ^~~~~~
+  // CHECK:STDERR:
+  let x:! () = ();
+  fn F() -> () { return x; }
+}
+
+// --- fail_multiple_lets.carbon
+
+library "[[@TEST_NAME]]";
+
+class C {
+  // CHECK:STDERR: fail_multiple_lets.carbon:[[@LINE+4]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let a:! () = ();
+  // CHECK:STDERR:       ^~~~~~
+  // CHECK:STDERR:
+  let a:! () = ();
+  fn F(b:! ((),)) {
+    let c:! ((), ()) = ((), ());
+
+    var a1: () = a;
+    var b1: ((),) = b;
+    var c1: ((), ()) = c;
+    var d1: ((), (), ()) = d;
+  }
+  // CHECK:STDERR: fail_multiple_lets.carbon:[[@LINE+4]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let d:! ((), (), ()) = ((), (), ());
+  // CHECK:STDERR:       ^~~~~~~~~~~~~~~~
+  // CHECK:STDERR:
+  let d:! ((), (), ()) = ((), (), ());
+}
+
+// --- fail_invalid_let_after.carbon
+
+library "[[@TEST_NAME]]";
+
+class C {
+  fn F() -> () { return x; }
+  // CHECK:STDERR: fail_invalid_let_after.carbon:[[@LINE+8]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let x:! ();
+  // CHECK:STDERR:       ^~~~~~
+  // CHECK:STDERR:
+  // CHECK:STDERR: fail_invalid_let_after.carbon:[[@LINE+4]]:13: error: expected `=`; `let` declaration must have an initializer
+  // CHECK:STDERR:   let x:! ();
+  // CHECK:STDERR:             ^
+  // CHECK:STDERR:
+  let x:! ();
+}
+
+// --- use_in_function.carbon
+
+library "[[@TEST_NAME]]";
+
+fn F() -> i32 {
+  let Zero:! i32 = 0;
+  return Zero;
+}
+
+// --- fail_return_in_interface.carbon
+
+library "[[@TEST_NAME]]";
+
+interface I {
+  let T:! type = i32;
+  // CHECK:STDERR: fail_return_in_interface.carbon:[[@LINE+7]]:13: error: cannot implicitly convert from `<associated type in I>` to `type`
+  // CHECK:STDERR:   fn F() -> T;
+  // CHECK:STDERR:             ^
+  // CHECK:STDERR: fail_return_in_interface.carbon:[[@LINE+4]]:13: note: type `<associated type in I>` does not implement interface `ImplicitAs`
+  // CHECK:STDERR:   fn F() -> T;
+  // CHECK:STDERR:             ^
+  // CHECK:STDERR:
+  fn F() -> T;
+}
+
+// --- fail_return_in_class.carbon
+
+library "[[@TEST_NAME]]";
+
+class I {
+  // CHECK:STDERR: fail_return_in_class.carbon:[[@LINE+4]]:7: error: semantics TODO: ``let` compile time binding outside function or interface`
+  // CHECK:STDERR:   let T:! type = i32;
+  // CHECK:STDERR:       ^~~~~~~~
+  // CHECK:STDERR:
+  let T:! type = i32;
+  // CHECK:STDERR: fail_return_in_class.carbon:[[@LINE+4]]:13: error: cannot evaluate type expression
+  // CHECK:STDERR:   fn F() -> T;
+  // CHECK:STDERR:             ^
+  // CHECK:STDERR:
+  fn F() -> T;
+}
+
+// --- fail_return_in_package_scope.carbon
+
+library "[[@TEST_NAME]]";
+
+// CHECK:STDERR: fail_return_in_package_scope.carbon:[[@LINE+4]]:5: error: semantics TODO: ``let` compile time binding outside function or interface`
+// CHECK:STDERR: let T:! type = i32;
+// CHECK:STDERR:     ^~~~~~~~
+// CHECK:STDERR:
+let T:! type = i32;
+// CHECK:STDERR: fail_return_in_package_scope.carbon:[[@LINE+3]]:11: error: cannot evaluate type expression
+// CHECK:STDERR: fn F() -> T;
+// CHECK:STDERR:           ^
+fn F() -> T;
+
+// CHECK:STDOUT: --- fail_let_after.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %.loc5_14.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc5_14.2: type = converted %.loc5_14.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %return.var: ref %.1 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc10_12.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc10_12.2: type = converted %.loc10_12.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc10_17: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc10_18: %.1 = converted %.loc10_17, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:   %x: %.1 = bind_name x, %.loc10_18
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .x = %x
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> %.1 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.1 = name_ref x, @C.%x
+// CHECK:STDOUT:   return %x.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_let_before.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc9_12.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc9_12.2: type = converted %.loc9_12.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc9_17: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc9_18: %.1 = converted %.loc9_17, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:   %x: %.1 = bind_name x, %.loc9_18
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %.loc10_14.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_14.2: type = converted %.loc10_14.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %return.var: ref %.1 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc11: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .x = %x
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> %.1 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.1 = name_ref x, @C.%x
+// CHECK:STDOUT:   return %x.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_multiple_lets.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %tuple.1: %.1 = tuple_value () [template]
+// CHECK:STDOUT:   %.2: type = tuple_type (%.1) [template]
+// CHECK:STDOUT:   %b: %.2 = bind_symbolic_name b 0 [symbolic]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = tuple_type (%.1, %.1, %.1) [template]
+// CHECK:STDOUT:   %.4: type = ptr_type %.3 [template]
+// CHECK:STDOUT:   %tuple.2: %.3 = tuple_value (%tuple.1, %tuple.1, %tuple.1) [template]
+// CHECK:STDOUT:   %.5: type = struct_type {} [template]
+// CHECK:STDOUT:   %.6: <witness> = complete_type_witness %.5 [template]
+// CHECK:STDOUT:   %.7: type = tuple_type (%.1, %.1) [template]
+// CHECK:STDOUT:   %.8: type = ptr_type %.7 [template]
+// CHECK:STDOUT:   %tuple.3: %.7 = tuple_value (%tuple.1, %tuple.1) [template]
+// CHECK:STDOUT:   %c: %.7 = bind_symbolic_name c 1 [symbolic]
+// CHECK:STDOUT:   %tuple.4: %.2 = tuple_value (%tuple.1) [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %.loc9_12.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc9_12.2: type = converted %.loc9_12.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc9_17: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %tuple.loc9: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:   %.loc9_18: %.1 = converted %.loc9_17, %tuple.loc9 [template = constants.%tuple.1]
+// CHECK:STDOUT:   %a: %.1 = bind_name a, %.loc9_18
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %.loc10_14: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc10_16.1: %.2 = tuple_literal (%.loc10_14)
+// CHECK:STDOUT:     %.loc10_16.2: type = converted %.loc10_14, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc10_16.3: type = converted %.loc10_16.1, constants.%.2 [template = constants.%.2]
+// CHECK:STDOUT:     %b.loc10_8.1: %.2 = param b, runtime_param<invalid>
+// CHECK:STDOUT:     %b.loc10_8.2: %.2 = bind_symbolic_name b 0, %b.loc10_8.1 [symbolic = @F.%b.1 (constants.%b)]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc22_13: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_17: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_21: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_22.1: %.3 = tuple_literal (%.loc22_13, %.loc22_17, %.loc22_21)
+// CHECK:STDOUT:   %.loc22_22.2: type = converted %.loc22_13, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc22_22.3: type = converted %.loc22_17, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc22_22.4: type = converted %.loc22_21, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc22_22.5: type = converted %.loc22_22.1, constants.%.3 [template = constants.%.3]
+// CHECK:STDOUT:   %.loc22_28: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_32: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_36: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc22_37.1: %.3 = tuple_literal (%.loc22_28, %.loc22_32, %.loc22_36)
+// CHECK:STDOUT:   %tuple.loc22_28: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:   %.loc22_37.2: %.1 = converted %.loc22_28, %tuple.loc22_28 [template = constants.%tuple.1]
+// CHECK:STDOUT:   %tuple.loc22_32: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:   %.loc22_37.3: %.1 = converted %.loc22_32, %tuple.loc22_32 [template = constants.%tuple.1]
+// CHECK:STDOUT:   %tuple.loc22_36: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:   %.loc22_37.4: %.1 = converted %.loc22_36, %tuple.loc22_36 [template = constants.%tuple.1]
+// CHECK:STDOUT:   %tuple.loc22_37: %.3 = tuple_value (%.loc22_37.2, %.loc22_37.3, %.loc22_37.4) [template = constants.%tuple.2]
+// CHECK:STDOUT:   %.loc22_38: %.3 = converted %.loc22_37.1, %tuple.loc22_37 [template = constants.%tuple.2]
+// CHECK:STDOUT:   %d: %.3 = bind_name d, %.loc22_38
+// CHECK:STDOUT:   %.loc23: <witness> = complete_type_witness %.5 [template = constants.%.6]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .a = %a
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .d = %d
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F(@C.%b.loc10_8.2: %.2) {
+// CHECK:STDOUT:   %b.1: %.2 = bind_symbolic_name b 0 [symbolic = %b.1 (constants.%b)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %c.1: %.7 = bind_symbolic_name c 1 [symbolic = %c.1 (constants.%c)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn(@C.%b.loc10_8.2: %.2) {
+// CHECK:STDOUT:   !entry:
+// CHECK:STDOUT:     %.loc11_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc11_19: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc11_20.1: %.7 = tuple_literal (%.loc11_15, %.loc11_19)
+// CHECK:STDOUT:     %.loc11_20.2: type = converted %.loc11_15, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc11_20.3: type = converted %.loc11_19, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc11_20.4: type = converted %.loc11_20.1, constants.%.7 [template = constants.%.7]
+// CHECK:STDOUT:     %.loc11_26: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc11_30: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc11_31.1: %.7 = tuple_literal (%.loc11_26, %.loc11_30)
+// CHECK:STDOUT:     %tuple.loc11_26: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc11_31.2: %.1 = converted %.loc11_26, %tuple.loc11_26 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %tuple.loc11_30: %.1 = tuple_value () [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc11_31.3: %.1 = converted %.loc11_30, %tuple.loc11_30 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %tuple.loc11_31: %.7 = tuple_value (%.loc11_31.2, %.loc11_31.3) [template = constants.%tuple.3]
+// CHECK:STDOUT:     %.loc11_32: %.7 = converted %.loc11_31.1, %tuple.loc11_31 [template = constants.%tuple.3]
+// CHECK:STDOUT:     %c.loc11: %.7 = bind_symbolic_name c 1, %.loc11_32 [symbolic = %c.1 (constants.%c)]
+// CHECK:STDOUT:     %.loc13_14.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc13_14.2: type = converted %.loc13_14.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %a1.var: ref %.1 = var a1
+// CHECK:STDOUT:     %a1: ref %.1 = bind_name a1, %a1.var
+// CHECK:STDOUT:     %a.ref: %.1 = name_ref a, @C.%a
+// CHECK:STDOUT:     %.loc13_18: init %.1 = tuple_init () to %a1.var [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc13_19: init %.1 = converted %a.ref, %.loc13_18 [template = constants.%tuple.1]
+// CHECK:STDOUT:     assign %a1.var, %.loc13_19
+// CHECK:STDOUT:     %.loc14_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc14_17.1: %.2 = tuple_literal (%.loc14_15)
+// CHECK:STDOUT:     %.loc14_17.2: type = converted %.loc14_15, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc14_17.3: type = converted %.loc14_17.1, constants.%.2 [template = constants.%.2]
+// CHECK:STDOUT:     %b1.var: ref %.2 = var b1
+// CHECK:STDOUT:     %b1: ref %.2 = bind_name b1, %b1.var
+// CHECK:STDOUT:     %b.ref: %.2 = name_ref b, @C.%b.loc10_8.2 [symbolic = %b.1 (constants.%b)]
+// CHECK:STDOUT:     %.loc14_21.1: %.1 = tuple_access %b.ref, element0
+// CHECK:STDOUT:     %.loc14_21.2: ref %.1 = tuple_access %b1.var, element0
+// CHECK:STDOUT:     %.loc14_21.3: init %.1 = tuple_init () to %.loc14_21.2 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc14_21.4: init %.1 = converted %.loc14_21.1, %.loc14_21.3 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc14_21.5: init %.2 = tuple_init (%.loc14_21.4) to %b1.var [template = constants.%tuple.4]
+// CHECK:STDOUT:     %.loc14_22: init %.2 = converted %b.ref, %.loc14_21.5 [template = constants.%tuple.4]
+// CHECK:STDOUT:     assign %b1.var, %.loc14_22
+// CHECK:STDOUT:     %.loc15_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc15_19: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc15_20.1: %.7 = tuple_literal (%.loc15_15, %.loc15_19)
+// CHECK:STDOUT:     %.loc15_20.2: type = converted %.loc15_15, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc15_20.3: type = converted %.loc15_19, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc15_20.4: type = converted %.loc15_20.1, constants.%.7 [template = constants.%.7]
+// CHECK:STDOUT:     %c1.var: ref %.7 = var c1
+// CHECK:STDOUT:     %c1: ref %.7 = bind_name c1, %c1.var
+// CHECK:STDOUT:     %c.ref: %.7 = name_ref c, %c.loc11 [symbolic = %c.1 (constants.%c)]
+// CHECK:STDOUT:     %.loc15_24.1: %.1 = tuple_access %c.ref, element0
+// CHECK:STDOUT:     %.loc15_24.2: ref %.1 = tuple_access %c1.var, element0
+// CHECK:STDOUT:     %.loc15_24.3: init %.1 = tuple_init () to %.loc15_24.2 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc15_24.4: init %.1 = converted %.loc15_24.1, %.loc15_24.3 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc15_24.5: %.1 = tuple_access %c.ref, element1
+// CHECK:STDOUT:     %.loc15_24.6: ref %.1 = tuple_access %c1.var, element1
+// CHECK:STDOUT:     %.loc15_24.7: init %.1 = tuple_init () to %.loc15_24.6 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc15_24.8: init %.1 = converted %.loc15_24.5, %.loc15_24.7 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc15_24.9: init %.7 = tuple_init (%.loc15_24.4, %.loc15_24.8) to %c1.var [template = constants.%tuple.3]
+// CHECK:STDOUT:     %.loc15_25: init %.7 = converted %c.ref, %.loc15_24.9 [template = constants.%tuple.3]
+// CHECK:STDOUT:     assign %c1.var, %.loc15_25
+// CHECK:STDOUT:     %.loc16_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc16_19: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc16_23: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc16_24.1: %.3 = tuple_literal (%.loc16_15, %.loc16_19, %.loc16_23)
+// CHECK:STDOUT:     %.loc16_24.2: type = converted %.loc16_15, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc16_24.3: type = converted %.loc16_19, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc16_24.4: type = converted %.loc16_23, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %.loc16_24.5: type = converted %.loc16_24.1, constants.%.3 [template = constants.%.3]
+// CHECK:STDOUT:     %d1.var: ref %.3 = var d1
+// CHECK:STDOUT:     %d1: ref %.3 = bind_name d1, %d1.var
+// CHECK:STDOUT:     %d.ref: %.3 = name_ref d, @C.%d
+// CHECK:STDOUT:     %.loc16_28.1: %.1 = tuple_access %d.ref, element0
+// CHECK:STDOUT:     %.loc16_28.2: ref %.1 = tuple_access %d1.var, element0
+// CHECK:STDOUT:     %.loc16_28.3: init %.1 = tuple_init () to %.loc16_28.2 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.4: init %.1 = converted %.loc16_28.1, %.loc16_28.3 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.5: %.1 = tuple_access %d.ref, element1
+// CHECK:STDOUT:     %.loc16_28.6: ref %.1 = tuple_access %d1.var, element1
+// CHECK:STDOUT:     %.loc16_28.7: init %.1 = tuple_init () to %.loc16_28.6 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.8: init %.1 = converted %.loc16_28.5, %.loc16_28.7 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.9: %.1 = tuple_access %d.ref, element2
+// CHECK:STDOUT:     %.loc16_28.10: ref %.1 = tuple_access %d1.var, element2
+// CHECK:STDOUT:     %.loc16_28.11: init %.1 = tuple_init () to %.loc16_28.10 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.12: init %.1 = converted %.loc16_28.9, %.loc16_28.11 [template = constants.%tuple.1]
+// CHECK:STDOUT:     %.loc16_28.13: init %.3 = tuple_init (%.loc16_28.4, %.loc16_28.8, %.loc16_28.12) to %d1.var [template = constants.%tuple.2]
+// CHECK:STDOUT:     %.loc16_29: init %.3 = converted %d.ref, %.loc16_28.13 [template = constants.%tuple.2]
+// CHECK:STDOUT:     assign %d1.var, %.loc16_29
+// CHECK:STDOUT:     return
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F(constants.%b) {
+// CHECK:STDOUT:   %b.1 => constants.%b
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_invalid_let_after.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %C: type = class_type @C [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .C = %C.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %C.decl: type = class_decl @C [template = constants.%C] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @C {
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %.loc5_14.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:     %.loc5_14.2: type = converted %.loc5_14.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %return.var: ref %.1 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc14_12.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc14_12.2: type = converted %.loc14_12.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %x: %.1 = bind_name x, <error>
+// CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%C
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT:   .x = %x
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> %.1 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %x.ref: %.1 = name_ref x, @C.%x
+// CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template = constants.%tuple]
+// CHECK:STDOUT:   %.loc5: %.1 = converted %x.ref, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:   return %.loc5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- use_in_function.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: i32 = int_literal 0 [template]
+// CHECK:STDOUT:   %Zero: i32 = bind_symbolic_name Zero 0 [symbolic]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int32 = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc4_11.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc4_11.2: type = converted %int.make_type_32, %.loc4_11.1 [template = i32]
+// CHECK:STDOUT:     @F.%return: ref i32 = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc5_14.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc5_14.2: type = converted %int.make_type_32, %.loc5_14.1 [template = i32]
+// CHECK:STDOUT:   %.loc5_20: i32 = int_literal 0 [template = constants.%.2]
+// CHECK:STDOUT:   %Zero: i32 = bind_symbolic_name Zero 0, %.loc5_20 [symbolic = constants.%Zero]
+// CHECK:STDOUT:   %Zero.ref: i32 = name_ref Zero, %Zero [symbolic = constants.%Zero]
+// CHECK:STDOUT:   return %Zero.ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_return_in_interface.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self.1: %.1 = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.2: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: type = assoc_entity_type %.1, type [template]
+// CHECK:STDOUT:   %.4: %.3 = assoc_entity element0, @I.%T [template]
+// CHECK:STDOUT:   %ImplicitAs.type: type = generic_interface_type @ImplicitAs [template]
+// CHECK:STDOUT:   %ImplicitAs: %ImplicitAs.type = struct_value () [template]
+// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic]
+// CHECK:STDOUT:   %.5: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic]
+// CHECK:STDOUT:   %Self.2: @ImplicitAs.%.1 (%.5) = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Self.3: %.5 = bind_symbolic_name Self 1 [symbolic]
+// CHECK:STDOUT:   %Convert.type.1: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic]
+// CHECK:STDOUT:   %Convert.1: %Convert.type.1 = struct_value () [symbolic]
+// CHECK:STDOUT:   %.6: type = assoc_entity_type %.5, %Convert.type.1 [symbolic]
+// CHECK:STDOUT:   %.7: %.6 = assoc_entity element0, imports.%import_ref.6 [symbolic]
+// CHECK:STDOUT:   %.8: type = interface_type @ImplicitAs, @ImplicitAs(type) [template]
+// CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert, @ImplicitAs(type) [template]
+// CHECK:STDOUT:   %Convert.2: %Convert.type.2 = struct_value () [template]
+// CHECK:STDOUT:   %.9: type = assoc_entity_type %.8, %Convert.type.2 [template]
+// CHECK:STDOUT:   %.10: %.9 = assoc_entity element0, imports.%import_ref.6 [template]
+// CHECK:STDOUT:   %.11: %.6 = assoc_entity element0, imports.%import_ref.7 [symbolic]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.12: type = assoc_entity_type %.1, %F.type [template]
+// CHECK:STDOUT:   %.13: %.12 = assoc_entity element1, @I.%F.decl [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int32 = %import_ref.1
+// CHECK:STDOUT:     .ImplicitAs = %import_ref.2
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT:   %import_ref.2: %ImplicitAs.type = import_ref Core//prelude/operators/as, inst+37, loaded [template = constants.%ImplicitAs]
+// CHECK:STDOUT:   %import_ref.3 = import_ref Core//prelude/operators/as, inst+42, unloaded
+// CHECK:STDOUT:   %import_ref.4: @ImplicitAs.%.2 (%.6) = import_ref Core//prelude/operators/as, inst+59, loaded [symbolic = @ImplicitAs.%.3 (constants.%.11)]
+// CHECK:STDOUT:   %import_ref.5 = import_ref Core//prelude/operators/as, inst+52, unloaded
+// CHECK:STDOUT:   %import_ref.6 = import_ref Core//prelude/operators/as, inst+52, unloaded
+// CHECK:STDOUT:   %import_ref.7 = import_ref Core//prelude/operators/as, inst+52, unloaded
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: %.1 = bind_symbolic_name Self 0 [symbolic = constants.%Self.1]
+// CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc5_21.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc5_21.2: type = converted %int.make_type_32, %.loc5_21.1 [template = i32]
+// CHECK:STDOUT:   %T: type = assoc_const_decl T [template]
+// CHECK:STDOUT:   %.loc5_21.3: %.3 = assoc_entity element0, %T [template = constants.%.4]
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %T.ref: %.3 = name_ref T, %.loc5_21.3 [template = constants.%.4]
+// CHECK:STDOUT:     %.loc13_13.1: type = interface_type @ImplicitAs, @ImplicitAs(type) [template = constants.%.8]
+// CHECK:STDOUT:     %.loc13_13.2: %.9 = specific_constant imports.%import_ref.4, @ImplicitAs(type) [template = constants.%.10]
+// CHECK:STDOUT:     %Convert.ref: %.9 = name_ref Convert, %.loc13_13.2 [template = constants.%.10]
+// CHECK:STDOUT:     %.loc13_13.3: type = converted %T.ref, <error> [template = <error>]
+// CHECK:STDOUT:     %return.var: ref <error> = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc13_14: %.12 = assoc_entity element1, %F.decl [template = constants.%.13]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .T = %.loc5_21.3
+// CHECK:STDOUT:   .F = %.loc13_14
+// CHECK:STDOUT:   witness = (%T, %F.decl)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic interface @ImplicitAs(constants.%Dest: type) {
+// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.3)]
+// CHECK:STDOUT:   %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.1)]
+// CHECK:STDOUT:   %Convert: @ImplicitAs.%Convert.type (%Convert.type.1) = struct_value () [symbolic = %Convert (constants.%Convert.1)]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type @ImplicitAs.%.1 (%.5), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.2 (constants.%.6)]
+// CHECK:STDOUT:   %.3: @ImplicitAs.%.2 (%.6) = assoc_entity element0, imports.%import_ref.6 [symbolic = %.3 (constants.%.7)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   interface {
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = imports.%import_ref.3
+// CHECK:STDOUT:     .Convert = imports.%import_ref.4
+// CHECK:STDOUT:     witness = (imports.%import_ref.5)
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @Convert(constants.%Dest: type, constants.%Self.2: @ImplicitAs.%.1 (%.5)) {
+// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
+// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.5)]
+// CHECK:STDOUT:   %Self: %.5 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.3)]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn[%self: @Convert.%Self (%Self.3)]() -> @Convert.%Dest (%Dest);
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F(@I.%Self: %.1) {
+// CHECK:STDOUT:
+// CHECK:STDOUT:   fn() -> <error>;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @ImplicitAs(constants.%Dest) {
+// CHECK:STDOUT:   %Dest => constants.%Dest
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @ImplicitAs(@ImplicitAs.%Dest) {
+// CHECK:STDOUT:   %Dest => constants.%Dest
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @ImplicitAs(@Convert.%Dest) {
+// CHECK:STDOUT:   %Dest => constants.%Dest
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @Convert(constants.%Dest, constants.%Self.2) {
+// CHECK:STDOUT:   %Dest => constants.%Dest
+// CHECK:STDOUT:   %.1 => constants.%.5
+// CHECK:STDOUT:   %Self => constants.%Self.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @ImplicitAs(type) {
+// CHECK:STDOUT:   %Dest => type
+// CHECK:STDOUT:
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:   %.1 => constants.%.8
+// CHECK:STDOUT:   %Self => constants.%Self.3
+// CHECK:STDOUT:   %Convert.type => constants.%Convert.type.2
+// CHECK:STDOUT:   %Convert => constants.%Convert.2
+// CHECK:STDOUT:   %.2 => constants.%.9
+// CHECK:STDOUT:   %.3 => constants.%.10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @F(constants.%Self.1) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_return_in_class.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I: type = class_type @I [template]
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.2: type = struct_type {} [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int32 = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %I.decl: type = class_decl @I [template = constants.%I] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @I {
+// CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc9_21.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc9_21.2: type = converted %int.make_type_32, %.loc9_21.1 [template = i32]
+// CHECK:STDOUT:   %T: type = bind_name T, %.loc9_21.2
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, %T
+// CHECK:STDOUT:     %return.var: ref <error> = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc15: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%I
+// CHECK:STDOUT:   .T = %T
+// CHECK:STDOUT:   .F = %F.decl
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> <error>;
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_return_in_package_scope.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Int32 = %import_ref
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/operators
+// CHECK:STDOUT:     import Core//prelude/types
+// CHECK:STDOUT:     import Core//prelude/operators/arithmetic
+// CHECK:STDOUT:     import Core//prelude/operators/as
+// CHECK:STDOUT:     import Core//prelude/operators/bitwise
+// CHECK:STDOUT:     import Core//prelude/operators/comparison
+// CHECK:STDOUT:     import Core//prelude/types/bool
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .T = @__global_init.%T
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %T.ref: type = name_ref T, @__global_init.%T
+// CHECK:STDOUT:     @F.%return: ref <error> = var <return slot>
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() -> <error>;
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @__global_init() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc8_19.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc8_19.2: type = converted %int.make_type_32, %.loc8_19.1 [template = i32]
+// CHECK:STDOUT:   %T: type = bind_name T, %.loc8_19.2
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:

+ 16 - 102
toolchain/check/testdata/let/fail_generic_import.carbon

@@ -8,10 +8,14 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/let/fail_generic_import.carbon
 
-// --- implicit.carbon
+// --- fail_implicit.carbon
 
 package Implicit;
 
+// CHECK:STDERR: fail_implicit.carbon:[[@LINE+4]]:5: error: semantics TODO: ``let` compile time binding outside function or interface`
+// CHECK:STDERR: let T:! type = i32;
+// CHECK:STDERR:     ^~~~~~~~
+// CHECK:STDERR:
 let T:! type = i32;
 
 // --- fail_implicit.impl.carbon
@@ -19,21 +23,17 @@ let T:! type = i32;
 impl package Implicit;
 
 // TODO: Should this be valid?
-// CHECK:STDERR: fail_implicit.impl.carbon:[[@LINE+6]]:1: error: cannot implicitly convert from `i32` to `T`
+// CHECK:STDERR: fail_implicit.impl.carbon:[[@LINE+3]]:8: error: cannot evaluate type expression
 // CHECK:STDERR: let a: T = 0;
-// CHECK:STDERR: ^~~~~~~~~~~~~
-// CHECK:STDERR: fail_implicit.impl.carbon:[[@LINE+3]]:1: note: type `i32` does not implement interface `ImplicitAs`
-// CHECK:STDERR: let a: T = 0;
-// CHECK:STDERR: ^~~~~~~~~~~~~
+// CHECK:STDERR:        ^
 let a: T = 0;
 
-// CHECK:STDOUT: --- implicit.carbon
+// CHECK:STDOUT: --- fail_implicit.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -64,40 +64,21 @@ let a: T = 0;
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc4_19.1: type = value_of_initializer %int.make_type_32 [template = i32]
-// CHECK:STDOUT:   %.loc4_19.2: type = converted %int.make_type_32, %.loc4_19.1 [template = i32]
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, %.loc4_19.2 [symbolic = constants.%T]
+// CHECK:STDOUT:   %.loc8_19.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc8_19.2: type = converted %int.make_type_32, %.loc8_19.1 [template = i32]
+// CHECK:STDOUT:   %T: type = bind_name T, %.loc8_19.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_implicit.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT:   %.1: i32 = int_literal 0 [template]
-// CHECK:STDOUT:   %ImplicitAs.type: type = generic_interface_type @ImplicitAs [template]
-// CHECK:STDOUT:   %.2: type = tuple_type () [template]
-// CHECK:STDOUT:   %ImplicitAs: %ImplicitAs.type = struct_value () [template]
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic]
-// CHECK:STDOUT:   %.3: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic]
-// CHECK:STDOUT:   %Self.1: @ImplicitAs.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic]
-// CHECK:STDOUT:   %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic]
-// CHECK:STDOUT:   %Convert.type.1: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic]
-// CHECK:STDOUT:   %Convert.1: %Convert.type.1 = struct_value () [symbolic]
-// CHECK:STDOUT:   %.4: type = assoc_entity_type %.3, %Convert.type.1 [symbolic]
-// CHECK:STDOUT:   %.5: %.4 = assoc_entity element0, imports.%import_ref.6 [symbolic]
-// CHECK:STDOUT:   %.6: type = interface_type @ImplicitAs, @ImplicitAs(%T) [symbolic]
-// CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert, @ImplicitAs(%T) [symbolic]
-// CHECK:STDOUT:   %Convert.2: %Convert.type.2 = struct_value () [symbolic]
-// CHECK:STDOUT:   %.7: type = assoc_entity_type %.6, %Convert.type.2 [symbolic]
-// CHECK:STDOUT:   %.8: %.7 = assoc_entity element0, imports.%import_ref.6 [symbolic]
-// CHECK:STDOUT:   %.9: %.4 = assoc_entity element0, imports.%import_ref.7 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref.1: type = import_ref Implicit//default, inst+3, loaded [symbolic = constants.%T]
+// CHECK:STDOUT:   %import_ref: type = import_ref Implicit//default, inst+3, loaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
-// CHECK:STDOUT:     .ImplicitAs = %import_ref.2
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/operators
 // CHECK:STDOUT:     import Core//prelude/types
@@ -107,91 +88,24 @@ let a: T = 0;
 // CHECK:STDOUT:     import Core//prelude/operators/comparison
 // CHECK:STDOUT:     import Core//prelude/types/bool
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.2: %ImplicitAs.type = import_ref Core//prelude/operators/as, inst+37, loaded [template = constants.%ImplicitAs]
-// CHECK:STDOUT:   %import_ref.3 = import_ref Core//prelude/operators/as, inst+42, unloaded
-// CHECK:STDOUT:   %import_ref.4: @ImplicitAs.%.2 (%.4) = import_ref Core//prelude/operators/as, inst+59, loaded [symbolic = @ImplicitAs.%.3 (constants.%.9)]
-// CHECK:STDOUT:   %import_ref.5 = import_ref Core//prelude/operators/as, inst+52, unloaded
-// CHECK:STDOUT:   %import_ref.6 = import_ref Core//prelude/operators/as, inst+52, unloaded
-// CHECK:STDOUT:   %import_ref.7 = import_ref Core//prelude/operators/as, inst+52, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .T = imports.%import_ref.1
+// CHECK:STDOUT:     .T = imports.%import_ref
 // CHECK:STDOUT:     .Core = imports.%Core
 // CHECK:STDOUT:     .a = @__global_init.%a
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import = import Implicit
 // CHECK:STDOUT:   %default.import = import <invalid>
 // CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %T.ref: type = name_ref T, imports.%import_ref.1 [symbolic = constants.%T]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: generic interface @ImplicitAs(constants.%Dest: type) {
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
-// CHECK:STDOUT:   %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.1)]
-// CHECK:STDOUT:   %Convert: @ImplicitAs.%Convert.type (%Convert.type.1) = struct_value () [symbolic = %Convert (constants.%Convert.1)]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @ImplicitAs.%.1 (%.3), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.2 (constants.%.4)]
-// CHECK:STDOUT:   %.3: @ImplicitAs.%.2 (%.4) = assoc_entity element0, imports.%import_ref.6 [symbolic = %.3 (constants.%.5)]
-// CHECK:STDOUT:
-// CHECK:STDOUT:   interface {
-// CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = imports.%import_ref.3
-// CHECK:STDOUT:     .Convert = imports.%import_ref.4
-// CHECK:STDOUT:     witness = (imports.%import_ref.5)
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Convert(constants.%Dest: type, constants.%Self.1: @ImplicitAs.%.1 (%.3)) {
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
-// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
-// CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: @Convert.%Self (%Self.2)]() -> @Convert.%Dest (%Dest);
+// CHECK:STDOUT:   %T.ref: type = name_ref T, imports.%import_ref
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc11_12: i32 = int_literal 0 [template = constants.%.1]
-// CHECK:STDOUT:   %.loc11_13.1: type = interface_type @ImplicitAs, @ImplicitAs(constants.%T) [symbolic = constants.%.6]
-// CHECK:STDOUT:   %.loc11_13.2: %.7 = specific_constant imports.%import_ref.4, @ImplicitAs(constants.%T) [symbolic = constants.%.8]
-// CHECK:STDOUT:   %Convert.ref: %.7 = name_ref Convert, %.loc11_13.2 [symbolic = constants.%.8]
-// CHECK:STDOUT:   %.loc11_13.3: %T = converted %.loc11_12, <error> [template = <error>]
-// CHECK:STDOUT:   %a: %T = bind_name a, <error>
+// CHECK:STDOUT:   %.loc8: i32 = int_literal 0 [template = constants.%.1]
+// CHECK:STDOUT:   %a: <error> = bind_name a, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(constants.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(@ImplicitAs.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(@Convert.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Convert(constants.%Dest, constants.%Self.1) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT:   %.1 => constants.%.3
-// CHECK:STDOUT:   %Self => constants.%Self.1
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(constants.%T) {
-// CHECK:STDOUT:   %Dest => constants.%T
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1 => constants.%.6
-// CHECK:STDOUT:   %Self => constants.%Self.2
-// CHECK:STDOUT:   %Convert.type => constants.%Convert.type.2
-// CHECK:STDOUT:   %Convert => constants.%Convert.2
-// CHECK:STDOUT:   %.2 => constants.%.7
-// CHECK:STDOUT:   %.3 => constants.%.8
-// CHECK:STDOUT: }
-// CHECK:STDOUT:

+ 29 - 26
toolchain/check/testdata/let/generic_import.carbon

@@ -8,26 +8,36 @@
 // TIP: To dump output, run:
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/let/generic_import.carbon
 
-// --- implicit.carbon
+// --- fail_implicit.carbon
 
 package Implicit;
 
+// CHECK:STDERR: fail_implicit.carbon:[[@LINE+4]]:5: error: semantics TODO: ``let` compile time binding outside function or interface`
+// CHECK:STDERR: let T:! type = i32;
+// CHECK:STDERR:     ^~~~~~~~
+// CHECK:STDERR:
 let T:! type = i32;
 
-// --- implicit.impl.carbon
+// --- fail_implicit.impl.carbon
 
 impl package Implicit;
 
+// CHECK:STDERR: fail_implicit.impl.carbon:[[@LINE+4]]:8: error: cannot evaluate type expression
+// CHECK:STDERR: var a: T*;
+// CHECK:STDERR:        ^~
+// CHECK:STDERR:
 var a: T*;
+// CHECK:STDERR: fail_implicit.impl.carbon:[[@LINE+3]]:8: error: cannot evaluate type expression
+// CHECK:STDERR: var b: T = *a;
+// CHECK:STDERR:        ^
 var b: T = *a;
 
-// CHECK:STDOUT: --- implicit.carbon
+// CHECK:STDOUT: --- fail_implicit.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -58,21 +68,16 @@ var b: T = *a;
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %int.make_type_32: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc4_19.1: type = value_of_initializer %int.make_type_32 [template = i32]
-// CHECK:STDOUT:   %.loc4_19.2: type = converted %int.make_type_32, %.loc4_19.1 [template = i32]
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0, %.loc4_19.2 [symbolic = constants.%T]
+// CHECK:STDOUT:   %.loc8_19.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:   %.loc8_19.2: type = converted %int.make_type_32, %.loc8_19.1 [template = i32]
+// CHECK:STDOUT:   %T: type = bind_name T, %.loc8_19.2
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- implicit.impl.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 0 [symbolic]
-// CHECK:STDOUT:   %.1: type = ptr_type %T [symbolic]
-// CHECK:STDOUT: }
+// CHECK:STDOUT: --- fail_implicit.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref: type = import_ref Implicit//default, inst+3, loaded [symbolic = constants.%T]
+// CHECK:STDOUT:   %import_ref: type = import_ref Implicit//default, inst+3, loaded
 // CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
 // CHECK:STDOUT:     import Core//prelude
 // CHECK:STDOUT:     import Core//prelude/operators
@@ -95,22 +100,20 @@ var b: T = *a;
 // CHECK:STDOUT:   %Implicit.import = import Implicit
 // CHECK:STDOUT:   %default.import = import <invalid>
 // CHECK:STDOUT:   %Core.import = import Core
-// CHECK:STDOUT:   %T.ref.loc4: type = name_ref T, imports.%import_ref [symbolic = constants.%T]
-// CHECK:STDOUT:   %.loc4: type = ptr_type %T [symbolic = constants.%.1]
-// CHECK:STDOUT:   %a.var: ref %.1 = var a
-// CHECK:STDOUT:   %a: ref %.1 = bind_name a, %a.var
-// CHECK:STDOUT:   %T.ref.loc5: type = name_ref T, imports.%import_ref [symbolic = constants.%T]
-// CHECK:STDOUT:   %b.var: ref %T = var b
-// CHECK:STDOUT:   %b: ref %T = bind_name b, %b.var
+// CHECK:STDOUT:   %T.ref.loc8: type = name_ref T, imports.%import_ref
+// CHECK:STDOUT:   %.loc8: type = ptr_type <error> [template = <error>]
+// CHECK:STDOUT:   %a.var: ref <error> = var a
+// CHECK:STDOUT:   %a: ref <error> = bind_name a, %a.var
+// CHECK:STDOUT:   %T.ref.loc12: type = name_ref T, imports.%import_ref
+// CHECK:STDOUT:   %b.var: ref <error> = var b
+// CHECK:STDOUT:   %b: ref <error> = bind_name b, %b.var
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %a.ref: ref %.1 = name_ref a, file.%a
-// CHECK:STDOUT:   %.loc5_13: %.1 = bind_value %a.ref
-// CHECK:STDOUT:   %.loc5_12.1: ref %T = deref %.loc5_13
-// CHECK:STDOUT:   %.loc5_12.2: %T = bind_value %.loc5_12.1
-// CHECK:STDOUT:   assign file.%b.var, %.loc5_12.2
+// CHECK:STDOUT:   %a.ref: ref <error> = name_ref a, file.%a
+// CHECK:STDOUT:   %.loc12: ref <error> = deref <error>
+// CHECK:STDOUT:   assign file.%b.var, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 24 - 30
toolchain/check/testdata/let/no_prelude/import.carbon

@@ -12,48 +12,47 @@
 
 package Implicit;
 
-let a:! () = ();
+let a: () = ();
 
 // --- implicit.impl.carbon
 
 impl package Implicit;
 
-let b:! () = a;
+let b: () = a;
 
 // --- other.carbon
 
 package Other;
 
-let a:! () = ();
+let a: () = ();
 
 // --- import_other.carbon
 
 import Other;
 
-let b:! () = Other.a;
+let b: () = Other.a;
 
 // CHECK:STDOUT: --- implicit.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .a = @__global_init.%a
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc4_10.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:   %.loc4_10.2: type = converted %.loc4_10.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc4_9.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_9.2: type = converted %.loc4_9.1, constants.%.1 [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc4_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_14: %.1 = tuple_literal ()
 // CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc4_16: %.1 = converted %.loc4_15, %tuple [template = constants.%tuple]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0, %.loc4_16 [symbolic = constants.%a]
+// CHECK:STDOUT:   %.loc4_15: %.1 = converted %.loc4_14, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:   %a: %.1 = bind_name a, %.loc4_15
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -61,12 +60,10 @@ let b:! () = Other.a;
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0 [symbolic]
-// CHECK:STDOUT:   %b: %.1 = bind_symbolic_name b 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %import_ref: %.1 = import_ref Implicit//default, inst+4, loaded [symbolic = constants.%a]
+// CHECK:STDOUT:   %import_ref: %.1 = import_ref Implicit//default, inst+4, loaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -76,14 +73,14 @@ let b:! () = Other.a;
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Implicit.import = import Implicit
 // CHECK:STDOUT:   %default.import = import <invalid>
-// CHECK:STDOUT:   %.loc4_10.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:   %.loc4_10.2: type = converted %.loc4_10.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc4_9.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_9.2: type = converted %.loc4_9.1, constants.%.1 [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %a.ref: %.1 = name_ref a, imports.%import_ref [symbolic = constants.%a]
-// CHECK:STDOUT:   %b: %.1 = bind_symbolic_name b 0, %a.ref [symbolic = constants.%b]
+// CHECK:STDOUT:   %a.ref: %.1 = name_ref a, imports.%import_ref
+// CHECK:STDOUT:   %b: %.1 = bind_name b, %a.ref
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -92,23 +89,22 @@ let b:! () = Other.a;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
 // CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .a = @__global_init.%a
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc4_10.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:   %.loc4_10.2: type = converted %.loc4_10.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc4_9.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_9.2: type = converted %.loc4_9.1, constants.%.1 [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %.loc4_15: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_14: %.1 = tuple_literal ()
 // CHECK:STDOUT:   %tuple: %.1 = tuple_value () [template = constants.%tuple]
-// CHECK:STDOUT:   %.loc4_16: %.1 = converted %.loc4_15, %tuple [template = constants.%tuple]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0, %.loc4_16 [symbolic = constants.%a]
+// CHECK:STDOUT:   %.loc4_15: %.1 = converted %.loc4_14, %tuple [template = constants.%tuple]
+// CHECK:STDOUT:   %a: %.1 = bind_name a, %.loc4_15
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -116,8 +112,6 @@ let b:! () = Other.a;
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
-// CHECK:STDOUT:   %a: %.1 = bind_symbolic_name a 0 [symbolic]
-// CHECK:STDOUT:   %b: %.1 = bind_symbolic_name b 0 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -125,7 +119,7 @@ let b:! () = Other.a;
 // CHECK:STDOUT:     .a = %import_ref
 // CHECK:STDOUT:     import Other//default
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref: %.1 = import_ref Other//default, inst+4, loaded [symbolic = constants.%a]
+// CHECK:STDOUT:   %import_ref: %.1 = import_ref Other//default, inst+4, loaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -134,15 +128,15 @@ let b:! () = Other.a;
 // CHECK:STDOUT:     .b = @__global_init.%b
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Other.import = import Other
-// CHECK:STDOUT:   %.loc4_10.1: %.1 = tuple_literal ()
-// CHECK:STDOUT:   %.loc4_10.2: type = converted %.loc4_10.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:   %.loc4_9.1: %.1 = tuple_literal ()
+// CHECK:STDOUT:   %.loc4_9.2: type = converted %.loc4_9.1, constants.%.1 [template = constants.%.1]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %Other.ref: <namespace> = name_ref Other, imports.%Other [template = imports.%Other]
-// CHECK:STDOUT:   %a.ref: %.1 = name_ref a, imports.%import_ref [symbolic = constants.%a]
-// CHECK:STDOUT:   %b: %.1 = bind_symbolic_name b 0, %a.ref [symbolic = constants.%b]
+// CHECK:STDOUT:   %a.ref: %.1 = name_ref a, imports.%import_ref
+// CHECK:STDOUT:   %b: %.1 = bind_name b, %a.ref
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 15 - 106
toolchain/check/testdata/return/fail_let_in_type.carbon

@@ -16,20 +16,25 @@ let x: type = i32;
 fn Six() -> x { return 6; }
 
 // TODO: This should probably work.
+// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+4]]:5: error: semantics TODO: ``let` compile time binding outside function or interface`
+// CHECK:STDERR: let y:! type = i32;
+// CHECK:STDERR:     ^~~~~~~~
+// CHECK:STDERR:
 let y:! type = i32;
-// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+7]]:23: error: cannot implicitly convert from `i32` to `y`
-// CHECK:STDERR: fn HalfDozen() -> y { return 6; }
-// CHECK:STDERR:                       ^~~~~~~~~
-// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+4]]:23: note: type `i32` does not implement interface `ImplicitAs`
+// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+4]]:19: error: cannot evaluate type expression
 // CHECK:STDERR: fn HalfDozen() -> y { return 6; }
-// CHECK:STDERR:                       ^~~~~~~~~
+// CHECK:STDERR:                   ^
 // CHECK:STDERR:
 fn HalfDozen() -> y { return 6; }
 
 // TODO: This should work.
-// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+3]]:5: error: semantics TODO: `HandleTemplate`
+// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+7]]:5: error: semantics TODO: `HandleTemplate`
 // CHECK:STDERR: let template z:! type = i32;
 // CHECK:STDERR:     ^~~~~~~~~~~~~~~~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_let_in_type.carbon:[[@LINE+3]]:14: error: semantics TODO: ``let` compile time binding outside function or interface`
+// CHECK:STDERR: let template z:! type = i32;
+// CHECK:STDERR:              ^~~~~~~~
 let template z:! type = i32;
 fn FirstPerfectNumber() -> z { return 6; }
 
@@ -42,48 +47,12 @@ fn FirstPerfectNumber() -> z { return 6; }
 // CHECK:STDOUT:   %Six.type: type = fn_type @Six [template]
 // CHECK:STDOUT:   %Six: %Six.type = struct_value () [template]
 // CHECK:STDOUT:   %.2: i32 = int_literal 6 [template]
-// CHECK:STDOUT:   %y: type = bind_symbolic_name y 0 [symbolic]
 // CHECK:STDOUT:   %HalfDozen.type: type = fn_type @HalfDozen [template]
 // CHECK:STDOUT:   %HalfDozen: %HalfDozen.type = struct_value () [template]
-// CHECK:STDOUT:   %ImplicitAs.type: type = generic_interface_type @ImplicitAs [template]
-// CHECK:STDOUT:   %ImplicitAs: %ImplicitAs.type = struct_value () [template]
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic]
-// CHECK:STDOUT:   %.3: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic]
-// CHECK:STDOUT:   %Self.1: @ImplicitAs.%.1 (%.3) = bind_symbolic_name Self 1 [symbolic]
-// CHECK:STDOUT:   %Self.2: %.3 = bind_symbolic_name Self 1 [symbolic]
-// CHECK:STDOUT:   %Convert.type.1: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic]
-// CHECK:STDOUT:   %Convert.1: %Convert.type.1 = struct_value () [symbolic]
-// CHECK:STDOUT:   %.4: type = assoc_entity_type %.3, %Convert.type.1 [symbolic]
-// CHECK:STDOUT:   %.5: %.4 = assoc_entity element0, <unexpected>.inst+54 [symbolic]
-// CHECK:STDOUT:   %.6: type = interface_type @ImplicitAs, @ImplicitAs(%y) [symbolic]
-// CHECK:STDOUT:   %Convert.type.2: type = fn_type @Convert, @ImplicitAs(%y) [symbolic]
-// CHECK:STDOUT:   %Convert.2: %Convert.type.2 = struct_value () [symbolic]
-// CHECK:STDOUT:   %.7: type = assoc_entity_type %.6, %Convert.type.2 [symbolic]
-// CHECK:STDOUT:   %.8: %.7 = assoc_entity element0, <unexpected>.inst+54 [symbolic]
-// CHECK:STDOUT:   %.9: %.4 = assoc_entity element0, <unexpected>.inst+71 [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic interface @ImplicitAs(constants.%Dest: type) {
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
-// CHECK:STDOUT:   %Convert.type: type = fn_type @Convert, @ImplicitAs(%Dest) [symbolic = %Convert.type (constants.%Convert.type.1)]
-// CHECK:STDOUT:   %Convert: @ImplicitAs.%Convert.type (%Convert.type.1) = struct_value () [symbolic = %Convert (constants.%Convert.1)]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @ImplicitAs.%.1 (%.3), @ImplicitAs.%Convert.type (%Convert.type.1) [symbolic = %.2 (constants.%.4)]
-// CHECK:STDOUT:   %.3: @ImplicitAs.%.2 (%.4) = assoc_entity element0, <unexpected>.inst+54 [symbolic = %.3 (constants.%.5)]
-// CHECK:STDOUT:
-// CHECK:STDOUT:   interface {
-// CHECK:STDOUT:   !members:
-// CHECK:STDOUT:     .Self = <unexpected>.inst+42
-// CHECK:STDOUT:     .Convert = <unexpected>.inst+43
-// CHECK:STDOUT:     witness = (<unexpected>.inst+44)
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Six() -> <error> {
@@ -92,69 +61,9 @@ fn FirstPerfectNumber() -> z { return 6; }
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @HalfDozen(<unexpected>.inst+21.loc19_5: type) {
-// CHECK:STDOUT:   %y: type = bind_symbolic_name y 0 [symbolic = %y (constants.%y)]
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%y) [symbolic = %.1 (constants.%.6)]
-// CHECK:STDOUT:   %Convert.type: type = fn_type @Convert, @ImplicitAs(%y) [symbolic = %Convert.type (constants.%Convert.type.2)]
-// CHECK:STDOUT:   %.2: type = assoc_entity_type @HalfDozen.%.1 (%.6), @HalfDozen.%Convert.type (%Convert.type.2) [symbolic = %.2 (constants.%.7)]
-// CHECK:STDOUT:   %.3: @HalfDozen.%.2 (%.7) = assoc_entity element0, <unexpected>.inst+54 [symbolic = %.3 (constants.%.8)]
-// CHECK:STDOUT:
-// CHECK:STDOUT:   fn() -> @HalfDozen.%y (%y) {
-// CHECK:STDOUT:   !entry:
-// CHECK:STDOUT:     %.loc27_30: i32 = int_literal 6 [template = constants.%.2]
-// CHECK:STDOUT:     %.loc27_31.1: type = interface_type @ImplicitAs, @ImplicitAs(constants.%y) [symbolic = %.1 (constants.%.6)]
-// CHECK:STDOUT:     %.loc27_31.2: @HalfDozen.%.2 (%.7) = specific_constant <unexpected>.inst+43, @ImplicitAs(constants.%y) [symbolic = %.3 (constants.%.8)]
-// CHECK:STDOUT:     %Convert.ref: @HalfDozen.%.2 (%.7) = name_ref Convert, %.loc27_31.2 [symbolic = %.3 (constants.%.8)]
-// CHECK:STDOUT:     %.loc27_31.3: @HalfDozen.%y (%y) = converted %.loc27_30, <error> [template = <error>]
-// CHECK:STDOUT:     return <error>
-// CHECK:STDOUT:   }
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Convert(constants.%Dest: type, constants.%Self.1: @ImplicitAs.%.1 (%.3)) {
-// CHECK:STDOUT:   %Dest: type = bind_symbolic_name Dest 0 [symbolic = %Dest (constants.%Dest)]
-// CHECK:STDOUT:   %.1: type = interface_type @ImplicitAs, @ImplicitAs(%Dest) [symbolic = %.1 (constants.%.3)]
-// CHECK:STDOUT:   %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self.2)]
-// CHECK:STDOUT:
-// CHECK:STDOUT:   fn[%self: @Convert.%Self (%Self.2)]() -> @Convert.%Dest (%Dest);
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @HalfDozen(constants.%y) {
-// CHECK:STDOUT:   %y => constants.%y
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(constants.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(@ImplicitAs.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(@Convert.%Dest) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Convert(constants.%Dest, constants.%Self.1) {
-// CHECK:STDOUT:   %Dest => constants.%Dest
-// CHECK:STDOUT:   %.1 => constants.%.3
-// CHECK:STDOUT:   %Self => constants.%Self.1
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(constants.%y) {
-// CHECK:STDOUT:   %Dest => constants.%y
-// CHECK:STDOUT:
-// CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %.1 => constants.%.6
-// CHECK:STDOUT:   %Self => constants.%Self.2
-// CHECK:STDOUT:   %Convert.type => constants.%Convert.type.2
-// CHECK:STDOUT:   %Convert => constants.%Convert.2
-// CHECK:STDOUT:   %.2 => constants.%.7
-// CHECK:STDOUT:   %.3 => constants.%.8
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @ImplicitAs(@HalfDozen.%y) {
-// CHECK:STDOUT:   %Dest => constants.%y
+// CHECK:STDOUT: fn @HalfDozen() -> <error> {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %.loc28: i32 = int_literal 6 [template = constants.%.2]
+// CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT: