about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2019-11-05 09:49:58 +0100
committerGitHub <noreply@github.com>2019-11-05 09:49:58 +0100
commit1d5cb17ebec9723f5d24e6bc41835a24dbb373cb (patch)
tree740e715c2d4538817c3a8a1f2e06f64e69f38342
parentd32a262ab8ec6d81f443b5d73b549361221c8d4e (diff)
parent8c909344ed19c9f9a51f82c8e270ded09671fd8b (diff)
downloadrust-1d5cb17ebec9723f5d24e6bc41835a24dbb373cb.tar.gz
rust-1d5cb17ebec9723f5d24e6bc41835a24dbb373cb.zip
Rollup merge of #66042 - ohadravid:suggest-correct-code-when-ref-current-trait, r=estebank
Suggest correct code when encountering an incorrect trait bound referencing the current trait

Fixes #65985 and also improves the suggestion for code like this:

```
trait Grab {
    type Value;
    fn grab(&self) -> Grab::Value;
}
```

To suggest `<Self as Grab>::Value`.

I wasn't sure which of the syntax versions is better (`<Self as ..>::` vs `Self::`), so I used the former simply because it was less change to the existing code.

r? @estebank
-rw-r--r--src/librustc_typeck/astconv.rs28
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/collect.rs4
-rw-r--r--src/test/ui/associated-types/associated-types-in-ambiguous-context.rs10
-rw-r--r--src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr18
5 files changed, 60 insertions, 4 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index aa05a08686a..b14121da79f 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -43,6 +43,8 @@ pub struct PathSeg(pub DefId, pub usize);
 pub trait AstConv<'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
+    fn item_def_id(&self) -> Option<DefId>;
+
     /// Returns predicates in scope of the form `X: Foo`, where `X` is
     /// a type parameter `X` with the given id `def_id`. This is a
     /// subset of the full set of predicates.
@@ -1759,17 +1761,41 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                    -> Ty<'tcx>
     {
         let tcx = self.tcx();
+
         let trait_def_id = tcx.parent(item_def_id).unwrap();
 
+        debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
+
         self.prohibit_generics(slice::from_ref(item_segment));
 
         let self_ty = if let Some(ty) = opt_self_ty {
             ty
         } else {
             let path_str = tcx.def_path_str(trait_def_id);
+
+            let def_id = self.item_def_id();
+
+            debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
+
+            let parent_def_id = def_id.and_then(|def_id| tcx.hir().as_local_hir_id(def_id))
+                .map(|hir_id| tcx.hir().get_parent_did(hir_id));
+
+            debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
+
+            // If the trait in segment is the same as the trait defining the item,
+            // use the `<Self as ..>` syntax in the error.
+            let is_part_of_self_trait_constraints = def_id == Some(trait_def_id);
+            let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
+
+            let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+                "Self"
+            } else {
+                "Type"
+            };
+
             self.report_ambiguous_associated_type(
                 span,
-                "Type",
+                type_name,
                 &path_str,
                 item_segment.ident.name,
             );
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f7132cd868a..a2af29aef09 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2279,6 +2279,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         self.tcx
     }
 
+    fn item_def_id(&self) -> Option<DefId> {
+        None
+    }
+
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
         let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 001d98aece2..7ef842cb757 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -182,6 +182,10 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         self.tcx
     }
 
+    fn item_def_id(&self) -> Option<DefId> {
+        Some(self.item_def_id)
+    }
+
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         self.tcx
             .at(span)
diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs
index 1b1ea9d52a9..51b53908f98 100644
--- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs
+++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs
@@ -10,6 +10,16 @@ trait Grab {
     type Value;
     fn grab(&self) -> Grab::Value;
     //~^ ERROR ambiguous associated type
+
+    fn get(&self) -> Get::Value;
+    //~^ ERROR ambiguous associated type
+}
+
+trait Bar {}
+
+trait Foo where Foo::Assoc: Bar {
+//~^ ERROR ambiguous associated type
+    type Assoc;
 }
 
 type X = std::ops::Deref::Target;
diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
index 83667b54807..77835c5f676 100644
--- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -5,7 +5,13 @@ LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
    |                                    ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
 
 error[E0223]: ambiguous associated type
-  --> $DIR/associated-types-in-ambiguous-context.rs:15:10
+  --> $DIR/associated-types-in-ambiguous-context.rs:20:17
+   |
+LL | trait Foo where Foo::Assoc: Bar {
+   |                 ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc`
+
+error[E0223]: ambiguous associated type
+  --> $DIR/associated-types-in-ambiguous-context.rs:25:10
    |
 LL | type X = std::ops::Deref::Target;
    |          ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as std::ops::Deref>::Target`
@@ -14,8 +20,14 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:11:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Grab>::Value`
+   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+
+error[E0223]: ambiguous associated type
+  --> $DIR/associated-types-in-ambiguous-context.rs:14:22
+   |
+LL |     fn get(&self) -> Get::Value;
+   |                      ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0223`.