From 477dac3efb7b7a69fea585f81765ee3a678d35b0 Mon Sep 17 00:00:00 2001 From: Oleg Nosov Date: Sat, 8 Feb 2020 20:44:26 +0300 Subject: [PATCH 1/2] Suggest correct raw identifier in case of typo --- src/librustc_resolve/diagnostics.rs | 62 ++++++++++++------------ src/librustc_resolve/late/diagnostics.rs | 21 ++++---- src/test/ui/span/issue-68962.rs | 11 +++++ src/test/ui/span/issue-68962.stderr | 18 +++++++ 4 files changed, 72 insertions(+), 40 deletions(-) create mode 100644 src/test/ui/span/issue-68962.rs create mode 100644 src/test/ui/span/issue-68962.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 075dca8f01d7b..40edcea9c8b2b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -33,12 +33,12 @@ type Res = def::Res; crate type Suggestion = (Vec<(Span, String)>, String, Applicability); crate struct TypoSuggestion { - pub candidate: Symbol, + pub candidate: Ident, pub res: Res, } impl TypoSuggestion { - crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { + crate fn from_res(candidate: Ident, res: Res) -> TypoSuggestion { TypoSuggestion { candidate, res } } } @@ -107,7 +107,7 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) { - names.push(TypoSuggestion::from_res(key.ident.name, res)); + names.push(TypoSuggestion::from_res(key.ident, res)); } } } @@ -509,7 +509,7 @@ impl<'a> Resolver<'a> { .get(&expn_id) .into_iter() .flatten() - .map(|ident| TypoSuggestion::from_res(ident.name, res)), + .map(|ident| TypoSuggestion::from_res(*ident, res)), ); } } @@ -525,11 +525,9 @@ impl<'a> Resolver<'a> { false, false, ) { - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::from_res(*name, res)), - ); + suggestions.extend(ext.helper_attrs.iter().map(|name| { + TypoSuggestion::from_res(Ident::new(*name, derive.span), res) + })); } } } @@ -538,8 +536,7 @@ impl<'a> Resolver<'a> { if let LegacyScope::Binding(legacy_binding) = legacy_scope { let res = legacy_binding.binding.res(); if filter_fn(res) { - suggestions - .push(TypoSuggestion::from_res(legacy_binding.ident.name, res)) + suggestions.push(TypoSuggestion::from_res(legacy_binding.ident, res)) } } } @@ -557,7 +554,7 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_attrs .iter() - .map(|ident| TypoSuggestion::from_res(ident.name, res)), + .map(|ident| TypoSuggestion::from_res(*ident, res)), ); } } @@ -565,24 +562,24 @@ impl<'a> Resolver<'a> { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { let res = binding.res(); - filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) + let span = binding.span; + filter_fn(res) + .then_some(TypoSuggestion::from_res(Ident::new(*name, span), res)) }, )); } Scope::BuiltinAttrs => { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin); if filter_fn(res) { - suggestions.extend( - BUILTIN_ATTRIBUTES - .iter() - .map(|(name, ..)| TypoSuggestion::from_res(*name, res)), - ); + suggestions.extend(BUILTIN_ATTRIBUTES.iter().map(|(name, ..)| { + TypoSuggestion::from_res(Ident::with_dummy_span(*name), res) + })); } } Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)); - filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res)) + filter_fn(res).then_some(TypoSuggestion::from_res(*ident, res)) })); } Scope::ToolPrelude => { @@ -590,7 +587,7 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_tools .iter() - .map(|ident| TypoSuggestion::from_res(ident.name, res)), + .map(|ident| TypoSuggestion::from_res(*ident, res)), ); } Scope::StdLibPrelude => { @@ -608,7 +605,8 @@ impl<'a> Resolver<'a> { let primitive_types = &this.primitive_type_table.primitive_types; suggestions.extend(primitive_types.iter().flat_map(|(name, prim_ty)| { let res = Res::PrimTy(*prim_ty); - filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) + filter_fn(res) + .then_some(TypoSuggestion::from_res(Ident::with_dummy_span(*name), res)) })) } } @@ -620,12 +618,12 @@ impl<'a> Resolver<'a> { suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - suggestions.iter().map(|suggestion| &suggestion.candidate), + suggestions.iter().map(|suggestion| &suggestion.candidate.name), &ident.as_str(), None, ) { Some(found) if found != ident.name => { - suggestions.into_iter().find(|suggestion| suggestion.candidate == found) + suggestions.into_iter().find(|suggestion| suggestion.candidate.name == found) } _ => None, } @@ -805,7 +803,7 @@ impl<'a> Resolver<'a> { ) -> bool { if let Some(suggestion) = suggestion { // We shouldn't suggest underscore. - if suggestion.candidate == kw::Underscore { + if suggestion.candidate.name == kw::Underscore { return false; } @@ -814,12 +812,6 @@ impl<'a> Resolver<'a> { suggestion.res.article(), suggestion.res.descr() ); - err.span_suggestion( - span, - &msg, - suggestion.candidate.to_string(), - Applicability::MaybeIncorrect, - ); let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate { LOCAL_CRATE => self.definitions.opt_span(def_id), _ => Some( @@ -828,16 +820,24 @@ impl<'a> Resolver<'a> { .def_span(self.cstore().get_span_untracked(def_id, self.session)), ), }); + let candidate = def_span + .as_ref() + .map(|span| Ident::new(suggestion.candidate.name, *span)) + .unwrap_or(suggestion.candidate); + + err.span_suggestion(span, &msg, candidate.to_string(), Applicability::MaybeIncorrect); + if let Some(span) = def_span { err.span_label( span, &format!( "similarly named {} `{}` defined here", suggestion.res.descr(), - suggestion.candidate.as_str(), + candidate.to_string(), ), ); } + return true; } false diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 6ec4a13500edc..aa093c7c65894 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -647,7 +647,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { // Locals and type parameters for (ident, &res) in &rib.bindings { if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); + names.push(TypoSuggestion::from_res(*ident, res)); } } // Items in scope @@ -672,7 +672,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ); if filter_fn(crate_mod) { - Some(TypoSuggestion::from_res(ident.name, crate_mod)) + Some(TypoSuggestion::from_res(*ident, crate_mod)) } else { None } @@ -689,11 +689,14 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } // Add primitive types to the mix if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend( - self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| { - TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty)) - }), - ) + names.extend(self.r.primitive_type_table.primitive_types.iter().map( + |(name, prim_ty)| { + TypoSuggestion::from_res( + Ident::with_dummy_span(*name), + Res::PrimTy(*prim_ty), + ) + }, + )) } } else { // Search in module. @@ -712,12 +715,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate), + names.iter().map(|suggestion| &suggestion.candidate.name), &name.as_str(), None, ) { Some(found) if found != name => { - names.into_iter().find(|suggestion| suggestion.candidate == found) + names.into_iter().find(|suggestion| suggestion.candidate.name == found) } _ => None, } diff --git a/src/test/ui/span/issue-68962.rs b/src/test/ui/span/issue-68962.rs new file mode 100644 index 0000000000000..0b581308f6628 --- /dev/null +++ b/src/test/ui/span/issue-68962.rs @@ -0,0 +1,11 @@ +fn r#fn() {} + +fn main() { + let r#final = 1; + + // Should correctly suggest variable defined using raw identifier. + fina; //~ ERROR cannot find value + + // Should correctly suggest function defined using raw identifier. + f(); //~ ERROR cannot find function +} diff --git a/src/test/ui/span/issue-68962.stderr b/src/test/ui/span/issue-68962.stderr new file mode 100644 index 0000000000000..ca4c154fb07eb --- /dev/null +++ b/src/test/ui/span/issue-68962.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `fina` in this scope + --> $DIR/issue-68962.rs:7:5 + | +LL | fina; + | ^^^^ help: a local variable with a similar name exists: `r#final` + +error[E0425]: cannot find function `f` in this scope + --> $DIR/issue-68962.rs:10:5 + | +LL | fn r#fn() {} + | ------------ similarly named function `r#fn` defined here +... +LL | f(); + | ^ help: a function with a similar name exists: `r#fn` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. From 4bf61168242a9d2525ab2975450a6a19644c9383 Mon Sep 17 00:00:00 2001 From: Oleg Nosov Date: Fri, 21 Feb 2020 16:50:16 +0300 Subject: [PATCH 2/2] Add `to_stringified_ident_guess` to `Symbol` and suggest correct raw identifier in notes and help messages --- .../infer/error_reporting/need_type_info.rs | 24 ++++--- src/librustc/infer/error_reporting/note.rs | 10 ++- src/librustc/middle/stability.rs | 2 +- .../traits/error_reporting/suggestions.rs | 30 +++++---- src/librustc_lint/nonstandard_style.rs | 3 +- .../diagnostics/conflict_errors.rs | 2 +- .../borrow_check/diagnostics/mod.rs | 4 +- src/librustc_parse/parser/module.rs | 4 +- src/librustc_resolve/diagnostics.rs | 62 ++++++++++--------- src/librustc_resolve/late/diagnostics.rs | 21 +++---- src/librustc_span/symbol.rs | 7 +++ src/librustc_typeck/check/wfcheck.rs | 16 +++-- src/test/ui/issues/issue-69053.rs | 6 ++ src/test/ui/issues/issue-69053.stderr | 25 ++++++++ 14 files changed, 144 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/issues/issue-69053.rs create mode 100644 src/test/ui/issues/issue-69053.stderr diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 9947dea234096..e58274ce64d67 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FunctionRetTy, HirId, Local, Pat}; use rustc_span::source_map::DesugaringKind; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::{symbol::kw, Symbol}; use std::borrow::Cow; struct FindLocalByTypeVisitor<'a, 'tcx> { @@ -108,7 +108,7 @@ fn closure_return_type_suggestion( output: &FunctionRetTy<'_>, body: &Body<'_>, descr: &str, - name: &str, + name: Symbol, ret: &str, parent_name: Option, parent_descr: Option<&str>, @@ -129,7 +129,7 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label(span, InferCtxt::missing_type_msg(name, &descr, parent_name, parent_descr)); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -320,7 +320,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &decl.output, &body, &descr, - &name, + Symbol::intern(&name), &ret, parent_name, parent_descr, @@ -444,7 +444,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), + InferCtxt::missing_type_msg( + Symbol::intern(&name), + &descr, + parent_name, + parent_descr, + ), ); } @@ -518,17 +523,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::missing_type_msg(Symbol::intern(&name), &descr, parent_name, parent_descr), + ); err } fn missing_type_msg( - type_name: &str, + type_name: Symbol, descr: &str, parent_name: Option, parent_descr: Option<&str>, ) -> Cow<'static, str> { - if type_name == "_" { + if type_name == kw::Underscore { "cannot infer type".into() } else { let parent_desc = if let Some(parent_name) = parent_name { diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 11dda71b8cb89..ca3d87012d658 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -36,7 +36,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - err.span_note(span, &format!("...so that closure can access `{}`", var_name)); + err.span_note( + span, + &format!( + "...so that closure can access `{}`", + var_name.to_stringified_ident_guess() + ), + ); } infer::InfStackClosure(span) => { err.span_note(span, "...so that closure does not outlive its stack frame"); @@ -53,7 +59,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &format!( "...so that captured variable `{}` does not outlive the \ enclosing closure", - self.tcx.hir().name(id) + self.tcx.hir().name(id).to_stringified_ident_guess() ), ); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 7cbe77b9e82f0..afde0d9615525 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -161,7 +161,7 @@ pub fn deprecation_suggestion( diag.span_suggestion( span, "replace the use of the deprecated item", - suggestion.to_string(), + suggestion.to_stringified_ident_guess(), Applicability::MachineApplicable, ); } diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index b2973c642a21e..43177bc375992 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -143,12 +143,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { // Missing generic type parameter bound. let param_name = self_ty.to_string(); + let param = Symbol::intern(¶m_name); let constraint = trait_ref.print_only_trait_path().to_string(); if suggest_constraining_type_param( self.tcx, generics, &mut err, - ¶m_name, + param, &constraint, self.tcx.sess.source_map(), *span, @@ -1657,7 +1658,7 @@ pub fn suggest_constraining_type_param( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, err: &mut DiagnosticBuilder<'_>, - param_name: &str, + param_name: Symbol, constraint: &str, source_map: &SourceMap, span: Span, @@ -1665,7 +1666,7 @@ pub fn suggest_constraining_type_param( ) -> bool { let restrict_msg = "consider further restricting this bound"; if let Some(param) = - generics.params.iter().filter(|p| p.name.ident().as_str() == param_name).next() + generics.params.iter().filter(|p| p.name.ident().as_str() == param_name.as_str()).next() { if def_id == tcx.lang_items().sized_trait() { // Type parameters are already `Sized` by default. @@ -1673,14 +1674,14 @@ pub fn suggest_constraining_type_param( param.span, &format!("this type parameter needs to be `{}`", constraint), ); - } else if param_name.starts_with("impl ") { + } else if param_name.as_str().starts_with("impl ") { // `impl Trait` in argument: // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}` err.span_suggestion( param.span, restrict_msg, // `impl CurrentTrait + MissingTrait` - format!("{} + {}", param_name, constraint), + format!("{} + {}", param_name.to_stringified_ident_guess(), constraint), Applicability::MachineApplicable, ); } else if generics.where_clause.predicates.is_empty() && param.bounds.is_empty() { @@ -1690,7 +1691,7 @@ pub fn suggest_constraining_type_param( err.span_suggestion( param.span, "consider restricting this bound", - format!("{}: {}", param_name, constraint), + format!("{}: {}", param_name.to_stringified_ident_guess(), constraint), Applicability::MachineApplicable, ); } else if !generics.where_clause.predicates.is_empty() { @@ -1699,8 +1700,11 @@ pub fn suggest_constraining_type_param( // `fn foo(t: T) where T: Debug, T: Trait {}` err.span_suggestion( generics.where_clause.span().unwrap().shrink_to_hi(), - &format!("consider further restricting type parameter `{}`", param_name), - format!(", {}: {}", param_name, constraint), + &format!( + "consider further restricting type parameter `{}`", + param_name.to_stringified_ident_guess() + ), + format!(", {}: {}", param_name.to_stringified_ident_guess(), constraint), Applicability::MachineApplicable, ); } else { @@ -1716,13 +1720,17 @@ pub fn suggest_constraining_type_param( err.span_suggestion( span, restrict_msg, - format!("{}: {} + ", param_name, constraint), + format!("{}: {} + ", param_name.to_stringified_ident_guess(), constraint), Applicability::MachineApplicable, ); } else { err.span_label( param.span, - &format!("consider adding a `where {}: {}` bound", param_name, constraint), + &format!( + "consider adding a `where {}: {}` bound", + param_name.to_stringified_ident_guess(), + constraint + ), ); } } diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 6fdbfea7f03b3..ff010d828404d 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -107,7 +107,8 @@ impl NonCamelCaseTypes { let name = &ident.name.as_str(); if !is_camel_case(name) { - let msg = format!("{} `{}` should have an upper camel case name", sort, name); + let msg = + format!("{} `{}` should have an upper camel case name", sort, name.to_string()); cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, &msg) .span_suggestion( ident.span, diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index b49e7b7f0d9f8..82396b33b4ce1 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -220,7 +220,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { tcx, generics, &mut err, - ¶m.name.as_str(), + param.name, "Copy", tcx.sess.source_map(), span, diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index ba4af59eede06..ae0d7a255cad2 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -107,7 +107,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "closure cannot be invoked more than once because it moves the \ variable `{}` out of its environment", - name, + name.to_stringified_ident_guess(), ), ); return; @@ -129,7 +129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "closure cannot be moved more than once as it is not `Copy` due to \ moving the variable `{}` out of its environment", - name + name.to_stringified_ident_guess() ), ); } diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 6ce94d3c6793c..5e460d23f681b 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -6,7 +6,7 @@ use crate::{new_sub_parser_from_file, DirectoryOwnership}; use rustc_errors::PResult; use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP}; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use syntax::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use syntax::attr; use syntax::token::{self, TokenKind}; @@ -170,7 +170,7 @@ impl<'a> Parser<'a> { &format!( "... or maybe `use` the module `{}` instead \ of possibly redeclaring it", - paths.name + Symbol::intern(&paths.name).to_stringified_ident_guess() ), ); } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 40edcea9c8b2b..369e69d0748f1 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -33,12 +33,12 @@ type Res = def::Res; crate type Suggestion = (Vec<(Span, String)>, String, Applicability); crate struct TypoSuggestion { - pub candidate: Ident, + pub candidate: Symbol, pub res: Res, } impl TypoSuggestion { - crate fn from_res(candidate: Ident, res: Res) -> TypoSuggestion { + crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { TypoSuggestion { candidate, res } } } @@ -107,7 +107,7 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) { - names.push(TypoSuggestion::from_res(key.ident, res)); + names.push(TypoSuggestion::from_res(key.ident.name, res)); } } } @@ -273,7 +273,7 @@ impl<'a> Resolver<'a> { let help_msg = format!( "if you meant to match on a variant or a `const` item, consider \ making the path in the pattern qualified: `?::{}`", - name, + name.to_stringified_ident_guess(), ); err.span_help(span, &help_msg); } @@ -509,7 +509,7 @@ impl<'a> Resolver<'a> { .get(&expn_id) .into_iter() .flatten() - .map(|ident| TypoSuggestion::from_res(*ident, res)), + .map(|ident| TypoSuggestion::from_res(ident.name, res)), ); } } @@ -525,9 +525,11 @@ impl<'a> Resolver<'a> { false, false, ) { - suggestions.extend(ext.helper_attrs.iter().map(|name| { - TypoSuggestion::from_res(Ident::new(*name, derive.span), res) - })); + suggestions.extend( + ext.helper_attrs + .iter() + .map(|name| TypoSuggestion::from_res(*name, res)), + ); } } } @@ -536,7 +538,8 @@ impl<'a> Resolver<'a> { if let LegacyScope::Binding(legacy_binding) = legacy_scope { let res = legacy_binding.binding.res(); if filter_fn(res) { - suggestions.push(TypoSuggestion::from_res(legacy_binding.ident, res)) + suggestions + .push(TypoSuggestion::from_res(legacy_binding.ident.name, res)) } } } @@ -554,7 +557,7 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_attrs .iter() - .map(|ident| TypoSuggestion::from_res(*ident, res)), + .map(|ident| TypoSuggestion::from_res(ident.name, res)), ); } } @@ -562,24 +565,24 @@ impl<'a> Resolver<'a> { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { let res = binding.res(); - let span = binding.span; - filter_fn(res) - .then_some(TypoSuggestion::from_res(Ident::new(*name, span), res)) + filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) }, )); } Scope::BuiltinAttrs => { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin); if filter_fn(res) { - suggestions.extend(BUILTIN_ATTRIBUTES.iter().map(|(name, ..)| { - TypoSuggestion::from_res(Ident::with_dummy_span(*name), res) - })); + suggestions.extend( + BUILTIN_ATTRIBUTES + .iter() + .map(|(name, ..)| TypoSuggestion::from_res(*name, res)), + ); } } Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)); - filter_fn(res).then_some(TypoSuggestion::from_res(*ident, res)) + filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res)) })); } Scope::ToolPrelude => { @@ -587,7 +590,7 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_tools .iter() - .map(|ident| TypoSuggestion::from_res(*ident, res)), + .map(|ident| TypoSuggestion::from_res(ident.name, res)), ); } Scope::StdLibPrelude => { @@ -605,8 +608,7 @@ impl<'a> Resolver<'a> { let primitive_types = &this.primitive_type_table.primitive_types; suggestions.extend(primitive_types.iter().flat_map(|(name, prim_ty)| { let res = Res::PrimTy(*prim_ty); - filter_fn(res) - .then_some(TypoSuggestion::from_res(Ident::with_dummy_span(*name), res)) + filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) })) } } @@ -618,12 +620,12 @@ impl<'a> Resolver<'a> { suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - suggestions.iter().map(|suggestion| &suggestion.candidate.name), + suggestions.iter().map(|suggestion| &suggestion.candidate), &ident.as_str(), None, ) { Some(found) if found != ident.name => { - suggestions.into_iter().find(|suggestion| suggestion.candidate.name == found) + suggestions.into_iter().find(|suggestion| suggestion.candidate == found) } _ => None, } @@ -803,7 +805,7 @@ impl<'a> Resolver<'a> { ) -> bool { if let Some(suggestion) = suggestion { // We shouldn't suggest underscore. - if suggestion.candidate.name == kw::Underscore { + if suggestion.candidate == kw::Underscore { return false; } @@ -822,10 +824,10 @@ impl<'a> Resolver<'a> { }); let candidate = def_span .as_ref() - .map(|span| Ident::new(suggestion.candidate.name, *span)) - .unwrap_or(suggestion.candidate); + .map(|span| Ident::new(suggestion.candidate, *span).to_string()) + .unwrap_or_else(|| suggestion.candidate.to_stringified_ident_guess()); - err.span_suggestion(span, &msg, candidate.to_string(), Applicability::MaybeIncorrect); + err.span_suggestion(span, &msg, candidate.clone(), Applicability::MaybeIncorrect); if let Some(span) = def_span { err.span_label( @@ -833,7 +835,7 @@ impl<'a> Resolver<'a> { &format!( "similarly named {} `{}` defined here", suggestion.res.descr(), - candidate.to_string(), + candidate, ), ); } @@ -1477,7 +1479,11 @@ crate fn show_candidates( // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if found_use { "" } else { "\n" }; - *candidate = format!("use {};\n{}", candidate, additional_newline); + *candidate = format!( + "use {};\n{}", + Symbol::intern(candidate).to_stringified_ident_guess(), + additional_newline + ); } err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index aa093c7c65894..6ec4a13500edc 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -647,7 +647,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { // Locals and type parameters for (ident, &res) in &rib.bindings { if filter_fn(res) { - names.push(TypoSuggestion::from_res(*ident, res)); + names.push(TypoSuggestion::from_res(ident.name, res)); } } // Items in scope @@ -672,7 +672,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ); if filter_fn(crate_mod) { - Some(TypoSuggestion::from_res(*ident, crate_mod)) + Some(TypoSuggestion::from_res(ident.name, crate_mod)) } else { None } @@ -689,14 +689,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } // Add primitive types to the mix if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend(self.r.primitive_type_table.primitive_types.iter().map( - |(name, prim_ty)| { - TypoSuggestion::from_res( - Ident::with_dummy_span(*name), - Res::PrimTy(*prim_ty), - ) - }, - )) + names.extend( + self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| { + TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty)) + }), + ) } } else { // Search in module. @@ -715,12 +712,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate.name), + names.iter().map(|suggestion| &suggestion.candidate), &name.as_str(), None, ) { Some(found) if found != name => { - names.into_iter().find(|suggestion| suggestion.candidate.name == found) + names.into_iter().find(|suggestion| suggestion.candidate == found) } _ => None, } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 931a3c15cf08e..0f24e0e4e19cb 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -966,6 +966,13 @@ impl Symbol { }) } + /// Represent as stringified identifier, guessing raw formatting + /// (`r#`) if ident can be interpreted as a raw identifier according + /// to the edition used by current crate. + pub fn to_stringified_ident_guess(&self) -> String { + Ident::with_dummy_span(*self).to_string() + } + pub fn as_u32(self) -> u32 { self.0.as_u32() } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index fc194e3af97f2..5d09a64b36d1f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1100,11 +1100,14 @@ fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: ast::Name) { let msg = if let Some(def_id) = suggested_marker_id { format!( "consider removing `{}`, referring to it in a field, or using a marker such as `{}`", - param_name, + param_name.to_stringified_ident_guess(), tcx.def_path_str(def_id), ) } else { - format!("consider removing `{}` or referring to it in a field", param_name) + format!( + "consider removing `{}` or referring to it in a field", + param_name.to_stringified_ident_guess() + ) }; err.help(&msg); err.emit(); @@ -1218,8 +1221,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'_> { - let mut err = - struct_span_err!(tcx.sess, span, E0392, "parameter `{}` is never used", param_name); + let mut err = struct_span_err!( + tcx.sess, + span, + E0392, + "parameter `{}` is never used", + param_name.to_stringified_ident_guess() + ); err.span_label(span, "unused parameter"); err } diff --git a/src/test/ui/issues/issue-69053.rs b/src/test/ui/issues/issue-69053.rs new file mode 100644 index 0000000000000..d36d7577af2d1 --- /dev/null +++ b/src/test/ui/issues/issue-69053.rs @@ -0,0 +1,6 @@ +struct r#struct; +//~^ WARNING should have an upper camel case name +//~^^ WARNING should have an upper camel case name +//~^^^ ERROR parameter `fn` is never used + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/issues/issue-69053.stderr b/src/test/ui/issues/issue-69053.stderr new file mode 100644 index 0000000000000..ff29f6df3f36b --- /dev/null +++ b/src/test/ui/issues/issue-69053.stderr @@ -0,0 +1,25 @@ +warning: type `struct` should have an upper camel case name + --> $DIR/issue-69053.rs:1:8 + | +LL | struct r#struct; + | ^^^^^^^^ help: convert the identifier to upper camel case: `Struct` + | + = note: `#[warn(non_camel_case_types)]` on by default + +warning: type parameter `fn` should have an upper camel case name + --> $DIR/issue-69053.rs:1:17 + | +LL | struct r#struct; + | ^^^^ help: convert the identifier to upper camel case: `Fn` + +error[E0392]: parameter `fn` is never used + --> $DIR/issue-69053.rs:1:17 + | +LL | struct r#struct; + | ^^^^ unused parameter + | + = help: consider removing `r#fn`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0392`.