Skip to content

Commit 75552ef

Browse files
committed
Print regions in type_name.
Currently they are skipped, which is a bit weird, and it sometimes causes malformed output like `Foo<>` and `dyn Bar<, A = u32>`. Most regions are erased by the time `type_name` does its work. So all regions are now printed as `'_` in non-optional places. Not perfect, but better than the status quo. `c_name` is updated to trim lifetimes from MIR pass names, so that the `PASS_NAMES` sanity check still works. It is also renamed as `simplify_pass_type_name` and made non-const, because it doesn't need to be const and the non-const implementation is much shorter. The commit also renames `should_print_region` as `should_print_optional_region`, which makes it clearer that it only applies to some regions. Fixes #145168.
1 parent 3672a55 commit 75552ef

File tree

8 files changed

+78
-57
lines changed

8 files changed

+78
-57
lines changed

compiler/rustc_const_eval/src/util/type_name.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_hir::def_id::CrateNum;
55
use rustc_hir::definitions::DisambiguatedDefPathData;
66
use rustc_middle::bug;
77
use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
8-
use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
8+
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
99

1010
struct TypeNamePrinter<'tcx> {
1111
tcx: TyCtxt<'tcx>,
@@ -18,9 +18,10 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
1818
}
1919

2020
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
21-
// This is reachable (via `pretty_print_dyn_existential`) even though
22-
// `<Self As PrettyPrinter>::should_print_region` returns false. See #144994.
23-
Ok(())
21+
// FIXME: most regions have been erased by the time this code runs.
22+
// Just printing `'_` is a bit hacky but gives mostly good results, and
23+
// doing better is difficult. See `should_print_optional_region`.
24+
write!(self, "'_")
2425
}
2526

2627
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
@@ -125,19 +126,24 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
125126
args: &[GenericArg<'tcx>],
126127
) -> Result<(), PrintError> {
127128
print_prefix(self)?;
128-
let args =
129-
args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_)));
130-
if args.clone().next().is_some() {
131-
self.generic_delimiters(|cx| cx.comma_sep(args))
129+
if !args.is_empty() {
130+
self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied()))
132131
} else {
133132
Ok(())
134133
}
135134
}
136135
}
137136

138137
impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
139-
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
140-
false
138+
fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
139+
// Bound regions are always printed (as `'_`), which gives some idea that they are special,
140+
// even though the `for` is omitted by the pretty printer.
141+
// E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
142+
match _region.kind() {
143+
ty::ReErased => false,
144+
ty::ReBound(..) => true,
145+
_ => unreachable!(),
146+
}
141147
}
142148

143149
fn generic_delimiters(

compiler/rustc_lint/src/context.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -756,22 +756,22 @@ impl<'tcx> LateContext<'tcx> {
756756
}
757757

758758
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
759-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
759+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
760760
}
761761

762762
fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
763-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
763+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
764764
}
765765

766766
fn print_dyn_existential(
767767
&mut self,
768768
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
769769
) -> Result<(), PrintError> {
770-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
770+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
771771
}
772772

773773
fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
774-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
774+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
775775
}
776776

777777
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
337337
false
338338
}
339339

