Bladeren bron

Allow `extend adapt` of non-class types. (#4544)

Stop rejecting `extend adapt` of non-class types such as struct and
tuple. These don't actually work just yet because name lookup into
struct and tuple types is a special case that doesn't handle adapters,
but this gets us a bit closer.

This also slightly improves error recovery for name lookup into an
invalid scope.
Richard Smith 1 jaar geleden
bovenliggende
commit
145f878ce8

+ 6 - 0
toolchain/check/context.cpp

@@ -481,6 +481,12 @@ auto Context::AppendLookupScopesForConstant(
     }
     return true;
   }
+  if (base_const_id == SemIR::ConstantId::Error) {
+    // Lookup into this scope should fail without producing an error.
+    scopes->push_back(LookupScope{.name_scope_id = SemIR::NameScopeId::Invalid,
+                                  .specific_id = SemIR::SpecificId::Invalid});
+    return true;
+  }
   // TODO: Per the design, if `base_id` is any kind of type, then lookup should
   // treat it as a name scope, even if it doesn't have members. For example,
   // `(i32*).X` should fail because there's no name `X` in `i32*`, not because

+ 1 - 19
toolchain/check/handle_class.cpp

@@ -405,26 +405,8 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
 
   // Extend the class scope with the adapted type's scope if requested.
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
-    auto extended_scope_inst_id = SemIR::InstId::Invalid;
-    if (adapted_type_id == SemIR::TypeId::Error) {
-      // Recover by not extending any scope. We instead set has_error to true
-      // below.
-    } else if (auto* adapted_class_info =
-                   TryGetAsClass(context, adapted_type_id)) {
-      extended_scope_inst_id = adapted_inst_id;
-      CARBON_CHECK(adapted_class_info->scope_id.is_valid(),
-                   "Complete class should have a scope");
-    } else {
-      // TODO: Accept any type that has a scope.
-      context.TODO(node_id, "extending non-class type");
-    }
-
     auto& class_scope = context.name_scopes().Get(class_info.scope_id);
-    if (extended_scope_inst_id.is_valid()) {
-      class_scope.extended_scopes.push_back(extended_scope_inst_id);
-    } else {
-      class_scope.has_error = true;
-    }
+    class_scope.extended_scopes.push_back(adapted_inst_id);
   }
   return true;
 }

+ 243 - 14
toolchain/check/testdata/class/extend_adapt.carbon

@@ -85,17 +85,58 @@ fn F(a: SomeClassAdapter) -> i32 {
   return a.b;
 }
 
-// --- fail_todo_adapt_non_class.carbon
+// --- fail_todo_adapt_struct.carbon
 
 library "[[@TEST_NAME]]";
 
 class StructAdapter {
-  // CHECK:STDERR: fail_todo_adapt_non_class.carbon:[[@LINE+3]]:3: error: semantics TODO: `extending non-class type` [SemanticsTodo]
-  // CHECK:STDERR:   extend adapt {.a: i32, .b: i32};
-  // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   extend adapt {.a: i32, .b: i32};
 }
 
