فهرست منبع

Move CHECK lines in tests next to the line that caused the output. (#1224)

Use FileCheck's `[[@LINE+n]]` mechanism to refer to the next line.

This is made awkward by a couple of things:

* We want to keep the `CHECK` lines in the original order.
* Errors are sometimes more than one line long.

The approach we use is to interleave the original lines and the check lines, putting each check line as early as possible subject to two rules:

1) Check lines never precede the 'AUTOUPDATE' line
2) Except when required by rule (1), a check line that refers to a source line by line number is never placed earlier than a source line that precedes that source line.

The actual `[[@LINE+n]]` annotations are created in a second pass after we've interleaved the lines so that we can work out the correct offsets.

Co-authored-by: Jon Meow <jperkins@google.com>
Richard Smith 4 سال پیش
والد
کامیت
e85f45de10
89فایلهای تغییر یافته به همراه433 افزوده شده و 113 حذف شده
  1. 19 0
      executable_semantics/testdata/function/auto_return/fail_no_return.carbon
  2. 18 0
      executable_semantics/testdata/function/fail_non_exhaustive_match.carbon
  3. 18 0
      executable_semantics/testdata/import/fail_order.carbon
  4. 18 0
      executable_semantics/testdata/name_lookup/fail_block_duplicate.carbon
  5. 21 0
      executable_semantics/testdata/name_lookup/fail_class_duplicate.carbon
  6. 19 0
      executable_semantics/testdata/name_lookup/fail_global_duplicate.carbon
  7. 20 0
      executable_semantics/testdata/name_lookup/fail_match_duplicate.carbon
  8. 20 0
      executable_semantics/testdata/return/fail_explicit_with_no_return.carbon
  9. 21 0
      executable_semantics/testdata/return/fail_implicit_with_explicit_return.carbon
  10. 1 1
      explorer/testdata/array/fail_negative_size.carbon
  11. 1 1
      explorer/testdata/array/fail_size_mismatch.carbon
  12. 1 1
      explorer/testdata/basic_syntax/fail_assign_to_function.carbon
  13. 1 1
      explorer/testdata/basic_syntax/fail_assign_to_rval.carbon
  14. 1 1
      explorer/testdata/basic_syntax/fail_invalid_char.carbon
  15. 1 1
      explorer/testdata/basic_syntax/fail_invalid_integer.carbon
  16. 1 1
      explorer/testdata/basic_syntax/fail_invalid_var_expression.carbon
  17. 1 1
      explorer/testdata/basic_syntax/fail_missing_var.carbon
  18. 1 1
      explorer/testdata/basic_syntax/fail_nested_binding.carbon
  19. 1 1
      explorer/testdata/basic_syntax/fail_unimplemented_example.carbon
  20. 1 1
      explorer/testdata/basic_syntax/fail_var_type.carbon
  21. 1 1
      explorer/testdata/basic_syntax/not_compare_precedence.carbon
  22. 1 1
      explorer/testdata/class/fail_field_access_mismatch.carbon
  23. 1 1
      explorer/testdata/class/fail_field_mismatch.carbon
  24. 1 1
      explorer/testdata/class/fail_field_missing.carbon
  25. 1 1
      explorer/testdata/class/fail_method_from_class.carbon
  26. 1 1
      explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon
  27. 1 1
      explorer/testdata/function/auto_return/fail_direct_recurse.carbon
  28. 1 1
      explorer/testdata/function/auto_return/fail_multiple_returns.carbon
  29. 1 1
      explorer/testdata/function/auto_return/fail_no_return.carbon
  30. 1 1
      explorer/testdata/function/auto_return/fail_separate_decl.carbon
  31. 1 1
      explorer/testdata/function/fail_call_with_tuple.carbon
  32. 1 1
      explorer/testdata/function/fail_match_no_return.carbon
  33. 1 1
      explorer/testdata/function/fail_match_partial_return.carbon
  34. 1 1
      explorer/testdata/function/fail_non_exhaustive_match.carbon
  35. 1 1
      explorer/testdata/function/fail_parameter_type.carbon
  36. 1 1
      explorer/testdata/generic_class/fail_args_mismatch.carbon
  37. 3 3
      explorer/testdata/generic_class/fail_argument_deduction.carbon
  38. 1 1
      explorer/testdata/generic_class/fail_bad_parameter_type.carbon
  39. 1 1
      explorer/testdata/generic_class/fail_field_access_on_generic.carbon
  40. 1 1
      explorer/testdata/generic_class/fail_generic_class_arg.carbon
  41. 1 1
      explorer/testdata/generic_class/fail_generic_in_pattern.carbon
  42. 1 1
      explorer/testdata/generic_class/fail_instantiate_non_generic.carbon
  43. 1 1
      explorer/testdata/generic_class/fail_point_equal.carbon
  44. 1 1
      explorer/testdata/generic_class/fail_return_type_is_type.carbon
  45. 1 1
      explorer/testdata/generic_class/fail_two_arg_lists.carbon
  46. 3 3
      explorer/testdata/generic_function/fail_not_addable.carbon
  47. 3 3
      explorer/testdata/generic_function/fail_type_deduction_mismatch.carbon
  48. 2 2
      explorer/testdata/generic_function/fail_type_deduction_unused.carbon
  49. 1 1
      explorer/testdata/global_variable/fail_init_type_mismatch.carbon
  50. 1 1
      explorer/testdata/impl/fail_ambiguous_impl.carbon
  51. 1 1
      explorer/testdata/impl/fail_impl_as_not_constraint.carbon
  52. 1 1
      explorer/testdata/impl/fail_impl_as_parameterized.carbon
  53. 1 1
      explorer/testdata/impl/impl_as.carbon
  54. 1 1
      explorer/testdata/import/fail_order.carbon
  55. 1 1
      explorer/testdata/interface/fail_impl_bad_member.carbon
  56. 1 1
      explorer/testdata/interface/fail_impl_missing_member.carbon
  57. 1 1
      explorer/testdata/interface/fail_interface_missing_member.carbon
  58. 1 1
      explorer/testdata/interface/fail_no_impl.carbon
  59. 1 1
      explorer/testdata/let/fail_function_args.carbon
  60. 1 1
      explorer/testdata/let/fail_global_assign.carbon
  61. 1 1
      explorer/testdata/let/fail_local_assign.carbon
  62. 1 1
      explorer/testdata/let/fail_match_choice.carbon
  63. 1 1
      explorer/testdata/let/fail_method_args.carbon
  64. 1 1
      explorer/testdata/let/fail_tuple_pattern_let_context.carbon
  65. 1 1
      explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon
  66. 1 1
      explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon
  67. 1 1
      explorer/testdata/name_lookup/fail_block_duplicate.carbon
  68. 1 1
      explorer/testdata/name_lookup/fail_choice_duplicate.carbon
  69. 1 1
      explorer/testdata/name_lookup/fail_class_duplicate.carbon
  70. 1 1
      explorer/testdata/name_lookup/fail_global_duplicate.carbon
  71. 1 1
      explorer/testdata/name_lookup/fail_match_duplicate.carbon
  72. 1 1
      explorer/testdata/name_lookup/fail_use_before_declare.carbon
  73. 1 1
      explorer/testdata/package/fail_missing.carbon
  74. 1 1
      explorer/testdata/pointer/fail_rvalue_addressof.carbon
  75. 1 1
      explorer/testdata/return/fail_explicit_with_no_return.carbon
  76. 1 1
      explorer/testdata/return/fail_explicit_with_plain_return.carbon
  77. 1 1
      explorer/testdata/return/fail_implicit_with_explicit_return.carbon
  78. 1 1
      explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon
  79. 1 1
      explorer/testdata/string/fail_hex_lower.carbon
  80. 1 1
      explorer/testdata/string/fail_hex_truncated.carbon
  81. 1 1
      explorer/testdata/string/fail_invalid_escape.carbon
  82. 1 1
      explorer/testdata/string/fail_newline.carbon
  83. 1 1
      explorer/testdata/string/fail_octal.carbon
  84. 1 1
      explorer/testdata/string/fail_tab.carbon
  85. 3 3
      explorer/testdata/struct/fail_equality_type.carbon
  86. 1 1
      explorer/testdata/struct/fail_field_access_mismatch.carbon
  87. 3 3
      explorer/testdata/tuple/fail_equality_type.carbon
  88. 1 1
      explorer/testdata/tuple/fail_index.carbon
  89. 169 23
      explorer/update_checks.py

