From 9adb3dfdcb2cab7a10d7ac7a48170672b3961fe8 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sat, 13 Jun 2015 14:47:10 -0400 Subject: [PATCH 1/7] Uncomplete fix for #2392 --- src/librustc_typeck/check/method/suggest.rs | 22 ++++++++++++++++----- src/test/compile-fail/issue-18343.rs | 11 +++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b098fb56d4db6..be34c7057210c 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -59,12 +59,24 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // If the item has the name of a field, give a help note - if let (&ty::TyStruct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { + if let (&ty::TyStruct(did, substs), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { let fields = ty::lookup_struct_fields(cx, did); - 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)); + + if let Some(field) = fields.iter().find(|f| f.name == item_name) { + + match ty::lookup_field_type(cx, did, field.id, substs).sty { + ty::TyClosure(_, _) | ty::TyBareFn(_,_) => { + cx.sess.span_note(span, + &format!("use `({0}.{1})(...)` if you meant to call the \ + function stored in the `{1}` field", + ty::item_path_str(cx, did), item_name)); + }, + _ => { + cx.sess.span_note(span, + &format!("did you mean to write `{0}.{1}`?", + ty::item_path_str(cx, did), item_name)); + }, + }; } } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 43e9ca5fa6e7a..3572e5084c15a 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -10,10 +10,21 @@ struct Obj where F: FnMut() -> u32 { closure: F, + nfn: usize, +} + +fn func() -> u32 { + 0 } fn main() { let o = Obj { closure: || 42 }; o.closure(); //~ ERROR no method named `closure` found //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field + let x = o.nfn(); //~ ERROR no method named `closure` found + //~^ NOTE did you mean `o.nfn`? + + let b = Obj { closure: func }; + b.closure(); //~ ERROR no method named `closure` found + //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field } From 3f8a70b613d9e41dc6db11f1d267025bb26bf73d Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sun, 14 Jun 2015 02:49:00 -0400 Subject: [PATCH 2/7] Fixed note message to display expression in recommendations --- src/librustc_typeck/check/method/suggest.rs | 19 +++++++++++++--- src/test/compile-fail/issue-18343.rs | 24 +++++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index be34c7057210c..276794087176d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -59,22 +59,35 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // If the item has the name of a field, give a help note - if let (&ty::TyStruct(did, substs), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { + if let (&ty::TyStruct(did, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { let fields = ty::lookup_struct_fields(cx, did); 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 generic placeholder for expression + }; + // TODO Fix when closure note is displayed + // below commented code from eddyb on irc + // let substs = subst::Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()], Vec::new(), field_ty); + // let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)); + // let poly_trait_ref = trait_ref.to_poly_trait_ref(); + // let obligation = traits::Obligation::misc(span, fcx.body_id, poly_trait_ref.as_predicate()); + // let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx); + // if selcx.evaluate_obligation(&obligation) { /* suggest */ } + match ty::lookup_field_type(cx, did, field.id, substs).sty { ty::TyClosure(_, _) | ty::TyBareFn(_,_) => { cx.sess.span_note(span, &format!("use `({0}.{1})(...)` if you meant to call the \ function stored in the `{1}` field", - ty::item_path_str(cx, did), item_name)); + expr_string, item_name)); }, _ => { cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", - ty::item_path_str(cx, did), item_name)); + expr_string, item_name)); }, }; } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 3572e5084c15a..802b21d211cb4 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -13,18 +13,30 @@ struct Obj where F: FnMut() -> u32 { nfn: usize, } +struct S where F: FnMut() -> u32 { + v: Obj, +} + fn func() -> u32 { 0 } fn main() { - let o = Obj { closure: || 42 }; + let o = Obj { closure: || 42, nfn: 42 }; o.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field - let x = o.nfn(); //~ ERROR no method named `closure` found - //~^ NOTE did you mean `o.nfn`? + //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field - let b = Obj { closure: func }; + // TODO move these to a new test for #2392 + let x = o.nfn(); //~ ERROR no method named `nfn` found + //~^ NOTE did you mean to write `o.nfn`? + + let b = Obj { closure: func, nfn: 5 }; b.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ NOTE use `(b.closure)(...)` if you meant to call the function stored in the `closure` field + + let s = S { v: b }; + s.v.closure();//~ ERROR no method named `closure` found + //~^ NOTE use `(s.v.closure)(...)` if you meant to call the function stored in the `closure` field + s.v.nfn();//~ ERROR no method named `nfn` found + //~^ NOTE did you mean to write `s.v.nfn`? } From 9932870833a3d2c13431c0454a4a91bf54a0e5ab Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sun, 14 Jun 2015 20:07:05 -0400 Subject: [PATCH 3/7] Finished implementing proper function check (through FnOnce) and moved tests to new file and updated tests --- src/librustc_typeck/check/method/suggest.rs | 56 ++++++++++-------- src/test/compile-fail/issue-18343.rs | 25 +------- src/test/compile-fail/issue-2392.rs | 65 +++++++++++++++++++++ 3 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 src/test/compile-fail/issue-2392.rs diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 276794087176d..b6bb9d67a318e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,8 +15,11 @@ use CrateCtxt; use astconv::AstConv; use check::{self, FnCtxt}; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, ToPolyTraitRef, AsPredicate}; use middle::def; +use middle::lang_items::FnOnceTraitLangItem; +use middle::subst::Substs; +use middle::traits::{Obligation, SelectionContext}; use metadata::{csearch, cstore, decoder}; use syntax::{ast, ast_util}; @@ -65,31 +68,38 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, 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 generic placeholder for expression + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a string + // snippet }; - // TODO Fix when closure note is displayed - // below commented code from eddyb on irc - // let substs = subst::Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()], Vec::new(), field_ty); - // let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)); - // let poly_trait_ref = trait_ref.to_poly_trait_ref(); - // let obligation = traits::Obligation::misc(span, fcx.body_id, poly_trait_ref.as_predicate()); - // let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx); - // if selcx.evaluate_obligation(&obligation) { /* suggest */ } - - match ty::lookup_field_type(cx, did, field.id, substs).sty { - ty::TyClosure(_, _) | ty::TyBareFn(_,_) => { - 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)); - }, - _ => { - 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 fn_once_trait_did = match cx.lang_items.require(FnOnceTraitLangItem) { + Ok(trait_did) => trait_did, + Err(err) => cx.sess.fatal(&err[..]) }; + + let field_ty = ty::lookup_field_type(cx, did, field.id, substs); + let field_ty_substs = Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()], + Vec::new(), + field_ty); + let trait_ref = ty::TraitRef::new(fn_once_trait_did, + cx.mk_substs(field_ty_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(fcx.infcx(), fcx); + + if selcx.evaluate_obligation(&obligation) { + 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)); + } else { + cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } } } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 802b21d211cb4..4601db9dba0fc 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -10,33 +10,10 @@ struct Obj where F: FnMut() -> u32 { closure: F, - nfn: usize, -} - -struct S where F: FnMut() -> u32 { - v: Obj, -} - -fn func() -> u32 { - 0 } fn main() { - let o = Obj { closure: || 42, nfn: 42 }; + let o = Obj { closure: || 42 }; o.closure(); //~ ERROR no method named `closure` found //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field - - // TODO move these to a new test for #2392 - let x = o.nfn(); //~ ERROR no method named `nfn` found - //~^ NOTE did you mean to write `o.nfn`? - - let b = Obj { closure: func, nfn: 5 }; - b.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(b.closure)(...)` if you meant to call the function stored in the `closure` field - - let s = S { v: b }; - s.v.closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(s.v.closure)(...)` if you meant to call the function stored in the `closure` field - s.v.nfn();//~ ERROR no method named `nfn` found - //~^ NOTE did you mean to write `s.v.nfn`? } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs new file mode 100644 index 0000000000000..2e1fbdf6394f8 --- /dev/null +++ b/src/test/compile-fail/issue-2392.rs @@ -0,0 +1,65 @@ +// 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 or the MIT license +// , 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 where F: FnOnce() -> u32 { + closure: F, + not_closure: usize, +} + +struct BoxedObj { + boxed_closure: Box u32>, +} + +struct Wrapper where F: FnMut() -> u32 { + wrap: Obj, +} + +fn func() -> u32 { + 0 +} + +fn check_expression() -> Obj u32>> { + Obj { closure: Box::new(|| 42_u32) as Box 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 in the `closure` field + + 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 in the `closure` field + + 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 in the `boxed_closure` field + + let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box 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 in the `boxed_closure` field + + // 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 in the `closure` field + 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 in the `closure` field +} From 0230a530ce54102325537dc63dcabc45f5935771 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sun, 14 Jun 2015 21:01:26 -0400 Subject: [PATCH 4/7] fixup! Finished implementing proper function check (through FnOnce) and moved tests to new file and updated tests --- src/test/compile-fail/issue-2392.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index 2e1fbdf6394f8..c5598e8785cbd 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -34,32 +34,35 @@ fn check_expression() -> Obj u32>> { 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 in the `closure` field + //~^ 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 in the `closure` field + //~^ 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 in the `boxed_closure` field + //~^ 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 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 in the `boxed_closure` field + //~^ 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 in the `closure` field + //~^ 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 in the `closure` field + //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored } From c8a0b0eece9e3ac852413bc715f788261a217e74 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Mon, 15 Jun 2015 12:28:14 -0400 Subject: [PATCH 5/7] Handle error case safely with a fallback --- src/librustc_typeck/check/method/suggest.rs | 55 ++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b6bb9d67a318e..2abb53e55f64b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -73,33 +73,42 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // snippet }; - // Determine if the field can be used as a function in some way - let fn_once_trait_did = match cx.lang_items.require(FnOnceTraitLangItem) { - Ok(trait_did) => trait_did, - Err(err) => cx.sess.fatal(&err[..]) - }; + fn 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 field_ty = ty::lookup_field_type(cx, did, field.id, substs); - let field_ty_substs = Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()], - Vec::new(), - field_ty); - let trait_ref = ty::TraitRef::new(fn_once_trait_did, - cx.mk_substs(field_ty_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(fcx.infcx(), fcx); - - if selcx.evaluate_obligation(&obligation) { - 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)); - } else { + fn 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 fn_once_substs = Substs::new_trait(vec![fcx.inh.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(fcx.infcx(), fcx); + + if selcx.evaluate_obligation(&obligation) { + span_stored_function(); + } else { + span_did_you_mean(); + } + } else { + match field_ty.sty { + ty::TyClosure(_,_) | ty::TyFnPtr(_,_) => span_stored_function(), + _ => span_did_you_mean(), + } + } } } From 973da22ea3d8074d8ce1214f7a356e96efe4131a Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Mon, 15 Jun 2015 14:49:04 -0400 Subject: [PATCH 6/7] Wrapped inferred context changes in a probe, handle fnOnce trait require error with a fallback, renamed variable to something clearer --- src/librustc_typeck/check/method/suggest.rs | 63 ++++++++++++--------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2abb53e55f64b..a61985d3a00f6 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -73,40 +73,49 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // snippet }; - fn 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)); - } + macro_rules! 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)); + } + }; - fn span_did_you_mean() { - cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", - expr_string, item_name)); - } + macro_rules! 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 fn_once_substs = Substs::new_trait(vec![fcx.inh.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(fcx.infcx(), fcx); - - if selcx.evaluate_obligation(&obligation) { - span_stored_function(); - } else { - span_did_you_mean(); - } + 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 { - ty::TyClosure(_,_) | ty::TyFnPtr(_,_) => span_stored_function(), - _ => span_did_you_mean(), + // fallback to matching a closure or function pointer + ty::TyClosure(_,_) | ty::TyBareFn(None,_) => span_stored_function!(), + _ => span_did_you_mean!(), } } } From bae1df65aaabf6129636364d86d918c76ed52b6b Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Mon, 15 Jun 2015 18:20:18 -0400 Subject: [PATCH 7/7] fixup! Wrapped inferred context changes in a probe, handle fnOnce trait require error with a fallback, renamed variable to something clearer --- src/librustc_typeck/check/method/suggest.rs | 28 +++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index a61985d3a00f6..4fbe42455ae86 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -73,20 +73,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // snippet }; - macro_rules! 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_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)); }; - macro_rules! span_did_you_mean { - () => { - cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", - 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 @@ -106,16 +102,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mut selcx = SelectionContext::new(infcx, fcx); if selcx.evaluate_obligation(&obligation) { - span_stored_function!(); + span_stored_function(); } else { - span_did_you_mean!(); + span_did_you_mean(); } }); } else { match field_ty.sty { // fallback to matching a closure or function pointer - ty::TyClosure(_,_) | ty::TyBareFn(None,_) => span_stored_function!(), - _ => span_did_you_mean!(), + ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(), + _ => span_did_you_mean(), } } }