about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorWojciech Baranowski <wbaranowski@protonmail.com>2019-09-26 18:14:27 +0300
committerWojciech Baranowski <wbaranowski@protonmail.com>2019-09-27 21:01:47 +0300
commitf922483112e407d69c02eb653d7e4bc0ffe2cfa0 (patch)
treee7ef8818b2d387beb7dcded2a52729e3956ec409 /src
parent59367b074f1523353dddefa678ffe3cac9fd4e50 (diff)
downloadrust-f922483112e407d69c02eb653d7e4bc0ffe2cfa0.tar.gz
rust-f922483112e407d69c02eb653d7e4bc0ffe2cfa0.zip
Print ParamTy span when accessing a field (#52082)
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/expr.rs34
-rw-r--r--src/test/ui/typeck/issue-52082.rs54
-rw-r--r--src/test/ui/typeck/issue-52082.stderr99
3 files changed, 184 insertions, 3 deletions
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 97fcfd7151a..c2beaddecd5 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1393,9 +1393,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut err = self.no_such_field_err(field.span, field, expr_t);
 
             match expr_t.kind {
-                ty::Adt(def, _) if !def.is_enum() => {
-                    self.suggest_fields_on_recordish(&mut err, def, field);
-                }
                 ty::Array(_, len) => {
                     self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
                 }
@@ -1405,6 +1402,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => {}
             }
 
+            let deref_t = match expr_t.kind {
+                ty::Ref(_, ref_t, _) => ref_t,
+                _ => &expr_t
+            };
+            match deref_t.kind {
+                ty::Adt(def, _) if !def.is_enum() => {
+                    self.suggest_fields_on_recordish(&mut err, def, field);
+                }
+                ty::Param(param_ty) => {
+                    self.explain_param(&mut err, param_ty);
+                }
+                _ => {}
+            }
+
             if field.name == kw::Await {
                 // We know by construction that `<expr>.await` is either on Rust 2015
                 // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
@@ -1491,6 +1502,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit();
     }
 
+    fn explain_param(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        param: ty::ParamTy,
+    ) {
+        let generics = self.tcx.generics_of(self.body_id.owner_def_id());
+        let param_def_id = generics.type_param(&param, self.tcx).def_id;
+        let param_hir_id = match self.tcx.hir().as_local_hir_id(param_def_id) {
+            Some(x) => x,
+            None    => return,
+        };
+        let param_span = self.tcx.hir().span(param_hir_id);
+        let param_name = self.tcx.hir().ty_param_name(param_hir_id);
+
+        err.span_note(param_span, &format!("Type parameter '{}' was declared here", param_name));
+    }
+
     fn suggest_fields_on_recordish(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/src/test/ui/typeck/issue-52082.rs b/src/test/ui/typeck/issue-52082.rs
new file mode 100644
index 00000000000..c57e8149574
--- /dev/null
+++ b/src/test/ui/typeck/issue-52082.rs
@@ -0,0 +1,54 @@
+// Fix issue 52082: Confusing error if accidentially defining a type paramter with the same name as
+// an existing type
+//
+// To this end, make sure that when trying to retrieve a field of a (reference to) type parameter,
+// rustc points to the point where the parameter was defined.
+#[derive(Debug)]
+struct Point
+{
+    x: i32,
+    y: i32
+}
+
+impl Point
+{
+    fn add(a: &Point, b: &Point) -> Point
+    {
+        Point {x: a.x + b.x, y: a.y + b.y}
+    }
+}
+
+trait Eq
+{
+    fn equals_ref<T>(a: &T, b: &T) -> bool;
+    fn equals_val<T>(a: T, b: T) -> bool;
+}
+
+impl Eq for Point
+{
+    fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+    {
+        a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `&Point` [E0609]
+                                 //~|ERROR no field `x` on type `&Point` [E0609]
+                                 //~|ERROR no field `y` on type `&Point` [E0609]
+                                 //~|ERROR no field `y` on type `&Point` [E0609]
+    }
+
+    fn equals_val<Point>(a: Point, b: Point) -> bool
+    {
+        a.x == b.x && a.y == b.y //~ ERROR no field `x` on type `Point` [E0609]
+                                 //~|ERROR no field `x` on type `Point` [E0609]
+                                 //~|ERROR no field `y` on type `Point` [E0609]
+                                 //~|ERROR no field `y` on type `Point` [E0609]
+    }
+}
+
+fn main()
+{
+    let p1 = Point {x:  0, y: 10};
+    let p2 = Point {x: 20, y: 42};
+    println!("{:?}", Point::add(&p1, &p2));
+    println!("p1: {:?}, p2: {:?}", p1, p2);
+    println!("&p1 == &p2: {:?}", Point::equals_ref(&p1, &p2));
+    println!("p1 == p2: {:?}", Point::equals_val(p1, p2));
+}
diff --git a/src/test/ui/typeck/issue-52082.stderr b/src/test/ui/typeck/issue-52082.stderr
new file mode 100644
index 00000000000..b6b616630d5
--- /dev/null
+++ b/src/test/ui/typeck/issue-52082.stderr
@@ -0,0 +1,99 @@
+error[E0609]: no field `x` on type `&Point`
+  --> $DIR/issue-52082.rs:31:11
+   |
+LL |         a.x == b.x && a.y == b.y
+   |           ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:29:19
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `x` on type `&Point`
+  --> $DIR/issue-52082.rs:31:18
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                  ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:29:19
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `y` on type `&Point`
+  --> $DIR/issue-52082.rs:31:25
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                         ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:29:19
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `y` on type `&Point`
+  --> $DIR/issue-52082.rs:31:32
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                                ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:29:19
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `x` on type `Point`
+  --> $DIR/issue-52082.rs:39:11
+   |
+LL |         a.x == b.x && a.y == b.y
+   |           ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:37:19
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `x` on type `Point`
+  --> $DIR/issue-52082.rs:39:18
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                  ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:37:19
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `y` on type `Point`
+  --> $DIR/issue-52082.rs:39:25
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                         ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:37:19
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ^^^^^
+
+error[E0609]: no field `y` on type `Point`
+  --> $DIR/issue-52082.rs:39:32
+   |
+LL |         a.x == b.x && a.y == b.y
+   |                                ^
+   |
+note: Type parameter 'Point' was declared here
+  --> $DIR/issue-52082.rs:37:19
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ^^^^^
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0609`.