+ 19 - 0
executable_semantics/testdata/function/auto_return/fail_no_return.carbon

@@ -0,0 +1,19 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn NoReturn() -> auto {
+// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/function/auto_return/fail_no_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
+}
+
+fn Main() {
+  NoReturn();
+}

+ 18 - 0
executable_semantics/testdata/function/fail_non_exhaustive_match.carbon

@@ -0,0 +1,18 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn Main() -> i32 {
+  match (0) {
+    case 1 => return 0;
+  }
+// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/function/fail_non_exhaustive_match.carbon:[[@LINE+1]]: non-exhaustive match may allow control-flow to reach the end of a function that provides a `->` return type
+}

+ 18 - 0
executable_semantics/testdata/import/fail_order.carbon

@@ -0,0 +1,18 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/import/fail_order.carbon:[[@LINE+1]]: syntax error, unexpected IMPORT, expecting END_OF_FILE
+import ExecutableSemanticsTest library "Nonexistent";

+ 18 - 0
executable_semantics/testdata/name_lookup/fail_block_duplicate.carbon

@@ -0,0 +1,18 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn Main() -> i32 {
+  var x: i32 = 0;
+  // CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/name_lookup/fail_block_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/executable_semantics/testdata/name_lookup/fail_block_duplicate.carbon:14
+  var x: i32 = 0;
+  return 0;
+}

+ 21 - 0
executable_semantics/testdata/name_lookup/fail_class_duplicate.carbon

@@ -0,0 +1,21 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+class Foo {
+  var x: i32;
+  // CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/name_lookup/fail_class_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/executable_semantics/testdata/name_lookup/fail_class_duplicate.carbon:14
+  var x: i32;
+}
+
+fn Main() -> i32 {
+  return 0;
+}

+ 19 - 0
executable_semantics/testdata/name_lookup/fail_global_duplicate.carbon

@@ -0,0 +1,19 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+var x: i32 = 0;
+// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/name_lookup/fail_global_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/executable_semantics/testdata/name_lookup/fail_global_duplicate.carbon:13
+var x: i32 = 0;
+
+fn Main() -> i32 {
+  return 0;
+}

+ 20 - 0
executable_semantics/testdata/name_lookup/fail_match_duplicate.carbon

@@ -0,0 +1,20 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn Main() -> i32 {
+  match (0) {
+    case x: i32 =>
+      // CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/name_lookup/fail_match_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/executable_semantics/testdata/name_lookup/fail_match_duplicate.carbon:15
+      var x: i32 = 0;
+  }
+  return 0;
+}

+ 20 - 0
executable_semantics/testdata/return/fail_explicit_with_no_return.carbon

@@ -0,0 +1,20 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn F() -> () {
+// CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/return/fail_explicit_with_no_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
+}
+
+fn Main() -> i32 {
+  F();
+  return 0;
+}

+ 21 - 0
executable_semantics/testdata/return/fail_implicit_with_explicit_return.carbon

@@ -0,0 +1,21 @@
+// 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
+//
+// RUN: %{not} %{executable_semantics} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{executable_semantics} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{executable_semantics} %s
+
+package ExecutableSemanticsTest api;
+
+fn F() {
+  // CHECK: COMPILATION ERROR: {{.*}}/executable_semantics/testdata/return/fail_implicit_with_explicit_return.carbon:[[@LINE+1]]: return (); should not provide a return value, to match the function's signature.
+  return ();
+}
+
+fn Main() -> i32 {
+  F();
+  return 0;
+}

+ 1 - 1
explorer/testdata/array/fail_negative_size.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/array/fail_negative_size.carbon:15: Array size cannot be negative
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/array/fail_negative_size.carbon:[[@LINE+1]]: Array size cannot be negative
   var x: [i32; -1] = ();
   return x[0];
 }

+ 1 - 1
explorer/testdata/array/fail_size_mismatch.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/array/fail_size_mismatch.carbon:15: type error in name binding: '(i32, i32, i32)' is not implicitly convertible to '[i32; 2]'
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/array/fail_size_mismatch.carbon:[[@LINE+1]]: type error in name binding: '(i32, i32, i32)' is not implicitly convertible to '[i32; 2]'
   var x: [i32; 2] = (0, 1, 2);
   return x[0];
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_assign_to_function.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_function.carbon:18: Cannot assign to rvalue 'F'
 
 package ExplorerTest api;
 
