Skip to content

Commit d096eef

Browse files
committed
Use only the appropriate trait when looking up operator overloads.
1 parent 818203e commit d096eef

File tree

4 files changed

+198
-160
lines changed

4 files changed

+198
-160
lines changed

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

+88-25
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,14 @@ pub fn lookup(
134134
check_traits: CheckTraitsFlag, // Whether we check traits only.
135135
autoderef_receiver: AutoderefReceiverFlag)
136136
-> Option<method_origin> {
137-
let impl_dups = @RefCell::new(HashSet::new());
138137
let lcx = LookupContext {
139138
fcx: fcx,
140139
expr: expr,
141140
self_expr: self_expr,
142141
callee_id: callee_id,
143142
m_name: m_name,
144143
supplied_tps: supplied_tps,
145-
impl_dups: impl_dups,
144+
impl_dups: @RefCell::new(HashSet::new()),
146145
inherent_candidates: @RefCell::new(~[]),
147146
extension_candidates: @RefCell::new(~[]),
148147
deref_args: deref_args,
@@ -164,11 +163,50 @@ pub fn lookup(
164163

165164
debug!("searching extension candidates");
166165
lcx.reset_candidates();
167-
lcx.push_bound_candidates(self_ty);
166+
lcx.push_bound_candidates(self_ty, None);
168167
lcx.push_extension_candidates();
169168
return lcx.search(self_ty);
170169
}
171170

171+
pub fn lookup_in_trait(
172+
fcx: @FnCtxt,
173+
174+
// In a call `a.b::<X, Y, ...>(...)`:
175+
expr: &ast::Expr, // The expression `a.b(...)`.
176+
self_expr: &ast::Expr, // The expression `a`.
177+
callee_id: NodeId, /* Where to store `a.b`'s type,
178+
* also the scope of the call */
179+
m_name: ast::Name, // The name `b`.
180+
trait_did: DefId, // The trait to limit the lookup to.
181+
self_ty: ty::t, // The type of `a`.
182+
supplied_tps: &[ty::t], // The list of types X, Y, ... .
183+
autoderef_receiver: AutoderefReceiverFlag)
184+
-> Option<method_origin> {
185+
let lcx = LookupContext {
186+
fcx: fcx,
187+
expr: expr,
188+
self_expr: self_expr,
189+
callee_id: callee_id,
190+
m_name: m_name,
191+
supplied_tps: supplied_tps,
192+
impl_dups: @RefCell::new(HashSet::new()),
193+
inherent_candidates: @RefCell::new(~[]),
194+
extension_candidates: @RefCell::new(~[]),
195+
deref_args: check::DoDerefArgs,
196+
check_traits: CheckTraitsOnly,
197+
autoderef_receiver: autoderef_receiver,
198+
};
199+
200+
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
201+
debug!("method lookup_in_trait(self_ty={}, expr={}, self_expr={})",
202+
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
203+
self_expr.repr(fcx.tcx()));
204+
205+
lcx.push_bound_candidates(self_ty, Some(trait_did));
206+
lcx.push_extension_candidate(trait_did);
207+
lcx.search(self_ty)
208+
}
209+
172210
pub struct LookupContext<'a> {
173211
fcx: @FnCtxt,
174212
expr: &'a ast::Expr,
@@ -319,17 +357,17 @@ impl<'a> LookupContext<'a> {
319357
}
320358
}
321359

322-
fn push_bound_candidates(&self, self_ty: ty::t) {
360+
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
323361
let mut self_ty = self_ty;
324362
loop {
325363
match get(self_ty).sty {
326364
ty_param(p) => {
327-
self.push_inherent_candidates_from_param(self_ty, p);
365+
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
328366
}
329367
ty_self(..) => {
330368
// Call is of the form "self.foo()" and appears in one
331369
// of a trait's default method implementations.
332-
self.push_inherent_candidates_from_self(self_ty);
370+
self.push_inherent_candidates_from_self(self_ty, restrict_to);
333371
}
334372
_ => { /* No bound methods in these types */ }
335373
}
@@ -341,6 +379,19 @@ impl<'a> LookupContext<'a> {
341379
}
342380
}
343381

382+
fn push_extension_candidate(&self, trait_did: DefId) {
383+
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did);
384+
385+
// Look for explicit implementations.
386+
let trait_impls = self.tcx().trait_impls.borrow();
387+
for impl_infos in trait_impls.get().find(&trait_did).iter() {
388+
for impl_info in impl_infos.borrow().get().iter() {
389+
self.push_candidates_from_impl(
390+
self.extension_candidates.borrow_mut().get(), *impl_info);
391+
}
392+
}
393+
}
394+
344395
fn push_extension_candidates(&self) {
345396
// If the method being called is associated with a trait, then
346397
// find all the impls of that trait. Each of those are
@@ -428,7 +479,7 @@ impl<'a> LookupContext<'a> {
428479
self.construct_transformed_self_ty_for_object(
429480
did, &rcvr_substs, &m);
430481

431-
Candidate {
482+
Some(Candidate {
432483
rcvr_match_condition: RcvrMatchesIfObject(did),
433484
rcvr_substs: new_trait_ref.substs.clone(),
434485
method_ty: @m,
@@ -438,49 +489,61 @@ impl<'a> LookupContext<'a> {
438489
method_num: method_num,
439490
real_index: vtable_index
440491
})
441-
}
492+
})
442493
});
443494
}
444495

