Fix bug in auto-ref on bounded type parameters

This commit is contained in:
Niko Matsakis 2012-09-13 13:11:08 -07:00
parent 2f6b66ecd3
commit 0e584f2e74
4 changed files with 92 additions and 14 deletions

View File

@ -861,8 +861,7 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
// variables.
fn impl_self_ty(fcx: @fn_ctxt,
expr: @ast::expr, // (potential) receiver for this impl
did: ast::def_id,
require_rp: bool) -> ty_param_substs_and_ty {
did: ast::def_id) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let {n_tps, region_param, raw_ty} = if did.crate == ast::local_crate {
@ -897,7 +896,7 @@ fn impl_self_ty(fcx: @fn_ctxt,
raw_ty: ity.ty}
};
let self_r = if region_param.is_some() || require_rp {
let self_r = if region_param.is_some() {
Some(fcx.infcx().next_region_var(expr.span, expr.id))
} else {
None

View File

@ -99,7 +99,10 @@ fn lookup(
inherent_candidates: DVec(),
extension_candidates: DVec()
};
return lcx.do_lookup(self_ty);
let mme = lcx.do_lookup(self_ty);
debug!("method lookup for %s yielded %?",
expr_repr(fcx.tcx(), expr), mme);
return move mme;
}
struct LookupContext {
@ -333,6 +336,10 @@ impl LookupContext {
let rcvr_ty = ty::mk_param(tcx, param_ty.idx, param_ty.def_id);
let rcvr_substs = {self_ty: Some(rcvr_ty), ..bound_substs};
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty, rcvr_ty, move rcvr_substs);
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
rcvr_substs: rcvr_substs,
@ -384,8 +391,12 @@ impl LookupContext {
// candidate be selected if the method refers to `self`.
let rcvr_substs = {self_ty: Some(self_ty), ..*substs};
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty, self_ty, move rcvr_substs);
self.inherent_candidates.push(Candidate {
rcvr_ty: self_ty,
rcvr_ty: rcvr_ty,
rcvr_substs: move rcvr_substs,
num_method_tps: method.tps.len(),
self_mode: get_mode_from_self_type(method.self_ty),
@ -424,18 +435,14 @@ impl LookupContext {
let tcx = self.tcx();
let method = &impl_info.methods[idx];
let need_rp = match method.self_type {
ast::sty_region(_) => true,
_ => false
};
// determine the `self` of the impl with fresh
// variables for each parameter:
let {substs: impl_substs, ty: impl_ty} =
impl_self_ty(self.fcx, self.self_expr, impl_info.did, need_rp);
impl_self_ty(self.fcx, self.self_expr, impl_info.did);
let impl_ty = transform_self_type_for_method(
tcx, impl_substs.self_r, impl_ty, method.self_type);
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_type, impl_ty, move impl_substs);
candidates.push(Candidate {
rcvr_ty: impl_ty,
@ -446,6 +453,48 @@ impl LookupContext {
});
}
fn create_rcvr_ty_and_substs_for_method(&self,
self_decl: ast::self_ty_,
self_ty: ty::t,
+self_substs: ty::substs)
-> (ty::t, ty::substs)
{
// If the self type includes a region (like &self), we need to
// ensure that the receiver substitutions have a self region.
// If the receiver type does not itself contain borrowed
// pointers, there may not be one yet.
//
// FIXME(#3446)--this awkward situation comes about because
// the regions in the receiver are substituted before (and
// differently from) those in the argument types. This
// shouldn't really have to be.
let rcvr_substs = {
match self_decl {
sty_static | sty_value | sty_by_ref |
sty_box(_) | sty_uniq(_) => {
move self_substs
}
sty_region(_) if self_substs.self_r.is_some() => {
move self_substs
}
sty_region(_) => {
{self_r:
Some(self.infcx().next_region_var(
self.expr.span,
self.expr.id)),
..self_substs}
}
}
};
let rcvr_ty =
transform_self_type_for_method(
self.tcx(), rcvr_substs.self_r,
self_ty, self_decl);
(rcvr_ty, rcvr_substs)
}
// ______________________________________________________________________
// Candidate selection (see comment at start of file)

View File

@ -239,7 +239,7 @@ fn lookup_vtable(fcx: @fn_ctxt,
// to some_trait. If not, then we try the next
// impl.
let {substs: substs, ty: for_ty} =
impl_self_ty(fcx, expr, im.did, false);
impl_self_ty(fcx, expr, im.did);
let im_bs = ty::lookup_item_type(tcx,
im.did).bounds;
match fcx.mk_subty(false, expr.span, ty, for_ty) {

View File

@ -0,0 +1,30 @@
use to_str::ToStr;
trait Foo {
fn f(&self);
}
struct Bar {
x: int
}
trait Baz {
fn g(&self);
}
impl<T:Baz> T : Foo {
fn f(&self) {
self.g();
}
}
impl Bar : Baz {
fn g(&self) {
io::println(self.x.to_str());
}
}
fn main() {
let y = Bar { x: 42 };
y.f();
}