Fix vtable resolution for self to search supertraits. Closes #7661.

This commit is contained in:
Michael Sullivan 2013-07-23 16:28:53 -07:00
parent 17e30d6b4e
commit f37c7cd306
2 changed files with 85 additions and 31 deletions

View File

@ -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;
@ -244,44 +244,30 @@ 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.
@ -289,6 +275,38 @@ fn lookup_vtable(vcx: &VtableContext,
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,

View File

@ -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);
}