@@ -25,18 +25,56 @@ use middle::subst::Substs;
2525use middle:: traits:: { Obligation , SelectionContext } ;
2626use util:: nodemap:: { FnvHashSet } ;
2727
28+
2829use syntax:: ast;
2930use syntax:: codemap:: Span ;
3031use syntax:: errors:: DiagnosticBuilder ;
3132use rustc_front:: print:: pprust;
3233use rustc_front:: hir;
34+ use rustc_front:: hir:: Expr_ ;
3335
3436use std:: cell;
3537use std:: cmp:: Ordering ;
3638
3739use super :: { MethodError , NoMatchData , CandidateSource , impl_item, trait_item} ;
3840use super :: probe:: Mode ;
3941
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+
4078pub fn report_error < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
4179 span : Span ,
4280 rcvr_ty : Ty < ' tcx > ,
@@ -79,60 +117,41 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
79117 // snippet
80118 } ;
81119
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) ;
90121
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) ) ;
96130 }
131+ }
132+ }
97133
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+ }
100143
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) ;
136155 }
137156 }
138157 }
0 commit comments