From 84034d4598bca00250723557e02614b72503861b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 14:52:48 +0200 Subject: [PATCH] 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 --- src/librustc_typeck/check/method/mod.rs | 5 +++-- src/librustc_typeck/check/mod.rs | 12 +++++++++--- src/test/compile-fail/issue-26472.rs | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/issue-26472.rs diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 26d1f50f8c549..bd395f16c923a 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -83,7 +83,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, '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; @@ -92,7 +93,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, '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 10789228b97fe..692dc53107931 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2947,12 +2947,18 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if let Some((did, field_ty)) = private_candidate { let struct_path = fcx.tcx().item_path_str(did); - let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); - fcx.tcx().sess.span_err(expr.span, &msg); fcx.write_ty(expr.id, field_ty); + let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); + let mut err = fcx.tcx().sess.struct_span_err(expr.span, &msg); + // Also check if an accessible method exists, which is often what is meant. + if method::exists(fcx, 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() { fcx.write_error(expr.id); - } else if method::exists(fcx, field.span, field.node, expr_t, expr.id) { + } else if method::exists(fcx, field.span, field.node, expr_t, expr.id, true) { fcx.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ diff --git a/src/test/compile-fail/issue-26472.rs b/src/test/compile-fail/issue-26472.rs new file mode 100644 index 0000000000000..0d59a897ef1af --- /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 or the MIT license +// , 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 +}