about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2016-05-15 20:13:39 +0530
committerManish Goregaokar <manishsmail@gmail.com>2016-05-15 20:13:39 +0530
commitc3086c2ef839a42f0cfa00df1b00785a975de8d3 (patch)
treee6cfe24e9ef22096f724dad1419f6a2b0c005153
parent1a26d2364f9da1667ca0098d3cc4a213d131f481 (diff)
parent843b174e93b253824a62fba3ac4be2753e30c9c2 (diff)
downloadrust-c3086c2ef839a42f0cfa00df1b00785a975de8d3.tar.gz
rust-c3086c2ef839a42f0cfa00df1b00785a975de8d3.zip
Rollup merge of #33342 - birkenfeld:issue-26472, r=jseyfried
typeck: if a private field exists, also check for a public method

For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten.

Fixes: #26472

NOTE: I added the parameter `allow_private` to `method::exists` since I don't want to suggest inaccessible methods. For the second case, where only the method exists, I think it would make sense to set it to `false` as well, but I wanted to preserve compatibility for this case.
-rw-r--r--src/librustc_typeck/check/method/mod.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs12
-rw-r--r--src/test/compile-fail/issue-26472.rs24
3 files changed, 36 insertions, 5 deletions
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f27ae181f77..00eeefa0449 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -84,7 +84,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          span: Span,
                          method_name: ast::Name,
                          self_ty: ty::Ty<'tcx>,
-                         call_expr_id: ast::NodeId)
+                         call_expr_id: ast::NodeId,
+                         allow_private: bool)
                          -> bool
     {
         let mode = probe::Mode::MethodCall;
@@ -93,7 +94,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Err(NoMatch(..)) => false,
             Err(Ambiguity(..)) => true,
             Err(ClosureAmbiguity(..)) => true,
-            Err(PrivateMatch(..)) => true,
+            Err(PrivateMatch(..)) => allow_private,
         }
     }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8f9e44c1365..69a17113bc7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3053,12 +3053,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
-            self.tcx().sess.span_err(expr.span, &msg);
             self.write_ty(expr.id, field_ty);
+            let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
+            let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
+            // Also check if an accessible method exists, which is often what is meant.
+            if self.method_exists(field.span, field.node, expr_t, expr.id, false) {
+                err.note(&format!("a method `{}` also exists, perhaps you wish to call it",
+                                  field.node));
+            }
+            err.emit();
         } else if field.node == keywords::Invalid.name() {
             self.write_error(expr.id);
-        } else if self.method_exists(field.span, field.node, expr_t, expr.id) {
+        } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
                          `{}`", field.node, actual)
diff --git a/src/test/compile-fail/issue-26472.rs b/src/test/compile-fail/issue-26472.rs
new file mode 100644
index 00000000000..0d59a897ef1
--- /dev/null
+++ b/src/test/compile-fail/issue-26472.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod sub {
+    pub struct S { len: usize }
+    impl S {
+        pub fn new() -> S { S { len: 0 } }
+        pub fn len(&self) -> usize { self.len }
+    }
+}
+
+fn main() {
+    let s = sub::S::new();
+    let v = s.len;
+    //~^ ERROR field `len` of struct `sub::S` is private
+    //~| NOTE a method `len` also exists, perhaps you wish to call it
+}