about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-28 22:12:07 +0200
committerGitHub <noreply@github.com>2019-09-28 22:12:07 +0200
commit6145757a264cea1e4adf019a6b70fd8206c2a7e0 (patch)
tree7f197d538411598b949ed44cd93ad69d909d09f0
parent69a3009cbf1b2be92b0520d11d29d11445918817 (diff)
parent9ad99c30cbf344b763602698b67c04ec3ce3de56 (diff)
downloadrust-6145757a264cea1e4adf019a6b70fd8206c2a7e0.tar.gz
rust-6145757a264cea1e4adf019a6b70fd8206c2a7e0.zip
Rollup merge of #64852 - Baranowski:param_note_52082, r=estebank
Print ParamTy span when accessing a field (#52082)
-rw-r--r--src/librustc_typeck/check/expr.rs78
-rw-r--r--src/test/ui/derived-errors/issue-30580.stderr2
-rw-r--r--src/test/ui/issues/issue-31011.stderr3
-rw-r--r--src/test/ui/structs/struct-pat-derived-error.stderr2
-rw-r--r--src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs54
-rw-r--r--src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.stderr75
6 files changed, 188 insertions, 26 deletions
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 0cdf2fa2a5b..6bed321d27f 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1394,30 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if self.method_exists(field, expr_t, expr.hir_id, true) {
             self.ban_take_value_of_method(expr, expr_t, field);
         } else if !expr_t.is_primitive_ty() {
-            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);
-                }
-                ty::RawPtr(..) => {
-                    self.suggest_first_deref_field(&mut err, expr, base, field);
-                }
-                _ => {}
-            }
-
-            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.
-                err.note("to `.await` a `Future`, switch to Rust 2018");
-                err.help("set `edition = \"2018\"` in `Cargo.toml`");
-                err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
-            }
-
-            err.emit();
+            self.ban_nonexisting_field(field, base, expr, expr_t);
         } else {
             type_error_struct!(
                 self.tcx().sess,
@@ -1433,6 +1410,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx().types.err
     }
 
+    fn ban_nonexisting_field(
+        &self,
+        field: ast::Ident,
+        base: &'tcx hir::Expr,
+        expr: &'tcx hir::Expr,
+        expr_t: Ty<'tcx>,
+    ) {
+        let mut err = self.no_such_field_err(field.span, field, expr_t);
+
+        match expr_t.peel_refs().kind {
+            ty::Array(_, len) => {
+                self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
+            }
+            ty::RawPtr(..) => {
+                self.suggest_first_deref_field(&mut err, expr, base, field);
+            }
+            ty::Adt(def, _) if !def.is_enum() => {
+                self.suggest_fields_on_recordish(&mut err, def, field);
+            }
+            ty::Param(param_ty) => {
+                self.point_at_param_definition(&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.
+            err.note("to `.await` a `Future`, switch to Rust 2018");
+            err.help("set `edition = \"2018\"` in `Cargo.toml`");
+            err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+        }
+
+        err.emit();
+    }
+
     fn ban_private_field_access(
         &self,
         expr: &hir::Expr,
@@ -1495,6 +1508,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit();
     }
 
+    fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) {
+        let generics = self.tcx.generics_of(self.body_id.owner_def_id());
+        let generic_param = generics.type_param(&param, self.tcx);
+        if let ty::GenericParamDefKind::Type{synthetic: Some(..), ..} = generic_param.kind {
+            return;
+        }
+        let param_def_id = generic_param.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_label(param_span, &format!("type parameter '{}' declared here", param_name));
+    }
+
     fn suggest_fields_on_recordish(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/src/test/ui/derived-errors/issue-30580.stderr b/src/test/ui/derived-errors/issue-30580.stderr
index 14c575f2699..7bd0eaf77a9 100644
--- a/src/test/ui/derived-errors/issue-30580.stderr
+++ b/src/test/ui/derived-errors/issue-30580.stderr
@@ -2,7 +2,7 @@ error[E0609]: no field `c` on type `&Foo`
   --> $DIR/issue-30580.rs:12:11
    |
 LL |         b.c;
-   |           ^
+   |           ^ help: a field with a similar name exists: `a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-31011.stderr b/src/test/ui/issues/issue-31011.stderr
index ab0069510fc..c7618e0835b 100644
--- a/src/test/ui/issues/issue-31011.stderr
+++ b/src/test/ui/issues/issue-31011.stderr
@@ -4,6 +4,9 @@ error[E0609]: no field `trace` on type `&T`
 LL |         if $ctx.trace {
    |                 ^^^^^
 ...
+LL | fn wrap<T>(context: &T) -> ()
+   |         - type parameter 'T' declared here
+LL | {
 LL |     log!(context, "entered wrapper");
    |     --------------------------------- in this macro invocation
 
diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr
index 673715cd3ef..6526ef58a44 100644
--- a/src/test/ui/structs/struct-pat-derived-error.stderr
+++ b/src/test/ui/structs/struct-pat-derived-error.stderr
@@ -2,7 +2,7 @@ error[E0609]: no field `d` on type `&A`
   --> $DIR/struct-pat-derived-error.rs:8:31
    |
 LL |         let A { x, y } = self.d;
-   |                               ^
+   |                               ^ help: a field with a similar name exists: `b`
 
 error[E0026]: struct `A` does not have fields named `x`, `y`
   --> $DIR/struct-pat-derived-error.rs:8:17
diff --git a/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs
new file mode 100644
index 00000000000..c57e8149574
--- /dev/null
+++ b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.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-type-param-shadows-existing-type.stderr b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.stderr
new file mode 100644
index 00000000000..4be4c91dfc2
--- /dev/null
+++ b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.stderr
@@ -0,0 +1,75 @@
+error[E0609]: no field `x` on type `&Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:11
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |           ^
+
+error[E0609]: no field `x` on type `&Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:18
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                  ^
+
+error[E0609]: no field `y` on type `&Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:25
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                         ^
+
+error[E0609]: no field `y` on type `&Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:31:32
+   |
+LL |     fn equals_ref<Point>(a: &Point, b: &Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                                ^
+
+error[E0609]: no field `x` on type `Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:11
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |           ^
+
+error[E0609]: no field `x` on type `Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:18
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                  ^
+
+error[E0609]: no field `y` on type `Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:25
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                         ^
+
+error[E0609]: no field `y` on type `Point`
+  --> $DIR/issue-52082-type-param-shadows-existing-type.rs:39:32
+   |
+LL |     fn equals_val<Point>(a: Point, b: Point) -> bool
+   |                   ----- type parameter 'Point' declared here
+LL |     {
+LL |         a.x == b.x && a.y == b.y
+   |                                ^
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0609`.