Skip to content

Commit 4f1b0b5

Browse files
committed
auto merge of #13685 : Ryman/rust/issue7575, r=alexcrichton
Closes #7575. I don't think the change from a contains lookup to an iteration of the HashSet in the resolver should be much of a burden as the set of methods with the same name should be relatively small.
2 parents 0c691df + cb08cb8 commit 4f1b0b5

File tree

5 files changed

+200
-35
lines changed

5 files changed

+200
-35
lines changed

src/librustc/middle/resolve.rs

+21-19
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
1616
use middle::lang_items::LanguageItems;
1717
use middle::lint::{UnnecessaryQualification, UnusedImports};
1818
use middle::pat_util::pat_bindings;
19-
use util::nodemap::{NodeMap, DefIdSet, FnvHashSet};
19+
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
2020

2121
use syntax::ast::*;
2222
use syntax::ast;
@@ -821,7 +821,7 @@ fn Resolver<'a>(session: &'a Session,
821821

822822
graph_root: graph_root,
823823

824-
method_set: RefCell::new(FnvHashSet::new()),
824+
method_map: RefCell::new(FnvHashMap::new()),
825825
structs: HashSet::new(),
826826

827827
unresolved_imports: 0,
@@ -860,7 +860,7 @@ struct Resolver<'a> {
860860

861861
graph_root: NameBindings,
862862

863-
method_set: RefCell<FnvHashSet<(Name, DefId)>>,
863+
method_map: RefCell<FnvHashMap<(Name, DefId), ast::ExplicitSelf_>>,
864864
structs: HashSet<DefId>,
865865

866866
// The number of imports that are currently unresolved.
@@ -1371,10 +1371,8 @@ impl<'a> Resolver<'a> {
13711371
ty_m.span);
13721372
method_name_bindings.define_value(def, ty_m.span, true);
13731373

1374-
// Add it to the trait info if not static.
1375-
if ty_m.explicit_self.node != SelfStatic {
1376-
self.method_set.borrow_mut().insert((ident.name, def_id));
1377-
}
1374+
self.method_map.borrow_mut().insert((ident.name, def_id),
1375+
ty_m.explicit_self.node);
13781376
}
13791377

13801378
name_bindings.define_type(DefTrait(def_id), sp, is_public);
@@ -1660,10 +1658,8 @@ impl<'a> Resolver<'a> {
16601658
trait method '{}'",
16611659
token::get_ident(method_name));
16621660

