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 { // <A>
        fn bar(&self) {}
    }

    fn main() {
        1u.bar(); // impl_def_id == Some(<A>)
    }

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.
This commit is contained in:
Huon Wilson 2015-01-01 03:03:14 +11:00
parent 4be79d6acd
commit 000dc07f71
6 changed files with 40 additions and 7 deletions

View File

@ -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()

View File

@ -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<ty::TraitRef<'tcx>>,
// 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<ast::DefId>,
}
// details for a method invoked with a receiver whose type is an object

View File

@ -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) => {

View File

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

View File

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

View File

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