Skip to content

Commit f37c7cd

Browse files
committed
Fix vtable resolution for self to search supertraits. Closes #7661.
1 parent 17e30d6 commit f37c7cd

File tree

2 files changed

+85
-31
lines changed

2 files changed

+85
-31
lines changed

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

+49-31
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
1818
use middle::typeck::infer;
1919
use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res};
2020
use middle::typeck::{vtable_static, vtable_param, impl_res};
21-
use middle::typeck::{param_numbered, param_self};
21+
use middle::typeck::{param_numbered, param_self, param_index};
2222
use middle::subst::Subst;
2323
use util::common::indenter;
2424
use util::ppaux;
@@ -244,51 +244,69 @@ fn lookup_vtable(vcx: &VtableContext,
244244
}
245245
};
246246

247-
match ty::get(ty).sty {
247+
// If the type is self or a param, we look at the trait/supertrait
248+
// bounds to see if they include the trait we are looking for.
249+
let vtable_opt = match ty::get(ty).sty {
248250
ty::ty_param(param_ty {idx: n, def_id: did}) => {
249-
let mut n_bound = 0;
250251
let type_param_def = tcx.ty_param_defs.get(&did.node);
251-
for ty::each_bound_trait_and_supertraits(
252-
tcx, type_param_def.bounds.trait_bounds) |bound_trait_ref|
253-
{
254-
debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx()));
255-
256-
if bound_trait_ref.def_id == trait_ref.def_id {
257-
relate_trait_refs(vcx,
258-
location_info,
259-
bound_trait_ref,
260-
trait_ref);
261-
let vtable = vtable_param(param_numbered(n), n_bound);
262-
debug!("found param vtable: %?",
263-
vtable);
264-
return Some(vtable);
265-
}
266-
267-
n_bound += 1;
268-
}
252+
lookup_vtable_from_bounds(vcx, location_info,
253+
type_param_def.bounds.trait_bounds,
254+
param_numbered(n),
255+
trait_ref)
269256
}
270257

271258
ty::ty_self(trait_id) => {
272-
debug!("trying to find %? vtable for type %?",
273-
trait_ref.def_id, trait_id);
274-
275-
if trait_id == trait_ref.def_id {
276-
let vtable = vtable_param(param_self, 0);
277-
debug!("found self vtable: %?", vtable);
278-
return Some(vtable);
279-
}
259+
let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref;
260+
lookup_vtable_from_bounds(vcx, location_info,
261+
&[self_trait_ref],
262+
param_self,
263+
trait_ref)
280264
}
281265

282266
// Default case just falls through
283-
_ => { }
284-
}
267+
_ => None
268+
};
269+
270+
if vtable_opt.is_some() { return vtable_opt; }
285271

286272
// If we aren't a self type or param, or it was, but we didn't find it,
287273
// do a search.
288274
return search_for_vtable(vcx, location_info,
289275
ty, trait_ref, is_early)
290276
}
291277

278+
// Given a list of bounds on a type, search those bounds to see if any
279+
// of them are the vtable we are looking for.
280+
fn lookup_vtable_from_bounds(vcx: &VtableContext,
281+
location_info: &LocationInfo,
282+
bounds: &[@ty::TraitRef],
283+
param: param_index,
284+
trait_ref: @ty::TraitRef)
285+
-> Option<vtable_origin> {
286+
let tcx = vcx.tcx();
287+
288+
let mut n_bound = 0;
289+
for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| {
290+
debug!("checking bounds trait %s",
291+
bound_trait_ref.repr(vcx.tcx()));
292+
293+
if bound_trait_ref.def_id == trait_ref.def_id {
294+
relate_trait_refs(vcx,
295+
location_info,
296+
bound_trait_ref,
297+
trait_ref);
298+
let vtable = vtable_param(param, n_bound);
299+
debug!("found param vtable: %?",
300+
vtable);
301+
return Some(vtable);
302+
}
303+
304+
n_bound += 1;
305+
}
306+
307+
return None;
308+
}
309+
292310
fn search_for_vtable(vcx: &VtableContext,
293311
location_info: &LocationInfo,
294312
ty: ty::t,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
// Tests that we can call a function bounded over a supertrait from
13+
// a default method
14+
15+
fn require_y<T: Y>(x: T) -> int { x.y() }
16+
17+
trait Y {
18+
fn y(self) -> int;
19+
}
20+
21+
22+
trait Z: Y {
23+
fn x(self) -> int {
24+
require_y(self)
25+
}
26+
}
27+
28+
impl Y for int {
29+
fn y(self) -> int { self }
30+
}
31+
32+
impl Z for int;
33+
34+
fn main() {
35+
assert_eq!(12.x(), 12);
36+
}

0 commit comments

Comments
 (0)