1663-
// Add it to the trait info if not static.
1664-
if explicit_self != SelfStatic {
1665-
self.method_set.borrow_mut().insert((method_name.name, def_id));
1666-
}
1661+
self.method_map.borrow_mut().insert((method_name.name, def_id), explicit_self);
1662+
16671663
if is_exported {
16681664
self.external_exports.insert(method_def_id);
16691665
}
@@ -4718,10 +4714,16 @@ impl<'a> Resolver<'a> {
47184714
match containing_module.kind.get() {
47194715
TraitModuleKind | ImplModuleKind => {
47204716
match containing_module.def_id.get() {
4721-
Some(def_id) if self.method_set.borrow().contains(&(ident.name, def_id)) => {
4722-
debug!("containing module was a trait or impl \
4717+
Some(def_id) => {
4718+
match self.method_map.borrow().find(&(ident.name, def_id)) {
4719+
Some(x) if *x == SelfStatic => (),
4720+
None => (),
4721+
_ => {
4722+
debug!("containing module was a trait or impl \
47234723
and name was a method -> not resolved");
4724-
return None;
4724+
return None;
4725+
}
4726+
}
47254727
},
47264728
_ => (),
47274729
}
@@ -5110,9 +5112,9 @@ impl<'a> Resolver<'a> {
51105112
// Look for the current trait.
51115113
match self.current_trait_refs {
51125114
Some(ref trait_def_ids) => {
5113-
let method_set = self.method_set.borrow();
5115+
let method_map = self.method_map.borrow();
51145116
for &trait_def_id in trait_def_ids.iter() {
5115-
if method_set.contains(&(name, trait_def_id)) {
5117+
if method_map.contains_key(&(name, trait_def_id)) {
51165118
add_trait_info(&mut found_traits, trait_def_id, name);
51175119
}
51185120
}
@@ -5126,7 +5128,7 @@ impl<'a> Resolver<'a> {
51265128
self.populate_module_if_necessary(&search_module);
51275129

51285130
{
5129-
let method_set = self.method_set.borrow();
5131+
let method_map = self.method_map.borrow();
51305132
for (_, child_names) in search_module.children.borrow().iter() {
51315133
let def = match child_names.def_for_namespace(TypeNS) {
51325134
Some(def) => def,
@@ -5136,7 +5138,7 @@ impl<'a> Resolver<'a> {
51365138
DefTrait(trait_def_id) => trait_def_id,
51375139
_ => continue,
51385140
};
5139-
if method_set.contains(&(name, trait_def_id)) {
5141+
if method_map.contains_key(&(name, trait_def_id)) {
51405142
add_trait_info(&mut found_traits, trait_def_id, name);
51415143
}
51425144
}
@@ -5152,7 +5154,7 @@ impl<'a> Resolver<'a> {
51525154
Some(DefTrait(trait_def_id)) => trait_def_id,
51535155
Some(..) | None => continue,
51545156
};
5155-
if self.method_set.borrow().contains(&(name, did)) {
5157+
if self.method_map.borrow().contains_key(&(name, did)) {
51565158
add_trait_info(&mut found_traits, did, name);
51575159
self.used_imports.insert((import.type_id, TypeNS));
51585160
}

src/librustc/middle/typeck/check/method.rs

+58-11
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ pub enum AutoderefReceiverFlag {
118118
DontAutoderefReceiver,
119119
}
120120

121+
#[deriving(Eq)]
122+
pub enum StaticMethodsFlag {
123+
ReportStaticMethods,
124+
IgnoreStaticMethods,
125+
}
126+
121127
pub fn lookup<'a>(
122128
fcx: &'a FnCtxt<'a>,
123129

@@ -129,7 +135,8 @@ pub fn lookup<'a>(
129135
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
130136
deref_args: check::DerefArgs, // Whether we autopointer first.
131137
check_traits: CheckTraitsFlag, // Whether we check traits only.
132-
autoderef_receiver: AutoderefReceiverFlag)
138+
autoderef_receiver: AutoderefReceiverFlag,
139+
report_statics: StaticMethodsFlag)
133140
-> Option<MethodCallee> {
134141
let mut lcx = LookupContext {
135142
fcx: fcx,
@@ -143,6 +150,7 @@ pub fn lookup<'a>(
143150
deref_args: deref_args,
144151
check_traits: check_traits,
145152
autoderef_receiver: autoderef_receiver,
153+
report_statics: report_statics,
146154
};
147155

148156
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
@@ -173,7 +181,8 @@ pub fn lookup_in_trait<'a>(
173181
trait_did: DefId, // The trait to limit the lookup to.
174182
self_ty: ty::t, // The type of `a`.
175183
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
176-
autoderef_receiver: AutoderefReceiverFlag)
184+
autoderef_receiver: AutoderefReceiverFlag,
185+
report_statics: StaticMethodsFlag)
177186
-> Option<MethodCallee> {
178187
let mut lcx = LookupContext {
179188
fcx: fcx,
@@ -187,6 +196,7 @@ pub fn lookup_in_trait<'a>(
187196
deref_args: check::DoDerefArgs,
188197
check_traits: CheckTraitsOnly,
189198
autoderef_receiver: autoderef_receiver,
199+
report_statics: report_statics,
190200
};
191201

192202
debug!("method lookup_in_trait(self_ty={}, self_expr={})",
@@ -197,8 +207,6 @@ pub fn lookup_in_trait<'a>(
197207
lcx.search(self_ty)
198208
}
199209

200-
201-
202210
// Determine the index of a method in the list of all methods belonging
203211
// to a trait and its supertraits.
204212
fn get_method_index(tcx: &ty::ctxt,
@@ -301,6 +309,7 @@ struct LookupContext<'a> {
301309
deref_args: check::DerefArgs,
302310
check_traits: CheckTraitsFlag,
303311
autoderef_receiver: AutoderefReceiverFlag,
312+
report_statics: StaticMethodsFlag,
304313
}
305314

306315
/**
@@ -661,7 +670,17 @@ impl<'a> LookupContext<'a> {
661670
impl_did: DefId,
662671
impl_methods: &[DefId],
663672
is_extension: bool) {
664-
if !self.impl_dups.insert(impl_did) {
673+
let did = if self.report_statics == ReportStaticMethods {
674+
// we only want to report each base trait once
675+
match ty::impl_trait_ref(self.tcx(), impl_did) {
676+
Some(trait_ref) => trait_ref.def_id,
677+
None => impl_did
678+
}
679+
} else {
680+
impl_did
681+
};
682+
683+
if !self.impl_dups.insert(did) {
665684
return; // already visited
666685
}
667686

@@ -1018,6 +1037,25 @@ impl<'a> LookupContext<'a> {
10181037
return None;
10191038
}
10201039

1040+
if self.report_statics == ReportStaticMethods {
1041+
// lookup should only be called with ReportStaticMethods if a regular lookup failed
1042+
assert!(relevant_candidates.iter().all(|c| c.method_ty.explicit_self == SelfStatic));
1043+
1044+
self.tcx().sess.fileline_note(self.span,
1045+
"found defined static methods, maybe a `self` is missing?");
1046+
1047+
for (idx, candidate) in relevant_candidates.iter().enumerate() {
1048+
self.report_candidate(idx, &candidate.origin);
1049+
}
1050+
1051+
// return something so we don't get errors for every mutability
1052+
return Some(MethodCallee {
1053+
origin: relevant_candidates.get(0).origin,
1054+
ty: ty::mk_err(),
1055+
substs: substs::empty()
1056+
});
1057+
}
1058+
10211059
if relevant_candidates.len() > 1 {
10221060
self.tcx().sess.span_err(
10231061
self.span,
@@ -1305,7 +1343,7 @@ impl<'a> LookupContext<'a> {
13051343
return match candidate.method_ty.explicit_self {
13061344
SelfStatic => {
13071345
debug!("(is relevant?) explicit self is static");
1308-
false
1346+
self.report_statics == ReportStaticMethods
13091347
}
13101348

13111349
SelfValue => {
@@ -1391,11 +1429,20 @@ impl<'a> LookupContext<'a> {
13911429
fn report_candidate(&self, idx: uint, origin: &MethodOrigin) {
13921430
match *origin {
13931431
MethodStatic(impl_did) => {
1394-
// If it is an instantiated default method, use the original
1395-
// default method for error reporting.
1396-
let did = match provided_source(self.tcx(), impl_did) {
1397-
None => impl_did,
1398-
Some(did) => did
1432+
let did = if self.report_statics == ReportStaticMethods {
1433+
// If we're reporting statics, we want to report the trait
1434+
// definition if possible, rather than an impl
1435+
match ty::trait_method_of_method(self.tcx(), impl_did) {
1436+
None => {debug!("(report candidate) No trait method found"); impl_did},
1437+
Some(trait_did) => {debug!("(report candidate) Found trait ref"); trait_did}
1438+
}
1439+
} else {
1440+
// If it is an instantiated default method, use the original
1441+
// default method for error reporting.
1442+
match provided_source(self.tcx(), impl_did) {
1443+
None => impl_did,
1444+
Some(did) => did
1445+
}
13991446
};
14001447
self.report_static_candidate(idx, did)
14011448
}

src/librustc/middle/typeck/check/mod.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ use middle::typeck::check::method::{AutoderefReceiver};
9797
use middle::typeck::check::method::{AutoderefReceiverFlag};
9898
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
9999
use middle::typeck::check::method::{DontAutoderefReceiver};
100+
use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
100101
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
101102
use middle::typeck::check::regionmanip::relate_free_regions;
102103
use middle::typeck::check::vtable::VtableContext;
@@ -1360,7 +1361,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
13601361
(PreferMutLvalue, Some(trait_did)) => {
13611362
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
13621363
token::intern("deref_mut"), trait_did,
1363-
base_ty, [], DontAutoderefReceiver)
1364+
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
13641365
}
13651366
_ => None
13661367
};
@@ -1370,7 +1371,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
13701371
(None, Some(trait_did)) => {
13711372
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
13721373
token::intern("deref"), trait_did,
1373-
base_ty, [], DontAutoderefReceiver)
1374+
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
13741375
}
13751376
(method, _) => method
13761377
};
@@ -1956,7 +1957,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
19561957
expr_t, tps.as_slice(),
19571958
DontDerefArgs,
19581959
CheckTraitsAndInherentMethods,
1959-
AutoderefReceiver) {
1960+
AutoderefReceiver, IgnoreStaticMethods) {
19601961
Some(method) => {
19611962
let method_ty = method.ty;
19621963
let method_call = MethodCall::expr(expr.id);
@@ -1976,6 +1977,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
19761977

19771978
// Add error type for the result
19781979
fcx.write_error(expr.id);
1980+
1981+
// Check for potential static matches (missing self parameters)
1982+
method::lookup(fcx, expr, rcvr,
1983+
method_name.node.name,
1984+
expr_t, tps.as_slice(),
1985+
DontDerefArgs,
1986+
CheckTraitsAndInherentMethods,
1987+
DontAutoderefReceiver, ReportStaticMethods);
1988+
19791989
ty::mk_err()
19801990
}
19811991
};
@@ -2040,7 +2050,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
20402050
let method = match trait_did {
20412051
Some(trait_did) => {
20422052
method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
2043-
trait_did, self_t, [], autoderef_receiver)
2053+
trait_did, self_t, [], autoderef_receiver,
2054+
IgnoreStaticMethods)
20442055
}
20452056
None => None
20462057
};
@@ -2367,7 +2378,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
23672378
tps.as_slice(),
23682379
DontDerefArgs,
23692380
CheckTraitsAndInherentMethods,
2370-
AutoderefReceiver) {
2381+
AutoderefReceiver,
2382+
IgnoreStaticMethods) {
23712383
Some(_) => {
23722384
fcx.type_error_message(
23732385
expr.span,

0 commit comments

Comments
 (0)