+fn F(a: StructAdapter) -> i32 {
+  // TODO: This should be allowed.
+  // CHECK:STDERR: fail_todo_adapt_struct.carbon:[[@LINE+4]]:10: error: name `b` not found [NameNotFound]
+  // CHECK:STDERR:   return a.b;
+  // CHECK:STDERR:          ^~~
+  // CHECK:STDERR:
+  return a.b;
+}
+
+// --- fail_todo_adapt_tuple.carbon
+
+library "[[@TEST_NAME]]";
+
+class TupleAdapter {
+  extend adapt (i32, i32);
+}
+
+fn F(a: TupleAdapter) -> i32 {
+  // TODO: This should be allowed.
+  // CHECK:STDERR: fail_todo_adapt_tuple.carbon:[[@LINE+4]]:10: error: type `TupleAdapter` does not support tuple indexing; only tuples can be indexed that way [TupleIndexOnANonTupleType]
+  // CHECK:STDERR:   return a.1;
+  // CHECK:STDERR:          ^~~
+  // CHECK:STDERR:
+  return a.1;
+}
+
+// --- fail_adapt_builtin.carbon
+
+library "[[@TEST_NAME]]";
+
+fn MakeInt(N: Core.IntLiteral()) -> type = "int.make_type_signed";
+
+class IntAdapter {
+  extend adapt MakeInt(32);
+}
+
+fn F(a: IntAdapter) -> i32 {
+  // Builtin types have no member names.
+  // CHECK:STDERR: fail_adapt_builtin.carbon:[[@LINE+3]]:10: error: name `foo` not found [NameNotFound]
+  // CHECK:STDERR:   return a.foo;
+  // CHECK:STDERR:          ^~~~~
+  return a.foo;
+}
+
 // CHECK:STDOUT: --- basic.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -383,7 +424,7 @@ class StructAdapter {
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_todo_adapt_non_class.carbon
+// CHECK:STDOUT: --- fail_todo_adapt_struct.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %StructAdapter: type = class_type @StructAdapter [template]
@@ -391,6 +432,8 @@ class StructAdapter {
 // CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
 // CHECK:STDOUT:   %.1: type = struct_type {.a: i32, .b: i32} [template]
 // CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.1 [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 {
@@ -405,24 +448,210 @@ class StructAdapter {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .Core = imports.%Core
 // CHECK:STDOUT:     .StructAdapter = %StructAdapter.decl
+// CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %StructAdapter.decl: type = class_decl @StructAdapter [template = constants.%StructAdapter] {} {}
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %a.patt: %StructAdapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %StructAdapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %StructAdapter.ref: type = name_ref StructAdapter, file.%StructAdapter.decl [template = constants.%StructAdapter]
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc8_27.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc8_27.2: type = converted %int.make_type_32, %.loc8_27.1 [template = i32]
+// CHECK:STDOUT:     %a.param: %StructAdapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %StructAdapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref i32 = return_slot %return.param
+// CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @StructAdapter {
-// CHECK:STDOUT:   %int.make_type_32.loc8_21: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc8_21.1: type = value_of_initializer %int.make_type_32.loc8_21 [template = i32]
-// CHECK:STDOUT:   %.loc8_21.2: type = converted %int.make_type_32.loc8_21, %.loc8_21.1 [template = i32]
-// CHECK:STDOUT:   %int.make_type_32.loc8_30: init type = call constants.%Int32() [template = i32]
-// CHECK:STDOUT:   %.loc8_30.1: type = value_of_initializer %int.make_type_32.loc8_30 [template = i32]
-// CHECK:STDOUT:   %.loc8_30.2: type = converted %int.make_type_32.loc8_30, %.loc8_30.1 [template = i32]
-// CHECK:STDOUT:   %.loc8_33: type = struct_type {.a: i32, .b: i32} [template = constants.%.1]
+// CHECK:STDOUT:   %int.make_type_32.loc5_21: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc5_21.1: type = value_of_initializer %int.make_type_32.loc5_21 [template = i32]
+// CHECK:STDOUT:   %.loc5_21.2: type = converted %int.make_type_32.loc5_21, %.loc5_21.1 [template = i32]
+// CHECK:STDOUT:   %int.make_type_32.loc5_30: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc5_30.1: type = value_of_initializer %int.make_type_32.loc5_30 [template = i32]
+// CHECK:STDOUT:   %.loc5_30.2: type = converted %int.make_type_32.loc5_30, %.loc5_30.1 [template = i32]
+// CHECK:STDOUT:   %.loc5_33: type = struct_type {.a: i32, .b: i32} [template = constants.%.1]
 // CHECK:STDOUT:   adapt_decl %.1
-// CHECK:STDOUT:   %.loc9: <witness> = complete_type_witness %.1 [template = constants.%.3]
+// CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %.1 [template = constants.%.3]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%StructAdapter
-// CHECK:STDOUT:   has_error
+// CHECK:STDOUT:   extend %.loc5_33
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F(%a.param_patt: %StructAdapter) -> i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %StructAdapter = name_ref a, %a
+// CHECK:STDOUT:   %b.ref: <error> = name_ref b, <error> [template = <error>]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_todo_adapt_tuple.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %TupleAdapter: type = class_type @TupleAdapter [template]
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [template]
+// CHECK:STDOUT:   %Int32: %Int32.type = struct_value () [template]
+// CHECK:STDOUT:   %tuple.type.1: type = tuple_type (type, type) [template]
+// CHECK:STDOUT:   %tuple.type.2: type = tuple_type (i32, i32) [template]
+// CHECK:STDOUT:   %.2: <witness> = complete_type_witness %tuple.type.2 [template]
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %.3: Core.IntLiteral = int_value 1 [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/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .TupleAdapter = %TupleAdapter.decl
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %TupleAdapter.decl: type = class_decl @TupleAdapter [template = constants.%TupleAdapter] {} {}
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %a.patt: %TupleAdapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %TupleAdapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %TupleAdapter.ref: type = name_ref TupleAdapter, file.%TupleAdapter.decl [template = constants.%TupleAdapter]
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc8_26.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc8_26.2: type = converted %int.make_type_32, %.loc8_26.1 [template = i32]
+// CHECK:STDOUT:     %a.param: %TupleAdapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %TupleAdapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @TupleAdapter {
+// CHECK:STDOUT:   %int.make_type_32.loc5_17: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %int.make_type_32.loc5_22: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:   %.loc5_25: %tuple.type.1 = tuple_literal (%int.make_type_32.loc5_17, %int.make_type_32.loc5_22)
+// CHECK:STDOUT:   %.loc5_26.1: type = value_of_initializer %int.make_type_32.loc5_17 [template = i32]
+// CHECK:STDOUT:   %.loc5_26.2: type = converted %int.make_type_32.loc5_17, %.loc5_26.1 [template = i32]
+// CHECK:STDOUT:   %.loc5_26.3: type = value_of_initializer %int.make_type_32.loc5_22 [template = i32]
+// CHECK:STDOUT:   %.loc5_26.4: type = converted %int.make_type_32.loc5_22, %.loc5_26.3 [template = i32]
+// CHECK:STDOUT:   %.loc5_26.5: type = converted %.loc5_25, constants.%tuple.type.2 [template = constants.%tuple.type.2]
+// CHECK:STDOUT:   adapt_decl %tuple.type.2
+// CHECK:STDOUT:   %.loc6: <witness> = complete_type_witness %tuple.type.2 [template = constants.%.2]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%TupleAdapter
+// CHECK:STDOUT:   extend %.loc5_26.5
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F(%a.param_patt: %TupleAdapter) -> i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %TupleAdapter = name_ref a, %a
+// CHECK:STDOUT:   %.loc14: Core.IntLiteral = int_value 1 [template = constants.%.3]
+// CHECK:STDOUT:   return <error>
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_adapt_builtin.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %IntLiteral.type: type = fn_type @IntLiteral [template]
+// CHECK:STDOUT:   %IntLiteral: %IntLiteral.type = struct_value () [template]
+// CHECK:STDOUT:   %MakeInt.type: type = fn_type @MakeInt [template]
+// CHECK:STDOUT:   %MakeInt: %MakeInt.type = struct_value () [template]
+// CHECK:STDOUT:   %IntAdapter: type = class_type @IntAdapter [template]
+// CHECK:STDOUT:   %.1: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %.2: type = int_type signed, %.1 [template]
+// CHECK:STDOUT:   %.3: <witness> = complete_type_witness %.2 [template]
+// CHECK:STDOUT:   %Int32.type: type = fn_type @Int32 [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:     .IntLiteral = %import_ref.1
+// CHECK:STDOUT:     .Int32 = %import_ref.2
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref.1: %IntLiteral.type = import_ref Core//prelude/types, inst+7, loaded [template = constants.%IntLiteral]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .MakeInt = %MakeInt.decl
+// CHECK:STDOUT:     .IntAdapter = %IntAdapter.decl
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %MakeInt.decl: %MakeInt.type = fn_decl @MakeInt [template = constants.%MakeInt] {
+// CHECK:STDOUT:     %N.patt: Core.IntLiteral = binding_pattern N
+// CHECK:STDOUT:     %N.param_patt: Core.IntLiteral = value_param_pattern %N.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: type = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: type = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %Core.ref: <namespace> = name_ref Core, imports.%Core [template = imports.%Core]
+// CHECK:STDOUT:     %IntLiteral.ref: %IntLiteral.type = name_ref IntLiteral, imports.%import_ref.1 [template = constants.%IntLiteral]
+// CHECK:STDOUT:     %int_literal.make_type: init type = call %IntLiteral.ref() [template = Core.IntLiteral]
+// CHECK:STDOUT:     %.loc4_31.1: type = value_of_initializer %int_literal.make_type [template = Core.IntLiteral]
+// CHECK:STDOUT:     %.loc4_31.2: type = converted %int_literal.make_type, %.loc4_31.1 [template = Core.IntLiteral]
+// CHECK:STDOUT:     %N.param: Core.IntLiteral = value_param runtime_param0
+// CHECK:STDOUT:     %N: Core.IntLiteral = bind_name N, %N.param
+// CHECK:STDOUT:     %return.param: ref type = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref type = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %IntAdapter.decl: type = class_decl @IntAdapter [template = constants.%IntAdapter] {} {}
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {
+// CHECK:STDOUT:     %a.patt: %IntAdapter = binding_pattern a
+// CHECK:STDOUT:     %a.param_patt: %IntAdapter = value_param_pattern %a.patt, runtime_param0
+// CHECK:STDOUT:     %return.patt: i32 = return_slot_pattern
+// CHECK:STDOUT:     %return.param_patt: i32 = out_param_pattern %return.patt, runtime_param1
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %IntAdapter.ref: type = name_ref IntAdapter, file.%IntAdapter.decl [template = constants.%IntAdapter]
+// CHECK:STDOUT:     %int.make_type_32: init type = call constants.%Int32() [template = i32]
+// CHECK:STDOUT:     %.loc10_24.1: type = value_of_initializer %int.make_type_32 [template = i32]
+// CHECK:STDOUT:     %.loc10_24.2: type = converted %int.make_type_32, %.loc10_24.1 [template = i32]
+// CHECK:STDOUT:     %a.param: %IntAdapter = value_param runtime_param0
+// CHECK:STDOUT:     %a: %IntAdapter = bind_name a, %a.param
+// CHECK:STDOUT:     %return.param: ref i32 = out_param runtime_param1
+// CHECK:STDOUT:     %return: ref i32 = return_slot %return.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: class @IntAdapter {
+// CHECK:STDOUT:   %MakeInt.ref: %MakeInt.type = name_ref MakeInt, file.%MakeInt.decl [template = constants.%MakeInt]
+// CHECK:STDOUT:   %.loc7_24: Core.IntLiteral = int_value 32 [template = constants.%.1]
+// CHECK:STDOUT:   %int.make_type_signed: init type = call %MakeInt.ref(%.loc7_24) [template = constants.%.2]
+// CHECK:STDOUT:   %.loc7_27.1: type = value_of_initializer %int.make_type_signed [template = constants.%.2]
+// CHECK:STDOUT:   %.loc7_27.2: type = converted %int.make_type_signed, %.loc7_27.1 [template = constants.%.2]
+// CHECK:STDOUT:   adapt_decl %.2
+// CHECK:STDOUT:   %.loc8: <witness> = complete_type_witness %.2 [template = constants.%.3]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = constants.%IntAdapter
+// CHECK:STDOUT:   extend %.loc7_27.2
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @MakeInt(%N.param_patt: Core.IntLiteral) -> type = "int.make_type_signed";
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F(%a.param_patt: %IntAdapter) -> i32 {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %a.ref: %IntAdapter = name_ref a, %a
+// CHECK:STDOUT:   %foo.ref: <error> = name_ref foo, <error> [template = <error>]
+// CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/check/testdata/class/fail_abstract.carbon

@@ -678,6 +678,7 @@ fn CallReturnAbstract() {
 // CHECK:STDOUT:   %d.ref: %Derived = name_ref d, %d
 // CHECK:STDOUT:   %base.ref: %.5 = name_ref base, @Derived.%.loc9 [template = @Derived.%.loc9]
 // CHECK:STDOUT:   %.loc15: ref %Abstract = class_element_access %d.ref, element0
+// CHECK:STDOUT:   %a.ref: <error> = name_ref a, <error> [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 1
toolchain/check/testdata/class/fail_adapt_bad_decl.carbon

@@ -197,7 +197,7 @@ class C {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Bad
-// CHECK:STDOUT:   has_error
+// CHECK:STDOUT:   extend <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Use(%b.param_patt: %Bad) {

+ 1 - 0
toolchain/check/testdata/packages/no_prelude/export_name.carbon

@@ -818,6 +818,7 @@ private export C;
 // CHECK:STDOUT:   %C.ref: <error> = name_ref C, <error> [template = <error>]
 // CHECK:STDOUT:   %Local: <error> = bind_alias Local, <error> [template = <error>]
 // CHECK:STDOUT:   %NS.ref: <error> = name_ref NS, <error> [template = <error>]
+// CHECK:STDOUT:   %NSC.ref: <error> = name_ref NSC, <error> [template = <error>]
 // CHECK:STDOUT:   %NSLocal: <error> = bind_alias NSLocal, <error> [template = <error>]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/check/testdata/pointer/fail_deref_error.carbon

@@ -55,6 +55,7 @@ let n2: i32 = undeclared->foo;
 // CHECK:STDOUT:   %n: i32 = bind_name n, <error>
 // CHECK:STDOUT:   %undeclared.ref.loc19: <error> = name_ref undeclared, <error> [template = <error>]
 // CHECK:STDOUT:   %.loc19: ref <error> = deref <error>
+// CHECK:STDOUT:   %foo.ref: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   %n2: i32 = bind_name n2, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 1 - 0
toolchain/check/testdata/pointer/fail_deref_function.carbon

@@ -49,6 +49,7 @@ fn A() {
 // CHECK:STDOUT:   %.loc16: ref <error> = deref <error>
 // CHECK:STDOUT:   %A.ref.loc20: %A.type = name_ref A, file.%A.decl [template = constants.%A]
 // CHECK:STDOUT:   %.loc20: ref <error> = deref <error>
+// CHECK:STDOUT:   %foo.ref: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/check/testdata/pointer/fail_deref_namespace.carbon

@@ -53,6 +53,7 @@ fn F() {
 // CHECK:STDOUT:   %.loc18: ref <error> = deref <error>
 // CHECK:STDOUT:   %A.ref.loc22: <namespace> = name_ref A, file.%A [template = file.%A]
 // CHECK:STDOUT:   %.loc22: ref <error> = deref <error>
+// CHECK:STDOUT:   %foo.ref: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 3 - 0
toolchain/check/testdata/pointer/fail_deref_not_pointer.carbon

@@ -85,6 +85,7 @@ fn Deref(n: i32) {
 // CHECK:STDOUT:   %.loc16: ref <error> = deref %n.ref.loc16
 // CHECK:STDOUT:   %n.ref.loc21: i32 = name_ref n, %n
 // CHECK:STDOUT:   %.loc21: ref <error> = deref %n.ref.loc21
+// CHECK:STDOUT:   %foo.ref.loc21: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   %.loc26_5.1: %empty_tuple.type = tuple_literal ()
 // CHECK:STDOUT:   %empty_tuple.loc26: %empty_tuple.type = tuple_value () [template = constants.%empty_tuple]
 // CHECK:STDOUT:   %.loc26_5.2: %empty_tuple.type = converted %.loc26_5.1, %empty_tuple.loc26 [template = constants.%empty_tuple]
@@ -93,6 +94,7 @@ fn Deref(n: i32) {
 // CHECK:STDOUT:   %empty_tuple.loc31: %empty_tuple.type = tuple_value () [template = constants.%empty_tuple]
 // CHECK:STDOUT:   %.loc31_4.2: %empty_tuple.type = converted %.loc31_4.1, %empty_tuple.loc31 [template = constants.%empty_tuple]
 // CHECK:STDOUT:   %.loc31_5: ref <error> = deref %.loc31_4.2
+// CHECK:STDOUT:   %foo.ref.loc31: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   %.loc36_5.1: %.1 = struct_literal ()
 // CHECK:STDOUT:   %struct.loc36: %.1 = struct_value () [template = constants.%struct]
 // CHECK:STDOUT:   %.loc36_5.2: %.1 = converted %.loc36_5.1, %struct.loc36 [template = constants.%struct]
@@ -101,6 +103,7 @@ fn Deref(n: i32) {
 // CHECK:STDOUT:   %struct.loc40: %.1 = struct_value () [template = constants.%struct]
 // CHECK:STDOUT:   %.loc40_4.2: %.1 = converted %.loc40_4.1, %struct.loc40 [template = constants.%struct]
 // CHECK:STDOUT:   %.loc40_5: ref <error> = deref %.loc40_4.2
+// CHECK:STDOUT:   %foo.ref.loc40: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/check/testdata/pointer/fail_deref_type.carbon

@@ -53,6 +53,7 @@ var p2: i32->foo;
 // CHECK:STDOUT:   %.loc22_9.1: type = value_of_initializer %int.make_type_32.loc22 [template = i32]
 // CHECK:STDOUT:   %.loc22_9.2: type = converted %int.make_type_32.loc22, %.loc22_9.1 [template = i32]
 // CHECK:STDOUT:   %.loc22_12: ref <error> = deref %.loc22_9.2
+// CHECK:STDOUT:   %foo.ref: <error> = name_ref foo, <error> [template = <error>]
 // CHECK:STDOUT:   %p2.var: ref <error> = var p2
 // CHECK:STDOUT:   %p2: ref <error> = bind_name p2, %p2.var
 // CHECK:STDOUT: }

+ 1 - 0
toolchain/check/testdata/struct/fail_access_into_invalid.carbon

@@ -40,6 +40,7 @@ fn F() { a.b; }
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %a.ref: <error> = name_ref a, <error> [template = <error>]
+// CHECK:STDOUT:   %b.ref: <error> = name_ref b, <error> [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 1 - 0
toolchain/check/testdata/struct/fail_duplicate_name.carbon

@@ -143,6 +143,7 @@ var y: {.b: i32, .c: i32} = {.b = 3, .b = 4};
 // CHECK:STDOUT:   %v: <error> = bind_name v, <error>
 // CHECK:STDOUT:   %.loc36_22: Core.IntLiteral = int_value 1 [template = constants.%.1]
 // CHECK:STDOUT:   %.loc36_32: Core.IntLiteral = int_value 2 [template = constants.%.3]
+// CHECK:STDOUT:   %def.ref: <error> = name_ref def, <error> [template = <error>]
 // CHECK:STDOUT:   %w: i32 = bind_name w, <error>
 // CHECK:STDOUT:   %.loc45_26: Core.IntLiteral = int_value 1 [template = constants.%.1]
 // CHECK:STDOUT:   %.loc45_34: Core.IntLiteral = int_value 2 [template = constants.%.3]

+ 1 - 0
toolchain/check/testdata/struct/fail_member_of_function.carbon

@@ -41,6 +41,7 @@ fn A() {
 // CHECK:STDOUT: fn @A() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %A.ref: %A.type = name_ref A, file.%A.decl [template = constants.%A]
+// CHECK:STDOUT:   %y.ref: <error> = name_ref y, <error> [template = <error>]
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 2 - 1
toolchain/check/testdata/struct/no_prelude/fail_nested_incomplete.carbon

@@ -50,7 +50,8 @@ var p: Incomplete* = &s.a;
 // CHECK:STDOUT: fn @__global_init() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %s.ref: ref <error> = name_ref s, file.%s
-// CHECK:STDOUT:   %.loc21: <error> = addr_of <error> [template = <error>]
+// CHECK:STDOUT:   %a.ref: <error> = name_ref a, <error> [template = <error>]
+// CHECK:STDOUT:   %.loc21: <error> = addr_of %a.ref [template = <error>]
 // CHECK:STDOUT:   assign file.%p.var, <error>
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }

+ 2 - 0
toolchain/check/testdata/where_expr/designator.carbon

@@ -331,6 +331,7 @@ class D {
 // CHECK:STDOUT:   %x.var: ref %empty_tuple.type = var x
 // CHECK:STDOUT:   %x: ref %empty_tuple.type = bind_name x, %x.var
 // CHECK:STDOUT:   %.Self.ref: <error> = name_ref .Self, <error> [template = <error>]
+// CHECK:STDOUT:   %x.ref: <error> = name_ref x, <error> [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -369,6 +370,7 @@ class D {
 // CHECK:STDOUT: fn @Bar() -> %empty_tuple.type {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %.Self.ref: <error> = name_ref .Self, <error> [template = <error>]
+// CHECK:STDOUT:   %undef.ref: <error> = name_ref undef, <error> [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 2 - 1
toolchain/check/testdata/where_expr/fail_not_facet.carbon

@@ -173,9 +173,10 @@ var v: e where .x = 3;
 // CHECK:STDOUT:   %e.ref: <error> = name_ref e, <error> [template = <error>]
 // CHECK:STDOUT:   %.Self: <error> = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self]
 // CHECK:STDOUT:   %.Self.ref: <error> = name_ref .Self, %.Self [symbolic = constants.%.Self]
+// CHECK:STDOUT:   %x.ref: <error> = name_ref x, <error> [template = <error>]
 // CHECK:STDOUT:   %.loc7_21: Core.IntLiteral = int_value 3 [template = constants.%.1]
 // CHECK:STDOUT:   %.loc7_10: type = where_expr %.Self [template = <error>] {
-// CHECK:STDOUT:     requirement_rewrite <error>, <error>
+// CHECK:STDOUT:     requirement_rewrite %x.ref, <error>
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %v.var: ref <error> = var v
 // CHECK:STDOUT:   %v: ref <error> = bind_name v, %v.var