340-
/// Returns `true` if the region should be printed in
341-
/// optional positions, e.g., `&'a T` or `dyn Tr + 'b`.
342-
/// This is typically the case for all non-`'_` regions.
343-
fn should_print_region(&self, region: ty::Region<'tcx>) -> bool;
340+
/// Returns `true` if the region should be printed in optional positions,
341+
/// e.g., `&'a T` or `dyn Tr + 'b`. (Regions like the one in `Cow<'static, T>`
342+
/// will always be printed.)
343+
fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool;
344344

345345
fn reset_type_limit(&mut self) {}
346346

@@ -717,7 +717,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
717717
}
718718
ty::Ref(r, ty, mutbl) => {
719719
write!(self, "&")?;
720-
if self.should_print_region(r) {
720+
if self.should_print_optional_region(r) {
721721
r.print(self)?;
722722
write!(self, " ")?;
723723
}
@@ -785,7 +785,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
785785
},
786786
ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
787787
ty::Dynamic(data, r, repr) => {
788-
let print_r = self.should_print_region(r);
788+
let print_r = self.should_print_optional_region(r);
789789
if print_r {
790790
write!(self, "(")?;
791791
}
@@ -2494,7 +2494,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
24942494
!self.type_length_limit.value_within_limit(self.printed_type_count)
24952495
}
24962496

2497-
fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
2497+
fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool {
24982498
let highlight = self.region_highlight_mode;
24992499
if highlight.region_highlighted(region).is_some() {
25002500
return true;

compiler/rustc_mir_transform/src/pass_manager.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,40 @@ fn to_profiler_name(type_name: &'static str) -> &'static str {
4141
})
4242
}
4343

44-
// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
45-
const fn c_name(name: &'static str) -> &'static str {
44+
// A function that simplifies a pass's type_name. E.g. `Baz`, `Baz<'_>`,
45+
// `foo::bar::Baz`, and `foo::bar::Baz<'a, 'b>` all become `Baz`.
46+
//
47+
// It's `const` for perf reasons: it's called a lot, and doing the string
48+
// operations at runtime causes a non-trivial slowdown. If
49+
// `split_once`/`rsplit_once` become `const` its body could be simplified to
50+
// this:
51+
// ```ignore (fragment)
52+
// let name = if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name };
53+
// let name = if let Some((head, _)) = name.split_once('<') { head } else { name };
54+
// name
55+
// ```
56+
const fn simplify_pass_type_name(name: &'static str) -> &'static str {
4657
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
47-
// and inline into call site
58+
59+
// Work backwards from the end. If a ':' is hit, strip it and everything before it.
4860
let bytes = name.as_bytes();
4961
let mut i = bytes.len();
5062
while i > 0 && bytes[i - 1] != b':' {
51-
i = i - 1;
63+
i -= 1;
5264
}
5365
let (_, bytes) = bytes.split_at(i);
66+
67+
// Work forwards from the start of what's left. If a '<' is hit, strip it and everything after
68+
// it.
69+
let mut i = 0;
70+
while i < bytes.len() && bytes[i] != b'<' {
71+
i += 1;
72+
}
73+
let (bytes, _) = bytes.split_at(i);
74+
5475
match std::str::from_utf8(bytes) {
5576
Ok(name) => name,
56-
Err(_) => name,
77+
Err(_) => panic!(),
5778
}
5879
}
5980

@@ -62,12 +83,7 @@ const fn c_name(name: &'static str) -> &'static str {
6283
/// loop that goes over each available MIR and applies `run_pass`.
6384
pub(super) trait MirPass<'tcx> {
6485
fn name(&self) -> &'static str {
65-
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
66-
// See copypaste in `MirLint`
67-
const {
68-
let name = std::any::type_name::<Self>();
69-
c_name(name)
70-
}
86+
const { simplify_pass_type_name(std::any::type_name::<Self>()) }
7187
}
7288

7389
fn profiler_name(&self) -> &'static str {
@@ -101,12 +117,7 @@ pub(super) trait MirPass<'tcx> {
101117
/// disabled (via the `Lint` adapter).
102118
pub(super) trait MirLint<'tcx> {
103119
fn name(&self) -> &'static str {
104-
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
105-
// See copypaste in `MirPass`
106-
const {
107-
let name = std::any::type_name::<Self>();
108-
c_name(name)
109-
}
120+
simplify_pass_type_name(std::any::type_name::<Self>())
110121
}
111122

112123
fn is_enabled(&self, _sess: &Session) -> bool {

compiler/rustc_symbol_mangling/src/legacy.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
235235

236236
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
237237
// This might be reachable (via `pretty_print_dyn_existential`) even though
238-
// `<Self As PrettyPrinter>::should_print_region` returns false. See #144994.
238+
// `<Self As PrettyPrinter>::should_print_optional_region` returns false and
239+
// `print_path_with_generic_args` filters out lifetimes. See #144994.
239240
Ok(())
240241
}
241242

@@ -389,7 +390,6 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
389390

390391
let args =
391392
args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_)));
392-
393393
if args.clone().next().is_some() {
394394
self.generic_delimiters(|cx| cx.comma_sep(args))
395395
} else {
@@ -459,7 +459,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
459459
}
460460

461461
impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
462-
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
462+
fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
463463
false
464464
}
465465

compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,22 +235,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
235235
}
236236

