diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 2a450f4b4e8b1..59077c2bc1257 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -278,6 +278,17 @@ impl ItemCtxt<'tcx> {
pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
AstConv::ast_ty_to_ty(self, ast_ty)
}
+
+ pub fn hir_id(&self) -> hir::HirId {
+ self.tcx
+ .hir()
+ .as_local_hir_id(self.item_def_id)
+ .expect("Non-local call to local provider is_const_fn")
+ }
+
+ pub fn node(&self) -> hir::Node<'tcx> {
+ self.tcx.hir().get(self.hir_id())
+ }
}
impl AstConv<'tcx> for ItemCtxt<'tcx> {
@@ -290,15 +301,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
}
fn default_constness_for_trait_bounds(&self) -> ast::Constness {
- // FIXME: refactor this into a method
- let hir_id = self
- .tcx
- .hir()
- .as_local_hir_id(self.item_def_id)
- .expect("Non-local call to local provider is_const_fn");
-
- let node = self.tcx.hir().get(hir_id);
- if let Some(fn_like) = FnLikeNode::from_node(node) {
+ if let Some(fn_like) = FnLikeNode::from_node(self.node()) {
fn_like.constness()
} else {
ast::Constness::NotConst
@@ -352,14 +355,80 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
self.tcx().mk_projection(item_def_id, item_substs)
} else {
// There are no late-bound regions; we can just ignore the binder.
- struct_span_err!(
+ let mut err = struct_span_err!(
self.tcx().sess,
span,
E0212,
"cannot extract an associated type from a higher-ranked trait bound \
in this context"
- )
- .emit();
+ );
+
+ match self.node() {
+ 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(_)
+ | hir::Node::ImplItem(_) => {
+ err.span_suggestion(
+ span,
+ "use a fully qualified path with inferred lifetimes",
+ format!(
+ "{}::{}",
+ // Erase named lt, we want `::C`, not `::C`.
+ self.tcx.anonymize_late_bound_regions(&poly_trait_ref).skip_binder(),
+ item_segment.ident
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
+ err.emit();
self.tcx().types.err
}
}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed
new file mode 100644
index 0000000000000..760d2b433c87a
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.fixed
@@ -0,0 +1,37 @@
+#![allow(dead_code, unused_variables)]
+// run-rustfix
+// Check projection of an associated type out of a higher-ranked trait-bound
+// in the context of a function signature.
+
+pub trait Foo {
+ type A;
+
+ fn get(&self, t: T) -> Self::A;
+}
+
+fn foo2 Foo<&'x isize>>(
+ x: >::A)
+ //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
+{
+ // This case is illegal because we have to instantiate `'x`, and
+ // we don't know what region to instantiate it with.
+ //
+ // This could perhaps be made equivalent to the examples below,
+ // specifically for fn signatures.
+}
+
+fn foo3 Foo<&'x isize>>(
+ x: >::A)
+{
+ // OK, in this case we spelled out the precise regions involved, though we left one of
+ // them anonymous.
+}
+
+fn foo4<'a, I : for<'x> Foo<&'x isize>>(
+ x: >::A)
+{
+ // OK, in this case we spelled out the precise regions involved.
+}
+
+
+pub fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs
index bf13c410cc60b..6eb584ea645ac 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.rs
@@ -1,3 +1,5 @@
+#![allow(dead_code, unused_variables)]
+// run-rustfix
// Check projection of an associated type out of a higher-ranked trait-bound
// in the context of a function signature.
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr
index 09f4f99703f9c..f2137f68665db 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn.stderr
@@ -1,8 +1,8 @@
error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
- --> $DIR/associated-types-project-from-hrtb-in-fn.rs:11:8
+ --> $DIR/associated-types-project-from-hrtb-in-fn.rs:13:8
|
LL | x: I::A)
- | ^^^^
+ | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A`
error: aborting due to previous error
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
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed
new file mode 100644
index 0000000000000..acf32bccbecfd
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.fixed
@@ -0,0 +1,38 @@
+#![allow(dead_code)]
+// run-rustfix
+// Check projection of an associated type out of a higher-ranked trait-bound
+// in the context of a method definition in a trait.
+
+pub trait Foo {
+ type A;
+
+ fn get(&self, t: T) -> Self::A;
+}
+
+trait SomeTrait Foo<&'x isize>> {
+ fn some_method(&self, arg: >::A);
+ //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
+}
+
+trait AnotherTrait Foo<&'x isize>> {
+ fn some_method(&self, arg: >::A);
+}
+
+trait YetAnotherTrait Foo<&'x isize>> {
+ fn some_method<'a>(&self, arg: >::A);
+}
+
+trait Banana<'a> {
+ type Assoc: Default;
+}
+
+struct Peach(std::marker::PhantomData);
+
+impl Banana<'a>> Peach {
+ fn mango(&self) -> >::Assoc {
+ //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
+ Default::default()
+ }
+}
+
+pub fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs
index cb52c2b4f15d6..a249f89685e39 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.rs
@@ -1,3 +1,5 @@
+#![allow(dead_code)]
+// run-rustfix
// Check projection of an associated type out of a higher-ranked trait-bound
// in the context of a method definition in a trait.
@@ -20,4 +22,17 @@ trait YetAnotherTrait Foo<&'x isize>> {
fn some_method<'a>(&self, arg: >::A);
}
+trait Banana<'a> {
+ type Assoc: Default;
+}
+
+struct Peach(std::marker::PhantomData);
+
+impl Banana<'a>> Peach {
+ fn mango(&self) -> X::Assoc {
+ //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
+ Default::default()
+ }
+}
+
pub fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr
index e1c169028c5c4..a37fec244933c 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-trait-method.stderr
@@ -1,8 +1,14 @@
error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
- --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:11:32
+ --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:13:32
|
LL | fn some_method(&self, arg: I::A);
- | ^^^^
+ | ^^^^ help: use a fully qualified path with inferred lifetimes: `>::A`
-error: aborting due to previous error
+error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
+ --> $DIR/associated-types-project-from-hrtb-in-trait-method.rs:32:24
+ |
+LL | fn mango(&self) -> X::Assoc {
+ | ^^^^^^^^ help: use a fully qualified path with inferred lifetimes: `>::Assoc`
+
+error: aborting due to 2 previous errors