Change:
I forget if there's already a bug on this, but it would be nice if, when you wrote and doesn't have a field named , but does have a nullary method named , the compiler gave a hint like "did you mean to write ?" It could also do vice versa (if you write A.B()ABA.B?) I ran into this in trans, where I have frequently written instead of .
Test: The error message is better now than it was: in that it suggests there is a method named . But it could still be improved. (The intention may not have been to take the method's value; it seems more likely that the programmer thought it wasn't a method at all.)
My previous comment still holds. It would be great if you would see the "try writing an anonymous function" hint for something like and instead see a "did you mean to write ?" in situations like this one.
I'd also like to see one when trying to call a function-typed struct field: emits Foof. It'd be nice if it tried to see if it could auto-deref to a struct field, and if so, say (f.f)().
A nice idea. Assigning P-low.
Currently gives which is pretty close to the proposed behavior. Replacing the wih yields the same as before (i.e. does not suggest removing the ):
Updated the example gives: which now prints It's nice that the note is there, but the text is suboptimal: isn't a function.
I'm working on a fix for this, but I'm struggling with the final portion. With this code: I get the output: My current changes are . I'm not sure if it's possible to have the output say "" and "kitty.x" with the input to the function. Any ideas? Or should I just keep the message in the same format as it is now and output "s.func" and "did you mean to write ?"? Edit: Ideally, I would like to output: I'm wondering if that's at all possible, especially because instead of , there might be an expression.
I got around that error message. Now I'm making sure the previous message is displayed under the proper circumstances.

Discussion:
use astconv::AstConv; use check::{self, FnCtxt}; <del> use middle::ty::{self, Ty}; </del> <ins> use middle::ty::{self, Ty, ToPolyTraitRef, AsPredicate}; </ins> use middle::def; <ins> use middle::lang_items::FnOnceTraitLangItem; use middle::subst::Substs; use middle::traits::{Obligation, SelectionContext}; </ins> use metadata::{csearch, cstore, decoder}; use syntax::{ast, ast_util};

None); // If the item has the name of a field, give a help note <del> if let (&ty::TyStruct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { </del> <ins> if let (&ty::TyStruct(did, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { </ins> let fields = ty::lookup_struct_fields(cx, did); <del> if fields.iter().any(|f| f.name == item_name) { cx.sess.span_note(span, &format!("use `(s.{0})(...)` if you meant to call the  function stored in the `{0}` field", item_name)); </del> <ins> if let Some(field) = fields.iter().find(|f| f.name == item_name) { let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { Ok(expr_string) => expr_string, _ => "s".into() // Default to a generic placeholder for the // expression when we can't generate a string // snippet }; let span_stored_function = || { cx.sess.span_note(span, &format!("use `({0}.{1})(...)` if you meant to call  the function stored in the `{1}` field", expr_string, item_name)); }; let span_did_you_mean = || { cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", expr_string, item_name)); }; // Determine if the field can be used as a function in some way let field_ty = ty::lookup_field_type(cx, did, field.id, substs); if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) { let infcx = fcx.infcx(); infcx.probe(|_| { let fn_once_substs = Substs::new_trait(vec![infcx.next_ty_var()], Vec::new(), field_ty); let trait_ref = ty::TraitRef::new(fn_once_trait_did, cx.mk_substs(fn_once_substs)); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, fcx.body_id, poly_trait_ref.as_predicate()); let mut selcx = SelectionContext::new(infcx, fcx); if selcx.evaluate_obligation(&obligation) { span_stored_function(); } else { span_did_you_mean(); } }); } else { match field_ty.sty { // fallback to matching a closure or function pointer ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(), _ => span_did_you_mean(), } } </ins> } }

fn main() { let o = Obj { closure: || 42 }; o.closure(); //~ ERROR no method named `closure` found <del> //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field </del> <ins> //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field </ins> }

<ins> // Copyright 2014 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. #![feature(core)] use std::boxed::FnBox; struct Obj<F> where F: FnOnce() -> u32 { closure: F, not_closure: usize, } struct BoxedObj { boxed_closure: Box<FnBox() -> u32>, } struct Wrapper<F> where F: FnMut() -> u32 { wrap: Obj<F>, } fn func() -> u32 { 0 } fn check_expression() -> Obj<Box<FnBox() -> u32>> { Obj { closure: Box::new(|| 42_u32) as Box<FnBox() -> u32>, not_closure: 42 } } fn main() { // test variations of function let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored o_closure.not_closure(); //~ ERROR no method named `not_closure` found //~^ NOTE did you mean to write `o_closure.not_closure`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box<FnBox() -> u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored w.wrap.not_closure();//~ ERROR no method named `not_closure` found //~^ NOTE did you mean to write `w.wrap.not_closure`? check_expression().closure();//~ ERROR no method named `closure` found //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored } </ins>