@@ -15,6 +14,7 @@ fn F() {}
 fn G() {}
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_function.carbon:[[@LINE+1]]: Cannot assign to rvalue 'F'
   F = G;
   return 0;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_assign_to_rval.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_rval.carbon:15: Cannot assign to rvalue '1'
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_rval.carbon:[[@LINE+1]]: Cannot assign to rvalue '1'
   1 = 0;
   return 0;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_invalid_char.carbon

@@ -7,6 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_char.carbon:12: invalid character '\xEF' in source file.
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_char.carbon:[[@LINE+1]]: invalid character '\xEF' in source file.

+ 1 - 1
explorer/testdata/basic_syntax/fail_invalid_integer.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer.carbon:15: Invalid integer literal: 11111111111111111111111111
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer.carbon:[[@LINE+1]]: Invalid integer literal: 11111111111111111111111111
   return 11111111111111111111111111;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_invalid_var_expression.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_var_expression.carbon:14: Expected expression for variable type
 
 package ExplorerTest api;
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_var_expression.carbon:[[@LINE+1]]: Expected expression for variable type
 var a: auto;
 
 fn Main() -> i32 { return 0; }

+ 1 - 1
explorer/testdata/basic_syntax/fail_missing_var.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:16: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   // error
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
   x : i32;
   return 1;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_nested_binding.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_nested_binding.carbon:15: The type of a binding pattern cannot contain bindings.
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_nested_binding.carbon:[[@LINE+1]]: The type of a binding pattern cannot contain bindings.
   var x: (T: Type) = 1;
   return 1;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_unimplemented_example.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unimplemented_example.carbon:15: Unimplemented
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unimplemented_example.carbon:[[@LINE+1]]: Unimplemented
   return 1 __unimplemented_example_infix 2;
 }

+ 1 - 1
explorer/testdata/basic_syntax/fail_var_type.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_type.carbon:17: Expected a type, but got 42
 
 package ExplorerTest api;
 
 fn Main () -> i32
 {
   // 42 cannot be used as the type of a variable.
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_type.carbon:[[@LINE+1]]: Expected a type, but got 42
   var x: 42 = 0;
   return x;
 }

+ 1 - 1
explorer/testdata/basic_syntax/not_compare_precedence.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/not_compare_precedence.carbon:15: syntax error, unexpected EQUAL_EQUAL, expecting SEMICOLON
 
 package ExplorerTest api;
 
 fn CompareBools(a: Bool, b: Bool) -> Bool {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/not_compare_precedence.carbon:[[@LINE+1]]: syntax error, unexpected EQUAL_EQUAL, expecting SEMICOLON
   return not a == b;
 }

+ 1 - 1
explorer/testdata/class/fail_field_access_mismatch.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_access_mismatch.carbon:21: class Point does not have a field named z
 
 package ExplorerTest api;
 
