From 0e584f2e741ad5c6a1aefefe6eec3e2dd9fff518 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Sep 2012 13:11:08 -0700 Subject: [PATCH] Fix bug in auto-ref on bounded type parameters --- src/rustc/middle/typeck/check.rs | 5 +- src/rustc/middle/typeck/check/method.rs | 69 ++++++++++++++++--- src/rustc/middle/typeck/check/vtable.rs | 2 +- .../run-pass/auto-ref-bounded-ty-param.rs | 30 ++++++++ 4 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/auto-ref-bounded-ty-param.rs diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 44da6d94509..63ac6154810 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -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 diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index ff90f671d75..028a4560e4a 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -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) diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index ccc5e4c1a82..24c505d045d 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -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) { diff --git a/src/test/run-pass/auto-ref-bounded-ty-param.rs b/src/test/run-pass/auto-ref-bounded-ty-param.rs new file mode 100644 index 00000000000..29f65af239e --- /dev/null +++ b/src/test/run-pass/auto-ref-bounded-ty-param.rs @@ -0,0 +1,30 @@ +use to_str::ToStr; + +trait Foo { + fn f(&self); +} + +struct Bar { + x: int +} + +trait Baz { + fn g(&self); +} + +impl 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(); +} \ No newline at end of file