445496
fn push_inherent_candidates_from_param(&self,
446497
rcvr_ty: ty::t,
498+
restrict_to: Option<DefId>,
447499
param_ty: param_ty) {
448500
debug!("push_inherent_candidates_from_param(param_ty={:?})",
449501
param_ty);
450502
self.push_inherent_candidates_from_bounds(
451503
rcvr_ty,
452504
self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds,
505+
restrict_to,
453506
param_numbered(param_ty.idx));
454507
}
455508

456509

457510
fn push_inherent_candidates_from_self(&self,
458-
rcvr_ty: ty::t) {
511+
rcvr_ty: ty::t,
512+
restrict_to: Option<DefId>) {
459513
debug!("push_inherent_candidates_from_self()");
460514
self.push_inherent_candidates_from_bounds(
461515
rcvr_ty,
462516
[self.fcx.inh.param_env.self_param_bound.unwrap()],
517+
restrict_to,
463518
param_self)
464519
}
465520

466521
fn push_inherent_candidates_from_bounds(&self,
467522
self_ty: ty::t,
468523
bounds: &[@TraitRef],
524+
restrict_to: Option<DefId>,
469525
param: param_index) {
470526
self.push_inherent_candidates_from_bounds_inner(bounds,
471527
|trait_ref, m, method_num, bound_num| {
472-
Candidate {
473-
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
474-
rcvr_substs: trait_ref.substs.clone(),
475-
method_ty: m,
476-
origin: method_param(
477-
method_param {
528+
match restrict_to {
529+
Some(trait_did) => {
530+
if trait_did != trait_ref.def_id {
531+
return None;
532+
}
533+
}
534+
_ => {}
535+
}
536+
Some(Candidate {
537+
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
538+
rcvr_substs: trait_ref.substs.clone(),
539+
method_ty: m,
540+
origin: method_param(method_param {
478541
trait_id: trait_ref.def_id,
479542
method_num: method_num,
480543
param_num: param,
481544
bound_num: bound_num,
482545
})
483-
}
546+
})
484547
})
485548
}
486549

@@ -492,7 +555,7 @@ impl<'a> LookupContext<'a> {
492555
m: @ty::Method,
493556
method_num: uint,
494557
bound_num: uint|
495-
-> Candidate) {
558+
-> Option<Candidate>) {
496559
let tcx = self.tcx();
497560
let mut next_bound_idx = 0; // count only trait bounds
498561

@@ -508,17 +571,17 @@ impl<'a> LookupContext<'a> {
508571
Some(pos) => {
509572
let method = trait_methods[pos];
510573

511-
let cand = mk_cand(bound_trait_ref, method,
512-
pos, this_bound_idx);
513-
514-
debug!("pushing inherent candidate for param: {:?}", cand);
515-
let mut inherent_candidates = self.inherent_candidates
516-
.borrow_mut();
517-
inherent_candidates.get().push(cand);
574+
match mk_cand(bound_trait_ref, method, pos, this_bound_idx) {
575+
Some(cand) => {
576+
debug!("pushing inherent candidate for param: {:?}", cand);
577+
self.inherent_candidates.borrow_mut().get().push(cand);
578+
}
579+
None => {}
580+
}
518581
}
519582
None => {
520583
debug!("trait doesn't contain method: {:?}",
521-
bound_trait_ref.def_id);
584+
bound_trait_ref.def_id);
522585
// check next trait or bound
523586
}
524587
}

0 commit comments

Comments
 (0)