237237
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
238-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
238+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
239239
}
240240

241241
fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
242-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
242+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
243243
}
244244

245245
fn print_dyn_existential(
246246
&mut self,
247247
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
248248
) -> Result<(), PrintError> {
249-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
249+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
250250
}
251251

252252
fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
253-
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
253+
unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs`
254254
}
255255

256256
fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {

library/core/src/any.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,9 +835,9 @@ impl fmt::Debug for TypeId {
835835
///
836836
/// The returned string must not be considered to be a unique identifier of a
837837
/// type as multiple types may map to the same type name. Similarly, there is no
838-
/// guarantee that all parts of a type will appear in the returned string: for
839-
/// example, lifetime specifiers are currently not included. In addition, the
840-
/// output may change between versions of the compiler.
838+
/// guarantee that all parts of a type will appear in the returned string. In
839+
/// addition, the output may change between versions of the compiler. For
840+
/// example, lifetime specifiers were omitted in some earlier versions.
841841
///
842842
/// The current implementation uses the same infrastructure as compiler
843843
/// diagnostics and debuginfo, but this is not guaranteed.

tests/ui/type/type-name-basic.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,32 @@ pub fn main() {
6262

6363
t!(Vec<Vec<u32>>, "alloc::vec::Vec<alloc::vec::Vec<u32>>");
6464
t!(Foo<usize>, "type_name_basic::Foo<usize>");
65-
t!(Bar<'static>, "type_name_basic::Bar");
66-
t!(Baz<'static, u32>, "type_name_basic::Baz<u32>");
65+
t!(Bar<'static>, "type_name_basic::Bar<'_>");
66+
t!(Baz<'static, u32>, "type_name_basic::Baz<'_, u32>");
6767

68-
// FIXME: lifetime omission means these all print badly.
69-
t!(dyn TrL<'static>, "dyn type_name_basic::TrL<>");
70-
t!(dyn TrLA<'static, A = u32>, "dyn type_name_basic::TrLA<, A = u32>");
68+
t!(dyn TrL<'static>, "dyn type_name_basic::TrL<'_>");
69+
t!(dyn TrLA<'static, A = u32>, "dyn type_name_basic::TrLA<'_, A = u32>");
7170
t!(
7271
dyn TrLT<'static, Cow<'static, ()>>,
73-
"dyn type_name_basic::TrLT<, alloc::borrow::Cow<()>>"
72+
"dyn type_name_basic::TrLT<'_, alloc::borrow::Cow<'_, ()>>"
7473
);
7574
t!(
7675
dyn TrLTA<'static, u32, A = Cow<'static, ()>>,
77-
"dyn type_name_basic::TrLTA<, u32, A = alloc::borrow::Cow<()>>"
76+
"dyn type_name_basic::TrLTA<'_, u32, A = alloc::borrow::Cow<'_, ()>>"
7877
);
7978

8079
t!(fn(i32) -> i32, "fn(i32) -> i32");
81-
t!(dyn for<'a> Fn(&'a u32), "dyn core::ops::function::Fn(&u32)");
80+
t!(fn(&'static u32), "fn(&u32)");
81+
82+
// FIXME: these are sub-optimal, ideally the `for<...>` would be printed.
83+
t!(for<'a> fn(&'a u32), "fn(&'_ u32)");
84+
t!(for<'a, 'b> fn(&'a u32, &'b u32), "fn(&'_ u32, &'_ u32)");
85+
t!(for<'a> fn(for<'b> fn(&'a u32, &'b u32)), "fn(fn(&'_ u32, &'_ u32))");
8286

8387
struct S<'a, T>(&'a T);
8488
impl<'a, T: Clone> S<'a, T> {
8589
fn test() {
86-
t!(Cow<'a, T>, "alloc::borrow::Cow<u32>");
90+
t!(Cow<'a, T>, "alloc::borrow::Cow<'_, u32>");
8791
}
8892
}
8993
S::<u32>::test();

0 commit comments

Comments
 (0)