about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-02-11 12:37:12 -0800
committerEsteban Küber <esteban@kuber.com.ar>2020-02-11 12:37:12 -0800
commitbde96776a199064dec3c825ca5ada8f90e1e12d4 (patch)
tree989e99721bc07f01d73d410485f75cbad6534b35
parent24be307b53931a9824829f63aa65fa5c6042ed21 (diff)
downloadrust-bde96776a199064dec3c825ca5ada8f90e1e12d4.tar.gz
rust-bde96776a199064dec3c825ca5ada8f90e1e12d4.zip
Suggest named lifetime in ADT with hrtb
-rw-r--r--src/librustc_typeck/collect.rs52
-rw-r--r--src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs11
-rw-r--r--src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr34
3 files changed, 87 insertions, 10 deletions
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8d2b6512cfe..59077c2bc12 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 20f11ecf638..8a5777d4d7c 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<T> {
     fn get(&self, t: T) -> Self::A;
 }
 
-struct SomeStruct<I : for<'x> Foo<&'x isize>> {
+struct SomeStruct<I: for<'x> Foo<&'x isize>> {
     field: I::A
     //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
 }
 
+enum SomeEnum<I: for<'x> 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<I : for<'x> Foo<&'x isize>> {
 //     field: <I as for<'y> Foo<&'y isize>>::A
 // }
 
-struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> {
+struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> {
     field: <I as Foo<&'a isize>>::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 189b19461f4..c71bc70ea6c 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: <I as Foo<&'a isize>>::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(<I as Foo<&'a isize>>::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: <I as Foo<&'a isize>>::A },
+   |
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors