Skip to content

Commit 90812c1

Browse files
committed
Rework method lookup to properly handle self types for non impl matches. Closes #3268. Closes #3274.
1 parent 6a56212 commit 90812c1

File tree

1 file changed

+72
-15
lines changed

1 file changed

+72
-15
lines changed

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

+72-15
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,24 @@ struct lookup {
140140
immutable_reference_mode, mutable_reference_mode];
141141

142142
loop {
143-
self.add_candidates_from_type();
143+
// Try to find a method that is keyed directly off of the
144+
// type. This only happens for boxed traits, type params,
145+
// classes, and self. If we see some sort of pointer, then
146+
// we look at candidates for the pointed to type to match
147+
// them against methods that take explicit self parameters.
148+
// N.B.: this looking through boxes to match against
149+
// explicit self parameters is *not* the same as
150+
// autoderef.
151+
// Try each of the possible matching semantics in turn.
152+
for matching_modes.each |mode| {
153+
match ty::get(self.self_ty).struct {
154+
ty::ty_box(mt) | ty::ty_uniq(mt) | ty::ty_rptr(_, mt) => {
155+
self.add_candidates_from_type(mt.ty, mode);
156+
}
157+
_ => { self.add_candidates_from_type(self.self_ty, mode); }
158+
}
159+
if self.candidates.len() > 0u { break; }
160+
}
144161

145162
// if we found anything, stop now. otherwise continue to
146163
// loop for impls in scope. Note: I don't love these
@@ -235,18 +252,17 @@ struct lookup {
235252
ty::item_path_str(self.tcx(), did)));
236253
}
237254

238-
fn add_candidates_from_type() {
239-
match ty::get(self.self_ty).struct {
255+
fn add_candidates_from_type(inner_ty: ty::t, mode: method_lookup_mode) {
256+
match ty::get(inner_ty).struct {
240257
// First, see whether this is a bounded parameter.
241258
ty::ty_param(p) => {
242-
self.add_candidates_from_param(p.idx, p.def_id);
259+
self.add_candidates_from_param(inner_ty, mode, p.idx, p.def_id);
243260
}
244-
245261
ty::ty_trait(did, substs, _) => {
246-
self.add_candidates_from_trait(did, substs);
262+
self.add_candidates_from_trait(inner_ty, mode, did, substs);
247263
}
248264
ty::ty_class(did, substs) => {
249-
self.add_candidates_from_class(did, substs);
265+
self.add_candidates_from_class(inner_ty, mode, did, substs);
250266
}
251267
ty::ty_self => {
252268
// Call is of the form "self.foo()" and appears in one
@@ -260,13 +276,15 @@ struct lookup {
260276
tps: ~[],
261277
};
262278

263-
self.add_candidates_from_trait(self_def_id, substs);
279+
self.add_candidates_from_trait(inner_ty, mode,
280+
self_def_id, substs);
264281
}
265282
_ => ()
266283
}
267284
}
268285

269-
fn add_candidates_from_param(n: uint, did: ast::def_id) {
286+
fn add_candidates_from_param(inner_ty: ty::t, mode: method_lookup_mode,
287+
n: uint, did: ast::def_id) {
270288
debug!("add_candidates_from_param");
271289

272290
let tcx = self.tcx();
@@ -304,6 +322,8 @@ struct lookup {
304322
with bound_substs};
305323

306324
self.add_candidates_from_m(
325+
inner_ty,
326+
mode,
307327
substs, trt_methods[pos],
308328
method_param({trait_id:trait_id,
309329
method_num:pos,
@@ -315,7 +335,10 @@ struct lookup {
315335

316336
}
317337

318-
fn add_candidates_from_trait(did: ast::def_id, trait_substs: ty::substs) {
338+
fn add_candidates_from_trait(inner_ty: ty::t,
339+
mode: method_lookup_mode,
340+
did: ast::def_id,
341+
trait_substs: ty::substs) {
319342

320343
debug!("add_candidates_from_trait");
321344

@@ -346,11 +369,14 @@ struct lookup {
346369
with trait_substs};
347370

348371
self.add_candidates_from_m(
349-
substs, m, method_trait(did, i));
372+
inner_ty, mode, substs, m, method_trait(did, i));
350373
}
351374
}
352375

353-
fn add_candidates_from_class(did: ast::def_id, class_substs: ty::substs) {
376+
fn add_candidates_from_class(inner_ty: ty::t,
377+
mode: method_lookup_mode,
378+
did: ast::def_id,
379+
class_substs: ty::substs) {
354380

355381
debug!("add_candidates_from_class");
356382

@@ -371,7 +397,7 @@ struct lookup {
371397
self.tcx(), did, self.m_name, self.expr.span);
372398

373399
self.add_candidates_from_m(
374-
class_substs, m, method_static(m_declared));
400+
inner_ty, mode, class_substs, m, method_static(m_declared));
375401
}
376402
}
377403

@@ -488,11 +514,42 @@ struct lookup {
488514
return added_any;
489515
}
490516

491-
fn add_candidates_from_m(self_substs: ty::substs,
517+
fn add_candidates_from_m(inner_ty: ty::t,
518+
mode: method_lookup_mode,
519+
self_substs: ty::substs,
492520
m: ty::method,
493521
origin: method_origin) {
494522
let tcx = self.fcx.ccx.tcx;
495523

524+
// If we don't have a self region but have an region pointer
525+
// explicit self, we need to make up a new region.
526+
let self_r = match self_substs.self_r {
527+
none => {
528+
match m.self_ty {
529+
ast::sty_region(_) =>
530+
some(self.fcx.infcx.next_region_var(
531+
self.self_expr.span,
532+
self.self_expr.id)),
533+
_ => none
534+
}
535+
}
536+
some(_) => self_substs.self_r
537+
};
538+
let self_substs = {self_r: self_r with self_substs};
539+
540+
// Before we can be sure we succeeded we need to match the
541+
// self type against the impl type that we get when we apply
542+
// the explicit self parameter to whatever inner type we are
543+
// looking at (which may be something that the self_type
544+
// points to).
545+
let impl_ty = transform_self_type_for_method(
546+
self.tcx(), self_substs.self_r,
547+
inner_ty, m.self_ty);
548+
549+
let matches = self.check_type_match(impl_ty, mode);
550+
debug!("matches = %?", matches);
551+
if matches.is_err() { return; }
552+
496553
// a bit hokey, but the method unbound has a bare protocol, whereas
497554
// a.b has a protocol like fn@() (perhaps eventually fn&()):
498555
let fty = ty::mk_fn(tcx, {proto: ty::proto_vstore(ty::vstore_box)
@@ -507,7 +564,7 @@ struct lookup {
507564
entry: {derefs: self.derefs,
508565
self_mode: get_mode_from_self_type(m.self_ty),
509566
origin: origin},
510-
mode: subtyping_mode});
567+
mode: mode});
511568
}
512569

513570
fn add_inherent_and_extension_candidates(optional_inherent_methods:

0 commit comments

Comments
 (0)