Skip to content

Commit 5863963

Browse files
committed
Add lifetime-aware support for Display of Ident and add LabelSymbol
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent 131581a commit 5863963

File tree

7 files changed

+103
-33
lines changed

7 files changed

+103
-33
lines changed

compiler/rustc_errors/src/diagnostic_impls.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_ast_pretty::pprust;
1111
use rustc_attr_data_structures::RustcVersion;
1212
use rustc_macros::Subdiagnostic;
1313
use rustc_span::edition::Edition;
14+
use rustc_span::symbol::LabelSymbol;
1415
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
1516
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTuple};
1617
use rustc_type_ir::{ClosureKind, FloatTy};
@@ -168,6 +169,12 @@ impl IntoDiagArg for Symbol {
168169
}
169170
}
170171

172+
impl IntoDiagArg for LabelSymbol {
173+
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
174+
self.to_string().into_diag_arg(path)
175+
}
176+
}
177+
171178
impl<'a> IntoDiagArg for &'a str {
172179
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
173180
self.to_string().into_diag_arg(path)

compiler/rustc_parse/src/errors.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_errors::{
1212
use rustc_macros::{Diagnostic, Subdiagnostic};
1313
use rustc_session::errors::ExprParenthesesNeeded;
1414
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
15+
use rustc_span::symbol::LabelSymbol;
1516
use rustc_span::{Ident, Span, Symbol};
1617

1718
use crate::fluent_generated as fluent;
@@ -2191,7 +2192,7 @@ pub(crate) struct KeywordLifetime {
21912192
pub(crate) struct InvalidLabel {
21922193
#[primary_span]
21932194
pub span: Span,
2194-
pub name: Symbol,
2195+
pub name: LabelSymbol,
21952196
}
21962197

21972198
#[derive(Diagnostic)]

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3077,7 +3077,7 @@ impl<'a> Parser<'a> {
30773077
if let Some((ident, is_raw)) = self.token.lifetime() {
30783078
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
30793079
if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() {
3080-
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
3080+
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.into() });
30813081
}
30823082

30833083
self.bump();

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,7 +3127,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31273127
} else {
31283128
self.suggest_introducing_lifetime(
31293129
&mut err,
3130-
Some(lifetime_ref.ident.name.as_str()),
3130+
Some(lifetime_ref.ident),
31313131
|err, _, span, message, suggestion, span_suggs| {
31323132
err.multipart_suggestion_verbose(
31333133
message,
@@ -3145,7 +3145,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31453145
fn suggest_introducing_lifetime(
31463146
&self,
31473147
err: &mut Diag<'_>,
3148-
name: Option<&str>,
3148+
name: Option<Ident>,
31493149
suggest: impl Fn(
31503150
&mut Diag<'_>,
31513151
bool,
@@ -3192,7 +3192,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31923192
let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
31933193
let (span, sugg) = if span.is_empty() {
31943194
let mut binder_idents: FxIndexSet<Ident> = Default::default();
3195-
binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
3195+
binder_idents
3196+
.insert(name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)));
31963197

31973198
// We need to special case binders in the following situation:
31983199
// Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
@@ -3226,9 +3227,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
32263227
"".to_string(),
32273228
|mut binders, (i, x)| {
32283229
if i != 0 {
3229-
binders += ", ";
3230+
binders.push_str(", ");
32303231
}
3231-
binders += x.as_str();
3232+
binders.push_str(&x.to_string());
32323233
binders
32333234
},
32343235
);
@@ -3247,15 +3248,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
32473248
.source_map()
32483249
.span_through_char(span, '<')
32493250
.shrink_to_hi();
3250-
let sugg = format!("{}, ", name.unwrap_or("'a"));
3251+
let sugg = format!(
3252+
"{}, ",
3253+
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime))
3254+
);
32513255
(span, sugg)
32523256
};
32533257

32543258
if higher_ranked {
32553259
let message = Cow::from(format!(
32563260
"consider making the {} lifetime-generic with a new `{}` lifetime",
32573261
kind.descr(),
3258-
name.unwrap_or("'a"),
3262+
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)),
32593263
));
32603264
should_continue = suggest(
32613265
err,

compiler/rustc_span/src/symbol.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ symbols! {
812812
default_field_values,
813813
default_fn,
814814
default_lib_allocator,
815+
default_lifetime: "'a",
815816
default_method_body_is_const,
816817
// --------------------------
817818
// Lang items which are used only for experiments with auto traits with default bounds.
@@ -2477,6 +2478,10 @@ impl Ident {
24772478
pub fn as_str(&self) -> &str {
24782479
self.name.as_str()
24792480
}
2481+
2482+
pub fn as_lifetime(&self) -> Option<Ident> {
2483+
self.name.as_lifetime().map(|sym| Ident::with_dummy_span(sym))
2484+
}
24802485
}
24812486

24822487
impl PartialEq for Ident {
@@ -2546,6 +2551,14 @@ impl IdentPrinter {
25462551

25472552
impl fmt::Display for IdentPrinter {
25482553
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2554+
if let Some(lifetime) = self.symbol.as_lifetime() {
2555+
f.write_str("'")?;
2556+
if self.is_raw {
2557+
f.write_str("r#")?;
2558+
}
2559+
return fmt::Display::fmt(&lifetime, f);
2560+
}
2561+
25492562
if self.is_raw {
25502563
f.write_str("r#")?;
25512564
} else if self.symbol == kw::DollarCrate {
@@ -2640,6 +2653,11 @@ impl Symbol {
26402653
self == sym::empty
26412654
}
26422655

2656+
pub fn as_lifetime(self) -> Option<Symbol> {
2657+
let name = self.as_str();
2658+
name.strip_prefix("'").map(Symbol::intern)
2659+
}
2660+
26432661
/// This method is supposed to be used in error messages, so it's expected to be
26442662
/// identical to printing the original identifier token written in source code
26452663
/// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag
@@ -2946,7 +2964,13 @@ impl Ident {
29462964
/// We see this identifier in a normal identifier position, like variable name or a type.
29472965
/// How was it written originally? Did it use the raw form? Let's try to guess.
29482966
pub fn is_raw_guess(self) -> bool {
2949-
self.name.can_be_raw() && self.is_reserved()
2967+
if self.name == kw::StaticLifetime || self.name == kw::UnderscoreLifetime {
2968+
false
2969+
} else if let Some(lifetime) = self.as_lifetime() {
2970+
lifetime.is_raw_guess()
2971+
} else {
2972+
self.name.can_be_raw() && self.is_reserved()
2973+
}
29502974
}
29512975

29522976
/// Whether this would be the identifier for a tuple field like `self.0`, as
@@ -2972,3 +2996,27 @@ pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec<Symbol> {
29722996
})
29732997
.collect()
29742998
}
2999+
3000+
/// A newtype around `Symbol` specifically for label printing.
3001+
/// This ensures type safety when dealing with labels and provides
3002+
/// specialized formatting behavior for label contexts.
3003+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
3004+
pub struct LabelSymbol(Symbol);
3005+
3006+
impl fmt::Display for LabelSymbol {
3007+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3008+
write!(f, "{}", self.0.as_str())
3009+
}
3010+
}
3011+
3012+
impl From<Symbol> for LabelSymbol {
3013+
fn from(symbol: Symbol) -> Self {
3014+
LabelSymbol(symbol)
3015+
}
3016+
}
3017+
3018+
impl From<Ident> for LabelSymbol {
3019+
fn from(ident: Ident) -> Self {
3020+
LabelSymbol(ident.name)
3021+
}
3022+
}

tests/ui/lifetimes/lifetime-errors/error-lifetime-name-issue-143150.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
//@ edition: 2021
2-
fn a(_: dyn Trait + 'r#fn) { //~ ERROR use of undeclared lifetime name `'fn` [E0261]
2+
fn a(_: dyn Trait + 'r#fn) { //~ ERROR use of undeclared lifetime name `'r#fn` [E0261]
33

44
}
55

66
trait Trait {}
77

88
#[derive(Eq, PartialEq)]
99
struct Test {
10-
a: &'r#fn str,
11-
//~^ ERROR use of undeclared lifetime name `'fn` [E0261]
12-
//~| ERROR use of undeclared lifetime name `'fn` [E0261]
10+
a: &'r#fn str,
11+
//~^ ERROR use of undeclared lifetime name `'r#fn` [E0261]
12+
//~| ERROR use of undeclared lifetime name `'r#fn` [E0261]
1313
}
1414

1515
trait Trait1<T>
16-
where T: for<'a> Trait1<T> + 'r#fn { } //~ ERROR use of undeclared lifetime name `'fn` [E0261]
16+
where T: for<'a> Trait1<T> + 'r#fn { } //~ ERROR use of undeclared lifetime name `'r#fn` [E0261]
1717

1818

1919

tests/ui/lifetimes/lifetime-errors/error-lifetime-name-issue-143150.stderr

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,55 @@
1-
error[E0261]: use of undeclared lifetime name `'fn`
1+
error[E0261]: use of undeclared lifetime name `'r#fn`
22
--> $DIR/error-lifetime-name-issue-143150.rs:2:21
33
|
44
LL | fn a(_: dyn Trait + 'r#fn) {
5-
| - ^^^^^ undeclared lifetime
6-
| |
7-
| help: consider introducing lifetime `'fn` here: `<'fn>`
5+
| ^^^^^ undeclared lifetime
6+
|
7+
help: consider introducing lifetime `'r#fn` here
8+
|
9+
LL | fn a<'r#fn>(_: dyn Trait + 'r#fn) {
10+
| +++++++
811

9-
error[E0261]: use of undeclared lifetime name `'fn`
12+
error[E0261]: use of undeclared lifetime name `'r#fn`
1013
--> $DIR/error-lifetime-name-issue-143150.rs:10:9
1114
|
12-
LL | struct Test {
13-
| - help: consider introducing lifetime `'fn` here: `<'fn>`
14-
LL | a: &'r#fn str,
15+
LL | a: &'r#fn str,
1516
| ^^^^^ undeclared lifetime
17+
|
18+
help: consider introducing lifetime `'r#fn` here
19+
|
20+
LL | struct Test<'r#fn> {
21+
| +++++++
1622

17-
error[E0261]: use of undeclared lifetime name `'fn`
23+
error[E0261]: use of undeclared lifetime name `'r#fn`
1824
--> $DIR/error-lifetime-name-issue-143150.rs:10:9
1925
|
2026
LL | #[derive(Eq, PartialEq)]
21-
| -- lifetime `'fn` is missing in item created through this procedural macro
27+
| -- lifetime `'r#fn` is missing in item created through this procedural macro
2228
LL | struct Test {
23-
| - help: consider introducing lifetime `'fn` here: `<'fn>`
24-
LL | a: &'r#fn str,
29+
LL | a: &'r#fn str,
2530
| ^^^^^ undeclared lifetime
31+
|
32+
help: consider introducing lifetime `'r#fn` here
33+
|
34+
LL | struct Test<'r#fn> {
35+
| +++++++
2636

27-
error[E0261]: use of undeclared lifetime name `'fn`
37+
error[E0261]: use of undeclared lifetime name `'r#fn`
2838
--> $DIR/error-lifetime-name-issue-143150.rs:16:32
2939
|
3040
LL | where T: for<'a> Trait1<T> + 'r#fn { }
3141
| ^^^^^ undeclared lifetime
3242
|
3343
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
34-
help: consider making the bound lifetime-generic with a new `'fn` lifetime
44+
help: consider making the bound lifetime-generic with a new `'r#fn` lifetime
3545
|
3646
LL - where T: for<'a> Trait1<T> + 'r#fn { }
37-
LL + where for<'fn, 'a> T: Trait1<T> + 'r#fn { }
47+
LL + where for<'r#fn, 'a> T: Trait1<T> + 'r#fn { }
3848
|
39-
help: consider introducing lifetime `'fn` here
49+
help: consider introducing lifetime `'r#fn` here
4050
|
41-
LL | trait Trait1<'fn, T>
42-
| ++++
51+
LL | trait Trait1<'r#fn, T>
52+
| ++++++
4353

4454
error: aborting due to 4 previous errors
4555

0 commit comments

Comments
 (0)