소스 검색

Migrate explorer tests to file_test and remove lit support. (#3050)

This migrates explorer tests to file_test, using the new --autoupdate
functionality. Per discussion, the trace tests that were using "not"
output are mostly migrated to checking full output. The main exception
is tests that were including trace output from the prelude: the prelude
output is pretty long (multiple MB already) and I think it wasn't the
intent to include, only trace output from the small program.

This is the remaining use of lit support, so the supporting libraries
are also removed here.
Jon Ross-Perkins 2 년 전
부모
커밋
96517a1ee3
48개의 변경된 파일633개의 추가작업 그리고 1252개의 파일을 삭제
  1. 8 7
      explorer/BUILD
  2. 0 25
      explorer/README.md
  3. 0 35
      explorer/autoupdate_lit_testdata.py
  4. 0 32
      explorer/autoupdate_testdata.py
  5. 4 8
      explorer/autoupdate_testdata.sh
  6. 0 42
      explorer/autoupdate_trace_testdata.py
  7. 39 6
      explorer/file_test.cpp
  8. 0 35
      explorer/lit_testdata/BUILD
  9. 0 14
      explorer/lit_testdata/fail_compile_error.carbon
  10. 0 16
      explorer/lit_testdata/hello.carbon
  11. 0 1
      explorer/lit_testdata/lit.cfg.py
  12. 0 66
      explorer/lit_testdata/trace.carbon
  13. 0 31
      explorer/lit_testdata/trace_file_filters.carbon
  14. 1 1
      explorer/testdata/assert/fail_assert.carbon
  15. 1 1
      explorer/testdata/assert/fail_convert.carbon
  16. 0 2
      explorer/testdata/basic_syntax/zero.carbon
  17. 1 1
      explorer/testdata/destructor/fail_delete_base_without_virtual_destructor.carbon
  18. 1 1
      explorer/testdata/operators/fail_left_shift_large_rhs.carbon
  19. 1 1
      explorer/testdata/operators/fail_left_shift_negative_rhs.carbon
  20. 1 1
      explorer/testdata/operators/fail_right_shift_large_rhs.carbon
  21. 1 1
      explorer/testdata/operators/fail_right_shift_negative_rhs.carbon
  22. 1 1
      explorer/testdata/optional/fail_optional_get_empty.carbon
  23. 1 1
      explorer/testdata/random/fail_empty_range.carbon
  24. 1 1
      explorer/testdata/random/fail_reverse_range.carbon
  25. 22 0
      explorer/testdata/trace/context_all.carbon
  26. 50 0
      explorer/testdata/trace/context_main.carbon
  27. 19 0
      explorer/testdata/trace/context_prelude.carbon
  28. 98 97
      explorer/testdata/trace/phase_all.carbon
  29. 19 0
      explorer/testdata/trace/phase_control_flow_resolution.carbon
  30. 26 0
      explorer/testdata/trace/phase_declarations.carbon
  31. 78 0
      explorer/testdata/trace/phase_execution.carbon
  32. 34 0
      explorer/testdata/trace/phase_name_resolution.carbon
  33. 26 0
      explorer/testdata/trace/phase_source_program.carbon
  34. 22 0
      explorer/testdata/trace/phase_timing.carbon
  35. 22 0
      explorer/testdata/trace/phase_type_checking.carbon
  36. 22 0
      explorer/testdata/trace/phase_unformed_variables_resolution.carbon
  37. 77 28
      testing/file_test/autoupdate.cpp
  38. 2 2
      testing/file_test/autoupdate.h
  39. 48 30
      testing/file_test/file_test_base.cpp
  40. 5 2
      testing/file_test/file_test_base.h
  41. 0 0
      testing/lit_test/__init__.py
  42. 0 58
      testing/lit_test/lit.cfg.py
  43. 0 57
      testing/lit_test/lit_test.py
  44. 0 38
      testing/lit_test/merge_output.py
  45. 0 66
      testing/lit_test/rules.bzl
  46. 0 0
      testing/scripts/__init__.py
  47. 0 542
      testing/scripts/autoupdate_testdata_base.py
  48. 2 2
      toolchain/lexer/lexer_file_test.cpp

+ 8 - 7
explorer/BUILD

@@ -51,6 +51,7 @@ cc_library(
         "//testing/file_test:file_test_base",
         "//testing/util:test_raw_ostream",
         "@com_google_absl//absl/flags:flag",
+        "@com_googlesource_code_re2//:re2",
     ],
 )
 
