@@ -15,8 +15,11 @@ use CrateCtxt;
15
15
16
16
use astconv:: AstConv ;
17
17
use check:: { self , FnCtxt } ;
18
- use middle:: ty:: { self , Ty } ;
18
+ use middle:: ty:: { self , Ty , ToPolyTraitRef , AsPredicate } ;
19
19
use middle:: def;
20
+ use middle:: lang_items:: FnOnceTraitLangItem ;
21
+ use middle:: subst:: Substs ;
22
+ use middle:: traits:: { Obligation , SelectionContext } ;
20
23
use metadata:: { csearch, cstore, decoder} ;
21
24
22
25
use syntax:: { ast, ast_util} ;
@@ -59,12 +62,58 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
59
62
None ) ;
60
63
61
64
// 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) {
63
66
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
+ }
68
117
}
69
118
}
70
119
0 commit comments