@@ -25,18 +25,56 @@ use middle::subst::Substs;
25
25
use middle:: traits:: { Obligation , SelectionContext } ;
26
26
use util:: nodemap:: { FnvHashSet } ;
27
27
28
+
28
29
use syntax:: ast;
29
30
use syntax:: codemap:: Span ;
30
31
use syntax:: errors:: DiagnosticBuilder ;
31
32
use rustc_front:: print:: pprust;
32
33
use rustc_front:: hir;
34
+ use rustc_front:: hir:: Expr_ ;
33
35
34
36
use std:: cell;
35
37
use std:: cmp:: Ordering ;
36
38
37
39
use super :: { MethodError , NoMatchData , CandidateSource , impl_item, trait_item} ;
38
40
use super :: probe:: Mode ;
39
41
42
+ fn is_fn_ty < ' a , ' tcx > ( ty : & Ty < ' tcx > , fcx : & FnCtxt < ' a , ' tcx > , span : Span ) -> bool {
43
+ let cx = fcx. tcx ( ) ;
44
+ println ! ( "{:?}" , ty) ;
45
+ match ty. sty {
46
+ // Not all of these (e.g. unsafe fns) implement FnOnce
47
+ // so we look for these beforehand
48
+ ty:: TyClosure ( ..) | ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) => true ,
49
+ // If it's not a simple function, look for things which implement FnOnce
50
+ _ => {
51
+ if let Ok ( fn_once_trait_did) =
52
+ cx. lang_items . require ( FnOnceTraitLangItem ) {
53
+ let infcx = fcx. infcx ( ) ;
54
+ infcx. probe ( |_| {
55
+ let fn_once_substs =
56
+ Substs :: new_trait ( vec ! [ infcx. next_ty_var( ) ] ,
57
+ Vec :: new ( ) ,
58
+ ty) ;
59
+ let trait_ref =
60
+ ty:: TraitRef :: new ( fn_once_trait_did,
61
+ cx. mk_substs ( fn_once_substs) ) ;
62
+ let poly_trait_ref = trait_ref. to_poly_trait_ref ( ) ;
63
+ let obligation = Obligation :: misc ( span,
64
+ fcx. body_id ,
65
+ poly_trait_ref
66
+ . to_predicate ( ) ) ;
67
+ let mut selcx = SelectionContext :: new ( infcx) ;
68
+
69
+ return selcx. evaluate_obligation ( & obligation)
70
+ } )
71
+ } else {
72
+ false
73
+ }
74
+ }
75
+ }
76
+ }
77
+
40
78
pub fn report_error < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
41
79
span : Span ,
42
80
rcvr_ty : Ty < ' tcx > ,
@@ -79,60 +117,41 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
79
117
// snippet
80
118
} ;
81
119
82
- macro_rules! span_stored_function {
83
- ( ) => {
84
- err. span_note( span,
85
- & format!( "use `({0}.{1})(...)` if you meant to call \
86
- the function stored in the `{1}` field",
87
- expr_string, item_name) ) ;
88
- }
89
- }
120
+ let field_ty = field. ty ( cx, substs) ;
90
121
91
- macro_rules! span_did_you_mean {
92
- ( ) => {
93
- err. span_note( span, & format!( "did you mean to write `{0}.{1}`?" ,
94
- expr_string, item_name) ) ;
95
- }
122
+ if is_fn_ty ( & field_ty, & fcx, span) {
123
+ err. span_note ( span,
124
+ & format ! ( "use `({0}.{1})(...)` if you meant to call \
125
+ the function stored in the `{1}` field",
126
+ expr_string, item_name) ) ;
127
+ } else {
128
+ err. span_note ( span, & format ! ( "did you mean to write `{0}.{1}`?" ,
129
+ expr_string, item_name) ) ;
96
130
}
131
+ }
132
+ }
97
133
98
- // Determine if the field can be used as a function in some way
99
- let field_ty = field. ty ( cx, substs) ;
134
+ if is_fn_ty ( & rcvr_ty, & fcx, span) {
135
+ macro_rules! report_function {
136
+ ( $span: expr, $name: expr) => {
137
+ err. fileline_note(
138
+ $span,
139
+ & format!( "{} is a function, perhaps you wish to call it" ,
140
+ $name) ) ;
141
+ }
142
+ }
100
143
101
- match field_ty. sty {
102
- // Not all of these (e.g. unsafe fns) implement FnOnce
103
- // so we look for these beforehand
104
- ty:: TyClosure ( ..) | ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) => {
105
- span_stored_function ! ( ) ;
106
- }
107
- // If it's not a simple function, look for things which implement FnOnce
108
- _ => {
109
- if let Ok ( fn_once_trait_did) =
110
- cx. lang_items . require ( FnOnceTraitLangItem ) {
111
- let infcx = fcx. infcx ( ) ;
112
- infcx. probe ( |_| {
113
- let fn_once_substs =
114
- Substs :: new_trait ( vec ! [ infcx. next_ty_var( ) ] ,
115
- Vec :: new ( ) ,
116
- field_ty) ;
117
- let trait_ref =
118
- ty:: TraitRef :: new ( fn_once_trait_did,
119
- cx. mk_substs ( fn_once_substs) ) ;
120
- let poly_trait_ref = trait_ref. to_poly_trait_ref ( ) ;
121
- let obligation = Obligation :: misc ( span,
122
- fcx. body_id ,
123
- poly_trait_ref
124
- . to_predicate ( ) ) ;
125
- let mut selcx = SelectionContext :: new ( infcx) ;
126
-
127
- if selcx. evaluate_obligation ( & obligation) {
128
- span_stored_function ! ( ) ;
129
- } else {
130
- span_did_you_mean ! ( ) ;
131
- }
132
- } ) ;
133
- } else {
134
- span_did_you_mean ! ( ) ;
135
- }
144
+ if let Some ( expr) = rcvr_expr {
145
+ if let Ok ( expr_string) = cx. sess . codemap ( ) . span_to_snippet ( expr. span ) {
146
+ report_function ! ( expr. span, expr_string) ;
147
+ err. span_suggestion ( expr. span ,
148
+ "try calling the base function:" ,
149
+ format ! ( "{}()" ,
150
+ expr_string) ) ;
151
+ }
152
+ else if let Expr_ :: ExprPath ( _, path) = expr. node . clone ( ) {
153
+ if let Some ( segment) = path. segments . last ( ) {
154
+ report_function ! ( expr. span, segment. identifier. name) ;
136
155
}
137
156
}
138
157
}
0 commit comments