@@ -58,11 +59,11 @@ file_test(
     name = "file_test",
     size = "small",
     shard_count = 20,
-    tests = glob([
-        "testdata/**/*.carbon",
-        "trace_testdata/**/*.carbon",
-    ]),
-    deps = [":file_test_common"],
+    tests = glob(["testdata/**/*.carbon"]),
+    deps = [
+        ":file_test_common",
+        "@com_googlesource_code_re2//:re2",
+    ],
 )
 
 file_test(
@@ -71,14 +72,14 @@ file_test(
     args = ["--trace"],
     shard_count = 30,
     tests = glob(
-        # This omits trace_testdata because that's run with trace in the
-        # default mode.
         ["testdata/**/*.carbon"],
         exclude = [
             # `limits` tests check for various limit conditions (such as an
             # infinite loop). The tests collectively don't test tracing
             # because it creates substantial additional overhead.
             "testdata/limits/**",
+            # `trace` tests do tracing by default.
+            "testdata/trace/**",
             # Expensive tests to trace.
             "testdata/assoc_const/rewrite_large_type.carbon",
             "testdata/linked_list/typed_linked_list.carbon",

+ 0 - 25
explorer/README.md

@@ -117,31 +117,6 @@ To explain this boilerplate:
         braces indicate a contained regular expression.
 -   The `package` is required in all test files, per normal Carbon syntax rules.
 
-### lit tests
-
-The [`lit_testdata/`](lit_testdata/) subdirectory includes other example
-programs.
-
-These tests make use of LLVM's
-[lit](https://llvm.org/docs/CommandGuide/lit.html) and
-[FileCheck](https://llvm.org/docs/CommandGuide/FileCheck.html).
-
-They share most of their header with those in `testdata`, with an additional
-`RUN` rule:
-
-```
-// RUN: %{explorer-run}
-// RUN: %{explorer-run-trace}
-```
-
-The `RUN` lines indicate two commands for `lit` to execute using the file: one
-without trace and debug output, one with.
-
--   `RUN:` will be followed by the `not` command when failure is expected. In
-    particular, `RUN: not %{explorer-run}`.
--   The full command is in `lit.cfg.py`; it will run explorer and pass results
-    to [`FileCheck`](https://llvm.org/docs/CommandGuide/FileCheck.html).
-
 ### Useful commands
 
 -   `./autoupdate_testdata.py` -- Updates expected output.

+ 0 - 35
explorer/autoupdate_lit_testdata.py

@@ -1,35 +0,0 @@
-#!/usr/bin/env python3
-
-"""Updates the CHECK: lines in tests with an AUTOUPDATE line."""
-
-__copyright__ = """
-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
-"""
-
-import subprocess
-import sys
-from pathlib import Path
-
-
-def main() -> None:
-    # Subprocess to the main script in order to avoid Python import behaviors.
-    this_py = Path(__file__).resolve()
-    autoupdate_py = this_py.parent.parent.joinpath(
-        "testing", "scripts", "autoupdate_testdata_base.py"
-    )
-    args = [
-        str(autoupdate_py),
-        # Flags to configure for explorer testing.
-        "--tool=explorer",
-        "--testdata=explorer/lit_testdata",
-        "--lit_run=%{explorer} | %{FileCheck-strict}",
-        "--lit_run=%{explorer} --parser_debug --trace_file=- | "
-        "%{FileCheck-allow-unmatched}",
-    ] + sys.argv[1:]
-    exit(subprocess.call(args))
-
-
-if __name__ == "__main__":
-    main()

+ 0 - 32
explorer/autoupdate_testdata.py

@@ -1,32 +0,0 @@
-#!/usr/bin/env python3
-
-"""Updates the CHECK: lines in tests with an AUTOUPDATE line."""
-
-__copyright__ = """
-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
-"""
-
-import subprocess
-import sys
-from pathlib import Path
-
-
-def main() -> None:
-    # Subprocess to the main script in order to avoid Python import behaviors.
-    this_py = Path(__file__).resolve()
-    autoupdate_py = this_py.parent.parent.joinpath(
-        "testing", "scripts", "autoupdate_testdata_base.py"
-    )
-    args = [
-        str(autoupdate_py),
-        # Flags to configure for explorer testing.
-        "--tool=explorer",
-        "--testdata=explorer/testdata",
-    ] + sys.argv[1:]
-    exit(subprocess.call(args))
-
-
-if __name__ == "__main__":
-    main()

+ 4 - 8
testing/lit_test/BUILD → explorer/autoupdate_testdata.sh

@@ -1,12 +1,8 @@
+#!/usr/bin/env bash
+
 # 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
 
-package(default_visibility = ["//visibility:public"])
-
-exports_files(["lit_test.py"])
-
-py_binary(
-    name = "merge_output",
-    srcs = ["merge_output.py"],
-)
+bazel run -c opt --test_sharding_strategy=disabled //explorer:file_test \
+  -- --autoupdate

+ 0 - 42
explorer/autoupdate_trace_testdata.py

@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-
-"""Updates the CHECK: lines in tests with an AUTOUPDATE line."""
-
-__copyright__ = """
-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
-"""
-
-import subprocess
-import sys
-from pathlib import Path
-
-
-def main() -> None:
-    # Subprocess to the main script in order to avoid Python import behaviors.
-    this_py = Path(__file__).resolve()
-    autoupdate_py = this_py.parent.parent.joinpath(
-        "testing", "scripts", "autoupdate_testdata_base.py"
-    )
-
-    args = [
-        str(autoupdate_py),
-        # Flags to configure for explorer testing.
-        "--tool=explorer",
-        "--testdata=explorer/trace_testdata",
-        "--autoupdate_arg=--trace_file=-",
-        "--autoupdate_arg=-trace_phase=all",
-        "--extra_check_replacement",
-        r".+Time elapsed in (\S+): (\d+)ms",
-        r"Time elapsed in (\S+): (\d+)ms",
-        r"Time elapsed in \1: {{[0-9]+}}ms",
-        # Do not perform line number replacement.
-        "--line_number_pattern",
-        "(?!)",
-    ] + sys.argv[1:]
-    exit(subprocess.call(args))
-
-
-if __name__ == "__main__":
-    main()

+ 39 - 6
explorer/file_test.cpp

@@ -4,6 +4,7 @@
 
 #include "absl/flags/flag.h"
 #include "explorer/main.h"
+#include "re2/re2.h"
 #include "testing/file_test/file_test_base.h"
 #include "testing/util/test_raw_ostream.h"
 
@@ -17,7 +18,13 @@ namespace {
 
 class ExplorerFileTest : public FileTestBase {
  public:
-  using FileTestBase::FileTestBase;
+  explicit ExplorerFileTest(std::filesystem::path path)
+      : FileTestBase(std::move(path)),
+        prelude_line_re_(R"(prelude.carbon:(\d+))"),
+        timing_re_(R"((Time elapsed in \w+: )\d+(ms))") {
+    CARBON_CHECK(prelude_line_re_.ok()) << prelude_line_re_.error();
+    CARBON_CHECK(timing_re_.ok()) << timing_re_.error();
+  }
 
   auto Run(const llvm::SmallVector<llvm::StringRef>& test_args,
            const llvm::SmallVector<TestFile>& test_files,
@@ -52,13 +59,9 @@ class ExplorerFileTest : public FileTestBase {
       args.push_back(arg.data());
     }
 
-    // Trace output is only checked for a few tests.
-    bool check_trace_output =
-        path().string().find("trace_testdata/") != std::string::npos;
-
     int exit_code = ExplorerMain(
         args.size(), args.data(), /*install_path=*/"", PreludePath, stdout,
-        stderr, check_trace_output ? stdout : trace_stream_, fs);
+        stderr, check_trace_output() ? stdout : trace_stream_, fs);
 
     return exit_code == EXIT_SUCCESS;
   }
@@ -83,7 +86,37 @@ class ExplorerFileTest : public FileTestBase {
     return args;
   }
 
+  auto GetLineNumberReplacement(llvm::ArrayRef<llvm::StringRef> filenames)
+      -> LineNumberReplacement override {
+    if (check_trace_output()) {
+      return {.has_file = false,
+              .pattern = R"((DO NOT MATCH))",
+              // The `{{{{` becomes `{{`.
+              .line_formatv = "{{{{ *}}{0}"};
+    }
+    return FileTestBase::GetLineNumberReplacement(filenames);
+  }
+
+  auto DoExtraCheckReplacements(std::string& check_line) -> void override {
+    // Ignore the resulting column of EndOfFile because it's often the end of
+    // the CHECK comment.
+    RE2::GlobalReplace(&check_line, prelude_line_re_,
+                       R"(prelude.carbon:{{\\d+}})");
+    if (check_trace_output()) {
+      // Replace timings in trace output.
+      RE2::GlobalReplace(&check_line, timing_re_, R"(\1{{\\d+}}\2)");
+    }
+  }
+
+ private:
+  // Trace output is directly checked for a few tests.
+  auto check_trace_output() -> bool {
+    return path().string().find("/trace/") != std::string::npos;
+  }
+
   TestRawOstream trace_stream_;
+  RE2 prelude_line_re_;
+  RE2 timing_re_;
 };
 
 }  // namespace

+ 0 - 35
explorer/lit_testdata/BUILD

@@ -1,35 +0,0 @@
-# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-# Exceptions. See /LICENSE for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-load("//bazel/sh_run:rules.bzl", "glob_sh_run")
-load("//testing/lit_test:rules.bzl", "glob_lit_tests")
-
-glob_lit_tests(
-    name = "all_lit_tests",
-    data = [
-        "//explorer",
-        "//testing/lit_test:merge_output",
-        "@llvm-project//llvm:FileCheck",
-        "@llvm-project//llvm:not",
-    ],
-    driver = "lit.cfg.py",
-    test_file_exts = ["carbon"],
-)
-
-glob_sh_run(
-    args = ["$(location //explorer)"],
-    data = ["//explorer"],
-    file_exts = ["carbon"],
-)
-
-glob_sh_run(
-    args = [
-        "$(location //explorer)",
-        "--parser_debug",
-        "--trace_file=-",
-    ],
-    data = ["//explorer"],
-    file_exts = ["carbon"],
-    run_ext = "verbose",
-)

+ 0 - 14
explorer/lit_testdata/fail_compile_error.carbon

@@ -1,14 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-// NOAUTOUPDATE
-// RUN: %{not} %{explorer} | %{FileCheck-strict}
-// RUN: %{not} %{explorer} --parser_debug --trace_file=- | %{FileCheck-allow-unmatched}
-
-package ExplorerTest api;
-
-// Just needs to produce an error to validate basic structure.
-fn Main() -> i32 {
-// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/lit_testdata/fail_compile_error.carbon:[[@LINE+1]]: {{.*}}
-}

+ 0 - 16
explorer/lit_testdata/hello.carbon

@@ -1,16 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-// AUTOUPDATE
-// RUN: %{explorer} | %{FileCheck-strict}
-// RUN: %{explorer} --parser_debug --trace_file=- | %{FileCheck-allow-unmatched}
-// CHECK:STDOUT: Hello
-// CHECK:STDOUT: result: 0
-
-package ExplorerTest api;
-
-fn Main() -> i32 {
-  Print("Hello");
-  return 0;
-}

+ 0 - 1
explorer/lit_testdata/lit.cfg.py

@@ -1 +0,0 @@
-../../testing/lit_test/lit.cfg.py

+ 0 - 66
explorer/lit_testdata/trace.carbon

@@ -1,66 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-// A lot of output is elided: this is only checking for a few things for simple
-// sanity checking on --parser_debug --trace_file=- along with filter flags output.
-//
-// NOAUTOUPDATE
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=execution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=source_program | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=name_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=control_flow_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=type_checking | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=unformed_variables_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=declarations | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=timing | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=all | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NAMES,NO-PRELUDE,FLOW,TYPE,UNFORMED,DECLS,EXEC,TIMING
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=source_program,declarations | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
-// NO-SOURCE-NOT:STDOUT: ********** source program **********
-//        SOURCE:STDOUT: ********** source program **********
-// NO-SOURCE-NOT:STDOUT: interface TestInterface {
-//        SOURCE:STDOUT: interface TestInterface {
-// NO-NAMES-NOT:STDOUT: ********** resolving names **********
-//        NAMES:STDOUT: ********** resolving names **********
-// NO-PRELUDE-NOT:STDOUT: interface ImplicitAs {
-// NO-FLOW-NOT:STDOUT: ********** resolving control flow **********
-//        FLOW:STDOUT: ********** resolving control flow **********
-// NO-TYPE-NOT:STDOUT: ********** type checking **********
-//        TYPE:STDOUT: ********** type checking **********
-// NO-TYPE-NOT:STDOUT: ** declaring interface TestInterface
-//        TYPE:STDOUT: ** declaring interface TestInterface
-// NO-UNFORMED-NOT:STDOUT: ********** resolving unformed variables **********
-//        UNFORMED:STDOUT: ********** resolving unformed variables **********
-// NO-DECLS-NOT:STDOUT: ********** printing declarations **********
-//        DECLS:STDOUT: ********** printing declarations **********
-// NO-DECLS-NOT:STDOUT: interface TestInterface {
-//        DECLS:STDOUT: interface TestInterface {
-// NO-EXEC-NOT:STDOUT: ********** starting execution **********
-//        EXEC:STDOUT: ********** starting execution **********
-// NO-EXEC-NOT:STDOUT: ********** initializing globals **********
-//        EXEC:STDOUT: ********** initializing globals **********
-// NO-EXEC-NOT:STDOUT: ********** calling main function **********
-//        EXEC:STDOUT: ********** calling main function **********
-// NO-EXEC-NOT:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-//        EXEC:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-// NO-EXEC-NOT:STDOUT: interpreter result: 0
-//        EXEC:STDOUT: interpreter result: 0
-// NO-TIMING-NOT:STDOUT: ********** printing timing **********
-//        TIMING:STDOUT: ********** printing timing **********
-// NO-TIMING-NOT:STDOUT: Time elapsed in ExecProgram: {{[0-9]+}}ms
-//        TIMING:STDOUT: Time elapsed in ExecProgram: {{[0-9]+}}ms
-// NO-TIMING-NOT:STDOUT: Time elapsed in AnalyzeProgram: {{[0-9]+}}ms
-//        TIMING:STDOUT: Time elapsed in AnalyzeProgram: {{[0-9]+}}ms
-// NO-TIMING-NOT:STDOUT: Time elapsed in AddPrelude: {{[0-9]+}}ms
-//        TIMING:STDOUT: Time elapsed in AddPrelude: {{[0-9]+}}ms
-// NO-TIMING-NOT:STDOUT: Time elapsed in Parse: {{[0-9]+}}ms
-//        TIMING:STDOUT: Time elapsed in Parse: {{[0-9]+}}ms
-
-package ExplorerTest api;
-
-interface TestInterface {}
-
-fn Main() -> i32 {
-  return 0;
-}

+ 0 - 31
explorer/lit_testdata/trace_file_filters.carbon

@@ -1,31 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-// A lot of output is elided: this is only checking for a few things for simple
-// sanity checking on --parser_debug --trace_file=- along with file context
-// filter flags output.
-//
-// NOAUTOUPDATE
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=main | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,NO-PRELUDE
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=prelude | %{FileCheck-allow-unmatched} --check-prefixes=NO-MAIN,PRELUDE
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=all | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,PRELUDE
-// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=main,prelude | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,PRELUDE
-// NO-PRELUDE-NOT:STDOUT: ** declaring interface As
-//        PRELUDE:STDOUT: ** declaring interface As
-// NO-MAIN-NOT:STDOUT: ** declaring function Main
-//        MAIN:STDOUT: ** declaring function Main
-// NO-PRELUDE-NOT:STDOUT: interface As {
-//        PRELUDE:STDOUT: interface As {
-// NO-MAIN-NOT:STDOUT: fn Main ()-> i32 {
-//        MAIN:STDOUT: fn Main ()-> i32 {
-// NO-MAIN-NOT:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-//        MAIN:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-
-package ExplorerTest api;
-
-interface TestInterface {}
-
-fn Main() -> i32 {
-  return 0;
-}

+ 1 - 1
explorer/testdata/assert/fail_assert.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: "HALLO WELT"
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: "HALLO WELT"
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/assert/fail_convert.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: "Fail"
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: "Fail"
 
 package ExplorerTest api;
 

+ 0 - 2
explorer/lit_testdata/zero.carbon → explorer/testdata/basic_syntax/zero.carbon

@@ -3,8 +3,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// RUN: %{explorer} | %{FileCheck-strict}
-// RUN: %{explorer} --parser_debug --trace_file=- | %{FileCheck-allow-unmatched}
 // CHECK:STDOUT: result: 0
 
 package ExplorerTest api;

+ 1 - 1
explorer/testdata/destructor/fail_delete_base_without_virtual_destructor.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Deallocating a derived class from base class pointer requires a virtual destructor
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Deallocating a derived class from base class pointer requires a virtual destructor
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/operators/fail_left_shift_large_rhs.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Integer overflow
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Integer overflow
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/operators/fail_left_shift_negative_rhs.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Integer overflow
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Integer overflow
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/operators/fail_right_shift_large_rhs.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Integer overflow
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Integer overflow
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/operators/fail_right_shift_negative_rhs.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Integer overflow
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Integer overflow
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/optional/fail_optional_get_empty.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: "Attempted to unwrap empty Optional"
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: "Attempted to unwrap empty Optional"
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/random/fail_empty_range.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Rand inputs must be ordered for a non-empty range: 0 must be less than 0
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Rand inputs must be ordered for a non-empty range: 0 must be less than 0
 
 package ExplorerTest api;
 

+ 1 - 1
explorer/testdata/random/fail_reverse_range.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // AUTOUPDATE
-// CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: Rand inputs must be ordered for a non-empty range: 1 must be less than -1
+// CHECK:STDERR: RUNTIME ERROR: /explorer/data/prelude.carbon:{{\d+}}: Rand inputs must be ordered for a non-empty range: 1 must be less than -1
 
 package ExplorerTest api;
 

+ 22 - 0
explorer/testdata/trace/context_all.carbon

@@ -0,0 +1,22 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=all --trace_file_context=all %s
+// NOAUTOUPDATE
+// SET-CHECK-SUBSET
+// CHECK:STDOUT: ** declaring interface As
+// CHECK:STDOUT: ** declaring function Main
+// CHECK:STDOUT: interface As {
+// CHECK:STDOUT: fn Main ()-> i32 {
+// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 50 - 0
explorer/testdata/trace/context_main.carbon


+ 19 - 0
explorer/testdata/trace/context_prelude.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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=all --trace_file_context=prelude %s
+// NOAUTOUPDATE
+// SET-CHECK-SUBSET
+// CHECK:STDOUT: ** declaring interface As
+// CHECK:STDOUT: interface As {

+ 98 - 97
explorer/trace_testdata/full_trace.carbon → explorer/testdata/trace/phase_all.carbon

@@ -17,7 +17,8 @@ fn Main() -> i32 {
   return x;
 }
 
-// Place checks after code so that line numbers are stable, reducing merge conflicts.
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
 // ARGS: --trace_file=- --trace_phase=all %s
 // AUTOUPDATE
 // CHECK:STDOUT: ********** source program **********
@@ -37,48 +38,48 @@ fn Main() -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: }
 // CHECK:STDOUT: ********** resolving names **********
-// CHECK:STDOUT: --- declared `TestInterface` as `interface TestInterface` in `package` (full_trace.carbon:7)
-// CHECK:STDOUT: --- declared `N` as `namespace N` in `package` (full_trace.carbon:9)
-// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (full_trace.carbon:11)
-// CHECK:STDOUT: --- declared `Foo` as `fn N.Foo` in `namespace N` (full_trace.carbon:13)
-// CHECK:STDOUT: --- declared `Main` as `fn Main` in `package` (full_trace.carbon:18)
-// CHECK:STDOUT: ** resolving decl `interface TestInterface` (full_trace.carbon:7)
+// CHECK:STDOUT: --- declared `TestInterface` as `interface TestInterface` in `package` (phase_all.carbon:7)
+// CHECK:STDOUT: --- declared `N` as `namespace N` in `package` (phase_all.carbon:9)
+// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (phase_all.carbon:11)
+// CHECK:STDOUT: --- declared `Foo` as `fn N.Foo` in `namespace N` (phase_all.carbon:13)
+// CHECK:STDOUT: --- declared `Main` as `fn Main` in `package` (phase_all.carbon:18)
+// CHECK:STDOUT: ** resolving decl `interface TestInterface` (phase_all.carbon:7)
 // CHECK:STDOUT: --- marked `TestInterface` declared but not usable in `package`
 // CHECK:STDOUT: --- marked `TestInterface` usable in `package`
-// CHECK:STDOUT: --- declared `Self` as `Self` in `interface TestInterface` (full_trace.carbon:7)
-// CHECK:STDOUT: ** finished resolving decl `interface TestInterface` (full_trace.carbon:7)
-// CHECK:STDOUT: ** resolving decl `namespace N` (full_trace.carbon:9)
+// CHECK:STDOUT: --- declared `Self` as `Self` in `interface TestInterface` (phase_all.carbon:7)
+// CHECK:STDOUT: ** finished resolving decl `interface TestInterface` (phase_all.carbon:7)
+// CHECK:STDOUT: ** resolving decl `namespace N` (phase_all.carbon:9)
 // CHECK:STDOUT: --- marked `N` usable in `package`
-// CHECK:STDOUT: ** finished resolving decl `namespace N` (full_trace.carbon:9)
-// CHECK:STDOUT: ** resolving decl `fn N.Foo` (full_trace.carbon:13)
-// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (full_trace.carbon:11)
+// CHECK:STDOUT: ** finished resolving decl `namespace N` (phase_all.carbon:9)
+// CHECK:STDOUT: ** resolving decl `fn N.Foo` (phase_all.carbon:13)
+// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (phase_all.carbon:11)
 // CHECK:STDOUT: --- marked `Foo` declared but not usable in `namespace N`
-// CHECK:STDOUT: --- declared `n` as `n` in `fn N.Foo` (full_trace.carbon:11)
+// CHECK:STDOUT: --- declared `n` as `n` in `fn N.Foo` (phase_all.carbon:11)
 // CHECK:STDOUT: --- marked `Foo` usable in `namespace N`
-// CHECK:STDOUT: ** resolving stmt `{return (n + 1);}` (full_trace.carbon:13)
-// CHECK:STDOUT: ** resolving stmt `return (n + 1);` (full_trace.carbon:12)
-// CHECK:STDOUT: --- resolved `n` as `n` in `fn N.Foo` (full_trace.carbon:12)
-// CHECK:STDOUT: ** finished resolving stmt `return (n + 1);` (full_trace.carbon:12)
-// CHECK:STDOUT: ** finished resolving stmt `{return (n + 1);}` (full_trace.carbon:13)
-// CHECK:STDOUT: ** finished resolving decl `fn N.Foo` (full_trace.carbon:13)
-// CHECK:STDOUT: ** resolving decl `fn Main` (full_trace.carbon:18)
+// CHECK:STDOUT: ** resolving stmt `{return (n + 1);}` (phase_all.carbon:13)
+// CHECK:STDOUT: ** resolving stmt `return (n + 1);` (phase_all.carbon:12)
+// CHECK:STDOUT: --- resolved `n` as `n` in `fn N.Foo` (phase_all.carbon:12)
+// CHECK:STDOUT: ** finished resolving stmt `return (n + 1);` (phase_all.carbon:12)
+// CHECK:STDOUT: ** finished resolving stmt `{return (n + 1);}` (phase_all.carbon:13)
+// CHECK:STDOUT: ** finished resolving decl `fn N.Foo` (phase_all.carbon:13)
+// CHECK:STDOUT: ** resolving decl `fn Main` (phase_all.carbon:18)
 // CHECK:STDOUT: --- marked `Main` declared but not usable in `package`
 // CHECK:STDOUT: --- marked `Main` usable in `package`
-// CHECK:STDOUT: ** resolving stmt `{var x: i32 = N.Foo(0);return x;}` (full_trace.carbon:18)
-// CHECK:STDOUT: ** resolving stmt `var x: i32 = N.Foo(0);` (full_trace.carbon:16)
-// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (full_trace.carbon:16)
-// CHECK:STDOUT: --- resolved `Foo` as `fn N.Foo` in `namespace N` (full_trace.carbon:16)
-// CHECK:STDOUT: --- declared `x` as `x` in `{var x: i32 = N.Foo(0);return x;}` (full_trace.carbon:16)
-// CHECK:STDOUT: ** finished resolving stmt `var x: i32 = N.Foo(0);` (full_trace.carbon:16)
-// CHECK:STDOUT: ** resolving stmt `return x;` (full_trace.carbon:17)
-// CHECK:STDOUT: --- resolved `x` as `x` in `{var x: i32 = N.Foo(0);return x;}` (full_trace.carbon:17)
-// CHECK:STDOUT: ** finished resolving stmt `return x;` (full_trace.carbon:17)
-// CHECK:STDOUT: ** finished resolving stmt `{var x: i32 = N.Foo(0);return x;}` (full_trace.carbon:18)
-// CHECK:STDOUT: ** finished resolving decl `fn Main` (full_trace.carbon:18)
+// CHECK:STDOUT: ** resolving stmt `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:18)
+// CHECK:STDOUT: ** resolving stmt `var x: i32 = N.Foo(0);` (phase_all.carbon:16)
+// CHECK:STDOUT: --- resolved `N` as `namespace N` in `package` (phase_all.carbon:16)
+// CHECK:STDOUT: --- resolved `Foo` as `fn N.Foo` in `namespace N` (phase_all.carbon:16)
+// CHECK:STDOUT: --- declared `x` as `x` in `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:16)
+// CHECK:STDOUT: ** finished resolving stmt `var x: i32 = N.Foo(0);` (phase_all.carbon:16)
+// CHECK:STDOUT: ** resolving stmt `return x;` (phase_all.carbon:17)
+// CHECK:STDOUT: --- resolved `x` as `x` in `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:17)
+// CHECK:STDOUT: ** finished resolving stmt `return x;` (phase_all.carbon:17)
+// CHECK:STDOUT: ** finished resolving stmt `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:18)
+// CHECK:STDOUT: ** finished resolving decl `fn Main` (phase_all.carbon:18)
 // CHECK:STDOUT: --- resolved `Main` as `fn Main` in `package` (<Main()>:0)
 // CHECK:STDOUT: ********** resolving control flow **********
-// CHECK:STDOUT: --- flow-resolved return statement `return (n + 1);` in `fn N.Foo` (full_trace.carbon:12)
-// CHECK:STDOUT: --- flow-resolved return statement `return x;` in `fn Main` (full_trace.carbon:17)
+// CHECK:STDOUT: --- flow-resolved return statement `return (n + 1);` in `fn N.Foo` (phase_all.carbon:12)
+// CHECK:STDOUT: --- flow-resolved return statement `return x;` in `fn Main` (phase_all.carbon:17)
 // CHECK:STDOUT: ********** type checking **********
 // CHECK:STDOUT: ** declaring interface TestInterface
 // CHECK:STDOUT: ** finished declaring interface TestInterface
@@ -95,16 +96,16 @@ fn Main() -> i32 {
 // CHECK:STDOUT: checking IntTypeLiteral i32
 // CHECK:STDOUT: (+) stack-push: i32 .0.
 // CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (full_trace.carbon:11) --->
+// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:11) --->
 // CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{[[][[]}}i32]]
+// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
 // CHECK:STDOUT: finished checking tuple pattern field n: i32
 // CHECK:STDOUT: checking IntTypeLiteral i32
 // CHECK:STDOUT: (+) stack-push: i32 .0.
 // CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (full_trace.carbon:11) --->
+// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:11) --->
 // CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{[[][[]}}i32]]
+// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
 // CHECK:STDOUT: ** finished declaring function Foo of type fn (i32,) -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Foo
@@ -124,9 +125,9 @@ fn Main() -> i32 {
 // CHECK:STDOUT: checking IntTypeLiteral i32
 // CHECK:STDOUT: (+) stack-push: i32 .0.
 // CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (full_trace.carbon:15) --->
+// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:15) --->
 // CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{[[][[]}}i32]]
+// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
 // CHECK:STDOUT: ** finished declaring function Main of type fn () -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Main
@@ -153,9 +154,9 @@ fn Main() -> i32 {
 // CHECK:STDOUT: checking IntTypeLiteral i32
 // CHECK:STDOUT: (+) stack-push: i32 .0.
 // CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{[[][[]}}i32]]
+// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
 // CHECK:STDOUT: checking ReturnExpression return x;
 // CHECK:STDOUT: checking IdentifierExpression x
 // CHECK:STDOUT: ** finished checking function Main
@@ -167,18 +168,18 @@ fn Main() -> i32 {
 // CHECK:STDOUT: performing argument deduction for bindings:{{ }}
 // CHECK:STDOUT: deduction succeeded with results: {}
 // CHECK:STDOUT: ********** resolving unformed variables **********
-// CHECK:STDOUT: *** resolving-unformed in decl `interface TestInterface` (full_trace.carbon:7)
-// CHECK:STDOUT: *** resolving-unformed in decl `namespace N` (full_trace.carbon:9)
-// CHECK:STDOUT: *** resolving-unformed in decl `fn N.Foo` (full_trace.carbon:13)
-// CHECK:STDOUT: *** resolving-unformed in stmt `{return (n + 1);}` (full_trace.carbon:13)
-// CHECK:STDOUT: *** resolving-unformed in stmt `return (n + 1);` (full_trace.carbon:12)
-// CHECK:STDOUT: --- check `n` (full_trace.carbon:12)
-// CHECK:STDOUT: *** resolving-unformed in decl `fn Main` (full_trace.carbon:18)
-// CHECK:STDOUT: *** resolving-unformed in stmt `{var x: i32 = N.Foo(0);return x;}` (full_trace.carbon:18)
-// CHECK:STDOUT: *** resolving-unformed in stmt `var x: i32 = N.Foo(0);` (full_trace.carbon:16)
-// CHECK:STDOUT: --- add init `x` (full_trace.carbon:16)
-// CHECK:STDOUT: *** resolving-unformed in stmt `return x;` (full_trace.carbon:17)
-// CHECK:STDOUT: --- check `x` (full_trace.carbon:17)
+// CHECK:STDOUT: *** resolving-unformed in decl `interface TestInterface` (phase_all.carbon:7)
+// CHECK:STDOUT: *** resolving-unformed in decl `namespace N` (phase_all.carbon:9)
+// CHECK:STDOUT: *** resolving-unformed in decl `fn N.Foo` (phase_all.carbon:13)
+// CHECK:STDOUT: *** resolving-unformed in stmt `{return (n + 1);}` (phase_all.carbon:13)
+// CHECK:STDOUT: *** resolving-unformed in stmt `return (n + 1);` (phase_all.carbon:12)
+// CHECK:STDOUT: --- check `n` (phase_all.carbon:12)
+// CHECK:STDOUT: *** resolving-unformed in decl `fn Main` (phase_all.carbon:18)
+// CHECK:STDOUT: *** resolving-unformed in stmt `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:18)
+// CHECK:STDOUT: *** resolving-unformed in stmt `var x: i32 = N.Foo(0);` (phase_all.carbon:16)
+// CHECK:STDOUT: --- add init `x` (phase_all.carbon:16)
+// CHECK:STDOUT: *** resolving-unformed in stmt `return x;` (phase_all.carbon:17)
+// CHECK:STDOUT: --- check `x` (phase_all.carbon:17)
 // CHECK:STDOUT: ********** printing declarations **********
 // CHECK:STDOUT: interface TestInterface {
 // CHECK:STDOUT: }
@@ -200,12 +201,12 @@ fn Main() -> i32 {
 // CHECK:STDOUT: (+) stack-push: interface TestInterface {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl interface TestInterface .0. (full_trace.carbon:7) --->
+// CHECK:STDOUT: --- step decl interface TestInterface .0. (phase_all.carbon:7) --->
 // CHECK:STDOUT: (-) stack-pop: interface TestInterface {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:  .0.
 // CHECK:STDOUT: (+) stack-push: namespace N; .0.
-// CHECK:STDOUT: --- step decl namespace N .0. (full_trace.carbon:9) --->
+// CHECK:STDOUT: --- step decl namespace N .0. (phase_all.carbon:9) --->
 // CHECK:STDOUT: (-) stack-pop: namespace N; .0.
 // CHECK:STDOUT: (+) stack-push: fn Foo (n: i32)-> i32 {
 // CHECK:STDOUT: {
@@ -214,7 +215,7 @@ fn Main() -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn N.Foo .0. (full_trace.carbon:13) --->
+// CHECK:STDOUT: --- step decl fn N.Foo .0. (phase_all.carbon:13) --->
 // CHECK:STDOUT: (-) stack-pop: fn Foo (n: i32)-> i32 {
 // CHECK:STDOUT: {
 // CHECK:STDOUT: return (n + 1);
@@ -230,7 +231,7 @@ fn Main() -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn Main .0. (full_trace.carbon:18) --->
+// CHECK:STDOUT: --- step decl fn Main .0. (phase_all.carbon:18) --->
 // CHECK:STDOUT: (-) stack-pop: fn Main ()-> i32 {
 // CHECK:STDOUT: {
 // CHECK:STDOUT: var x: i32 = N.Foo(0);
@@ -247,32 +248,32 @@ fn Main() -> i32 {
 // CHECK:STDOUT: (+) stack-push: Main .0.
 // CHECK:STDOUT: --- step exp Main .0. (<Main()>:0) --->
 // CHECK:STDOUT: (-) stack-pop: Main .0.
-// CHECK:STDOUT: (-) stack-pop: Main .1. {{[[][[]}}fun<Main>]]
+// CHECK:STDOUT: (-) stack-pop: Main .1. {{\[\[}}fun<Main>]]
 // CHECK:STDOUT: --- step exp Main() .1. (<Main()>:0) --->
 // CHECK:STDOUT: calling function: fun<Main>
 // CHECK:STDOUT: match pattern ()
 // CHECK:STDOUT: from value expression with value ()
 // CHECK:STDOUT: (+) stack-push: .0. {}
 // CHECK:STDOUT: (+) stack-push: {var x: i32 = N.Foo(0);return x;} .0.
-// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .0. (full_trace.carbon:18) --->
+// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .0. (phase_all.carbon:18) --->
 // CHECK:STDOUT: (+) stack-push: var x: i32 = N.Foo(0); .0.
-// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (+) memory-alloc: #1 `Uninit<i32>` uninitialized
 // CHECK:STDOUT: (+) stack-push: N.Foo(0) .0.
-// CHECK:STDOUT: --- step exp N.Foo(0) .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp N.Foo(0) .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (+) stack-push: N.Foo .0.
 // CHECK:STDOUT: (+) stack-push: N.Foo .0.
-// CHECK:STDOUT: --- step exp N.Foo .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp N.Foo .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (-) stack-pop: N.Foo .0.
 // CHECK:STDOUT: (+) stack-push: Foo .0.
-// CHECK:STDOUT: --- step exp Foo .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp Foo .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (-) stack-pop: Foo .0.
-// CHECK:STDOUT: (-) stack-pop: N.Foo .1. {{[[][[]}}fun<N.Foo>]]
-// CHECK:STDOUT: --- step exp N.Foo(0) .1. (full_trace.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop: N.Foo .1. {{\[\[}}fun<N.Foo>]]
+// CHECK:STDOUT: --- step exp N.Foo(0) .1. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: --- step exp 0 .0. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp 0 .0. (phase_all.carbon:16) --->
 // CHECK:STDOUT: (-) stack-pop: 0 .0.
-// CHECK:STDOUT: --- step exp N.Foo(0) .2. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step exp N.Foo(0) .2. (phase_all.carbon:16) --->
 // CHECK:STDOUT: calling function: fun<N.Foo>
 // CHECK:STDOUT: match pattern (Placeholder<n>,)
 // CHECK:STDOUT: from value expression with value (0,)
@@ -280,55 +281,55 @@ fn Main() -> i32 {
 // CHECK:STDOUT: from value expression with value 0
 // CHECK:STDOUT: (+) stack-push: .0. {n: i32: 0}
 // CHECK:STDOUT: (+) stack-push: {return (n + 1);} .0.
-// CHECK:STDOUT: --- step stmt {return (n + 1);} .0. (full_trace.carbon:13) --->
+// CHECK:STDOUT: --- step stmt {return (n + 1);} .0. (phase_all.carbon:13) --->
 // CHECK:STDOUT: (+) stack-push: return (n + 1); .0.
-// CHECK:STDOUT: --- step stmt return (n + 1); .0. (full_trace.carbon:12) --->
+// CHECK:STDOUT: --- step stmt return (n + 1); .0. (phase_all.carbon:12) --->
 // CHECK:STDOUT: (+) stack-push: (n + 1) .0.
 // CHECK:STDOUT: (+) stack-push: (n + 1) .0.
-// CHECK:STDOUT: --- step exp (n + 1) .0. (full_trace.carbon:12) --->
+// CHECK:STDOUT: --- step exp (n + 1) .0. (phase_all.carbon:12) --->
 // CHECK:STDOUT: (+) stack-push: n .0.
 // CHECK:STDOUT: (+) stack-push: n .0.
-// CHECK:STDOUT: --- step exp n .0. (full_trace.carbon:12) --->
+// CHECK:STDOUT: --- step exp n .0. (phase_all.carbon:12) --->
 // CHECK:STDOUT: (-) stack-pop: n .0.
-// CHECK:STDOUT: (-) stack-pop: n .1. {{[[][[]}}0]]
-// CHECK:STDOUT: --- step exp (n + 1) .1. (full_trace.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop: n .1. {{\[\[}}0]]
+// CHECK:STDOUT: --- step exp (n + 1) .1. (phase_all.carbon:12) --->
 // CHECK:STDOUT: (+) stack-push: 1 .0.
 // CHECK:STDOUT: (+) stack-push: 1 .0.
-// CHECK:STDOUT: --- step exp 1 .0. (full_trace.carbon:12) --->
+// CHECK:STDOUT: --- step exp 1 .0. (phase_all.carbon:12) --->
 // CHECK:STDOUT: (-) stack-pop: 1 .0.
-// CHECK:STDOUT: (-) stack-pop: 1 .1. {{[[][[]}}1]]
-// CHECK:STDOUT: --- step exp (n + 1) .2. (full_trace.carbon:12) --->
-// CHECK:STDOUT: (-) stack-pop: (n + 1) .2. {{[[][[]}}0, 1]]
-// CHECK:STDOUT: (-) stack-pop: (n + 1) .1. {{[[][[]}}1]]
-// CHECK:STDOUT: --- step stmt return (n + 1); .1. (full_trace.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop: 1 .1. {{\[\[}}1]]
+// CHECK:STDOUT: --- step exp (n + 1) .2. (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop: (n + 1) .2. {{\[\[}}0, 1]]
+// CHECK:STDOUT: (-) stack-pop: (n + 1) .1. {{\[\[}}1]]
+// CHECK:STDOUT: --- step stmt return (n + 1); .1. (phase_all.carbon:12) --->
 // CHECK:STDOUT: +++ memory-write: #1 `1`
-// CHECK:STDOUT: (-) stack-pop: return (n + 1); .1. {{[[][[]}}1]]
+// CHECK:STDOUT: (-) stack-pop: return (n + 1); .1. {{\[\[}}1]]
 // CHECK:STDOUT: (-) stack-pop: {return (n + 1);} .1. {}
 // CHECK:STDOUT: (-) stack-pop: .0. {n: i32: 0}
 // CHECK:STDOUT: (+) stack-push: clean up.0. {n: i32: 0}
 // CHECK:STDOUT: (+) stack-push: clean up.0. {}
 // CHECK:STDOUT: (-) stack-pop: clean up.0. {}
 // CHECK:STDOUT: (-) stack-pop: clean up.0. {n: i32: 0}
-// CHECK:STDOUT: --- step exp N.Foo(0) .3. (full_trace.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: N.Foo(0) .3. {{[[][[]}}fun<N.Foo>, 0, 1]] {}
+// CHECK:STDOUT: --- step exp N.Foo(0) .3. (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop: N.Foo(0) .3. {{\[\[}}fun<N.Foo>, 0, 1]] {}
 // CHECK:STDOUT: (+) stack-push: clean up.0. {}
 // CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .1. (full_trace.carbon:16) --->
+// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .1. (phase_all.carbon:16) --->
 // CHECK:STDOUT: +++ memory-read: #1 `1`
 // CHECK:STDOUT: match pattern Placeholder<x>
 // CHECK:STDOUT: from initializing expression with value 1
-// CHECK:STDOUT: (-) stack-pop: var x: i32 = N.Foo(0); .1. {{[[][[]}}1]]
-// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .1. (full_trace.carbon:18) --->
+// CHECK:STDOUT: (-) stack-pop: var x: i32 = N.Foo(0); .1. {{\[\[}}1]]
+// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .1. (phase_all.carbon:18) --->
 // CHECK:STDOUT: (+) stack-push: return x; .0.
-// CHECK:STDOUT: --- step stmt return x; .0. (full_trace.carbon:17) --->
+// CHECK:STDOUT: --- step stmt return x; .0. (phase_all.carbon:17) --->
 // CHECK:STDOUT: (+) stack-push: x .0.
 // CHECK:STDOUT: (+) stack-push: x .0.
-// CHECK:STDOUT: --- step exp x .0. (full_trace.carbon:17) --->
+// CHECK:STDOUT: --- step exp x .0. (phase_all.carbon:17) --->
 // CHECK:STDOUT: +++ memory-read: #1 `1`
 // CHECK:STDOUT: (-) stack-pop: x .0.
-// CHECK:STDOUT: (-) stack-pop: x .1. {{[[][[]}}ref_expr<Allocation(1)>]]
-// CHECK:STDOUT: --- step stmt return x; .1. (full_trace.carbon:17) --->
-// CHECK:STDOUT: (-) stack-pop: return x; .1. {{[[][[]}}1]]
+// CHECK:STDOUT: (-) stack-pop: x .1. {{\[\[}}ref_expr<Allocation(1)>]]
+// CHECK:STDOUT: --- step stmt return x; .1. (phase_all.carbon:17) --->
+// CHECK:STDOUT: (-) stack-pop: return x; .1. {{\[\[}}1]]
 // CHECK:STDOUT: (-) stack-pop: {var x: i32 = N.Foo(0);return x;} .2. {x: i32: lval<Allocation(1)>}
 // CHECK:STDOUT: (-) stack-pop: .0. {}
 // CHECK:STDOUT: (+) stack-push: clean up.0. {}
@@ -340,14 +341,14 @@ fn Main() -> i32 {
 // CHECK:STDOUT: (-) stack-pop: clean up.2. {x: i32: lval<Allocation(1)>}
 // CHECK:STDOUT: (-) stack-pop: clean up.0. {}
 // CHECK:STDOUT: --- step exp Main() .2. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main() .2. {{[[][[]}}fun<Main>, 1]] {}
+// CHECK:STDOUT: (-) stack-pop: Main() .2. {{\[\[}}fun<Main>, 1]] {}
 // CHECK:STDOUT: (+) stack-push: clean up.0. {}
 // CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: Main() .1. {{[[][[]}}1]]
+// CHECK:STDOUT: (-) stack-pop: Main() .1. {{\[\[}}1]]
 // CHECK:STDOUT: interpreter result: 1
 // CHECK:STDOUT: ********** printing timing **********
-// CHECK:STDOUT: Time elapsed in ExecProgram: {{[0-9]+}}ms
-// CHECK:STDOUT: Time elapsed in AnalyzeProgram: {{[0-9]+}}ms
-// CHECK:STDOUT: Time elapsed in AddPrelude: {{[0-9]+}}ms
-// CHECK:STDOUT: Time elapsed in Parse: {{[0-9]+}}ms
+// CHECK:STDOUT: Time elapsed in ExecProgram: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in AnalyzeProgram: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in AddPrelude: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in Parse: {{\d+}}ms
 // CHECK:STDOUT: result: 1

+ 19 - 0
explorer/testdata/trace/phase_control_flow_resolution.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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=control_flow_resolution %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** resolving control flow **********
+// CHECK:STDOUT: --- flow-resolved return statement `return 0;` in `fn Main` (phase_control_flow_resolution.carbon:10)
+// CHECK:STDOUT: result: 0

+ 26 - 0
explorer/testdata/trace/phase_declarations.carbon

@@ -0,0 +1,26 @@
+// 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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=declarations %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** printing declarations **********
+// CHECK:STDOUT: interface TestInterface {
+// CHECK:STDOUT: }
+// CHECK:STDOUT: fn Main ()-> i32 {
+// CHECK:STDOUT: {
+// CHECK:STDOUT: return 0;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: }
+// CHECK:STDOUT: result: 0

+ 78 - 0
explorer/testdata/trace/phase_execution.carbon

@@ -0,0 +1,78 @@
+// 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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=execution %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** starting execution **********
+// CHECK:STDOUT: ********** initializing globals **********
+// CHECK:STDOUT: (+) stack-push: interface TestInterface {
+// CHECK:STDOUT: }
+// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: --- step decl interface TestInterface .0. (phase_execution.carbon:7) --->
+// CHECK:STDOUT: (-) stack-pop: interface TestInterface {
+// CHECK:STDOUT: }
+// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: (+) stack-push: fn Main ()-> i32 {
+// CHECK:STDOUT: {
+// CHECK:STDOUT: return 0;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: }
+// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: --- step decl fn Main .0. (phase_execution.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop: fn Main ()-> i32 {
+// CHECK:STDOUT: {
+// CHECK:STDOUT: return 0;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: }
+// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: ********** calling main function **********
+// CHECK:STDOUT: (+) stack-push: Main() .0.
+// CHECK:STDOUT: (+) stack-push: Main() .0.
+// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: Main .0.
+// CHECK:STDOUT: (+) stack-push: Main .0.
+// CHECK:STDOUT: --- step exp Main .0. (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop: Main .0.
+// CHECK:STDOUT: (-) stack-pop: Main .1. {{\[\[}}fun<Main>]]
+// CHECK:STDOUT: --- step exp Main() .1. (<Main()>:0) --->
+// CHECK:STDOUT: calling function: fun<Main>
+// CHECK:STDOUT: match pattern ()
+// CHECK:STDOUT: from value expression with value ()
+// CHECK:STDOUT: (+) stack-push: .0. {}
+// CHECK:STDOUT: (+) stack-push: {return 0;} .0.
+// CHECK:STDOUT: --- step stmt {return 0;} .0. (phase_execution.carbon:11) --->
+// CHECK:STDOUT: (+) stack-push: return 0; .0.
+// CHECK:STDOUT: --- step stmt return 0; .0. (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (+) stack-push: 0 .0.
+// CHECK:STDOUT: (+) stack-push: 0 .0.
+// CHECK:STDOUT: --- step exp 0 .0. (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop: 0 .0.
+// CHECK:STDOUT: (-) stack-pop: 0 .1. {{\[\[}}0]]
+// CHECK:STDOUT: --- step stmt return 0; .1. (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop: return 0; .1. {{\[\[}}0]]
+// CHECK:STDOUT: (-) stack-pop: {return 0;} .1. {}
+// CHECK:STDOUT: (-) stack-pop: .0. {}
+// CHECK:STDOUT: (+) stack-push: clean up.0. {}
+// CHECK:STDOUT: (+) stack-push: clean up.0. {}
+// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
+// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
+// CHECK:STDOUT: --- step exp Main() .2. (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop: Main() .2. {{\[\[}}fun<Main>, 0]] {}
+// CHECK:STDOUT: (+) stack-push: clean up.0. {}
+// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
+// CHECK:STDOUT: (-) stack-pop: Main() .1. {{\[\[}}0]]
+// CHECK:STDOUT: interpreter result: 0
+// CHECK:STDOUT: result: 0

+ 34 - 0
explorer/testdata/trace/phase_name_resolution.carbon

@@ -0,0 +1,34 @@
+// 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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=name_resolution %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** resolving names **********
+// CHECK:STDOUT: --- declared `TestInterface` as `interface TestInterface` in `package` (phase_name_resolution.carbon:7)
+// CHECK:STDOUT: --- declared `Main` as `fn Main` in `package` (phase_name_resolution.carbon:11)
+// CHECK:STDOUT: ** resolving decl `interface TestInterface` (phase_name_resolution.carbon:7)
+// CHECK:STDOUT: --- marked `TestInterface` declared but not usable in `package`
+// CHECK:STDOUT: --- marked `TestInterface` usable in `package`
+// CHECK:STDOUT: --- declared `Self` as `Self` in `interface TestInterface` (phase_name_resolution.carbon:7)
+// CHECK:STDOUT: ** finished resolving decl `interface TestInterface` (phase_name_resolution.carbon:7)
+// CHECK:STDOUT: ** resolving decl `fn Main` (phase_name_resolution.carbon:11)
+// CHECK:STDOUT: --- marked `Main` declared but not usable in `package`
+// CHECK:STDOUT: --- marked `Main` usable in `package`
+// CHECK:STDOUT: ** resolving stmt `{return 0;}` (phase_name_resolution.carbon:11)
+// CHECK:STDOUT: ** resolving stmt `return 0;` (phase_name_resolution.carbon:10)
+// CHECK:STDOUT: ** finished resolving stmt `return 0;` (phase_name_resolution.carbon:10)
+// CHECK:STDOUT: ** finished resolving stmt `{return 0;}` (phase_name_resolution.carbon:11)
+// CHECK:STDOUT: ** finished resolving decl `fn Main` (phase_name_resolution.carbon:11)
+// CHECK:STDOUT: --- resolved `Main` as `fn Main` in `package` (<Main()>:0)
+// CHECK:STDOUT: result: 0

+ 26 - 0
explorer/testdata/trace/phase_source_program.carbon

@@ -0,0 +1,26 @@
+// 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
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=source_program %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** source program **********
+// CHECK:STDOUT: interface TestInterface {
+// CHECK:STDOUT: }
+// CHECK:STDOUT: fn Main ()-> i32 {
+// CHECK:STDOUT: {
+// CHECK:STDOUT: return 0;
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: }
+// CHECK:STDOUT: result: 0

+ 22 - 0
explorer/testdata/trace/phase_timing.carbon

@@ -0,0 +1,22 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=timing %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** printing timing **********
+// CHECK:STDOUT: Time elapsed in ExecProgram: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in AnalyzeProgram: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in AddPrelude: {{\d+}}ms
+// CHECK:STDOUT: Time elapsed in Parse: {{\d+}}ms
+// CHECK:STDOUT: result: 0

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 22 - 0
explorer/testdata/trace/phase_type_checking.carbon


+ 22 - 0
explorer/testdata/trace/phase_unformed_variables_resolution.carbon

@@ -0,0 +1,22 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+package ExplorerTest api;
+
+interface TestInterface {}
+
+fn Main() -> i32 {
+  return 0;
+}
+
+// Place checks after code so that line numbers are stable, reducing merge
+// conflicts.
+// ARGS: --trace_file=- --trace_phase=unformed_variables_resolution %s
+// AUTOUPDATE
+// CHECK:STDOUT: ********** resolving unformed variables **********
+// CHECK:STDOUT: *** resolving-unformed in decl `interface TestInterface` (phase_unformed_variables_resolution.carbon:7)
+// CHECK:STDOUT: *** resolving-unformed in decl `fn Main` (phase_unformed_variables_resolution.carbon:11)
+// CHECK:STDOUT: *** resolving-unformed in stmt `{return 0;}` (phase_unformed_variables_resolution.carbon:11)
+// CHECK:STDOUT: *** resolving-unformed in stmt `return 0;` (phase_unformed_variables_resolution.carbon:10)
+// CHECK:STDOUT: result: 0

+ 77 - 28
testing/file_test/autoupdate.cpp

@@ -19,12 +19,23 @@ namespace Carbon::Testing {
 // Put helper classes in an anonymous namespace.
 namespace {
 
+// Converts a matched line number to an int, trimming whitespace.
+static auto ParseLineNumber(absl::string_view matched_line_number) -> int {
+  llvm::StringRef trimmed = matched_line_number;
+  trimmed = trimmed.trim();
+  // NOLINTNEXTLINE(google-runtime-int): API requirement.
+  long long val;
+  CARBON_CHECK(!llvm::getAsSignedInteger(trimmed, 10, val));
+  return val;
+}
+
 class CheckLine : public FileTestLineBase {
  public:
   // RE2 is passed by a pointer because it doesn't support std::optional.
-  explicit CheckLine(int line_number, const RE2* line_number_re,
-                     std::string line)
+  explicit CheckLine(int line_number, bool line_number_re_has_file,
+                     const RE2* line_number_re, std::string line)
       : FileTestLineBase(line_number),
+        line_number_re_has_file_(line_number_re_has_file),
         line_number_re_(line_number_re),
         line_(std::move(line)) {}
 
@@ -41,20 +52,50 @@ class CheckLine : public FileTestLineBase {
 
   // When the location of all lines in a file are known, we can set the line
   // offset based on the target line.
-  auto SetRemappedLine(const std::string& sub_for_formatv,
-                       int target_line_number) -> void {
-    // Should only be called when we have a regex.
-    CARBON_CHECK(line_number_re_);
-
-    int offset = target_line_number - output_line_number_;
-    const char* offset_prefix = offset < 0 ? "" : "+";
-    std::string replacement =
-        llvm::formatv(sub_for_formatv.data(),
-                      llvm::formatv("[[@LINE{0}{1}]]", offset_prefix, offset));
-    RE2::Replace(&line_, *line_number_re_, replacement);
+  auto RemapLineNumbers(const llvm::DenseMap<int, int>& output_line_remap,
+                        const std::string& line_formatv) -> void {
+    // Only need to do remappings when there's a regex.
+    if (!line_number_re_) {
+      return;
+    }
+
+    bool found_one = false;
+    while (true) {
+      // Look for a line number to replace. There may be multiple, so we
+      // repeatedly check.
+      absl::string_view matched_line_number;
+      if (line_number_re_has_file_) {
+        RE2::PartialMatch(line_, *line_number_re_, nullptr,
+                          &matched_line_number);
+      } else {
+        RE2::PartialMatch(line_, *line_number_re_, &matched_line_number);
+      }
+      if (matched_line_number.empty()) {
+        CARBON_CHECK(found_one) << line_;
+        return;
+      }
+      found_one = true;
+
+      // Calculate the offset from the CHECK line to the new line number
+      // (possibly with new CHECK lines added, or some removed).
+      // NOLINTNEXTLINE(google-runtime-int): API requirement.
+      auto remapped =
+          output_line_remap.find(ParseLineNumber(matched_line_number));
+      CARBON_CHECK(remapped != output_line_remap.end());
+      int offset = remapped->second - output_line_number_;
+
+      // Update the line offset in the CHECK line.
+      const char* offset_prefix = offset < 0 ? "" : "+";
+      std::string replacement = llvm::formatv(
+          line_formatv.c_str(),
+          llvm::formatv("[[@LINE{0}{1}]]", offset_prefix, offset));
+      line_.replace(matched_line_number.data() - line_.data(),
+                    matched_line_number.size(), replacement);
+    }
   }
 
  private:
+  bool line_number_re_has_file_;
   const RE2* line_number_re_;
   std::string line_;
   llvm::StringRef indent_;
@@ -90,10 +131,19 @@ static auto AddCheckLines(
     lines.pop_back();
   }
 
+  // `{{` and `[[` are escaped as a regex matcher.
+  RE2 double_brace_re(R"(\{\{)");
+  RE2 double_square_bracket_re(R"(\[\[)");
+  // End-of-line whitespace is replaced with a regex matcher to make it visible.
+  RE2 end_of_line_whitespace_re(R"((\s+)$)");
+
   int append_to = 0;
   for (const auto& line : lines) {
     std::string check_line = llvm::formatv("// CHECK:{0}:{1}{2}", label,
                                            line.empty() ? "" : " ", line);
+    RE2::Replace(&check_line, double_brace_re, R"({{\\{\\{}})");
+    RE2::Replace(&check_line, double_square_bracket_re, R"({{\\[\\[}})");
+    RE2::Replace(&check_line, end_of_line_whitespace_re, R"({{\1}})");
 
     // Ignore TEST_TMPDIR in output.
     if (auto pos = check_line.find(tmpdir); pos != std::string::npos) {
@@ -102,10 +152,10 @@ static auto AddCheckLines(
 
     do_extra_check_replacements(check_line);
 
-    // Look for line information in the output. line_number is only set if the
-    // match is correct.
-    int line_number = -1;
-    int match_line_number;
+    // Look for line information in the output. use_line_number is only set if
+    // the match is correct.
+    std::optional<llvm::StringRef> use_line_number;
+    absl::string_view match_line_number;
     if (line_number_re_has_file) {
       absl::string_view match_filename;
       if (RE2::PartialMatch(check_line, line_number_re, &match_filename,
@@ -119,22 +169,25 @@ static auto AddCheckLines(
           if (pos != filenames.end()) {
             remaining_filenames = pos + 1;
             append_to = pos - filenames.begin();
-            line_number = match_line_number;
+            use_line_number = match_line_number;
           }
         } else {
           // The line applies to the current file.
-          line_number = match_line_number;
+          use_line_number = match_line_number;
         }
       }
     } else {
       // There's no file association, so we only look at the line.
       if (RE2::PartialMatch(check_line, line_number_re, &match_line_number)) {
-        line_number = match_line_number;
+        use_line_number = match_line_number;
       }
     }
+    // NOLINTNEXTLINE(google-runtime-int): API requirement.
+    long long line_number =
+        use_line_number ? ParseLineNumber(*use_line_number) : -1;
     check_lines[append_to].push_back(
-        CheckLine(line_number, line_number == -1 ? nullptr : &line_number_re,
-                  check_line));
+        CheckLine(line_number, line_number_re_has_file,
+                  use_line_number ? &line_number_re : nullptr, check_line));
   }
 }
 
@@ -212,12 +265,8 @@ auto AutoupdateFileTest(
 
     // Update all remapped lines in CHECK output.
     for (auto& offset_check_line : check_file) {
-      if (offset_check_line.line_number() >= 1) {
-        auto new_line = output_line_remap.find(offset_check_line.line_number());
-        CARBON_CHECK(new_line != output_line_remap.end());
-        offset_check_line.SetRemappedLine(
-            line_number_replacement.sub_for_formatv, new_line->second);
-      }
+      offset_check_line.RemapLineNumbers(output_line_remap,
+                                         line_number_replacement.line_formatv);
     }
   }
 

+ 2 - 2
testing/file_test/autoupdate.h

@@ -20,8 +20,8 @@ struct FileTestLineNumberReplacement {
   // should have a file and line group; otherwise, only a line group.
   std::string pattern;
 
-  // sub_for_formatv should provide {0} to substitute with [[@LINE...]] deltas.
-  std::string sub_for_formatv;
+  // line_formatv should provide {0} to substitute with [[@LINE...]] deltas.
+  std::string line_formatv;
 };
 
 // Automatically updates CHECKs in the provided file. Returns true if updated.

+ 48 - 30
testing/file_test/file_test_base.cpp

@@ -52,15 +52,11 @@ static auto SplitOutput(llvm::StringRef output)
 // Runs a test and compares output. This keeps output split by line so that
 // issues are a little easier to identify by the different line.
 auto FileTestBase::TestBody() -> void {
-  const char* src_dir = getenv("TEST_SRCDIR");
-  CARBON_CHECK(src_dir);
-  std::string test_file = path().lexically_relative(
-      std::filesystem::path(src_dir).append("carbon"));
   const char* target = getenv("TEST_TARGET");
   CARBON_CHECK(target);
   // This advice overrides the --file_tests flag provided by the file_test rule.
   llvm::errs() << "\nTo test this file alone, run:\n  bazel test " << target
-               << " --test_arg=--file_tests=" << test_file << "\n\n";
+               << " --test_arg=--file_tests=" << GetTestFilename() << "\n\n";
 
   TestContext context;
   auto run_result = ProcessTestFileAndRun(context);
@@ -86,10 +82,13 @@ auto FileTestBase::TestBody() -> void {
   }
 }
 
-auto FileTestBase::Autoupdate() -> bool {
+auto FileTestBase::Autoupdate() -> ErrorOr<bool> {
   TestContext context;
   auto run_result = ProcessTestFileAndRun(context);
-  CARBON_CHECK(run_result.ok()) << run_result.error();
+  if (!run_result.ok()) {
+    return ErrorBuilder() << "Error updating " << GetTestFilename() << ": "
+                          << run_result.error();
+  }
   if (!context.autoupdate_line_number) {
     return false;
   }
@@ -120,8 +119,8 @@ auto FileTestBase::GetLineNumberReplacement(
     llvm::ArrayRef<llvm::StringRef> filenames) -> LineNumberReplacement {
   return {
       .has_file = true,
-      .pattern = llvm::formatv(R"(({0}):(\d+):)", llvm::join(filenames, "|")),
-      .sub_for_formatv = R"(\1:{0}:)"};
+      .pattern = llvm::formatv(R"(({0}):(\d+))", llvm::join(filenames, "|")),
+      .line_formatv = R"({0})"};
 }
 
 auto FileTestBase::ProcessTestFileAndRun(TestContext& context)
@@ -258,15 +257,21 @@ auto FileTestBase::ProcessTestFile(TestContext& context) -> ErrorOr<Success> {
 
     // Process expectations when found.
     if (line_trimmed.consume_front("// CHECK")) {
-      llvm::SmallVector<Matcher<std::string>>* expected = nullptr;
-      if (line_trimmed.consume_front(":STDOUT:")) {
-        expected = &context.expected_stdout;
-      } else if (line_trimmed.consume_front(":STDERR:")) {
-        expected = &context.expected_stderr;
-      } else {
-        return ErrorBuilder() << "Unexpected CHECK in input: " << line.str();
+      // Don't build expectations when doing an autoupdate. We don't want to
+      // break the autoupdate on an invalid CHECK line.
+      if (!absl::GetFlag(FLAGS_autoupdate)) {
+        llvm::SmallVector<Matcher<std::string>>* expected = nullptr;
+        if (line_trimmed.consume_front(":STDOUT:")) {
+          expected = &context.expected_stdout;
+        } else if (line_trimmed.consume_front(":STDERR:")) {
+          expected = &context.expected_stderr;
+        } else {
+          return ErrorBuilder() << "Unexpected CHECK in input: " << line.str();
+        }
+        CARBON_ASSIGN_OR_RETURN(Matcher<std::string> check_matcher,
+                                TransformExpectation(line_index, line_trimmed));
+        expected->push_back(check_matcher);
       }
-      expected->push_back(TransformExpectation(line_index, line_trimmed));
     } else {
       context.non_check_lines.back().push_back(FileTestLine(line_index, line));
       if (line_trimmed.consume_front("// ARGS: ")) {
@@ -330,11 +335,13 @@ auto FileTestBase::ProcessTestFile(TestContext& context) -> ErrorOr<Success> {
 }
 
 auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in)
-    -> Matcher<std::string> {
+    -> ErrorOr<Matcher<std::string>> {
   if (in.empty()) {
-    return StrEq("");
+    return Matcher<std::string>{StrEq("")};
+  }
+  if (in[0] != ' ') {
+    return ErrorBuilder() << "Malformated CHECK line: " << in;
   }
-  CARBON_CHECK(in[0] == ' ') << "Malformated input: " << in;
   std::string str = in.substr(1).str();
   for (int pos = 0; pos < static_cast<int>(str.size());) {
     switch (str[pos]) {
@@ -364,18 +371,20 @@ auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in)
             line_keyword_cursor.consume_front("+");
             int offset;
             // consumeInteger returns true for errors, not false.
-            CARBON_CHECK(!line_keyword_cursor.consumeInteger(10, offset) &&
-                         line_keyword_cursor.consume_front("]]"))
-                << "Unexpected @LINE offset at `"
-                << line_keyword_cursor.substr(0, 5) << "` in: " << in;
+            if (line_keyword_cursor.consumeInteger(10, offset) ||
+                !line_keyword_cursor.consume_front("]]")) {
+              return ErrorBuilder()
+                     << "Unexpected @LINE offset at `"
+                     << line_keyword_cursor.substr(0, 5) << "` in: " << in;
+            }
             std::string int_str = llvm::Twine(line_index + offset).str();
             int remove_len = (line_keyword_cursor.data() - str.data()) - pos;
             str.replace(pos, remove_len, int_str);
             pos += int_str.size();
           } else {
-            CARBON_FATAL() << "Unexpected [[, should be {{\\[\\[}} at `"
-                           << line_keyword_cursor.substr(0, 5)
-                           << "` in: " << in;
+            return ErrorBuilder()
+                   << "Unexpected [[, should be {{\\[\\[}} at `"
+                   << line_keyword_cursor.substr(0, 5) << "` in: " << in;
           }
         } else {
           // Escape the `[`.
@@ -408,7 +417,14 @@ auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in)
     }
   }
 
-  return MatchesRegex(str);
+  return Matcher<std::string>{MatchesRegex(str)};
+}
+
+auto FileTestBase::GetTestFilename() -> std::string {
+  const char* src_dir = getenv("TEST_SRCDIR");
+  CARBON_CHECK(src_dir);
+  return path().lexically_relative(
+      std::filesystem::path(src_dir).append("carbon"));
 }
 
 }  // namespace Carbon::Testing
@@ -429,7 +445,7 @@ auto main(int argc, char** argv) -> int {
 
   // Configure the base directory for test names.
   const char* target = getenv("TEST_TARGET");
-  CARBON_CHECK(target != nullptr);
+  CARBON_CHECK(target);
   llvm::StringRef target_dir = target;
   std::error_code ec;
   std::filesystem::path working_dir = std::filesystem::current_path(ec);
@@ -450,7 +466,9 @@ auto main(int argc, char** argv) -> int {
     if (absl::GetFlag(FLAGS_autoupdate)) {
       std::unique_ptr<Carbon::Testing::FileTestBase> test(
           test_factory.factory_fn(path));
-      llvm::errs() << (test->Autoupdate() ? "!" : ".");
+      auto result = test->Autoupdate();
+      llvm::errs() << (result.ok() ? (*result ? "!" : ".")
+                                   : result.error().message());
     } else {
       std::string test_name = path.string().substr(base_dir.size());
       testing::RegisterTest(test_factory.name, test_name.c_str(), nullptr,

+ 5 - 2
testing/file_test/file_test_base.h

@@ -79,7 +79,7 @@ class FileTestBase : public testing::Test {
   auto TestBody() -> void final;
 
   // Runs the test and autoupdates checks. Returns true if updated.
-  auto Autoupdate() -> bool;
+  auto Autoupdate() -> ErrorOr<bool>;
 
   // Returns the full path of the file being tested.
   auto path() -> const std::filesystem::path& { return path_; };
@@ -134,10 +134,13 @@ class FileTestBase : public testing::Test {
   // Processes the test input, producing test files and expected output.
   auto ProcessTestFile(TestContext& context) -> ErrorOr<Success>;
 
+  // Gets the test filename, relative to the target directory.
+  auto GetTestFilename() -> std::string;
+
   // Transforms an expectation on a given line from `FileCheck` syntax into a
   // standard regex matcher.
   static auto TransformExpectation(int line_index, llvm::StringRef in)
-      -> testing::Matcher<std::string>;
+      -> ErrorOr<testing::Matcher<std::string>>;
 
   const std::filesystem::path path_;
 };

+ 0 - 0
testing/lit_test/__init__.py


+ 0 - 58
testing/lit_test/lit.cfg.py

@@ -1,58 +0,0 @@
-__copyright__ = """
-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
-"""
-
-import lit.formats
-import os
-from pathlib import Path
-
-
-# This is a provided variable, ignore the undefined name warning.
-config = config  # noqa: F821
-
-
-def fullpath(relative_path):
-    return Path(os.environ["TEST_SRCDIR"]).joinpath(relative_path)
-
-
-def add_substitution(before, after):
-    """Adds a substitution to the config. Wraps before as `%{before}`."""
-    config.substitutions.append((f"%{{{before}}}", after))
-
-
-def add_substitutions():
-    """Adds required substitutions to the config."""
-    tools = {
-        "carbon": fullpath("carbon/toolchain/driver/carbon"),
-        "explorer": fullpath("carbon/explorer/explorer"),
-        "explorer_prelude": fullpath("carbon/explorer/data/prelude.carbon"),
-        "filecheck": fullpath("llvm-project/llvm/FileCheck"),
-        "not": fullpath("llvm-project/llvm/not"),
-        "merge_output": fullpath("carbon/testing/lit_test/merge_output"),
-    }
-
-    run_carbon = f"{tools['merge_output']} {tools['carbon']}"
-    run_explorer = (
-        f"{tools['merge_output']} {tools['explorer']} %s "
-        f"--prelude={tools['explorer_prelude']}"
-    )
-    filecheck_allow_unmatched = (
-        f"{tools['filecheck']} %s --match-full-lines --strict-whitespace"
-    )
-    filecheck_strict = (
-        f"{filecheck_allow_unmatched} --implicit-check-not={{{{.}}}}"
-    )
-
-    add_substitution("carbon", f"{run_carbon}")
-    add_substitution("explorer", f"{run_explorer}")
-    add_substitution("FileCheck-allow-unmatched", filecheck_allow_unmatched)
-    add_substitution("FileCheck-strict", filecheck_strict)
-    add_substitution("not", tools["not"])
-
-
-config.name = "lit"
-config.suffixes = [".carbon"]
-config.test_format = lit.formats.ShTest()
-add_substitutions()

+ 0 - 57
testing/lit_test/lit_test.py

@@ -1,57 +0,0 @@
-"""Runs `lit` for testing."""
-
-__copyright__ = """
-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
-"""
-
-import argparse
-import os
-from pathlib import Path
-import shutil
-import subprocess
-
-
-def _parse_args():
-    """Parses command line arguments, returning the result."""
-    arg_parser = argparse.ArgumentParser(description=__doc__)
-    arg_parser.add_argument(
-        "--package_name", help="The directory containing tests to run."
-    )
-    arg_parser.add_argument(
-        "lit_args", nargs="*", help="Arguments to pass through to lit."
-    )
-    return arg_parser.parse_args()
-
-
-def main():
-    parsed_args = _parse_args()
-
-    args = [
-        str(Path(os.environ["TEST_SRCDIR"]).joinpath("llvm-project/llvm/lit")),
-        str(Path.cwd().joinpath(parsed_args.package_name)),
-        "-v",
-    ]
-
-    # Force tests to be explicit about command paths. Some tools are required by
-    # bazel's py_binary output in order to find python3, so we add these. The
-    # list of tools may prove to be fragile: if so, we may need to change or
-    # remove the PATH hiding.
-    system_tools = Path(os.environ["TEST_TMPDIR"]).joinpath("system_tools")
-    system_tools.mkdir()
-    for tool in ("env", "grep", "python3", "sh", "which"):
-        system_tools.joinpath(tool).symlink_to(shutil.which(tool))
-    env = os.environ.copy()
-    env["PATH"] = str(system_tools)
-
-    # Run lit.
-    try:
-        subprocess.check_call(args=args + parsed_args.lit_args, env=env)
-    except subprocess.CalledProcessError as e:
-        # Print without the stack trace.
-        exit(e)
-
-
-if __name__ == "__main__":
-    exit(main())

+ 0 - 38
testing/lit_test/merge_output.py

@@ -1,38 +0,0 @@
-"""Merges stdout and stderr into a single stream with labels."""
-
-__copyright__ = """
-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
-"""
-
-import subprocess
-import sys
-
-
-def label_output(label: str, output: str) -> None:
-    """Prints output with labels.
-
-    This mirrors label_output in scripts/autoupdate_testdata_base.py and should
-    be kept in sync. They're separate in order to avoid a subprocess or import
-    complexity.
-    """
-    if output:
-        for line in output.splitlines():
-            print(" ".join(filter(None, (label, line))))
-
-
-def main() -> None:
-    p = subprocess.run(
-        sys.argv[1:],
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-        encoding="utf-8",
-    )
-    label_output("STDOUT:", p.stdout)
-    label_output("STDERR:", p.stderr)
-    exit(p.returncode)
-
-
-if __name__ == "__main__":
-    main()

+ 0 - 66
testing/lit_test/rules.bzl

@@ -1,66 +0,0 @@
-# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-# Exceptions. See /LICENSE for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-"""Rule for a lit test."""
-
-def glob_lit_tests(name, driver, data, test_file_exts, exclude = None, **kwargs):
-    """Runs `lit` on test_dir.
-
-    `lit` reference:
-      https://llvm.org/docs/CommandGuide/lit.html
-
-    This will generate three types of rules:
-    1. For each test file, a rule with ".test" at the end. For example,
-       "foo/bar/baz.carbon" will generate ":foo/bar/baz.carbon.test"
-    2. If any test exists in subdirectory, a test_suite is generated for each
-       directory. For example, ":foo" will run all tests under directory "foo",
-       and ":foo/bar" will run all tests under "foo/bar".
-    3. A test_suite containing all tests. The name of this will be the "name"
-       arg passed to the glob_lit_tests rule.
-
-    Args:
-      name: The name of the test_suite rule to generate for running all tests.
-      driver: The path to the lit config.
-      data: A list of tools to provide to the tests. These will be aliased for
-        execution.
-      test_file_exts: A list of extensions to use for tests.
-      exclude: A list of paths to exclude from the glob.
-      **kwargs: Any additional parameters for the generated py_test.
-    """
-    if not exclude:
-        exclude = []
-    test_files = native.glob(
-        ["**"],
-        exclude = exclude,
-        exclude_directories = 1,
-    )
-    data.append("@llvm-project//llvm:lit")
-    suites = dict()
-    all_tests = list()
-    for f in test_files:
-        if f.split(".")[-1] not in test_file_exts:
-            continue
-        test = "%s.test" % f
-        all_tests.append(test)
-        native.py_test(
-            name = test,
-            srcs = ["//testing/lit_test:lit_test.py"],
-            main = "//testing/lit_test:lit_test.py",
-            data = data + [driver, f],
-            args = ["--package_name=%s" % native.package_name(), "--"],
-            size = "small",
-            **kwargs
-        )
-
-        # Cluster tests by directory in order to produce suites. For example,
-        # foo/bar/baz.carbon.test is added to suites :foo and :foo/bar.
-        dirs = f.split("/")[:-1]
-        for num_parts in range(1, 1 + len(dirs)):
-            dir = "/".join(dirs[:num_parts])
-            if dir not in suites:
-                suites[dir] = []
-            suites[dir].append(test)
-    native.test_suite(name = name, tests = all_tests)
-    for suite, tests in suites.items():
-        native.test_suite(name = suite, tests = tests)

+ 0 - 0
testing/scripts/__init__.py


+ 0 - 542
testing/scripts/autoupdate_testdata_base.py

@@ -1,542 +0,0 @@
-#!/usr/bin/env python3
-
-"""Updates the CHECK: lines in tests with an AUTOUPDATE line."""
-
-__copyright__ = """
-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
-"""
-
-from abc import ABC, abstractmethod
-import argparse
-from concurrent import futures
-import os
-from pathlib import Path
-import re
-import subprocess
-from typing import (
-    Any,
-    Dict,
-    List,
-    Match,
-    NamedTuple,
-    Optional,
-    Pattern,
-    Set,
-    Tuple,
-)
-
-# A prefix followed by a command to run for autoupdating checked output.
-AUTOUPDATE_MARKER = "// AUTOUPDATE"
-
-# Indicates no autoupdate is requested.
-NOAUTOUPDATE_MARKER = "// NOAUTOUPDATE"
-
-# Supported tools.
-TOOLS = {
-    "carbon": "//toolchain/driver:carbon",
-    "explorer": "//explorer:explorer",
-}
-
-
-class ParsedArgs(NamedTuple):
-    autoupdate_args: List[str]
-    build_mode: str
-    extra_check_replacements: List[Tuple[Pattern, Pattern, str]]
-    line_number_delta_prefix: str
-    line_number_pattern: Pattern
-    lit_run: List[str]
-    testdata: str
-    tests: List[Path]
-    tool: str
-
-
-def parse_args() -> ParsedArgs:
-    """Parses command-line arguments and flags."""
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument("tests", nargs="*")
-    parser.add_argument(
-        "--autoupdate_arg",
-        metavar="COMMAND",
-        default=[],
-        action="append",
-        help="Optional arguments to pass to the autoupdate command.",
-    )
-    parser.add_argument(
-        "--build_mode",
-        metavar="MODE",
-        default="opt",
-        help="The build mode to use. Defaults to opt for faster execution.",
-    )
-    parser.add_argument(
-        "--extra_check_replacement",
-        nargs=3,
-        metavar=("MATCHING", "BEFORE", "AFTER"),
-        default=[],
-        action="append",
-        help="On a CHECK line with MATCHING, does a regex replacement of "
-        "BEFORE with AFTER.",
-    )
-    parser.add_argument(
-        "--line_number_delta_prefix",
-        metavar="PREFIX",
-        default="",
-        help="An optional prefix to add before the [[@LINE+delta]] marker.",
-    )
-    parser.add_argument(
-        "--line_number_pattern",
-        metavar="PATTERN",
-        default=r"(?P<prefix>(?P<filename>\w+\.carbon):)"
-        r"(?P<line>\d+)(?P<suffix>(?:\D|$))",
-        help="A regular expression which matches line numbers to update as its "
-        "only group. Capture groups 'prefix', 'line', and 'suffix' are "
-        "required for structure. The 'filename' capture group is optional and "
-        "should be provided when lines may belong to different files.",
-    )
-    parser.add_argument(
-        "--lit_run",
-        metavar="COMMAND",
-        default=[],
-        required=False,
-        action="append",
-        help="RUN lines to set.",
-    )
-    parser.add_argument(
-        "--testdata",
-        metavar="PATH",
-        required=True,
-        help="The path to the testdata to update, relative to the workspace "
-        "root.",
-    )
-    parser.add_argument(
-        "--tool",
-        metavar="TOOL",
-        required=True,
-        choices=TOOLS.keys(),
-        help="The tool being tested.",
-    )
-    parsed_args = parser.parse_args()
-    extra_check_replacements = [
-        (re.compile(line_matcher), re.compile(before), after)
-        for line_matcher, before, after in parsed_args.extra_check_replacement
-    ]
-    return ParsedArgs(
-        autoupdate_args=parsed_args.autoupdate_arg,
-        build_mode=parsed_args.build_mode,
-        extra_check_replacements=extra_check_replacements,
-        line_number_delta_prefix=parsed_args.line_number_delta_prefix,
-        line_number_pattern=re.compile(parsed_args.line_number_pattern),
-        lit_run=parsed_args.lit_run,
-        testdata=parsed_args.testdata,
-        tests=[Path(test).resolve() for test in parsed_args.tests],
-        tool=parsed_args.tool,
-    )
-
-
-def get_tests(testdata: str) -> Set[Path]:
-    """Get the list of tests from the filesystem."""
-    tests = set()
-    for root, _, files in os.walk(testdata):
-        for f in files:
-            if f in {"lit.cfg.py", "BUILD", "README.md"}:
-                # Ignore the lit config.
-                continue
-            if os.path.splitext(f)[1] == ".carbon":
-                tests.add(Path(root).joinpath(f))
-            else:
-                exit(f"Unrecognized file type in testdata: {f}")
-    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 RunLine(Line):
-    """A RUN line."""
-
-    def __init__(self, text: str) -> None:
-        self.text = text
-
-    def format(self, **kwargs: Any) -> str:
-        return self.text
-
-
-class CheckLine(Line):
-    """A `// CHECK:` line generated from the test output.
-
-    If there's a line number, it'll 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,
-        test: str,
-        out_line: str,
-        line_number_delta_prefix: str,
-        line_number_pattern: Pattern,
-    ) -> None:
-        super().__init__()
-        self.filename = Path(test).name
-        self.indent = ""
-        self.out_line = out_line
-        self.line_number_delta_prefix = line_number_delta_prefix
-        self.line_number_pattern = line_number_pattern
-        self.trailing_whitespace_pattern = re.compile(r"(\s+$)")
-
-        # If any match is specific to this file, use the first matched line for
-        # the location of the CHECK comment.
-        self.line_in_file = None
-        for match in line_number_pattern.finditer(self.out_line):
-            if self._matches_filename(match):
-                self.line_in_file = int(match.group("line")) - 1
-                break
-
-    def format(
-        self, *, output_line_number: int, line_number_remap: Dict[int, int]
-    ) -> str:
-        assert self.out_line
-        result = self.out_line
-        while True:
-            line_match = self.line_number_pattern.search(result)
-            trailing_match = self.trailing_whitespace_pattern.search(result)
-            if line_match:
-                if self._matches_filename(line_match):
-                    line_number = int(line_match.group("line")) - 1
-                    delta = line_number_remap[line_number] - output_line_number
-                    # We use `:+d` here to produce `LINE-n` or `LINE+n` as
-                    # appropriate.
-                    result = self.line_number_pattern.sub(
-                        rf"\g<prefix>{self.line_number_delta_prefix}"
-                        rf"[[@LINE{delta:+d}]]\g<suffix>",
-                        result,
-                        count=1,
-                    )
-                else:
-                    result = self.line_number_pattern.sub(
-                        r"\g<prefix>{{.*}}\g<suffix>",
-                        result,
-                        count=1,
-                    )
-            elif trailing_match:
-                result = self.trailing_whitespace_pattern.sub(r"{{\1}}", result)
-            else:
-                break
-
-        return f"{self.indent}// CHECK:{result}\n"
-
-    def _matches_filename(self, match: Match) -> bool:
-        return (
-            "filename" not in match.groupdict()
-            or match.group("filename") == self.filename
-        )
-
-
-def find_autoupdate(test: str, orig_lines: List[str]) -> Optional[int]:
-    """Figures out whether autoupdate should occur.
-
-    For AUTOUPDATE, returns the line. For NOAUTOUPDATE, returns None.
-    """
-    found = 0
-    result = None
-    for line_number, line in enumerate(orig_lines):
-        if line.startswith(AUTOUPDATE_MARKER):
-            found += 1
-            result = line_number
-        elif line.startswith(NOAUTOUPDATE_MARKER):
-            found += 1
-    if found == 0:
-        raise ValueError(
-            f"{test} must have either '{AUTOUPDATE_MARKER}' or "
-            f"'{NOAUTOUPDATE_MARKER}'"
-        )
-    elif found > 1:
-        raise ValueError(
-            f"{test} must have only one of '{AUTOUPDATE_MARKER}' or "
-            f"'{NOAUTOUPDATE_MARKER}'"
-        )
-    return result
-
-
-def replace_all(s: str, replacements: List[Tuple[str, str]]) -> str:
-    """Runs multiple replacements on a string."""
-    for before, after in replacements:
-        s = s.replace(before, after)
-    return s
-
-
-def label_output(label: str, output: str) -> List[str]:
-    """Merges output with labels.
-
-    This mirrors label_output in lit_test/merge_output.py and should
-    be kept in sync. They're separate in order to avoid a subprocess or import
-    complexity.
-    """
-    result = []
-    if output:
-        for line in output.splitlines():
-            result.append(" ".join(filter(None, (label, line))))
-    return result
-
-
-def get_matchable_test_output(
-    autoupdate_args: List[str],
-    extra_check_replacements: List[Tuple[Pattern, Pattern, str]],
-    tool: str,
-    bazel_runfiles: Pattern,
-    llvm_symbolizer: str,
-    test: str,
-) -> List[str]:
-    """Runs the autoupdate command and returns the output lines."""
-    # Run the autoupdate command to generate output.
-    # (`bazel run` would serialize)
-    autoupdate_cmd = Path.cwd().joinpath(
-        TOOLS[tool].replace("//", "./bazel-bin/").replace(":", "/")
-    )
-    p = subprocess.run(
-        [str(autoupdate_cmd)] + autoupdate_args + [Path(test).name],
-        env={"LLVM_SYMBOLIZER_PATH": llvm_symbolizer},
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-        encoding="utf-8",
-        cwd=str(Path(test).parent),
-    )
-
-    out_lines = label_output("STDOUT:", p.stdout)
-    out_lines.extend(label_output("STDERR:", p.stderr))
-
-    for i, line in enumerate(out_lines):
-        # Escape things that mirror FileCheck special characters.
-        line = line.replace("{{", "{{[{][{]}}")
-        line = line.replace("[[", "{{[[][[]}}")
-        line = bazel_runfiles.sub("{{.*}}/", line)
-
-        for line_matcher, before, after in extra_check_replacements:
-            if line_matcher.match(line):
-                line = before.sub(after, line)
-
-        out_lines[i] = line
-
-    return out_lines
-
-
-def is_replaced(line: str) -> bool:
-    """Returns true if autoupdate should replace the line."""
-    line = line.lstrip()
-    return line.startswith("// CHECK") or line.startswith("// RUN:")
-
-
-def merge_lines(
-    line_number_delta_prefix: str,
-    line_number_pattern: Pattern,
-    lit_run: List[str],
-    test: str,
-    autoupdate_line_number: int,
-    raw_orig_lines: List[str],
-    out_lines: List[str],
-) -> List[Line]:
-    """Merges the original output and new lines."""
-    orig_lines = [
-        OriginalLine(i, line)
-        for i, line in enumerate(raw_orig_lines)
-        if not is_replaced(line)
-    ]
-    check_lines = [
-        CheckLine(test, out_line, line_number_delta_prefix, line_number_pattern)
-        for out_line in out_lines
-    ]
-
-    result_lines: List[Line] = []
-    # CHECK lines must go after AUTOUPDATE.
-    while orig_lines and orig_lines[0].line_number <= autoupdate_line_number:
-        result_lines.append(orig_lines.pop(0))
-    for line in lit_run:
-        run_not = ""
-        if Path(test).name.startswith("fail_"):
-            run_not = "%{not} "
-        result_lines.append(RunLine(f"// RUN: {run_not}{line}\n"))
-    # Interleave the original lines and the CHECK: lines.
-    while orig_lines and check_lines:
-        # Original lines go first when the CHECK line is known and later.
-        if (
-            check_lines[0].line_in_file is not None
-            and check_lines[0].line_in_file > orig_lines[0].line_number
-        ):
-            result_lines.append(orig_lines.pop(0))
-        else:
-            check_line = check_lines.pop(0)
-            # Indent to match the next original line.
-            check_line.indent = re.findall("^ *", orig_lines[0].text)[0]
-            result_lines.append(check_line)
-    # One list is non-empty; append remaining lines from both to catch it.
-    result_lines.extend(orig_lines)
-    result_lines.extend(check_lines)
-
-    return result_lines
-
-
-def update_check(
-    parsed_args: ParsedArgs,
-    bazel_runfiles: Pattern,
-    llvm_symbolizer: str,
-    test: Path,
-) -> bool:
-    """Updates the CHECK: lines for `test` by running the tool.
-
-    Returns true if a change was made.
-    """
-    with test.open() as f:
-        orig_lines = f.readlines()
-
-    # Make sure we're supposed to autoupdate.
-    autoupdate_line = find_autoupdate(str(test), orig_lines)
-    if autoupdate_line is None:
-        return False
-
-    # Determine the merged output lines.
-    out_lines = get_matchable_test_output(
-        parsed_args.autoupdate_args,
-        parsed_args.extra_check_replacements,
-        parsed_args.tool,
-        bazel_runfiles,
-        llvm_symbolizer,
-        str(test),
-    )
-    result_lines = merge_lines(
-        parsed_args.line_number_delta_prefix,
-        parsed_args.line_number_pattern,
-        parsed_args.lit_run,
-        str(test),
-        autoupdate_line,
-        orig_lines,
-        out_lines,
-    )
-
-    # Calculate the remap for original lines.
-    line_number_remap = dict(
-        [
-            (line.line_number, i)
-            for i, line in enumerate(result_lines)
-            if isinstance(line, OriginalLine)
-        ]
-    )
-    # If the last line of the original output was a CHECK, replace it with an
-    # empty line.
-    if orig_lines[-1].lstrip().startswith("// CHECK"):
-        line_number_remap[len(orig_lines) - 1] = len(result_lines) - 1
-
-    # 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 test.open("w") as f:
-        f.writelines(formatted_result_lines)
-        return True
-
-
-def update_checks(
-    parsed_args: ParsedArgs,
-    bazel_runfiles: Pattern,
-    llvm_symbolizer: str,
-    tests: Set[Path],
-) -> None:
-    """Updates CHECK: lines in lit tests."""
-
-    def map_helper(test: Path) -> bool:
-        try:
-            updated = update_check(
-                parsed_args, bazel_runfiles, llvm_symbolizer, test
-            )
-        except Exception as e:
-            raise ValueError(f"Failed to update {test}") from e
-        print(".", end="", flush=True)
-        return updated
-
-    print(f"Updating {len(tests)} lit test(s)...")
-    with futures.ThreadPoolExecutor() as exec:
-        # list() iterates in order to immediately propagate exceptions.
-        results = list(exec.map(map_helper, tests))
-
-    # Each update call indicates progress with a dot without a newline, so put a
-    # newline to wrap.
-    print(f"\nUpdated {results.count(True)} lit test(s).")
-
-
-def main() -> None:
-    # Parse arguments relative to the working directory.
-    parsed_args = parse_args()
-
-    # Remaining script logic should be relative to the repository root.
-    root = Path(__file__).parent.parent.parent
-    os.chdir(root)
-
-    if parsed_args.tests:
-        tests = {test.relative_to(root) for test in parsed_args.tests}
-    else:
-        print(
-            "HINT: run `autoupdate_testdata.py f1 f2 ...` "
-            "to update specific tests"
-        )
-        tests = get_tests(parsed_args.testdata)
-
-    # Build inputs.
-    print(f"Building {parsed_args.tool}...")
-    subprocess.check_call(
-        [
-            "bazel",
-            "build",
-            "-c",
-            parsed_args.build_mode,
-            TOOLS[parsed_args.tool],
-        ]
-    )
-    bazel_bin_dir = subprocess.check_output(
-        ["bazel", "info", "-c", parsed_args.build_mode, "bazel-bin"],
-        encoding="utf-8",
-    ).strip()
-    bazel_runfiles = re.compile(
-        r"{0}/.*\.runfiles/carbon/".format(re.escape(bazel_bin_dir))
-    )
-
-    # Grab the symbolizer.
-    clang_var_content = Path(
-        "bazel-execroot/external/bazel_cc_toolchain/"
-        "clang_detected_variables.bzl"
-    ).read_text()
-    llvm_symbolizer = re.search(
-        '(?m)^llvm_symbolizer = "(.*)"$', clang_var_content
-    )
-    assert llvm_symbolizer is not None
-
-    # Run updates.
-    update_checks(parsed_args, bazel_runfiles, llvm_symbolizer[1], tests)
-
-
-if __name__ == "__main__":
-    main()

+ 2 - 2
toolchain/lexer/lexer_file_test.cpp

@@ -24,9 +24,9 @@ class LexerFileTest : public DriverFileTestBase {
   auto GetLineNumberReplacement(llvm::ArrayRef<llvm::StringRef> /*filenames*/)
       -> LineNumberReplacement override {
     return {.has_file = false,
-            .pattern = R"(line: +(\d+))",
+            .pattern = R"(line: (\s*\d+))",
             // The `{{{{` becomes `{{`.
-            .sub_for_formatv = "line: {{{{ *}}{0}"};
+            .line_formatv = "{{{{ *}}{0}"};
   }
 
   auto DoExtraCheckReplacements(std::string& check_line) -> void override {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.