Просмотр исходного кода

Adjust formatting of blocks and scopes (#5474)

This is making two inter-related changes:

- Change `file` to reuse the formatter logic of `constants` and
`imports`, meaning empty `file` scopes will be omitted
- Mark `<elided>` sections in blocks (not in non-block scopes, because
they're not as sequential)
Jon Ross-Perkins 11 месяцев назад
Родитель
Сommit
e78a57bb82
24 измененных файлов с 108 добавлено и 114 удалено
  1. 0 4
      toolchain/check/testdata/alias/fail_control_flow.carbon
  2. 38 1
      toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges.carbon
  3. 5 0
      toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_only.carbon
  4. 0 8
      toolchain/check/testdata/basics/type_literals.carbon
  5. 0 2
      toolchain/check/testdata/class/fail_base_as_declared_name.carbon
  6. 0 2
      toolchain/check/testdata/class/fail_self_type_member.carbon
  7. 0 2
      toolchain/check/testdata/class/no_prelude/comp_time_field.carbon
  8. 0 2
      toolchain/check/testdata/facet/min_prelude/access.carbon
  9. 21 2
      toolchain/check/testdata/facet/min_prelude/runtime_value.carbon
  10. 0 2
      toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon
  11. 0 4
      toolchain/check/testdata/function/declaration/no_prelude/fail_todo_no_params.carbon
  12. 0 10
      toolchain/check/testdata/if_expr/fail_not_in_function.carbon
  13. 0 4
      toolchain/check/testdata/interface/no_prelude/fail_assoc_const_not_binding.carbon
  14. 0 8
      toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon
  15. 0 2
      toolchain/check/testdata/packages/no_prelude/export_import.carbon
  16. 0 4
      toolchain/check/testdata/packages/no_prelude/missing_prelude.carbon
  17. 0 4
      toolchain/check/testdata/patterns/min_prelude/underscore.carbon
  18. 0 2
      toolchain/check/testdata/struct/fail_keyword_name.carbon
  19. 0 2
      toolchain/check/testdata/tuple/min_prelude/tuple_pattern.carbon
  20. 0 8
      toolchain/check/testdata/var/fail_todo_control_flow_init.carbon
  21. 0 4
      toolchain/check/testdata/var/min_prelude/var_pattern.carbon
  22. 0 2
      toolchain/check/testdata/var/no_prelude/fail_generic.carbon
  23. 41 33
      toolchain/sem_ir/formatter.cpp
  24. 3 2
      toolchain/sem_ir/formatter.h

+ 0 - 4
toolchain/check/testdata/alias/fail_control_flow.carbon

@@ -43,8 +43,6 @@ fn F() {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_nested.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -59,8 +57,6 @@ fn F() {
 // CHECK:STDOUT:   %false: bool = bool_literal false [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: generic class @C(<unexpected>.inst28.loc4_14: bool) {
 // CHECK:STDOUT:   %B: bool = bind_symbolic_name B, 0 [symbolic = %B (constants.%B.7dd)]
 // CHECK:STDOUT:

+ 38 - 1
toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges.carbon

@@ -88,6 +88,18 @@ fn F();
 
 // CHECK:STDOUT: --- function.carbon
 // CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A.type: type = fn_type @A [concrete]
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %A: %A.type = struct_value () [concrete]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %empty_tuple.type [concrete]
+// CHECK:STDOUT:   %B.type: type = fn_type @B [concrete]
+// CHECK:STDOUT:   %B: %B.type = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT:   %C.type: type = fn_type @C [concrete]
+// CHECK:STDOUT:   %C: %C.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   %C.decl: %C.type = fn_decl @C [concrete = constants.%C] {
 // CHECK:STDOUT:     %return.patt: %pattern_type = return_slot_pattern [concrete]
@@ -102,10 +114,12 @@ fn F();
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @B() -> %empty_tuple.type {
 // CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   %b.ref.loc11: ref %empty_tuple.type = name_ref b, %b
 // CHECK:STDOUT:   %A.ref: %A.type = name_ref A, file.%A.decl [concrete = constants.%A]
 // CHECK:STDOUT:   %A.call: init %empty_tuple.type = call %A.ref()
 // CHECK:STDOUT:   assign %b.ref.loc11, %A.call
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @C() -> %empty_tuple.type {
@@ -132,12 +146,23 @@ fn F();
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- class.carbon
 // CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %A: type = class_type @A [concrete]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [concrete]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %I.type: type = fn_type @I [concrete]
+// CHECK:STDOUT:   %I: %I.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @A {
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   complete_type_witness = %complete_type
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -148,6 +173,7 @@ fn F();
 // CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %I.decl: %I.type = fn_decl @I [concrete = constants.%I] {} {}
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   complete_type_witness = %complete_type
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
@@ -162,22 +188,33 @@ fn F();
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- call_params.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %A.type: type = fn_type @A [concrete]
+// CHECK:STDOUT:   %A: %A.type = struct_value () [concrete]
+// CHECK:STDOUT:   %C.type: type = fn_type @C [concrete]
+// CHECK:STDOUT:   %C: %C.type = struct_value () [concrete]
+// CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
+// CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @G() {
 // CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   %A.ref: %A.type = name_ref A, file.%A.decl [concrete = constants.%A]
 // CHECK:STDOUT:   %A.call: init %empty_tuple.type = call %A.ref()
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C]
 // CHECK:STDOUT:   %C.call: init %empty_tuple.type = call %C.ref()
 // CHECK:STDOUT:   %.loc13_7.1: ref %empty_tuple.type = temporary_storage
 // CHECK:STDOUT:   %.loc13_7.2: ref %empty_tuple.type = temporary %.loc13_7.1, %A.call
 // CHECK:STDOUT:   %tuple.loc13: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
 // CHECK:STDOUT:   %.loc13_7.3: %empty_tuple.type = converted %A.call, %tuple.loc13 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT:   %.loc17_7.1: ref %empty_tuple.type = temporary_storage
 // CHECK:STDOUT:   %.loc17_7.2: ref %empty_tuple.type = temporary %.loc17_7.1, %C.call
 // CHECK:STDOUT:   %tuple.loc17: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple]
 // CHECK:STDOUT:   %.loc17_7.3: %empty_tuple.type = converted %C.call, %tuple.loc17 [concrete = constants.%empty_tuple]
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- file_without_ranges.carbon

+ 5 - 0
toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_only.carbon

@@ -26,6 +26,11 @@ fn F();
 
 // CHECK:STDOUT: --- with-range.carbon
 // CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
 // CHECK:STDOUT: }

+ 0 - 8
toolchain/check/testdata/basics/type_literals.carbon

@@ -196,8 +196,6 @@ var test_f128: f128;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- uN.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -268,13 +266,7 @@ var test_f128: f128;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_fN_bad_width.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_fN_todo_unsupported.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/class/fail_base_as_declared_name.carbon

@@ -22,5 +22,3 @@ fn N.base() {}
 
 // CHECK:STDOUT: --- fail_base_as_declared_name.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/class/fail_self_type_member.carbon

@@ -37,8 +37,6 @@ fn F() -> bool {
 // CHECK:STDOUT:   %complete_type: <witness> = complete_type_witness %struct_type.b [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @Class {
 // CHECK:STDOUT:   %bool.make_type: init type = call constants.%Bool() [concrete = bool]
 // CHECK:STDOUT:   %.loc12_10.1: type = value_of_initializer %bool.make_type [concrete = bool]

+ 0 - 2
toolchain/check/testdata/class/no_prelude/comp_time_field.carbon

@@ -94,8 +94,6 @@ var x: Class = {};
 // CHECK:STDOUT:   %Class: type = class_type @Class [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @Class {
 // CHECK:STDOUT:   complete_type_witness = invalid
 // CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/facet/min_prelude/access.carbon

@@ -1049,8 +1049,6 @@ interface J {
 // CHECK:STDOUT:   %assoc0: %I.assoc_type = assoc_entity element0, @I.%T [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: interface @I {
 // CHECK:STDOUT:   %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
 // CHECK:STDOUT:   %T: type = assoc_const_decl @T [concrete] {

+ 21 - 2
toolchain/check/testdata/facet/min_prelude/runtime_value.carbon

@@ -113,7 +113,15 @@ fn F(T: Z where .X = (), v: T.X);
 
 // CHECK:STDOUT: --- facet_value_copy_from_reference.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %C.elem: type = unbound_element_type %C, %I.type [concrete]
+// CHECK:STDOUT:   %pattern_type.2b5: type = pattern_type %I.type [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%c.param: %C) {
 // CHECK:STDOUT: !entry:
@@ -126,11 +134,21 @@ fn F(T: Z where .X = (), v: T.X);
 // CHECK:STDOUT:   %.loc13_15.2: %I.type = bind_value %.loc13_15.1
 // CHECK:STDOUT:   %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
 // CHECK:STDOUT:   %a: %I.type = bind_name a, %.loc13_15.2
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_facet_copy_narrowing_from_reference.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %I.type: type = facet_type <@I> [concrete]
+// CHECK:STDOUT:   %C: type = class_type @C [concrete]
+// CHECK:STDOUT:   %facet_type: type = facet_type <@I & @J> [concrete]
+// CHECK:STDOUT:   %C.elem: type = unbound_element_type %C, %facet_type [concrete]
+// CHECK:STDOUT:   %pattern_type.2b5: type = pattern_type %I.type [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%c.param: %C) {
 // CHECK:STDOUT: !entry:
@@ -143,5 +161,6 @@ fn F(T: Z where .X = (), v: T.X);
 // CHECK:STDOUT:   %.loc21_15.2: %facet_type = bind_value %.loc21_15.1
 // CHECK:STDOUT:   %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
 // CHECK:STDOUT:   %a: %I.type = bind_name a, <error>
+// CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/function/declaration/no_prelude/extern_library.carbon

@@ -299,8 +299,6 @@ extern library "extern_library_owner" fn F() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_extern_library_mismatch_owner.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_extern_self_library.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {

+ 0 - 4
toolchain/check/testdata/function/declaration/no_prelude/fail_todo_no_params.carbon

@@ -166,12 +166,8 @@ fn A {
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_todo_arrow_body.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_invalid_file_generic_regression_test.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 10
toolchain/check/testdata/if_expr/fail_not_in_function.carbon

@@ -87,22 +87,16 @@ fn F() {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_types.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_in_param.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_class.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -110,8 +104,6 @@ fn F() {
 // CHECK:STDOUT:   %true: bool = bool_literal true [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   %true: bool = bool_literal true [concrete = constants.%true]
 // CHECK:STDOUT:   if %true br !if.expr.then else br !if.expr.else
@@ -134,8 +126,6 @@ fn F() {
 // CHECK:STDOUT:   %true: bool = bool_literal true [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: generic class @C(<unexpected>.inst17.loc4_14: type) {
 // CHECK:STDOUT:   %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
 // CHECK:STDOUT:

+ 0 - 4
toolchain/check/testdata/interface/no_prelude/fail_assoc_const_not_binding.carbon

@@ -123,8 +123,6 @@ interface I {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: interface @I {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = <unexpected>.inst17
@@ -136,8 +134,6 @@ interface I {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: interface @I {
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = <unexpected>.inst17

+ 0 - 8
toolchain/check/testdata/operators/builtin/fail_and_or_not_in_function.carbon

@@ -77,8 +77,6 @@ var or_val: bool = true or true;
 // CHECK:STDOUT:   %Float: %Float.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%b.param: bool) -> type {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %b.ref: bool = name_ref b, <unexpected>.inst28.loc5_6
@@ -106,8 +104,6 @@ var or_val: bool = true or true;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_or.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -118,8 +114,6 @@ var or_val: bool = true or true;
 // CHECK:STDOUT:   %Float: %Float.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%b.param: bool) -> type {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   %b.ref: bool = name_ref b, <unexpected>.inst28.loc5_6
@@ -147,5 +141,3 @@ var or_val: bool = true or true;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/packages/no_prelude/export_import.carbon

@@ -344,8 +344,6 @@ export Poison;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_export_in_impl.impl.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- export_export.impl.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {

+ 0 - 4
toolchain/check/testdata/packages/no_prelude/missing_prelude.carbon

@@ -374,9 +374,5 @@ var n: {} = i32;
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_prelude_as_namespace.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_prelude_as_class.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 4
toolchain/check/testdata/patterns/min_prelude/underscore.carbon

@@ -467,8 +467,6 @@ fn F() -> {} {
 // CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   complete_type_witness = invalid
 // CHECK:STDOUT:
@@ -525,7 +523,5 @@ fn F() -> {} {
 // CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() -> %empty_struct_type;
 // CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/struct/fail_keyword_name.carbon

@@ -26,5 +26,3 @@ fn G() { return {.return = 5}; };
 
 // CHECK:STDOUT: --- fail_keyword_name.carbon
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 2
toolchain/check/testdata/tuple/min_prelude/tuple_pattern.carbon

@@ -569,8 +569,6 @@ let (a: {}, b: {}) = ({}, {}, {});
 // CHECK:STDOUT:   %C: type = class_type @C [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: class @C {
 // CHECK:STDOUT:   complete_type_witness = invalid
 // CHECK:STDOUT:

+ 0 - 8
toolchain/check/testdata/var/fail_todo_control_flow_init.carbon

@@ -77,26 +77,18 @@ var y2: bool = false or true;
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_if_false.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_true_or_false.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_false_or_true.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:

+ 0 - 4
toolchain/check/testdata/var/min_prelude/var_pattern.carbon

@@ -361,8 +361,6 @@ class C {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @f();
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_implicit.carbon
@@ -370,8 +368,6 @@ class C {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @F(%.param: <error>);
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- var_self.carbon

+ 0 - 2
toolchain/check/testdata/var/no_prelude/fail_generic.carbon

@@ -25,7 +25,5 @@ fn Main() {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: file {}
-// CHECK:STDOUT:
 // CHECK:STDOUT: fn @Main();
 // CHECK:STDOUT:

+ 41 - 33
toolchain/sem_ir/formatter.cpp

@@ -64,26 +64,18 @@ Formatter::Formatter(const File* sem_ir,
 }
 
 auto Formatter::Format() -> void {
-  out_ << "--- " << sem_ir_->filename() << "\n\n";
-
-  FormatScopeIfUsed(InstNamer::ScopeId::Constants,
-                    sem_ir_->constants().array_ref());
-  FormatScopeIfUsed(InstNamer::ScopeId::ImportRefs,
-                    sem_ir_->inst_blocks().Get(InstBlockId::ImportRefs));
-
-  out_ << inst_namer_.GetScopeName(InstNamer::ScopeId::File) << " ";
-  OpenBrace();
-
-  // TODO: Handle the case where there are multiple top-level instruction
-  // blocks. For example, there may be branching in the initializer of a
-  // global or a type expression.
-  if (auto block_id = sem_ir_->top_inst_block_id(); block_id.has_value()) {
-    llvm::SaveAndRestore file_scope(scope_, InstNamer::ScopeId::File);
-    FormatCodeBlock(block_id);
-  }
-
-  CloseBrace();
-  out_ << '\n';
+  out_ << "--- " << sem_ir_->filename() << "\n";
+
+  FormatTopLevelScopeIfUsed(InstNamer::ScopeId::Constants,
+                            sem_ir_->constants().array_ref(),
+                            /*use_tentative_output_scopes=*/true);
+  FormatTopLevelScopeIfUsed(InstNamer::ScopeId::ImportRefs,
+                            sem_ir_->inst_blocks().Get(InstBlockId::ImportRefs),
+                            /*use_tentative_output_scopes=*/true);
+  FormatTopLevelScopeIfUsed(
+      InstNamer::ScopeId::File,
+      sem_ir_->inst_blocks().GetOrEmpty(sem_ir_->top_inst_block_id()),
+      /*use_tentative_output_scopes=*/false);
 
   for (auto [id, _] : sem_ir_->interfaces().enumerate()) {
     FormatInterface(id);
@@ -109,7 +101,6 @@ auto Formatter::Format() -> void {
     FormatSpecific(id);
   }
 
-  // End-of-file newline.
   out_ << "\n";
 }
 
@@ -284,9 +275,11 @@ auto Formatter::IndentLabel() -> void {
   Indent(-2);
 }
 
-auto Formatter::FormatScopeIfUsed(InstNamer::ScopeId scope_id,
-                                  llvm::ArrayRef<InstId> block) -> void {
-  if (use_dump_sem_ir_ranges_) {
+auto Formatter::FormatTopLevelScopeIfUsed(InstNamer::ScopeId scope_id,
+                                          llvm::ArrayRef<InstId> block,
+                                          bool use_tentative_output_scopes)
+    -> void {
+  if (!use_tentative_output_scopes && use_dump_sem_ir_ranges_) {
     // Don't format the scope if no instructions are in a dump range.
     block = block.drop_while(
         [&](InstId inst_id) { return !ShouldFormatInst(inst_id); });
@@ -299,13 +292,23 @@ auto Formatter::FormatScopeIfUsed(InstNamer::ScopeId scope_id,
   llvm::SaveAndRestore scope(scope_, scope_id);
   // Note, we don't use OpenBrace() / CloseBrace() here because we always want
   // a newline to avoid misformatting if the first instruction is omitted.
-  out_ << inst_namer_.GetScopeName(scope_id) << " {\n";
+  out_ << "\n" << inst_namer_.GetScopeName(scope_id) << " {\n";
   indent_ += 2;
   for (const InstId inst_id : block) {
-    TentativeOutputScope scope(*this, tentative_inst_chunks_[inst_id.index]);
-    FormatInst(inst_id);
+    // Format instructions when needed, but do nothing for elided entries;
+    // unlike normal code blocks, scopes are non-sequential so skipped
+    // instructions are assumed to be uninteresting.
+    if (use_tentative_output_scopes) {
+      // This is for constants and imports. These use tentative logic to
+      // determine whether an instruction is printed.
+      TentativeOutputScope scope(*this, tentative_inst_chunks_[inst_id.index]);
+      FormatInst(inst_id);
+    } else if (ShouldFormatInst(inst_id)) {
+      // This is for the file scope. It uses only the range-based filtering.
+      FormatInst(inst_id);
+    }
   }
-  out_ << "}\n\n";
+  out_ << "}\n";
   indent_ -= 2;
 }
 
@@ -645,8 +648,17 @@ auto Formatter::FormatParamList(InstBlockId params_id, bool has_return_slot)
 }
 
 auto Formatter::FormatCodeBlock(InstBlockId block_id) -> void {
+  bool elided = false;
   for (const InstId inst_id : sem_ir_->inst_blocks().GetOrEmpty(block_id)) {
-    FormatInst(inst_id);
+    if (ShouldFormatInst(inst_id)) {
+      FormatInst(inst_id);
+      elided = false;
+    } else if (!elided) {
+      // When formatting a block, leave a hint that instructions were elided.
+      Indent();
+      out_ << "<elided>\n";
+      elided = true;
+    }
   }
 }
 
@@ -753,10 +765,6 @@ auto Formatter::FormatInst(InstId inst_id, ImportRefUnloaded inst) -> void {
 }
 
 auto Formatter::FormatInst(InstId inst_id) -> void {
-  if (!ShouldFormatInst(inst_id)) {
-    return;
-  }
-
   if (!inst_id.has_value()) {
     Indent();
     out_ << "none\n";

+ 3 - 2
toolchain/sem_ir/formatter.h

@@ -142,8 +142,9 @@ class Formatter {
 
   // Formats a top-level scope, and any of the instructions in that scope that
   // are used.
-  auto FormatScopeIfUsed(InstNamer::ScopeId scope_id,
-                         llvm::ArrayRef<InstId> block) -> void;
+  auto FormatTopLevelScopeIfUsed(InstNamer::ScopeId scope_id,
+                                 llvm::ArrayRef<InstId> block,
+                                 bool use_tentative_output_scopes) -> void;
 
   // Formats a full class.
   auto FormatClass(ClassId id) -> void;