提交 cb08cb8a 编写于 作者: K Kevin Butler

Provide a note if method lookup fails and there are static definitions with the same name.

上级 b5d6b073
......@@ -16,7 +16,7 @@
use middle::lang_items::LanguageItems;
use middle::lint::{UnnecessaryQualification, UnusedImports};
use middle::pat_util::pat_bindings;
use util::nodemap::{NodeMap, DefIdSet, FnvHashSet};
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use syntax::ast::*;
use syntax::ast;
......@@ -821,7 +821,7 @@ fn Resolver<'a>(session: &'a Session,
graph_root: graph_root,
method_set: RefCell::new(FnvHashSet::new()),
method_map: RefCell::new(FnvHashMap::new()),
structs: HashSet::new(),
unresolved_imports: 0,
......@@ -860,7 +860,7 @@ struct Resolver<'a> {
graph_root: NameBindings,
method_set: RefCell<FnvHashSet<(Name, DefId)>>,
method_map: RefCell<FnvHashMap<(Name, DefId), ast::ExplicitSelf_>>,
structs: HashSet<DefId>,
// The number of imports that are currently unresolved.
......@@ -1371,10 +1371,8 @@ fn build_reduced_graph_for_item(&mut self,
ty_m.span);
method_name_bindings.define_value(def, ty_m.span, true);
// Add it to the trait info if not static.
if ty_m.explicit_self.node != SelfStatic {
self.method_set.borrow_mut().insert((ident.name, def_id));
}
self.method_map.borrow_mut().insert((ident.name, def_id),
ty_m.explicit_self.node);
}
name_bindings.define_type(DefTrait(def_id), sp, is_public);
......@@ -1660,10 +1658,8 @@ fn handle_external_def(&mut self,
trait method '{}'",
token::get_ident(method_name));
// Add it to the trait info if not static.
if explicit_self != SelfStatic {
self.method_set.borrow_mut().insert((method_name.name, def_id));
}
self.method_map.borrow_mut().insert((method_name.name, def_id), explicit_self);
if is_exported {
self.external_exports.insert(method_def_id);
}
......@@ -4718,10 +4714,16 @@ fn resolve_module_relative_path(&mut self,
match containing_module.kind.get() {
TraitModuleKind | ImplModuleKind => {
match containing_module.def_id.get() {
Some(def_id) if self.method_set.borrow().contains(&(ident.name, def_id)) => {
debug!("containing module was a trait or impl \
Some(def_id) => {
match self.method_map.borrow().find(&(ident.name, def_id)) {
Some(x) if *x == SelfStatic => (),
None => (),
_ => {
debug!("containing module was a trait or impl \
and name was a method -> not resolved");
return None;
return None;
}
}
},
_ => (),
}
......@@ -5110,9 +5112,9 @@ fn add_trait_info(found_traits: &mut Vec<DefId>,
// Look for the current trait.
match self.current_trait_refs {
Some(ref trait_def_ids) => {
let method_set = self.method_set.borrow();
let method_map = self.method_map.borrow();
for &trait_def_id in trait_def_ids.iter() {
if method_set.contains(&(name, trait_def_id)) {
if method_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
......@@ -5126,7 +5128,7 @@ fn add_trait_info(found_traits: &mut Vec<DefId>,
self.populate_module_if_necessary(&search_module);
{
let method_set = self.method_set.borrow();
let method_map = self.method_map.borrow();
for (_, child_names) in search_module.children.borrow().iter() {
let def = match child_names.def_for_namespace(TypeNS) {
Some(def) => def,
......@@ -5136,7 +5138,7 @@ fn add_trait_info(found_traits: &mut Vec<DefId>,
DefTrait(trait_def_id) => trait_def_id,
_ => continue,
};
if method_set.contains(&(name, trait_def_id)) {
if method_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
......@@ -5152,7 +5154,7 @@ fn add_trait_info(found_traits: &mut Vec<DefId>,
Some(DefTrait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
if self.method_set.borrow().contains(&(name, did)) {
if self.method_map.borrow().contains_key(&(name, did)) {
add_trait_info(&mut found_traits, did, name);
self.used_imports.insert((import.type_id, TypeNS));
}
......
......@@ -118,6 +118,12 @@ pub enum AutoderefReceiverFlag {
DontAutoderefReceiver,
}
#[deriving(Eq)]
pub enum StaticMethodsFlag {
ReportStaticMethods,
IgnoreStaticMethods,
}
pub fn lookup<'a>(
fcx: &'a FnCtxt<'a>,
......@@ -129,7 +135,8 @@ pub fn lookup<'a>(
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
deref_args: check::DerefArgs, // Whether we autopointer first.
check_traits: CheckTraitsFlag, // Whether we check traits only.
autoderef_receiver: AutoderefReceiverFlag)
autoderef_receiver: AutoderefReceiverFlag,
report_statics: StaticMethodsFlag)
-> Option<MethodCallee> {
let mut lcx = LookupContext {
fcx: fcx,
......@@ -143,6 +150,7 @@ pub fn lookup<'a>(
deref_args: deref_args,
check_traits: check_traits,
autoderef_receiver: autoderef_receiver,
report_statics: report_statics,
};
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
......@@ -173,7 +181,8 @@ pub fn lookup_in_trait<'a>(
trait_did: DefId, // The trait to limit the lookup to.
self_ty: ty::t, // The type of `a`.
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
autoderef_receiver: AutoderefReceiverFlag)
autoderef_receiver: AutoderefReceiverFlag,
report_statics: StaticMethodsFlag)
-> Option<MethodCallee> {
let mut lcx = LookupContext {
fcx: fcx,
......@@ -187,6 +196,7 @@ pub fn lookup_in_trait<'a>(
deref_args: check::DoDerefArgs,
check_traits: CheckTraitsOnly,
autoderef_receiver: autoderef_receiver,
report_statics: report_statics,
};
debug!("method lookup_in_trait(self_ty={}, self_expr={})",
......@@ -197,8 +207,6 @@ pub fn lookup_in_trait<'a>(
lcx.search(self_ty)
}
// Determine the index of a method in the list of all methods belonging
// to a trait and its supertraits.
fn get_method_index(tcx: &ty::ctxt,
......@@ -301,6 +309,7 @@ struct LookupContext<'a> {
deref_args: check::DerefArgs,
check_traits: CheckTraitsFlag,
autoderef_receiver: AutoderefReceiverFlag,
report_statics: StaticMethodsFlag,
}
/**
......@@ -661,7 +670,17 @@ fn push_candidates_from_impl(&mut self,
impl_did: DefId,
impl_methods: &[DefId],
is_extension: bool) {
if !self.impl_dups.insert(impl_did) {
let did = if self.report_statics == ReportStaticMethods {
// we only want to report each base trait once
match ty::impl_trait_ref(self.tcx(), impl_did) {
Some(trait_ref) => trait_ref.def_id,
None => impl_did
}
} else {
impl_did
};
if !self.impl_dups.insert(did) {
return; // already visited
}
......@@ -1018,6 +1037,25 @@ fn consider_candidates(&self, rcvr_ty: ty::t,
return None;
}
if self.report_statics == ReportStaticMethods {
// lookup should only be called with ReportStaticMethods if a regular lookup failed
assert!(relevant_candidates.iter().all(|c| c.method_ty.explicit_self == SelfStatic));
self.tcx().sess.fileline_note(self.span,
"found defined static methods, maybe a `self` is missing?");
for (idx, candidate) in relevant_candidates.iter().enumerate() {
self.report_candidate(idx, &candidate.origin);
}
// return something so we don't get errors for every mutability
return Some(MethodCallee {
origin: relevant_candidates.get(0).origin,
ty: ty::mk_err(),
substs: substs::empty()
});
}
if relevant_candidates.len() > 1 {
self.tcx().sess.span_err(
self.span,
......@@ -1305,7 +1343,7 @@ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
return match candidate.method_ty.explicit_self {
SelfStatic => {
debug!("(is relevant?) explicit self is static");
false
self.report_statics == ReportStaticMethods
}
SelfValue => {
......@@ -1391,11 +1429,20 @@ fn mutability_matches(self_mutbl: ast::Mutability,
fn report_candidate(&self, idx: uint, origin: &MethodOrigin) {
match *origin {
MethodStatic(impl_did) => {
// If it is an instantiated default method, use the original
// default method for error reporting.
let did = match provided_source(self.tcx(), impl_did) {
None => impl_did,
Some(did) => did
let did = if self.report_statics == ReportStaticMethods {
// If we're reporting statics, we want to report the trait
// definition if possible, rather than an impl
match ty::trait_method_of_method(self.tcx(), impl_did) {
None => {debug!("(report candidate) No trait method found"); impl_did},
Some(trait_did) => {debug!("(report candidate) Found trait ref"); trait_did}
}
} else {
// If it is an instantiated default method, use the original
// default method for error reporting.
match provided_source(self.tcx(), impl_did) {
None => impl_did,
Some(did) => did
}
};
self.report_static_candidate(idx, did)
}
......
......@@ -97,6 +97,7 @@
use middle::typeck::check::method::{AutoderefReceiverFlag};
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
use middle::typeck::check::method::{DontAutoderefReceiver};
use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::relate_free_regions;
use middle::typeck::check::vtable::VtableContext;
......@@ -1360,7 +1361,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
(PreferMutLvalue, Some(trait_did)) => {
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref_mut"), trait_did,
base_ty, [], DontAutoderefReceiver)
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
}
_ => None
};
......@@ -1370,7 +1371,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
(None, Some(trait_did)) => {
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref"), trait_did,
base_ty, [], DontAutoderefReceiver)
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
}
(method, _) => method
};
......@@ -1956,7 +1957,7 @@ fn check_method_call(fcx: &FnCtxt,
expr_t, tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
AutoderefReceiver) {
AutoderefReceiver, IgnoreStaticMethods) {
Some(method) => {
let method_ty = method.ty;
let method_call = MethodCall::expr(expr.id);
......@@ -1976,6 +1977,15 @@ fn check_method_call(fcx: &FnCtxt,
// Add error type for the result
fcx.write_error(expr.id);
// Check for potential static matches (missing self parameters)
method::lookup(fcx, expr, rcvr,
method_name.node.name,
expr_t, tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
DontAutoderefReceiver, ReportStaticMethods);
ty::mk_err()
}
};
......@@ -2040,7 +2050,8 @@ fn lookup_op_method(fcx: &FnCtxt,
let method = match trait_did {
Some(trait_did) => {
method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
trait_did, self_t, [], autoderef_receiver)
trait_did, self_t, [], autoderef_receiver,
IgnoreStaticMethods)
}
None => None
};
......@@ -2348,7 +2359,8 @@ fn check_field(fcx: &FnCtxt,
tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
AutoderefReceiver) {
AutoderefReceiver,
IgnoreStaticMethods) {
Some(_) => {
fcx.type_error_message(
expr.span,
......
// 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.
trait CtxtFn {
fn f8(self, uint) -> uint;
fn f9(uint) -> uint; //~ NOTE candidate #
}
trait OtherTrait {
fn f9(uint) -> uint; //~ NOTE candidate #
}
trait UnusedTrait { // This should never show up as a candidate
fn f9(uint) -> uint;
}
impl CtxtFn for uint {
fn f8(self, i: uint) -> uint {
i * 4u
}
fn f9(i: uint) -> uint {
i * 4u
}
}
impl OtherTrait for uint {
fn f9(i: uint) -> uint {
i * 8u
}
}
struct MyInt(int);
impl MyInt {
fn fff(i: int) -> int { //~ NOTE candidate #1 is `MyInt::fff`
i
}
}
trait ManyImplTrait {
fn is_str() -> bool { //~ NOTE candidate #1 is
false
}
}
impl ManyImplTrait for ~str {
fn is_str() -> bool {
true
}
}
impl ManyImplTrait for uint {}
impl ManyImplTrait for int {}
impl ManyImplTrait for char {}
impl ManyImplTrait for MyInt {}
fn no_param_bound(u: uint, m: MyInt) -> uint {
u.f8(42) + u.f9(342) + m.fff(42)
//~^ ERROR type `uint` does not implement any method in scope named `f9`
//~^^ NOTE found defined static methods, maybe a `self` is missing?
//~^^^ ERROR type `MyInt` does not implement any method in scope named `fff`
//~^^^^ NOTE found defined static methods, maybe a `self` is missing?
}
fn param_bound<T: ManyImplTrait>(t: T) -> bool {
t.is_str()
//~^ ERROR type `T` does not implement any method in scope named `is_str`
//~^^ NOTE found defined static methods, maybe a `self` is missing?
}
fn main() {
}
\ No newline at end of file
// 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.
trait Foo {
fn new() -> bool { false }
}
trait Bar {
fn new(&self) -> bool { true }
}
impl Bar for int {}
impl Foo for int {}
fn main() {
assert!(1i.new());
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册