From bde96776a199064dec3c825ca5ada8f90e1e12d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 11 Feb 2020 12:37:12 -0800 Subject: [PATCH] Suggest named lifetime in ADT with hrtb --- src/librustc_typeck/collect.rs | 52 ++++++++++++++++--- ...iated-types-project-from-hrtb-in-struct.rs | 11 +++- ...d-types-project-from-hrtb-in-struct.stderr | 34 +++++++++++- 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8d2b6512cfe46..59077c2bc1257 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -364,14 +364,52 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { ); match self.node() { - hir::Node::Field(_) - | hir::Node::Variant(_) - | hir::Node::Ctor(_) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(..), .. }) => { - // The suggestion is only valid if this is not an ADT. + hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => { + let item = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id())); + match &item.kind { + hir::ItemKind::Enum(_, generics) + | hir::ItemKind::Struct(_, generics) + | hir::ItemKind::Union(_, generics) => { + // FIXME: look for an appropriate lt name if `'a` is already used + let (lt_sp, sugg) = match &generics.params[..] { + [] => (generics.span, "<'a>".to_string()), + [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()), + }; + let suggestions = vec![ + (lt_sp, sugg), + ( + span, + format!( + "{}::{}", + // Replace the existing lifetimes with a new named lifetime. + self.tcx + .replace_late_bound_regions(&poly_trait_ref, |_| { + self.tcx.mk_region(ty::ReEarlyBound( + ty::EarlyBoundRegion { + def_id: item_def_id, + index: 0, + name: Symbol::intern("'a"), + }, + )) + }) + .0, + item_segment.ident + ), + ), + ]; + err.multipart_suggestion( + "use a fully qualified path with explicit lifetimes", + suggestions, + Applicability::MaybeIncorrect, + ); + } + _ => {} + } } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(..), .. }) => {} hir::Node::Item(_) | hir::Node::ForeignItem(_) | hir::Node::TraitItem(_) diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 20f11ecf63823..8a5777d4d7cb5 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -7,18 +7,25 @@ pub trait Foo { fn get(&self, t: T) -> Self::A; } -struct SomeStruct Foo<&'x isize>> { +struct SomeStruct Foo<&'x isize>> { field: I::A //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } +enum SomeEnum Foo<&'x isize>> { + TupleVariant(I::A), + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + StructVariant { field: I::A }, + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context +} + // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. // struct AnotherStruct Foo<&'x isize>> { // field: Foo<&'y isize>>::A // } -struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> { +struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { field: >::A } diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index 189b19461f479..c71bc70ea6c4e 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -3,6 +3,38 @@ error[E0212]: cannot extract an associated type from a higher-ranked trait bound | LL | field: I::A | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | struct SomeStruct<'a, I: for<'x> Foo<&'x isize>> { +LL | field: >::A + | + +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:16:18 + | +LL | TupleVariant(I::A), + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | TupleVariant(>::A), + | + +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:18:28 + | +LL | StructVariant { field: I::A }, + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | TupleVariant(I::A), +LL | +LL | StructVariant { field: >::A }, + | -error: aborting due to previous error +error: aborting due to 3 previous errors