From e37d012a0629a20ea9a79efc8434d636f37487d9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 Dec 2021 14:10:59 -0800 Subject: [PATCH] Tighten span when suggesting lifetime on path --- compiler/rustc_ast_lowering/src/path.rs | 4 +- .../rustc_resolve/src/late/diagnostics.rs | 9 ++-- .../missing-lifetime-in-alias.rs | 34 +++++++++++++++ .../missing-lifetime-in-alias.stderr | 43 +++++++++++++++++++ src/test/ui/lint/reasons.stderr | 6 +-- 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs create mode 100644 src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 78afc33974826..46928a1846540 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -277,7 +277,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label let elided_lifetime_span = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. - path_span + // HACK: we use find_ancestor_inside to properly suggest elided spans in paths + // originating from macros, since the segment's span might be from a macro arg. + segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span) } else if generic_args.is_empty() { // If there are brackets, but not generic arguments, then use the opening bracket generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e74a7a9565080..4cd1b34bedc95 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2115,10 +2115,13 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let spans_suggs: Vec<_> = formatters .into_iter() .zip(spans_with_counts.iter()) - .filter_map(|(fmt, (span, _))| { - if let Some(formatter) = fmt { Some((formatter, span)) } else { None } + .filter_map(|(formatter, (span, _))| { + if let Some(formatter) = formatter { + Some((*span, formatter(name))) + } else { + None + } }) - .map(|(formatter, span)| (*span, formatter(name))) .collect(); if spans_suggs.is_empty() { // If all the spans come from macros, we cannot extract snippets and then diff --git a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs b/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs new file mode 100644 index 0000000000000..800f03302ed38 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.rs @@ -0,0 +1,34 @@ +#![feature(generic_associated_types)] +#![allow(unused)] + +trait Trait<'a> { + type Foo; + + type Bar<'b> + //~^ NOTE associated type defined here, with 1 lifetime parameter + //~| NOTE + where + Self: 'b; +} + +struct Impl<'a>(&'a ()); + +impl<'a> Trait<'a> for Impl<'a> { + type Foo = &'a (); + type Bar<'b> = &'b (); +} + +type A<'a> = Impl<'a>; + +type B<'a> = as Trait>::Foo; +//~^ ERROR missing lifetime specifier +//~| NOTE expected named lifetime parameter + +type C<'a, 'b> = as Trait>::Bar; +//~^ ERROR missing lifetime specifier +//~| ERROR missing generics for associated type +//~| NOTE expected named lifetime parameter +//~| NOTE these named lifetimes are available to use +//~| NOTE expected 1 lifetime argument + +fn main() {} diff --git a/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr new file mode 100644 index 0000000000000..f1b951fc82632 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/missing-lifetime-in-alias.stderr @@ -0,0 +1,43 @@ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-alias.rs:23:24 + | +LL | type B<'a> = as Trait>::Foo; + | ^^^^^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | type B<'a> = as Trait<'a>>::Foo; + | ~~~~~~~~~ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-alias.rs:27:28 + | +LL | type C<'a, 'b> = as Trait>::Bar; + | ^^^^^ expected named lifetime parameter + | +note: these named lifetimes are available to use + --> $DIR/missing-lifetime-in-alias.rs:27:8 + | +LL | type C<'a, 'b> = as Trait>::Bar; + | ^^ ^^ + +error[E0107]: missing generics for associated type `Trait::Bar` + --> $DIR/missing-lifetime-in-alias.rs:27:36 + | +LL | type C<'a, 'b> = as Trait>::Bar; + | ^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'b` + --> $DIR/missing-lifetime-in-alias.rs:7:10 + | +LL | type Bar<'b> + | ^^^ -- +help: add missing lifetime argument + | +LL | type C<'a, 'b> = as Trait>::Bar<'a>; + | ~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0106, E0107. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr index f797c89a03269..a692d6af703ea 100644 --- a/src/test/ui/lint/reasons.stderr +++ b/src/test/ui/lint/reasons.stderr @@ -1,8 +1,8 @@ warning: hidden lifetime parameters in types are deprecated - --> $DIR/reasons.rs:20:29 + --> $DIR/reasons.rs:20:34 | LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - | ^^^^^^^^^^^^^^ expected named lifetime parameter + | ^^^^^^^^^ expected named lifetime parameter | = note: explicit anonymous lifetimes aid reasoning about ownership note: the lint level is defined here @@ -13,7 +13,7 @@ LL | #![warn(elided_lifetimes_in_paths, help: consider using the `'_` lifetime | LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ warning: variable `Social_exchange_psychology` should have a snake case name --> $DIR/reasons.rs:30:9