Finished implementing proper function check (through FnOnce) and moved tests to new file and updated tests
This commit is contained in:
parent
3f8a70b613
commit
9932870833
@ -15,8 +15,11 @@ use CrateCtxt;
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::{self, FnCtxt};
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty::{self, Ty, ToPolyTraitRef, AsPredicate};
|
||||
use middle::def;
|
||||
use middle::lang_items::FnOnceTraitLangItem;
|
||||
use middle::subst::Substs;
|
||||
use middle::traits::{Obligation, SelectionContext};
|
||||
use metadata::{csearch, cstore, decoder};
|
||||
|
||||
use syntax::{ast, ast_util};
|
||||
@ -65,31 +68,38 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
if let Some(field) = fields.iter().find(|f| f.name == item_name) {
|
||||
let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) {
|
||||
Ok(expr_string) => expr_string,
|
||||
_ => "s".into() // default to generic placeholder for expression
|
||||
_ => "s".into() // Default to a generic placeholder for the
|
||||
// expression when we can't generate a string
|
||||
// snippet
|
||||
};
|
||||
|
||||
// TODO Fix when closure note is displayed
|
||||
// below commented code from eddyb on irc
|
||||
// let substs = subst::Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()], Vec::new(), field_ty);
|
||||
// let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs));
|
||||
// let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
// let obligation = traits::Obligation::misc(span, fcx.body_id, poly_trait_ref.as_predicate());
|
||||
// let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx);
|
||||
// if selcx.evaluate_obligation(&obligation) { /* suggest */ }
|
||||
|
||||
match ty::lookup_field_type(cx, did, field.id, substs).sty {
|
||||
ty::TyClosure(_, _) | ty::TyBareFn(_,_) => {
|
||||
cx.sess.span_note(span,
|
||||
&format!("use `({0}.{1})(...)` if you meant to call the \
|
||||
function stored in the `{1}` field",
|
||||
expr_string, item_name));
|
||||
},
|
||||
_ => {
|
||||
cx.sess.span_note(span,
|
||||
&format!("did you mean to write `{0}.{1}`?",
|
||||
expr_string, item_name));
|
||||
},
|
||||
// Determine if the field can be used as a function in some way
|
||||
let fn_once_trait_did = match cx.lang_items.require(FnOnceTraitLangItem) {
|
||||
Ok(trait_did) => trait_did,
|
||||
Err(err) => cx.sess.fatal(&err[..])
|
||||
};
|
||||
|
||||
let field_ty = ty::lookup_field_type(cx, did, field.id, substs);
|
||||
let field_ty_substs = Substs::new_trait(vec![fcx.inh.infcx.next_ty_var()],
|
||||
Vec::new(),
|
||||
field_ty);
|
||||
let trait_ref = ty::TraitRef::new(fn_once_trait_did,
|
||||
cx.mk_substs(field_ty_substs));
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = Obligation::misc(span,
|
||||
fcx.body_id,
|
||||
poly_trait_ref.as_predicate());
|
||||
let mut selcx = SelectionContext::new(fcx.infcx(), fcx);
|
||||
|
||||
if selcx.evaluate_obligation(&obligation) {
|
||||
cx.sess.span_note(span,
|
||||
&format!("use `({0}.{1})(...)` if you meant to call the \
|
||||
function stored in the `{1}` field",
|
||||
expr_string, item_name));
|
||||
} else {
|
||||
cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?",
|
||||
expr_string, item_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,33 +10,10 @@
|
||||
|
||||
struct Obj<F> where F: FnMut() -> u32 {
|
||||
closure: F,
|
||||
nfn: usize,
|
||||
}
|
||||
|
||||
struct S<F> where F: FnMut() -> u32 {
|
||||
v: Obj<F>,
|
||||
}
|
||||
|
||||
fn func() -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let o = Obj { closure: || 42, nfn: 42 };
|
||||
let o = Obj { closure: || 42 };
|
||||
o.closure(); //~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
|
||||
// TODO move these to a new test for #2392
|
||||
let x = o.nfn(); //~ ERROR no method named `nfn` found
|
||||
//~^ NOTE did you mean to write `o.nfn`?
|
||||
|
||||
let b = Obj { closure: func, nfn: 5 };
|
||||
b.closure(); //~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(b.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
|
||||
let s = S { v: b };
|
||||
s.v.closure();//~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(s.v.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
s.v.nfn();//~ ERROR no method named `nfn` found
|
||||
//~^ NOTE did you mean to write `s.v.nfn`?
|
||||
}
|
||||
|
65
src/test/compile-fail/issue-2392.rs
Normal file
65
src/test/compile-fail/issue-2392.rs
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core)]
|
||||
use std::boxed::FnBox;
|
||||
|
||||
struct Obj<F> where F: FnOnce() -> u32 {
|
||||
closure: F,
|
||||
not_closure: usize,
|
||||
}
|
||||
|
||||
struct BoxedObj {
|
||||
boxed_closure: Box<FnBox() -> u32>,
|
||||
}
|
||||
|
||||
struct Wrapper<F> where F: FnMut() -> u32 {
|
||||
wrap: Obj<F>,
|
||||
}
|
||||
|
||||
fn func() -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn check_expression() -> Obj<Box<FnBox() -> u32>> {
|
||||
Obj { closure: Box::new(|| 42_u32) as Box<FnBox() -> u32>, not_closure: 42 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// test variations of function
|
||||
let o_closure = Obj { closure: || 42, not_closure: 42 };
|
||||
o_closure.closure(); //~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
|
||||
o_closure.not_closure(); //~ ERROR no method named `not_closure` found
|
||||
//~^ NOTE did you mean to write `o_closure.not_closure`?
|
||||
|
||||
let o_func = Obj { closure: func, not_closure: 5 };
|
||||
o_func.closure(); //~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
|
||||
let boxed_fn = BoxedObj { boxed_closure: Box::new(func) };
|
||||
boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found
|
||||
//~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
|
||||
|
||||
let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box<FnBox() -> u32> };
|
||||
boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found
|
||||
//~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
|
||||
|
||||
// test expression writing in the notes
|
||||
let w = Wrapper { wrap: o_func };
|
||||
w.wrap.closure();//~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
w.wrap.not_closure();//~ ERROR no method named `not_closure` found
|
||||
//~^ NOTE did you mean to write `w.wrap.not_closure`?
|
||||
|
||||
check_expression().closure();//~ ERROR no method named `closure` found
|
||||
//~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user