Skip to content

Commit

Permalink
Fix vtable resolution for self to search supertraits. Closes #7661.
Browse files Browse the repository at this point in the history
  • Loading branch information
msullivan committed Jul 25, 2013
1 parent 17e30d6 commit f37c7cd
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 31 deletions.
80 changes: 49 additions & 31 deletions src/librustc/middle/typeck/check/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer;
use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res};
use middle::typeck::{vtable_static, vtable_param, impl_res};
use middle::typeck::{param_numbered, param_self};
use middle::typeck::{param_numbered, param_self, param_index};
use middle::subst::Subst;
use util::common::indenter;
use util::ppaux;
Expand Down Expand Up @@ -244,51 +244,69 @@ fn lookup_vtable(vcx: &VtableContext,
}
};

match ty::get(ty).sty {
// If the type is self or a param, we look at the trait/supertrait
// bounds to see if they include the trait we are looking for.
let vtable_opt = match ty::get(ty).sty {
ty::ty_param(param_ty {idx: n, def_id: did}) => {
let mut n_bound = 0;
let type_param_def = tcx.ty_param_defs.get(&did.node);
for ty::each_bound_trait_and_supertraits(
tcx, type_param_def.bounds.trait_bounds) |bound_trait_ref|
{
debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx()));

if bound_trait_ref.def_id == trait_ref.def_id {
relate_trait_refs(vcx,
location_info,
bound_trait_ref,
trait_ref);
let vtable = vtable_param(param_numbered(n), n_bound);
debug!("found param vtable: %?",
vtable);
return Some(vtable);
}

n_bound += 1;
}
lookup_vtable_from_bounds(vcx, location_info,
type_param_def.bounds.trait_bounds,
param_numbered(n),
trait_ref)
}

ty::ty_self(trait_id) => {
debug!("trying to find %? vtable for type %?",
trait_ref.def_id, trait_id);

if trait_id == trait_ref.def_id {
let vtable = vtable_param(param_self, 0);
debug!("found self vtable: %?", vtable);
return Some(vtable);
}
let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref;
lookup_vtable_from_bounds(vcx, location_info,
&[self_trait_ref],
param_self,
trait_ref)
}

// Default case just falls through
_ => { }
}
_ => None
};

if vtable_opt.is_some() { return vtable_opt; }

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

// Given a list of bounds on a type, search those bounds to see if any
// of them are the vtable we are looking for.
fn lookup_vtable_from_bounds(vcx: &VtableContext,
location_info: &LocationInfo,
bounds: &[@ty::TraitRef],
param: param_index,
trait_ref: @ty::TraitRef)
-> Option<vtable_origin> {
let tcx = vcx.tcx();

let mut n_bound = 0;
for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| {
debug!("checking bounds trait %s",
bound_trait_ref.repr(vcx.tcx()));

if bound_trait_ref.def_id == trait_ref.def_id {
relate_trait_refs(vcx,
location_info,
bound_trait_ref,
trait_ref);
let vtable = vtable_param(param, n_bound);
debug!("found param vtable: %?",
vtable);
return Some(vtable);
}

n_bound += 1;
}

return None;
}

fn search_for_vtable(vcx: &VtableContext,
location_info: &LocationInfo,
ty: ty::t,
Expand Down
36 changes: 36 additions & 0 deletions src/test/run-pass/default-method-supertrait-vtable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2013 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.


// Tests that we can call a function bounded over a supertrait from
// a default method

fn require_y<T: Y>(x: T) -> int { x.y() }

trait Y {
fn y(self) -> int;
}


trait Z: Y {
fn x(self) -> int {
require_y(self)
}
}

impl Y for int {
fn y(self) -> int { self }
}

impl Z for int;

fn main() {
assert_eq!(12.x(), 12);
}

5 comments on commit f37c7cd

@bors
Copy link
Contributor

@bors bors commented on f37c7cd Jul 25, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from nikomatsakis
at msullivan@f37c7cd

@bors
Copy link
Contributor

@bors bors commented on f37c7cd Jul 25, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging msullivan/rust/default-methods = f37c7cd into auto

@bors
Copy link
Contributor

@bors bors commented on f37c7cd Jul 25, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

msullivan/rust/default-methods = f37c7cd merged ok, testing candidate = 906264b

@bors
Copy link
Contributor

@bors bors commented on f37c7cd Jul 25, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 906264b

Please sign in to comment.