@@ -18,5 +17,6 @@ class Point {
 
 fn Main() -> i32 {
   var p: Point = {.x = 1, .y = 2};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_access_mismatch.carbon:[[@LINE+1]]: class Point does not have a field named z
   return p.z - 1;
 }

+ 1 - 1
explorer/testdata/class/fail_field_mismatch.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_mismatch.carbon:20: type error in name binding: '{.x: i32, .z: i32}' is not implicitly convertible to 'class Point'
 
 package ExplorerTest api;
 
@@ -17,6 +16,7 @@ class Point {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_mismatch.carbon:[[@LINE+1]]: type error in name binding: '{.x: i32, .z: i32}' is not implicitly convertible to 'class Point'
   var p: Point = {.x = 1, .z = 2};
   return p.x - 1;
 }

+ 1 - 1
explorer/testdata/class/fail_field_missing.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_missing.carbon:20: type error in name binding: '{.x: i32}' is not implicitly convertible to 'class Point'
 
 package ExplorerTest api;
 
@@ -17,6 +16,7 @@ class Point {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_field_missing.carbon:[[@LINE+1]]: type error in name binding: '{.x: i32}' is not implicitly convertible to 'class Point'
   var p: Point = {.x = 1};
   return p.x - 1;
 }

+ 1 - 1
explorer/testdata/class/fail_method_from_class.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_method_from_class.carbon:28: GetX is not a class function
 
 package ExplorerTest api;
 
@@ -25,5 +24,6 @@ class Point {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_method_from_class.carbon:[[@LINE+1]]: GetX is not a class function
   return Point.GetX();
 }

+ 1 - 1
explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon:16: syntax error, unexpected identifier, expecting LEFT_CURLY_BRACE
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: i32 = 0;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon:[[@LINE+1]]: syntax error, unexpected identifier, expecting LEFT_CURLY_BRACE
   __continuation k x = 3;
   __run k;
   return x;

+ 1 - 1
explorer/testdata/function/auto_return/fail_direct_recurse.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_direct_recurse.carbon:18: Function calls itself, but has a deduced return type
 
 package ExplorerTest api;
 
@@ -15,6 +14,7 @@ package ExplorerTest api;
 // used.
 fn Recurse(x: i32, do_recurse: Bool) -> auto {
   if (do_recurse) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_direct_recurse.carbon:[[@LINE+1]]: Function calls itself, but has a deduced return type
     Recurse(x, false);
   }
   return x;

+ 1 - 1
explorer/testdata/function/auto_return/fail_multiple_returns.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_multiple_returns.carbon:18: Only one return is allowed in a function with an `auto` return type.
 
 package ExplorerTest api;
 
@@ -15,6 +14,7 @@ fn Add(x: i32, y: i32) -> auto {
   if (x == 0) {
     return x;
   } else if (y == 0) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_multiple_returns.carbon:[[@LINE+1]]: Only one return is allowed in a function with an `auto` return type.
     return y;
   } else {
     return x + y;

+ 1 - 1
explorer/testdata/function/auto_return/fail_no_return.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_no_return.carbon:15: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 
 package ExplorerTest api;
 
 fn NoReturn() -> auto {
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_no_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 }
 
 fn Main() {

+ 1 - 1
explorer/testdata/function/auto_return/fail_separate_decl.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_separate_decl.carbon:15: Function declaration has deduced return type but no body
 
 package ExplorerTest api;
 
 // This declaration is not allowed.
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/auto_return/fail_separate_decl.carbon:[[@LINE+1]]: Function declaration has deduced return type but no body
 fn Add(x: i32, y: i32) -> auto;
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/function/fail_call_with_tuple.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_call_with_tuple.carbon:19: type error in call: '((i32, i32))' is not implicitly convertible to '(i32, i32)'
 
 package ExplorerTest api;
 
@@ -16,5 +15,6 @@ fn f(x: i32, y: i32) -> i32 { return x + y; }
 fn Main() -> i32 {
   var xy: (i32, i32) = (1, 2);
   // should fail to type-check
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_call_with_tuple.carbon:[[@LINE+1]]: type error in call: '((i32, i32))' is not implicitly convertible to '(i32, i32)'
   return f(xy);
 }

+ 1 - 1
explorer/testdata/function/fail_match_no_return.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_match_no_return.carbon:17: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: i32 = 0;
   match(0) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_match_no_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
     case 1 => { x = 1; }
     case _: auto => { x = 2; }
   }

+ 1 - 1
explorer/testdata/function/fail_match_partial_return.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_match_partial_return.carbon:17: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: i32 = 0;
   match (0) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_match_partial_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
     case 1 => { x = 1; }
     case _: auto => { return 0; }
   }

+ 1 - 1
explorer/testdata/function/fail_non_exhaustive_match.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_non_exhaustive_match.carbon:18: non-exhaustive match may allow control-flow to reach the end of a function that provides a `->` return type
 
 package ExplorerTest api;
 
@@ -15,4 +14,5 @@ fn Main() -> i32 {
   match (0) {
     case 1 => return 0;
   }
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_non_exhaustive_match.carbon:[[@LINE+1]]: non-exhaustive match may allow control-flow to reach the end of a function that provides a `->` return type
 }

+ 1 - 1
explorer/testdata/function/fail_parameter_type.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_parameter_type.carbon:15: Expected a type, but got 42
 
 package ExplorerTest api;
 
 // 42 cannot be used as the type of a parameter.
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/function/fail_parameter_type.carbon:[[@LINE+1]]: Expected a type, but got 42
 fn f(x: 42) -> i32 {
   return x - 1;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_args_mismatch.carbon

@@ -5,12 +5,12 @@
 // RUN: %{not} %{explorer} %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false --dump-input=always -v %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_args_mismatch.carbon:14: type error in call: '(Type, Type)' is not implicitly convertible to '(Type)'
 
 package ExplorerTest api;
 
 class Point(T:! Type) {
   // Point(T, T) does not match class declaration
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_args_mismatch.carbon:[[@LINE+1]]: type error in call: '(Type, Type)' is not implicitly convertible to '(Type)'
   fn Origin(zero: T) -> Point(T, T) {
     return {.x = zero, .y = zero};
   }

+ 3 - 3
explorer/testdata/generic_class/fail_argument_deduction.carbon

@@ -7,9 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_argument_deduction.carbon:28: type error in argument deduction
-// CHECK: expected: i32
-// CHECK: actual: Bool
 
 package ExplorerTest api;
 
@@ -25,5 +22,8 @@ fn FirstOfTwoPoints[T:! Type](a: Point(T), b: Point(T)) -> Point(T) {
 fn Main() -> i32 {
   var p: Point(i32) = {.x = 0, .y = 1};
   var q: Point(Bool) = {.x = true, .y = false};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_argument_deduction.carbon:[[@LINE+3]]: type error in argument deduction
+  // CHECK: expected: i32
+  // CHECK: actual: Bool
   return FirstOfTwoPoints(p, q).x;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_bad_parameter_type.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_bad_parameter_type.carbon:28: type error in call: '(Type)' is not implicitly convertible to '(i32)'
 
 package ExplorerTest api;
 
@@ -25,6 +24,7 @@ class Point(T:! i32) {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_bad_parameter_type.carbon:[[@LINE+1]]: type error in call: '(Type)' is not implicitly convertible to '(i32)'
   var p: Point(i32) = Point(i32).Origin(0);
   return p.GetX();
 }

+ 1 - 1
explorer/testdata/generic_class/fail_field_access_on_generic.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_field_access_on_generic.carbon:15: field access, unexpected T:! Type of non-interface type Type in a.x
 
 package ExplorerTest api;
 
 fn BadFieldAccess[T:! Type](a: T) -> T {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_field_access_on_generic.carbon:[[@LINE+1]]: field access, unexpected T:! Type of non-interface type Type in a.x
   return a.x;
 }
 

+ 1 - 1
explorer/testdata/generic_class/fail_generic_class_arg.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_generic_class_arg.carbon:24: type error in call: '(Type, Type)' is not implicitly convertible to '(Type)'
 
 package ExplorerTest api;
 
@@ -21,6 +20,7 @@ class Point(T:! Type) {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_generic_class_arg.carbon:[[@LINE+1]]: type error in call: '(Type, Type)' is not implicitly convertible to '(Type)'
   var p: Point(i32) = Point(i32, i32).Create(0, 1);
   return p.x;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_generic_in_pattern.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_generic_in_pattern.carbon:17: Generic binding may not occur in pattern with expected type: T:! i32
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var t: auto = 5;
   match (t) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_generic_in_pattern.carbon:[[@LINE+1]]: Generic binding may not occur in pattern with expected type: T:! i32
     case T:! i32 =>
       return 0;
     default =>

+ 1 - 1
explorer/testdata/generic_class/fail_instantiate_non_generic.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:23: attempt to instantiate a non-generic class: Point(i32)
 
 package ExplorerTest api;
 
@@ -20,6 +19,7 @@ class Point {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:[[@LINE+1]]: attempt to instantiate a non-generic class: Point(i32)
   var p: Point(i32) = Point.Origin();
   return 0;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_point_equal.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_point_equal.carbon:21: type error in name binding: 'class Point(T = i32)' is not implicitly convertible to 'class Point(T = Bool)'
 
 package ExplorerTest api;
 
@@ -18,6 +17,7 @@ class Point(T:! Type) {
 
 fn Main() -> i32 {
   var p: Point(i32) = {.x = 0, .y = 0};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_point_equal.carbon:[[@LINE+1]]: type error in name binding: 'class Point(T = i32)' is not implicitly convertible to 'class Point(T = Bool)'
   var q: Point(Bool) = p;
   return 0;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_return_type_is_type.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_return_type_is_type.carbon:18: Expected a type, but got class Point
 
 package ExplorerTest api;
 
@@ -15,6 +14,7 @@ class Point(T:! Type) {
   // The return type should be Point(T). Point by itself is not a type.
   fn Create(x: T, y: T) -> Point {
     return {.x = x, .y = y};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_return_type_is_type.carbon:[[@LINE+1]]: Expected a type, but got class Point
   }
 
   var x: T;

+ 1 - 1
explorer/testdata/generic_class/fail_two_arg_lists.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:15: attempt to instantiate an already instantiated generic class: Point(T)(T)
 
 package ExplorerTest api;
 
 class Point(T:! Type) {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:[[@LINE+1]]: attempt to instantiate an already instantiated generic class: Point(T)(T)
   fn Origin(zero: T) -> Point(T)(T) {
     return {.x = zero, .y = zero};
   }

+ 3 - 3
explorer/testdata/generic_function/fail_not_addable.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_not_addable.carbon:17: type error in addition(1)
-// CHECK: expected: i32
-// CHECK: actual: T:! Type
 
 package ExplorerTest api;
 
 fn id[T:! Type](x: T) -> T {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_not_addable.carbon:[[@LINE+3]]: type error in addition(1)
+  // CHECK: expected: i32
+  // CHECK: actual: T:! Type
   return x + 0;
 }
 

+ 3 - 3
explorer/testdata/generic_function/fail_type_deduction_mismatch.carbon

@@ -7,9 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_type_deduction_mismatch.carbon:21: type error in argument deduction
-// CHECK: expected: i32
-// CHECK: actual: Bool
 
 package ExplorerTest api;
 
@@ -18,5 +15,8 @@ fn fst[T:! Type](x: T, y: T) -> T {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_type_deduction_mismatch.carbon:[[@LINE+3]]: type error in argument deduction
+  // CHECK: expected: i32
+  // CHECK: actual: Bool
   return fst(0, true);
 }

+ 2 - 2
explorer/testdata/generic_function/fail_type_deduction_unused.carbon

@@ -7,8 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_type_deduction_unused.carbon:20: could not deduce type argument for type parameter T
-// CHECK: in id(0)
 
 package ExplorerTest api;
 
@@ -17,5 +15,7 @@ fn id[T:! Type](x: i32) -> i32 {
 }
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_type_deduction_unused.carbon:[[@LINE+2]]: could not deduce type argument for type parameter T
+  // CHECK: in id(0)
   return id(0);
 }

+ 1 - 1
explorer/testdata/global_variable/fail_init_type_mismatch.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_init_type_mismatch.carbon:16: type error in initializer of variable: 'Bool' is not implicitly convertible to 'i32'
 
 package ExplorerTest api;
 
 // Test type checking of global variable. Error expected.
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_init_type_mismatch.carbon:[[@LINE+1]]: type error in initializer of variable: 'Bool' is not implicitly convertible to 'i32'
 var flag: i32 = true;
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/impl/fail_ambiguous_impl.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_ambiguous_impl.carbon:50: ambiguous implementations of interface Vector for class Point
 
 
 package ExplorerTest api;
@@ -47,6 +46,7 @@ fn AddAndScaleGeneric[T:! Vector](a: T, b: T, s: i32) -> T {
 fn Main() -> i32 {
   var a: Point = {.x = 1, .y = 1};
   var b: Point = {.x = 2, .y = 3};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_ambiguous_impl.carbon:[[@LINE+1]]: ambiguous implementations of interface Vector for class Point
   var p: Point = AddAndScaleGeneric(a, b, 5);
   return p.x - 15;
 }

+ 1 - 1
explorer/testdata/impl/fail_impl_as_not_constraint.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_not_constraint.carbon:14: expected constraint after `as`, found value of type i32
 
 package ExplorerTest api;
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_not_constraint.carbon:[[@LINE+1]]: expected constraint after `as`, found value of type i32
 external impl i32 as i32 {}
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/impl/fail_impl_as_parameterized.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_parameterized.carbon:17: missing arguments for parameterized interface
 
 package ExplorerTest api;
 
 interface Vector(Scalar:! Type) {
 }
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_parameterized.carbon:[[@LINE+1]]: missing arguments for parameterized interface
 external impl i32 as Vector {}
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/impl/impl_as.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/impl_as.carbon:14: expected constraint after `as`, found value of type i32
 
 package ExplorerTest api;
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/impl_as.carbon:[[@LINE+1]]: expected constraint after `as`, found value of type i32
 external impl i32 as i32 {}
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/import/fail_order.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/import/fail_order.carbon:18: syntax error, unexpected IMPORT, expecting END_OF_FILE
 
 package ExplorerTest api;
 
@@ -15,4 +14,5 @@ fn Main() -> i32 {
   return 0;
 }
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/import/fail_order.carbon:[[@LINE+1]]: syntax error, unexpected IMPORT, expecting END_OF_FILE
 import ExplorerTest library "Nonexistent";

+ 1 - 1
explorer/testdata/interface/fail_impl_bad_member.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_impl_bad_member.carbon:28: type error in member of implementation: 'fn (i32) -> i32' is not implicitly convertible to 'fn (i32) -> class Point'
 
 package ExplorerTest api;
 
@@ -25,6 +24,7 @@ class Point {
     }
     fn Scale[me: Point](v: i32) -> i32 {
       return 0;
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_impl_bad_member.carbon:[[@LINE+1]]: type error in member of implementation: 'fn (i32) -> i32' is not implicitly convertible to 'fn (i32) -> class Point'
     }
   }
 }

+ 1 - 1
explorer/testdata/interface/fail_impl_missing_member.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_impl_missing_member.carbon:26: implementation missing Scale
 
 package ExplorerTest api;
 
@@ -23,6 +22,7 @@ class Point {
     fn Add[me: Point](b: Point) -> Point {
       return {.x = me.x + b.x, .y = me.y + b.y};
     }
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_impl_missing_member.carbon:[[@LINE+1]]: implementation missing Scale
   }
 }
 

+ 1 - 1
explorer/testdata/interface/fail_interface_missing_member.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_interface_missing_member.carbon:19: field access, Scale not in Vector
 
 package ExplorerTest api;
 
@@ -16,6 +15,7 @@ interface Vector {
 }
 
 fn ScaleGeneric[T:! Vector](a: T, s: i32) -> T {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_interface_missing_member.carbon:[[@LINE+1]]: field access, Scale not in Vector
   return a.Scale(s);
 }
 

+ 1 - 1
explorer/testdata/interface/fail_no_impl.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_no_impl.carbon:31: could not find implementation of interface Vector for class Point
 
 package ExplorerTest api;
 
@@ -28,6 +27,7 @@ fn AddAndScaleGeneric[T:! Vector](a: T, b: T, s: i32) -> T {
 fn Main() -> i32 {
   var a: Point = {.x = 0, .y = 0};
   var b: Point = {.x = 2, .y = 3};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_no_impl.carbon:[[@LINE+1]]: could not find implementation of interface Vector for class Point
   var p: Point = AddAndScaleGeneric(a, b, 3);
   return p.x - 6;
 }

+ 1 - 1
explorer/testdata/let/fail_function_args.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_function_args.carbon:16: Cannot assign to rvalue 'y'
 
 package ExplorerTest api;
 
 fn f((var x: i32, y: i32)) -> i32 {
   x = 0;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_function_args.carbon:[[@LINE+1]]: Cannot assign to rvalue 'y'
   y = 0;
   return x - 1;
 }

+ 1 - 1
explorer/testdata/let/fail_global_assign.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_global_assign.carbon:17: Cannot assign to rvalue 'x'
 
 package ExplorerTest api;
 
 let x: i32 = 10;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_global_assign.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
   x = 0;
   return 0;
 }

+ 1 - 1
explorer/testdata/let/fail_local_assign.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_assign.carbon:16: Cannot assign to rvalue 'x'
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   let x: auto = 10;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_assign.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
   x = 0;
   return 0;
 }

+ 1 - 1
explorer/testdata/let/fail_match_choice.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_match_choice.carbon:29: Cannot assign to rvalue 'x'
 
 package ExplorerTest api;
 
@@ -26,6 +25,7 @@ fn Main() -> i32 {
     case Ints.None() =>
       n = n - 1;
     case Ints.Two(x: auto, y: auto) => {
+      // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_match_choice.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
       x = 0;
     }
   }

+ 1 - 1
explorer/testdata/let/fail_method_args.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_method_args.carbon:20: Cannot assign to rvalue 'x'
 
 package ExplorerTest api;
 
@@ -17,6 +16,7 @@ class Point {
   }
 
   fn SetX[me: Point](x: i32) {
+    // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_method_args.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
     x = 10;
   }
 

+ 1 - 1
explorer/testdata/let/fail_tuple_pattern_let_context.carbon

@@ -7,7 +7,6 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context.carbon:18: Cannot assign to rvalue 'c'
 
 package ExplorerTest api;
 
@@ -15,6 +14,7 @@ fn Main() -> i32 {
   let (var a: auto, b: auto, c: auto, d: auto) = (1, 2, 3, 4);
   a = 0;
   // should fail
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context.carbon:[[@LINE+1]]: Cannot assign to rvalue 'c'
   c = 0;
   return 0;
 }

+ 1 - 1
explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon:15: syntax error, unexpected LET
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon:[[@LINE+1]]: syntax error, unexpected LET
   let (var a: auto, b: auto, c: auto, var (d: auto, let e: auto)) =
       (1, 2, 3, (4, 5));
   return 0;

+ 1 - 1
explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon:15: syntax error, unexpected LET
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon:[[@LINE+1]]: syntax error, unexpected LET
   var (var a: auto, b: auto, let c: auto, d: auto) = (1, 2, 3, 4);
   return 0;
 }

+ 1 - 1
explorer/testdata/name_lookup/fail_block_duplicate.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_block_duplicate.carbon:16: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_block_duplicate.carbon:15
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: i32 = 0;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_block_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_block_duplicate.carbon:14
   var x: i32 = 0;
   return 0;
 }

+ 1 - 1
explorer/testdata/name_lookup/fail_choice_duplicate.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_choice_duplicate.carbon:16: Duplicate name `None` in choice type
 
 package ExplorerTest api;
 
 choice Ints {
   None,
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_choice_duplicate.carbon:[[@LINE+1]]: Duplicate name `None` in choice type
   None,
 }
 

+ 1 - 1
explorer/testdata/name_lookup/fail_class_duplicate.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_class_duplicate.carbon:16: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_class_duplicate.carbon:15
 
 package ExplorerTest api;
 
 class Foo {
   var x: i32;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_class_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_class_duplicate.carbon:14
   var x: i32;
 }
 

+ 1 - 1
explorer/testdata/name_lookup/fail_global_duplicate.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_global_duplicate.carbon:15: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_global_duplicate.carbon:14
 
 package ExplorerTest api;
 
 var x: i32 = 0;
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_global_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_global_duplicate.carbon:13
 var x: i32 = 0;
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/name_lookup/fail_match_duplicate.carbon

@@ -7,13 +7,13 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_match_duplicate.carbon:17: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_match_duplicate.carbon:16
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   match (0) {
     case x: i32 =>
+      // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_match_duplicate.carbon:[[@LINE+1]]: Duplicate name `x` also found at {{.*}}/explorer/testdata/name_lookup/fail_match_duplicate.carbon:15
       var x: i32 = 0;
   }
   return 0;

+ 1 - 1
explorer/testdata/name_lookup/fail_use_before_declare.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_use_before_declare.carbon:15: could not resolve 'x'
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/name_lookup/fail_use_before_declare.carbon:[[@LINE+1]]: could not resolve 'x'
   x = 0;
   var x: i32 = 0;
   return 0;

+ 1 - 1
explorer/testdata/package/fail_missing.carbon

@@ -7,8 +7,8 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/package/fail_missing.carbon:12: syntax error, unexpected FN, expecting PACKAGE
 
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/package/fail_missing.carbon:[[@LINE+1]]: syntax error, unexpected FN, expecting PACKAGE
 fn Main() -> i32 {
   return 0;
 }

+ 1 - 1
explorer/testdata/pointer/fail_rvalue_addressof.carbon

@@ -7,12 +7,12 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/pointer/fail_rvalue_addressof.carbon:16: Argument to & should be an lvalue.
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: i32 = 5;
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/pointer/fail_rvalue_addressof.carbon:[[@LINE+1]]: Argument to & should be an lvalue.
   var p: i32* = &5;
   return 0;
 }

+ 1 - 1
explorer/testdata/return/fail_explicit_with_no_return.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_explicit_with_no_return.carbon:15: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 
 package ExplorerTest api;
 
 fn F() -> () {
+// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_explicit_with_no_return.carbon:[[@LINE+1]]: control-flow reaches end of function that provides a `->` return type without reaching a return statement
 }
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/return/fail_explicit_with_plain_return.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_explicit_with_plain_return.carbon:15: return; should provide a return value, to match the function's signature.
 
 package ExplorerTest api;
 
 fn F() -> () {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_explicit_with_plain_return.carbon:[[@LINE+1]]: return; should provide a return value, to match the function's signature.
   return;
 }
 

+ 1 - 1
explorer/testdata/return/fail_implicit_with_explicit_return.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_implicit_with_explicit_return.carbon:15: return (); should not provide a return value, to match the function's signature.
 
 package ExplorerTest api;
 
 fn F() {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/return/fail_implicit_with_explicit_return.carbon:[[@LINE+1]]: return (); should not provide a return value, to match the function's signature.
   return ();
 }
 

+ 1 - 1
explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon:15: Invalid block string: Should end with triple quotes: error: closing """
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon:[[@LINE+1]]: Invalid block string: Should end with triple quotes: error: closing """
   var s: String = """
     error: closing """ is not on its own line.
   """;

+ 1 - 1
explorer/testdata/string/fail_hex_lower.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_lower.carbon:15: Invalid escaping in string: "str\xaa"
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_lower.carbon:[[@LINE+1]]: Invalid escaping in string: "str\xaa"
   Print("str\xaa");
   return 0;
 }

+ 1 - 1
explorer/testdata/string/fail_hex_truncated.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_truncated.carbon:15: Invalid escaping in string: "str\x"
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_truncated.carbon:[[@LINE+1]]: Invalid escaping in string: "str\x"
   Print("str\x");
   return 0;
 }

+ 1 - 1
explorer/testdata/string/fail_invalid_escape.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_invalid_escape.carbon:15: Invalid escaping in string: "str\e"
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_invalid_escape.carbon:[[@LINE+1]]: Invalid escaping in string: "str\e"
   Print("str\e");
   return 0;
 }

+ 1 - 1
explorer/testdata/string/fail_newline.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_newline.carbon:15: invalid character '\x22' in source file.
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_newline.carbon:[[@LINE+1]]: invalid character '\x22' in source file.
   Print("new
 line");
   return 0;

+ 1 - 1
explorer/testdata/string/fail_octal.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_octal.carbon:15: Invalid escaping in string: "str\01"
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_octal.carbon:[[@LINE+1]]: Invalid escaping in string: "str\01"
   Print("str\01");
   return 0;
 }

+ 1 - 1
explorer/testdata/string/fail_tab.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_tab.carbon:15: Invalid escaping in string: "new	line"
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_tab.carbon:[[@LINE+1]]: Invalid escaping in string: "new	line"
   Print("new	line");
   return 0;
 }

+ 3 - 3
explorer/testdata/struct/fail_equality_type.carbon

@@ -4,15 +4,15 @@
 //
 // RUN: %{not} %{explorer} %s 2>&1 2>&1 | %{FileCheck} %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_equality_type.carbon:16: type error in ==
-// CHECK: expected: {.x: i32, .y: i32}
-// CHECK: actual: {.x: i32}
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var t1: {.x: i32, .y: i32} = {.x = 5, .y = 2};
   var t2: {.x: i32,} = {.x = 5,};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_equality_type.carbon:[[@LINE+3]]: type error in ==
+  // CHECK: expected: {.x: i32, .y: i32}
+  // CHECK: actual: {.x: i32}
   if (t1 == t2) {
     return 1;
   } else {

+ 1 - 1
explorer/testdata/struct/fail_field_access_mismatch.carbon

@@ -7,10 +7,10 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_field_access_mismatch.carbon:15: struct {.x: i32, .y: i32} does not have a field named z
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_field_access_mismatch.carbon:[[@LINE+1]]: struct {.x: i32, .y: i32} does not have a field named z
   return {.x = 1, .y = 2}.z - 1;
 }

+ 3 - 3
explorer/testdata/tuple/fail_equality_type.carbon

@@ -4,15 +4,15 @@
 //
 // RUN: %{not} %{explorer} %s 2>&1 2>&1 | %{FileCheck} %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/tuple/fail_equality_type.carbon:16: type error in ==
-// CHECK: expected: (i32, i32)
-// CHECK: actual: (i32)
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var t1: (i32, i32) = (5, 2);
   var t2: (i32,) = (5,);
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/tuple/fail_equality_type.carbon:[[@LINE+3]]: type error in ==
+  // CHECK: expected: (i32, i32)
+  // CHECK: actual: (i32)
   if (t1 == t2) {
     return 1;
   } else {

+ 1 - 1
explorer/testdata/tuple/fail_index.carbon

@@ -7,11 +7,11 @@
 // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
 // RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
 // AUTOUPDATE: %{explorer} %s
-// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/tuple/fail_index.carbon:16: index 2 is out of range for type (i32, i32)
 
 package ExplorerTest api;
 
 fn Main() -> i32 {
   var x: auto = (0, 1);
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/tuple/fail_index.carbon:[[@LINE+1]]: index 2 is out of range for type (i32, i32)
   return x[2];
 }

+ 169 - 23
explorer/update_checks.py

@@ -10,9 +10,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 from concurrent import futures
 import os
+import re
 import subprocess
 import sys
-from typing import Set
+from abc import ABC, abstractmethod
+from typing import Any, Dict, List, Optional, Set
 
 _BIN = "./bazel-bin/explorer/explorer"
 _TESTDATA = "explorer/testdata"
@@ -23,6 +25,9 @@ _AUTOUPDATE_MARKER = "// AUTOUPDATE: "
 # Indicates no autoupdate is requested.
 _NOAUTOUPDATE_MARKER = "// NOAUTOUPDATE"
 
+# A regexp matching lines that contain line number references.
+_LINE_NUMBER_RE = r"(COMPILATION ERROR: [^:]*:)([1-9][0-9]*)(:.*)"
+
 
 def _get_tests() -> Set[str]:
     """Get the list of tests from the filesystem."""
@@ -39,6 +44,114 @@ def _get_tests() -> Set[str]:
     return tests
 
 
+class Line(ABC):
+    """A line that may appear in the resulting test file."""
+
+    @abstractmethod
+    def format(
+        self, *, output_line_number: int, line_number_remap: Dict[int, int]
+    ) -> str:
+        raise NotImplementedError
+
+
+class OriginalLine(Line):
+    """A line that was copied from the original test file."""
+
+    def __init__(self, line_number: int, text: str) -> None:
+        self.line_number = line_number
+        self.text = text
+
+    def format(self, **kwargs: Any) -> str:
+        return self.text
+
+
+class CheckLine(Line):
+    """A `// CHECK:` line generated from the test output."""
+
+    def __init__(self) -> None:
+        self.indent = ""
+
+    @staticmethod
+    def escape(s: str) -> str:
+        """Escape any FileCheck special characters in `s`."""
+        return s.replace("{{", "{{[{][{]}}").replace("[[", "{{[[][[]}}")
+
+    def print_before_line(self, line: int) -> bool:
+        """Determine if we'd prefer to print this CHECK before line `line`."""
+        return True
+
+
+class SimpleCheckLine(CheckLine):
+    """A `// CHECK:` line that checks for an exact string."""
+
+    def __init__(self, expected: str) -> None:
+        super().__init__()
+        self.expected = expected
+
+    def format(self, **kwargs: Any) -> str:
+        if self.expected:
+            return f"{self.indent}// CHECK: {self.expected}\n"
+        else:
+            return f"{self.indent}// CHECK-EMPTY\n"
+
+
+class CheckLineWithLineNumber(CheckLine):
+    """A `// CHECK:` line where the expected output includes a line number.
+
+    Such result lines need to be fixed up after we've figured out which lines
+    to include in the resulting test file and in what order, because their
+    contents depend on where an original input line appears in the output.
+    """
+
+    def __init__(self, before: str, line_number: int, after: str) -> None:
+        super().__init__()
+        self.before = before
+        self.line_number = line_number
+        self.after = after
+
+    def format(
+        self, *, output_line_number: int, line_number_remap: Dict[int, int]
+    ) -> str:
+        delta = line_number_remap[self.line_number] - output_line_number
+        # We use `:+d` here to produce `LINE-n` or `LINE+n` as appropriate.
+        return (
+            f"{self.indent}// CHECK: {self.before}[[@LINE{delta:+d}]]"
+            + f"{self.after}\n"
+        )
+
+    def print_before_line(self, line: int) -> bool:
+        return line >= self.line_number
+
+
+def _make_check_line(out_line: str) -> CheckLine:
+    """Given a line of output, determine what CHECK line to produce."""
+    out_line = out_line.rstrip()
+    match = re.match(_LINE_NUMBER_RE, out_line)
+    if match:
+        # Convert from 1-based line numbers to 0-based indexes.
+        diagnostic_line_number = int(match[2]) - 1
+        return CheckLineWithLineNumber(
+            match[1], diagnostic_line_number, match[3]
+        )
+    else:
+        return SimpleCheckLine(out_line)
+
+
+def _should_produce_check_line(
+    check_line: CheckLine,
+    orig_line: Optional[OriginalLine],
+    autoupdate_index: int,
+) -> bool:
+    """Determine whether it's time to produce a given CHECK line."""
+    if not orig_line:
+        # If there's no original line, we have no choice.
+        return True
+    if orig_line.line_number <= autoupdate_index:
+        # Don't put any CHECK lines before the AUTOUPDATE line.
+        return False
+    return check_line.print_before_line(orig_line.line_number)
+
+
 def _update_check_once(test: str) -> bool:
     """Updates the CHECK: lines for `test` by running explorer.
 
@@ -48,13 +161,9 @@ def _update_check_once(test: str) -> bool:
         orig_lines = f.readlines()
 
     # Remove old OUT.
-    lines_without_check = [
-        x for x in orig_lines if not x.startswith("// CHECK")
-    ]
-    num_orig_check_lines = len(orig_lines) - len(lines_without_check)
     autoupdate_index = None
     noautoupdate_index = None
-    for line_index, line in enumerate(lines_without_check):
+    for line_index, line in enumerate(orig_lines):
         if line.startswith(_AUTOUPDATE_MARKER):
             autoupdate_index = line_index
             autoupdate_cmd = line[len(_AUTOUPDATE_MARKER) :]
@@ -91,31 +200,68 @@ def _update_check_once(test: str) -> bool:
     # when used.
     # TODO: Maybe revisit and see if lit can be convinced to give a
     # root-relative path.
-    out = out.replace(test, "{{.*}}/%s" % test)
+    out = CheckLine.escape(out).replace(test, "{{.*}}/%s" % test)
     out_lines = out.splitlines()
 
+    orig_line_iter = iter(
+        OriginalLine(i, line) for i, line in enumerate(orig_lines)
+    )
+    check_line_iter = iter(_make_check_line(out_line) for out_line in out_lines)
+    next_orig_line: Optional[OriginalLine] = next(orig_line_iter, None)
+    next_check_line: Optional[CheckLine] = next(check_line_iter, None)
+
+    # Interleave the original lines and the CHECK: lines into a list of
+    # `result_lines`.
+    result_lines: List[Line] = []
+    # Mapping from `orig_lines` indexes to `result_lines` indexes.
+    line_number_remap: Dict[int, int] = {}
+    while next_orig_line or next_check_line:
+        if next_check_line and _should_produce_check_line(
+            next_check_line, next_orig_line, autoupdate_index
+        ):
+            # Indent the CHECK: line to match the next original line.
+            if next_orig_line:
+                match = re.match(" *", next_orig_line.text)
+                if match:
+                    next_check_line.indent = match[0]
+            result_lines.append(next_check_line)
+            next_check_line = next(check_line_iter, None)
+        else:
+            assert next_orig_line, "no lines left"
+            # Include this original line if it isn't a CHECK: line.
+            if not re.match(" *// CHECK", next_orig_line.text):
+                line_number_remap[next_orig_line.line_number] = len(
+                    result_lines
+                )
+                result_lines.append(next_orig_line)
+            next_orig_line = next(orig_line_iter, None)
+
+    # Generate contents for any lines that depend on line numbers.
+    formatted_result_lines = [
+        line.format(output_line_number=i, line_number_remap=line_number_remap)
+        for i, line in enumerate(result_lines)
+    ]
+
+    # If nothing's changed, we're done.
+    if formatted_result_lines == orig_lines:
+        return False
+
     # Interleave the new CHECK: lines with the tested content.
     with open(test, "w") as f:
-        f.writelines(lines_without_check[: autoupdate_index + 1])
-        for line in out_lines:
-            line = line.rstrip()
-            if line:
-                f.write("// CHECK: %s\n" % line)
-            else:
-                f.write("// CHECK-EMPTY:\n")
-        f.writelines(lines_without_check[autoupdate_index + 1 :])
-
-    # Compares the number of CHECK: lines originally with the number added.
-    return num_orig_check_lines != len(out_lines)
+        f.writelines(formatted_result_lines)
+    return True
 
 
 def _update_check(test: str) -> None:
     """Wraps CHECK: updates for test files."""
-    if _update_check_once(test):
-        # If the number of output lines changes, run again because output can be
-        # line-specific. However, output should stabilize quickly.
-        if _update_check_once(test):
-            raise ValueError("The output of %s kept changing" % test)
+    # If the number of output lines changes, run again because output can be
+    # line-specific. However, output should stabilize quickly.
+    if (
+        _update_check_once(test)
+        and _update_check_once(test)
+        and _update_check_once(test)
+    ):
+        raise ValueError("The output of %s kept changing" % test)
     print(".", end="", flush=True)