@@ -15,8 +15,11 @@ use CrateCtxt;
1515
1616use astconv:: AstConv ;
1717use check:: { self , FnCtxt } ;
18- use middle:: ty:: { self , Ty } ;
18+ use middle:: ty:: { self , Ty , ToPolyTraitRef , AsPredicate } ;
1919use middle:: def;
20+ use middle:: lang_items:: FnOnceTraitLangItem ;
21+ use middle:: subst:: Substs ;
22+ use middle:: traits:: { Obligation , SelectionContext } ;
2023use metadata:: { csearch, cstore, decoder} ;
2124
2225use syntax:: { ast, ast_util} ;
@@ -59,12 +62,58 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
5962 None ) ;
6063
6164 // If the item has the name of a field, give a help note
62- if let ( & ty:: TyStruct ( did, _ ) , Some ( _ ) ) = ( & rcvr_ty. sty , rcvr_expr) {
65+ if let ( & ty:: TyStruct ( did, substs ) , Some ( expr ) ) = ( & rcvr_ty. sty , rcvr_expr) {
6366 let fields = ty:: lookup_struct_fields ( cx, did) ;
64- if fields. iter ( ) . any ( |f| f. name == item_name) {
65- cx. sess . span_note ( span,
66- & format ! ( "use `(s.{0})(...)` if you meant to call the \
67- function stored in the `{0}` field", item_name) ) ;
67+
68+ if let Some ( field) = fields. iter ( ) . find ( |f| f. name == item_name) {
69+ let expr_string = match cx. sess . codemap ( ) . span_to_snippet ( expr. span ) {
70+ Ok ( expr_string) => expr_string,
71+ _ => "s" . into ( ) // Default to a generic placeholder for the
72+ // expression when we can't generate a string
73+ // snippet
74+ } ;
75+
76+ let span_stored_function = || {
77+ cx. sess . span_note ( span,
78+ & format ! ( "use `({0}.{1})(...)` if you meant to call \
79+ the function stored in the `{1}` field",
80+ expr_string, item_name) ) ;
81+ } ;
82+
83+ let span_did_you_mean = || {
84+ cx. sess . span_note ( span, & format ! ( "did you mean to write `{0}.{1}`?" ,
85+ expr_string, item_name) ) ;
86+ } ;
87+
88+ // Determine if the field can be used as a function in some way
89+ let field_ty = ty:: lookup_field_type ( cx, did, field. id , substs) ;
90+ if let Ok ( fn_once_trait_did) = cx. lang_items . require ( FnOnceTraitLangItem ) {
91+ let infcx = fcx. infcx ( ) ;
92+ infcx. probe ( |_| {
93+ let fn_once_substs = Substs :: new_trait ( vec ! [ infcx. next_ty_var( ) ] ,
94+ Vec :: new ( ) ,
95+ field_ty) ;
96+ let trait_ref = ty:: TraitRef :: new ( fn_once_trait_did,
97+ cx. mk_substs ( fn_once_substs) ) ;
98+ let poly_trait_ref = trait_ref. to_poly_trait_ref ( ) ;
99+ let obligation = Obligation :: misc ( span,
100+ fcx. body_id ,
101+ poly_trait_ref. as_predicate ( ) ) ;
102+ let mut selcx = SelectionContext :: new ( infcx, fcx) ;
103+
104+ if selcx. evaluate_obligation ( & obligation) {
105+ span_stored_function ( ) ;
106+ } else {
107+ span_did_you_mean ( ) ;
108+ }
109+ } ) ;
110+ } else {
111+ match field_ty. sty {
112+ // fallback to matching a closure or function pointer
113+ ty:: TyClosure ( ..) | ty:: TyBareFn ( ..) => span_stored_function ( ) ,
114+ _ => span_did_you_mean ( ) ,
115+ }
116+ }
68117 }
69118 }
70119
0 commit comments