Skip to content

Commit b6fcab5

Browse files
committed
Auto merge of #32358 - Manishearth:pr-32053, r=Manishearth
Add note if method is called on a function object rebase of #32053
2 parents 78e8a00 + 88ad229 commit b6fcab5

File tree

2 files changed

+104
-50
lines changed

2 files changed

+104
-50
lines changed

src/librustc_typeck/check/method/suggest.rs

+69-50
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,56 @@ use middle::subst::Substs;
2525
use middle::traits::{Obligation, SelectionContext};
2626
use util::nodemap::{FnvHashSet};
2727

28+
2829
use syntax::ast;
2930
use syntax::codemap::Span;
3031
use syntax::errors::DiagnosticBuilder;
3132
use rustc_front::print::pprust;
3233
use rustc_front::hir;
34+
use rustc_front::hir::Expr_;
3335

3436
use std::cell;
3537
use std::cmp::Ordering;
3638

3739
use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item};
3840
use 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+
4078
pub 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
}

src/test/compile-fail/issue-29124.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct ret;
12+
struct obj;
13+
14+
impl obj {
15+
fn func() -> ret {
16+
ret
17+
}
18+
}
19+
20+
fn func() -> ret {
21+
ret
22+
}
23+
24+
fn main() {
25+
obj::func.x();
26+
//~^ ERROR no method named `x` found for type `fn() -> ret {obj::func}` in the current scope
27+
//~^^ NOTE obj::func is a function, perhaps you wish to call it
28+
//~^^^ HELP try calling the base function:
29+
//~| SUGGESTION obj::func().x();
30+
func.x();
31+
//~^ ERROR no method named `x` found for type `fn() -> ret {func}` in the current scope
32+
//~^^ NOTE func is a function, perhaps you wish to call it
33+
//~^^^ HELP try calling the base function:
34+
//~| SUGGESTION func().x();
35+
}

0 commit comments

Comments
 (0)