Skip to content

Commit 36f25a0

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. 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 2fd855f commit 36f25a0

File tree

6 files changed

+61
-41
lines changed

6 files changed

+61
-41
lines changed

compiler/rustc_const_eval/src/util/type_name.rs

Lines changed: 13 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 AbsolutePathPrinter<'tcx> {
1111
tcx: TyCtxt<'tcx>,
@@ -18,9 +18,10 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'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 reasonable, even though for cases like
23+
// `for<'a, 'b> fn(&'a u32, &'b u32)` it prints "fn(&u32, &u32)".
24+
write!(self, "'_")
2425
}
2526

2627
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
@@ -125,19 +126,21 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'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 AbsolutePathPrinter<'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+
match _region.kind() {
140+
ty::ReErased => false,
141+
ty::ReBound(..) => true,
142+
_ => unreachable!(),
143+
}
141144
}
142145

143146
fn generic_delimiters(

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
333333
f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
334334
) -> Result<(), PrintError>;
335335

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

341341
fn reset_type_limit(&mut self) {}
342342

@@ -710,7 +710,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
710710
}
711711
ty::Ref(r, ty, mutbl) => {
712712
write!(self, "&")?;
713-
if self.should_print_region(r) {
713+
if self.should_print_optional_region(r) {
714714
r.print(self)?;
715715
write!(self, " ")?;
716716
}
@@ -778,7 +778,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
778778
},
779779
ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
780780
ty::Dynamic(data, r, repr) => {
781-
let print_r = self.should_print_region(r);
781+
let print_r = self.should_print_optional_region(r);
782782
if print_r {
783783
write!(self, "(")?;
784784
}
@@ -2487,7 +2487,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
24872487
Ok(())
24882488
}
24892489

2490-
fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
2490+
fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool {
24912491
let highlight = self.region_highlight_mode;
24922492
if highlight.region_highlighted(region).is_some() {
24932493
return true;

compiler/rustc_mir_transform/src/pass_manager.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,34 @@ 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 }`
44+
// A const function that simplifies a name like `Baz` or `Baz<'_>` or `foo::bar::Baz` or
45+
// `foo::bar::Baz<'a, 'b>` to `Baz`.
46+
//
47+
// FIXME(const-hack) Simplify the implementation once more `str` methods get
48+
// const-stable, e.g. `split` methods.
4549
const fn c_name(name: &'static str) -> &'static str {
46-
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
47-
// and inline into call site
4850
let bytes = name.as_bytes();
4951
let mut i = bytes.len();
5052
while i > 0 && bytes[i - 1] != b':' {
51-
i = i - 1;
53+
i -= 1;
5254
}
5355
let (_, bytes) = bytes.split_at(i);
56+
57+
// Strip everything after the first '<'.
58+
let mut i = 0;
59+
while i < bytes.len() && bytes[i] != b'<' {
60+
i += 1;
61+
}
62+
let bytes = if i < bytes.len() {
63+
let (bytes, _) = bytes.split_at(i);
64+
bytes
65+
} else {
66+
bytes
67+
};
68+
5469
match std::str::from_utf8(bytes) {
5570
Ok(name) => name,
56-
Err(_) => name,
71+
Err(_) => name, //compile_error!("bad name {name}"),
5772
}
5873
}
5974

@@ -62,8 +77,6 @@ const fn c_name(name: &'static str) -> &'static str {
6277
/// loop that goes over each available MIR and applies `run_pass`.
6378
pub(super) trait MirPass<'tcx> {
6479
fn name(&self) -> &'static str {
65-
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
66-
// See copypaste in `MirLint`
6780
const {
6881
let name = std::any::type_name::<Self>();
6982
c_name(name)
@@ -101,8 +114,6 @@ pub(super) trait MirPass<'tcx> {
101114
/// disabled (via the `Lint` adapter).
102115
pub(super) trait MirLint<'tcx> {
103116
fn name(&self) -> &'static str {
104-
// FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable.
105-
// See copypaste in `MirPass`
106117
const {
107118
let name = std::any::type_name::<Self>();
108119
c_name(name)
@@ -253,6 +264,8 @@ fn run_passes_inner<'tcx>(
253264
let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect();
254265

255266
let undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::<Vec<_>>();
267+
// eprintln!("XXX {}", std::any::type_name::<crate::promote_consts::PromoteTemps<'_>>());
268+
// eprintln!("XXX {}", c_name(std::any::type_name::<crate::promote_consts::PromoteTemps<'_>>()));
256269
if let Some((name, rest)) = undeclared.split_first() {
257270
let mut err =
258271
tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`"));

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 SymbolPrinter<'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+
// `path_generic_args` filters out lifetimes. See #144994.
239240
Ok(())
240241
}
241242

@@ -386,7 +387,6 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
386387

387388
let args =
388389
args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_)));
389-
390390
if args.clone().next().is_some() {
391391
self.generic_delimiters(|cx| cx.comma_sep(args))
392392
} else {
@@ -456,7 +456,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
456456
}
457457

458458
impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
459-
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
459+
fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
460460
false
461461
}
462462

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)