-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Add lifetime-aware support for Display
impl of Ident
#143185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3127,7 +3127,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { | |
} else { | ||
self.suggest_introducing_lifetime( | ||
&mut err, | ||
Some(lifetime_ref.ident.name.as_str()), | ||
Some(lifetime_ref.ident), | ||
|err, _, span, message, suggestion, span_suggs| { | ||
err.multipart_suggestion_verbose( | ||
message, | ||
|
@@ -3145,7 +3145,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { | |
fn suggest_introducing_lifetime( | ||
&self, | ||
err: &mut Diag<'_>, | ||
name: Option<&str>, | ||
name: Option<Ident>, | ||
suggest: impl Fn( | ||
&mut Diag<'_>, | ||
bool, | ||
|
@@ -3192,7 +3192,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { | |
let mut rm_inner_binders: FxIndexSet<Span> = Default::default(); | ||
let (span, sugg) = if span.is_empty() { | ||
let mut binder_idents: FxIndexSet<Ident> = Default::default(); | ||
binder_idents.insert(Ident::from_str(name.unwrap_or("'a"))); | ||
binder_idents | ||
.insert(name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime))); | ||
|
||
// We need to special case binders in the following situation: | ||
// 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> { | |
"".to_string(), | ||
|mut binders, (i, x)| { | ||
if i != 0 { | ||
binders += ", "; | ||
binders.push_str(", "); | ||
} | ||
binders += x.as_str(); | ||
binders.push_str(&x.to_string()); | ||
binders | ||
}, | ||
); | ||
|
@@ -3247,15 +3248,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { | |
.source_map() | ||
.span_through_char(span, '<') | ||
.shrink_to_hi(); | ||
let sugg = format!("{}, ", name.unwrap_or("'a")); | ||
let sugg = format!( | ||
"{}, ", | ||
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)) | ||
); | ||
(span, sugg) | ||
}; | ||
|
||
if higher_ranked { | ||
let message = Cow::from(format!( | ||
"consider making the {} lifetime-generic with a new `{}` lifetime", | ||
kind.descr(), | ||
name.unwrap_or("'a"), | ||
name.unwrap_or(Ident::with_dummy_span(sym::default_lifetime)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use interned |
||
)); | ||
should_continue = suggest( | ||
err, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -812,6 +812,7 @@ symbols! { | |
default_field_values, | ||
default_fn, | ||
default_lib_allocator, | ||
default_lifetime: "'a", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I pre-intern |
||
default_method_body_is_const, | ||
// -------------------------- | ||
// Lang items which are used only for experiments with auto traits with default bounds. | ||
|
@@ -2477,6 +2478,10 @@ impl Ident { | |
pub fn as_str(&self) -> &str { | ||
self.name.as_str() | ||
} | ||
|
||
pub fn as_lifetime(&self) -> Option<Ident> { | ||
self.name.as_lifetime().map(|sym| Ident::with_dummy_span(sym)) | ||
} | ||
xizheyin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
impl PartialEq for Ident { | ||
|
@@ -2546,6 +2551,14 @@ impl IdentPrinter { | |
|
||
impl fmt::Display for IdentPrinter { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
if let Some(lifetime) = self.symbol.as_lifetime() { | ||
f.write_str("'")?; | ||
if self.is_raw { | ||
f.write_str("r#")?; | ||
} | ||
return fmt::Display::fmt(&lifetime, f); | ||
} | ||
|
||
if self.is_raw { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When Ident starts with |
||
f.write_str("r#")?; | ||
} else if self.symbol == kw::DollarCrate { | ||
|
@@ -2640,6 +2653,11 @@ impl Symbol { | |
self == sym::empty | ||
} | ||
|
||
pub fn as_lifetime(self) -> Option<Symbol> { | ||
let name = self.as_str(); | ||
name.strip_prefix("'").map(Symbol::intern) | ||
} | ||
|
||
/// This method is supposed to be used in error messages, so it's expected to be | ||
/// identical to printing the original identifier token written in source code | ||
/// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag | ||
|
@@ -2946,7 +2964,13 @@ impl Ident { | |
/// We see this identifier in a normal identifier position, like variable name or a type. | ||
/// How was it written originally? Did it use the raw form? Let's try to guess. | ||
pub fn is_raw_guess(self) -> bool { | ||
self.name.can_be_raw() && self.is_reserved() | ||
if self.name == kw::StaticLifetime || self.name == kw::UnderscoreLifetime { | ||
false | ||
} else if let Some(lifetime) = self.as_lifetime() { | ||
lifetime.is_raw_guess() | ||
Comment on lines
+2969
to
+2970
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I use |
||
} else { | ||
self.name.can_be_raw() && self.is_reserved() | ||
} | ||
Comment on lines
+2967
to
+2973
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are two keywords that need to be excluded here. |
||
} | ||
|
||
/// 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> { | |
}) | ||
.collect() | ||
} | ||
|
||
/// A newtype around `Symbol` specifically for label printing. | ||
/// This ensures type safety when dealing with labels and provides | ||
/// specialized formatting behavior for label contexts. | ||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | ||
pub struct LabelSymbol(Symbol); | ||
Comment on lines
+3000
to
+3004
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I create a new type for label print. |
||
|
||
impl fmt::Display for LabelSymbol { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self.0.as_str()) | ||
} | ||
} | ||
|
||
impl From<Symbol> for LabelSymbol { | ||
fn from(symbol: Symbol) -> Self { | ||
LabelSymbol(symbol) | ||
} | ||
} | ||
|
||
impl From<Ident> for LabelSymbol { | ||
fn from(ident: Ident) -> Self { | ||
LabelSymbol(ident.name) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
//@ edition: 2021 | ||
fn a(_: dyn Trait + 'r#fn) { //~ ERROR use of undeclared lifetime name `'r#fn` [E0261] | ||
|
||
} | ||
|
||
trait Trait {} | ||
|
||
#[derive(Eq, PartialEq)] | ||
struct Test { | ||
a: &'r#fn str, | ||
//~^ ERROR use of undeclared lifetime name `'r#fn` [E0261] | ||
//~| ERROR use of undeclared lifetime name `'r#fn` [E0261] | ||
} | ||
|
||
trait Trait1<T> | ||
where T: for<'a> Trait1<T> + 'r#fn { } //~ ERROR use of undeclared lifetime name `'r#fn` [E0261] | ||
|
||
|
||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
error[E0261]: use of undeclared lifetime name `'r#fn` | ||
--> $DIR/error-lifetime-name-issue-143150.rs:2:21 | ||
| | ||
LL | fn a(_: dyn Trait + 'r#fn) { | ||
| ^^^^^ undeclared lifetime | ||
| | ||
help: consider introducing lifetime `'r#fn` here | ||
| | ||
LL | fn a<'r#fn>(_: dyn Trait + 'r#fn) { | ||
| +++++++ | ||
|
||
error[E0261]: use of undeclared lifetime name `'r#fn` | ||
--> $DIR/error-lifetime-name-issue-143150.rs:10:9 | ||
| | ||
LL | a: &'r#fn str, | ||
| ^^^^^ undeclared lifetime | ||
| | ||
help: consider introducing lifetime `'r#fn` here | ||
| | ||
LL | struct Test<'r#fn> { | ||
| +++++++ | ||
|
||
error[E0261]: use of undeclared lifetime name `'r#fn` | ||
--> $DIR/error-lifetime-name-issue-143150.rs:10:9 | ||
| | ||
LL | #[derive(Eq, PartialEq)] | ||
| -- lifetime `'r#fn` is missing in item created through this procedural macro | ||
LL | struct Test { | ||
LL | a: &'r#fn str, | ||
| ^^^^^ undeclared lifetime | ||
| | ||
help: consider introducing lifetime `'r#fn` here | ||
| | ||
LL | struct Test<'r#fn> { | ||
| +++++++ | ||
|
||
error[E0261]: use of undeclared lifetime name `'r#fn` | ||
--> $DIR/error-lifetime-name-issue-143150.rs:16:32 | ||
| | ||
LL | where T: for<'a> Trait1<T> + 'r#fn { } | ||
| ^^^^^ undeclared lifetime | ||
| | ||
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html | ||
help: consider making the bound lifetime-generic with a new `'r#fn` lifetime | ||
| | ||
LL - where T: for<'a> Trait1<T> + 'r#fn { } | ||
LL + where for<'r#fn, 'a> T: Trait1<T> + 'r#fn { } | ||
| | ||
help: consider introducing lifetime `'r#fn` here | ||
| | ||
LL | trait Trait1<'r#fn, T> | ||
| ++++++ | ||
|
||
error: aborting due to 4 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0261`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use
push_str
.