From 4f25c618ad1873a5616358a2b023888c071deaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 20 Nov 2019 14:50:13 -0800 Subject: [PATCH 1/2] Rework raw ident suggestions Use heuristics to determine whethersuggesting raw identifiers is appropriate. Account for raw identifiers when printing a path in a `use` suggestion. --- src/librustc_parse/parser/diagnostics.rs | 15 +++++++- src/librustc_resolve/lib.rs | 7 ++-- src/libsyntax_pos/symbol.rs | 12 +++++-- src/test/ui/async-await/no-const-async.stderr | 5 --- ...ed-types-project-from-hrtb-explicit.stderr | 5 --- .../missing-close-brace-in-struct.stderr | 5 --- .../ui/parser/removed-syntax-field-let.stderr | 5 --- .../use-as-where-use-ends-with-mod-sep.stderr | 5 --- .../ui/suggestions/raw-name-use-suggestion.rs | 9 +++++ .../raw-name-use-suggestion.stderr | 36 +++++++++++++++++++ .../try-block/try-block-in-edition2015.stderr | 5 --- 11 files changed, 73 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/suggestions/raw-name-use-suggestion.rs create mode 100644 src/test/ui/suggestions/raw-name-use-suggestion.stderr diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 5036759da3f0c..e3a17c5c5e3b2 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -225,8 +225,21 @@ impl<'a> Parser<'a> { self.token.span, &format!("expected identifier, found {}", self.this_token_descr()), ); + let valid_follow = &[ + TokenKind::Eq, + TokenKind::Colon, + TokenKind::Comma, + TokenKind::Semi, + TokenKind::ModSep, + TokenKind::OpenDelim(token::DelimToken::Brace), + TokenKind::OpenDelim(token::DelimToken::Paren), + TokenKind::CloseDelim(token::DelimToken::Brace), + TokenKind::CloseDelim(token::DelimToken::Paren), + ]; if let token::Ident(name, false) = self.token.kind { - if Ident::new(name, self.token.span).is_raw_guess() { + if Ident::new(name, self.token.span).is_raw_guess() && + self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + { err.span_suggestion( self.token.span, "you can escape reserved keywords to use them as identifiers", diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c49db39643bc7..4e78dfa3e7273 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2893,15 +2893,16 @@ fn names_to_string(names: &[Name]) -> String { if i > 0 { result.push_str("::"); } + if name.is_used_keyword() && name.can_be_raw() { + result.push_str("r#"); + } result.push_str(&name.as_str()); } result } fn path_names_to_string(path: &Path) -> String { - names_to_string(&path.segments.iter() - .map(|seg| seg.ident.name) - .collect::>()) + names_to_string(&path.segments.iter().map(|seg| seg.ident.name).collect::>()) } /// A somewhat inefficient routine to obtain the name of a module. diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 979074f17c7e0..1e4bfe1b4caaf 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -1013,7 +1013,15 @@ pub mod sym { } impl Symbol { - fn is_used_keyword_2018(self) -> bool { + pub fn is_used_keyword(self) -> bool { + self.is_used_keyword_2015() || self.is_used_keyword_2018() + } + + pub fn is_used_keyword_2015(self) -> bool { + self >= kw::As && self <= kw::While + } + + pub fn is_used_keyword_2018(self) -> bool { self >= kw::Async && self <= kw::Dyn } @@ -1057,7 +1065,7 @@ impl Ident { /// Returns `true` if the token is a keyword used in the language. pub fn is_used_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name >= kw::As && self.name <= kw::While || + self.name.is_used_keyword_2015() || self.name.is_used_keyword_2018() && self.span.rust_2018() } diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index 95ded537ab35b..7ed822a5cd5a1 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -3,11 +3,6 @@ error: expected identifier, found keyword `async` | LL | pub const async fn x() {} | ^^^^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | pub const r#async fn x() {} - | ^^^^^^^ error: expected `:`, found keyword `fn` --> $DIR/no-const-async.rs:5:17 diff --git a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr index 17bd5b54738b9..aa0fa0e3c0a5e 100644 --- a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr +++ b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr @@ -3,11 +3,6 @@ error: expected identifier, found keyword `for` | LL | fn foo2(x: Foo<&'x isize>>::A) | ^^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | fn foo2(x: Foo<&'x isize>>::A) - | ^^^^^ error: expected one of `::` or `>`, found `Foo` --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:29 diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr index ce399dbbf456d..15ce94a6d00fa 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr @@ -12,11 +12,6 @@ error: expected identifier, found keyword `trait` | LL | trait T { | ^^^^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | r#trait T { - | ^^^^^^^ error: expected `:`, found `T` --> $DIR/missing-close-brace-in-struct.rs:4:7 diff --git a/src/test/ui/parser/removed-syntax-field-let.stderr b/src/test/ui/parser/removed-syntax-field-let.stderr index 0d15151b7d451..7de2c730a7069 100644 --- a/src/test/ui/parser/removed-syntax-field-let.stderr +++ b/src/test/ui/parser/removed-syntax-field-let.stderr @@ -3,11 +3,6 @@ error: expected identifier, found keyword `let` | LL | let foo: (), | ^^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | r#let foo: (), - | ^^^^^ error: expected `:`, found `foo` --> $DIR/removed-syntax-field-let.rs:2:9 diff --git a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr index 7a461cf630c33..192ab5eb7f965 100644 --- a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr +++ b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr @@ -3,11 +3,6 @@ error: expected identifier, found keyword `as` | LL | use std::any:: as foo; | ^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | use std::any:: r#as foo; - | ^^^^ error: expected one of `::`, `;`, or `as`, found `foo` --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:19 diff --git a/src/test/ui/suggestions/raw-name-use-suggestion.rs b/src/test/ui/suggestions/raw-name-use-suggestion.rs new file mode 100644 index 0000000000000..6c01383d9610d --- /dev/null +++ b/src/test/ui/suggestions/raw-name-use-suggestion.rs @@ -0,0 +1,9 @@ +mod foo { + pub fn r#let() {} + pub fn break() {} //~ ERROR expected identifier, found keyword `break` +} + +fn main() { + foo::let(); //~ ERROR expected identifier, found keyword `let` + r#break(); //~ ERROR cannot find function `break` in this scope +} diff --git a/src/test/ui/suggestions/raw-name-use-suggestion.stderr b/src/test/ui/suggestions/raw-name-use-suggestion.stderr new file mode 100644 index 0000000000000..58eb87c00a411 --- /dev/null +++ b/src/test/ui/suggestions/raw-name-use-suggestion.stderr @@ -0,0 +1,36 @@ +error: expected identifier, found keyword `break` + --> $DIR/raw-name-use-suggestion.rs:3:12 + | +LL | pub fn break() {} + | ^^^^^ expected identifier, found keyword + | +help: you can escape reserved keywords to use them as identifiers + | +LL | pub fn r#break() {} + | ^^^^^^^ + +error: expected identifier, found keyword `let` + --> $DIR/raw-name-use-suggestion.rs:7:10 + | +LL | foo::let(); + | ^^^ expected identifier, found keyword + | +help: you can escape reserved keywords to use them as identifiers + | +LL | foo::r#let(); + | ^^^^^ + +error[E0425]: cannot find function `break` in this scope + --> $DIR/raw-name-use-suggestion.rs:8:5 + | +LL | r#break(); + | ^^^^^^^ not found in this scope + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use foo::r#break; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr index 7547dadf9e209..9b4fe2c1205db 100644 --- a/src/test/ui/try-block/try-block-in-edition2015.stderr +++ b/src/test/ui/try-block/try-block-in-edition2015.stderr @@ -6,11 +6,6 @@ LL | let try_result: Option<_> = try { LL | LL | let x = 5; | ^^^ expected identifier, found keyword - | -help: you can escape reserved keywords to use them as identifiers - | -LL | r#let x = 5; - | ^^^^^ error[E0574]: expected struct, variant or union type, found macro `try` --> $DIR/try-block-in-edition2015.rs:4:33 From 180388670ee38f49578ef2b9eb878c95c4a31e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Nov 2019 17:08:04 -0800 Subject: [PATCH 2/2] review comments --- src/librustc_resolve/lib.rs | 2 +- src/libsyntax_pos/symbol.rs | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4e78dfa3e7273..9070f70ddd02d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2893,7 +2893,7 @@ fn names_to_string(names: &[Name]) -> String { if i > 0 { result.push_str("::"); } - if name.is_used_keyword() && name.can_be_raw() { + if Ident::with_dummy_span(*name).is_raw_guess() { result.push_str("r#"); } result.push_str(&name.as_str()); diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 1e4bfe1b4caaf..979074f17c7e0 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -1013,15 +1013,7 @@ pub mod sym { } impl Symbol { - pub fn is_used_keyword(self) -> bool { - self.is_used_keyword_2015() || self.is_used_keyword_2018() - } - - pub fn is_used_keyword_2015(self) -> bool { - self >= kw::As && self <= kw::While - } - - pub fn is_used_keyword_2018(self) -> bool { + fn is_used_keyword_2018(self) -> bool { self >= kw::Async && self <= kw::Dyn } @@ -1065,7 +1057,7 @@ impl Ident { /// Returns `true` if the token is a keyword used in the language. pub fn is_used_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name.is_used_keyword_2015() || + self.name >= kw::As && self.name <= kw::While || self.name.is_used_keyword_2018() && self.span.rust_2018() }