From 000dc07f71baafc31da74e392ad5530fb6de9757 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 1 Jan 2015 03:03:14 +1100 Subject: [PATCH] Store a method-from-trait's impl in some cases when it is known. This allows one to look at an `ExprMethodCall` `foo.bar()` where `bar` is a method in some trait and (sometimes) extract the `impl` that `bar` is defined in, e.g. trait Foo { fn bar(&self); } impl Foo for uint { // fn bar(&self) {} } fn main() { 1u.bar(); // impl_def_id == Some() } This definitely doesn't handle all cases, but is correct when it is known, meaning it should only be used for certain linting/heuristic purposes; no safety analysis. --- src/librustc/middle/astencode.rs | 22 +++++++++++++++++++++ src/librustc/middle/ty.rs | 7 ++++++- src/librustc/middle/ty_fold.rs | 3 ++- src/librustc_trans/trans/meth.rs | 3 ++- src/librustc_typeck/check/method/confirm.rs | 9 ++++++--- src/librustc_typeck/check/method/mod.rs | 3 ++- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 537a2b3f545a..430b63f81c85 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -627,6 +627,7 @@ impl<'tcx> tr for MethodOrigin<'tcx> { // def-id is already translated when we read it out trait_ref: mp.trait_ref.clone(), method_num: mp.method_num, + impl_def_id: mp.impl_def_id.tr(dcx), } ) } @@ -879,6 +880,16 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { try!(this.emit_struct_field("method_num", 0, |this| { this.emit_uint(p.method_num) })); + try!(this.emit_struct_field("impl_def_id", 0, |this| { + this.emit_option(|this| { + match p.impl_def_id { + None => this.emit_option_none(), + Some(did) => this.emit_option_some(|this| { + Ok(this.emit_def_id(did)) + }) + } + }) + })); Ok(()) }) }) @@ -1452,6 +1463,17 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_struct_field("method_num", 1, |this| { this.read_uint() }).unwrap() + }, + impl_def_id: { + this.read_struct_field("impl_def_id", 2, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_def_id(dcx))) + } else { + Ok(None) + } + }) + }).unwrap() } })) }).unwrap() diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 83bbdf14e4a7..5b5b53d12468 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -453,9 +453,14 @@ pub struct MethodParam<'tcx> { // never contains bound regions; those regions should have been // instantiated with fresh variables at this point. pub trait_ref: Rc>, - // index of uint in the list of methods for the trait pub method_num: uint, + + /// The impl for the trait from which the method comes. This + /// should only be used for certain linting/heuristic purposes + /// since there is no guarantee that this is Some in every + /// situation that it could/should be. + pub impl_def_id: Option, } // details for a method invoked with a receiver whose type is an object diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index b4e6cff954bc..0b8c77860155 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -310,7 +310,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> { ty::MethodTypeParam(ref param) => { ty::MethodTypeParam(ty::MethodParam { trait_ref: param.trait_ref.fold_with(folder), - method_num: param.method_num + method_num: param.method_num, + impl_def_id: param.impl_def_id, }) } ty::MethodTraitObject(ref object) => { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index c2f19670e4f1..9356be1b9b41 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -132,7 +132,8 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::MethodTypeParam(ty::MethodParam { ref trait_ref, - method_num + method_num, + impl_def_id: _ }) => { let trait_ref = ty::Binder(bcx.monomorphize(trait_ref)); let span = bcx.tcx().map.span(method_call.expr_id); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 794607748597..4aa0a211221e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -256,7 +256,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { &impl_polytype.substs, &ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap()); let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(), - method_num: method_num }); + method_num: method_num, + impl_def_id: Some(impl_def_id) }); (impl_trait_ref.substs.clone(), origin) } @@ -275,7 +276,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs.clone()))); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, - method_num: method_num }); + method_num: method_num, + impl_def_id: None }); (substs, origin) } @@ -285,7 +287,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref); let substs = trait_ref.substs.clone(); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, - method_num: method_num }); + method_num: method_num, + impl_def_id: None }); (substs, origin) } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 345bc5fd2aa6..d92cc1dfc1e9 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -287,7 +287,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let callee = MethodCallee { origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(), - method_num: method_num}), + method_num: method_num, + impl_def_id: None}), ty: fty, substs: trait_ref.substs.clone() };