Auto merge of #26694 - eddyb:method-nan, r=arielb1
`MethodCallee` now has no information about the method, other than its `DefId`. The previous bits of information can be recovered as follows: ```rust let method_item = tcx.impl_or_trait_item(callee.def_id); let container = method_item.container(); ``` The method is inherent if `container` is a `ty::ImplContainer`: * the `impl` the method comes from is `container.id()` The method is a trait method if `container` is a `ty::TraitContainer: * the `trait` the method is part of is `container.id()` * a `ty::TraitRef` can be constructed by putting together: * `container.id()` as the `trait` ID * `callee.substs.clone().method_to_trait()` as the `trait` substs (including `Self`) * the above `trait_ref` is a valid `T: Trait<A, B, C>` predicate * selecting `trait_ref` could result in one of the following: * `traits::VtableImpl(data)`: static dispatch to `data.impl_def_id` * `traits::VtableObject(data)`: dynamic dispatch, with the vtable index: `traits::get_vtable_index_of_object_method(tcx, data, callee.def_id)` * other variants of `traits::Vtable`: various other `impl` sources
This commit is contained in:
commit
42e545ffa7
33 changed files with 587 additions and 1174 deletions
|
|
@ -29,7 +29,7 @@ use middle::check_const::ConstQualif;
|
|||
use middle::privacy::{AllPublic, LastMod};
|
||||
use middle::subst;
|
||||
use middle::subst::VecPerParamSpace;
|
||||
use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin};
|
||||
use middle::ty::{self, Ty};
|
||||
|
||||
use syntax::{ast, ast_util, codemap, fold};
|
||||
use syntax::codemap::Span;
|
||||
|
|
@ -600,21 +600,21 @@ impl tr for ty::UpvarCapture {
|
|||
|
||||
trait read_method_callee_helper<'tcx> {
|
||||
fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> (u32, MethodCallee<'tcx>);
|
||||
-> (u32, ty::MethodCallee<'tcx>);
|
||||
}
|
||||
|
||||
fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
rbml_w: &mut Encoder,
|
||||
autoderef: u32,
|
||||
method: &MethodCallee<'tcx>) {
|
||||
method: &ty::MethodCallee<'tcx>) {
|
||||
use serialize::Encoder;
|
||||
|
||||
rbml_w.emit_struct("MethodCallee", 4, |rbml_w| {
|
||||
rbml_w.emit_struct_field("autoderef", 0, |rbml_w| {
|
||||
autoderef.encode(rbml_w)
|
||||
});
|
||||
rbml_w.emit_struct_field("origin", 1, |rbml_w| {
|
||||
Ok(rbml_w.emit_method_origin(ecx, &method.origin))
|
||||
rbml_w.emit_struct_field("def_id", 1, |rbml_w| {
|
||||
Ok(rbml_w.emit_def_id(method.def_id))
|
||||
});
|
||||
rbml_w.emit_struct_field("ty", 2, |rbml_w| {
|
||||
Ok(rbml_w.emit_ty(ecx, method.ty))
|
||||
|
|
@ -627,21 +627,20 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
|
|||
|
||||
impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
|
||||
fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> (u32, MethodCallee<'tcx>) {
|
||||
-> (u32, ty::MethodCallee<'tcx>) {
|
||||
|
||||
self.read_struct("MethodCallee", 4, |this| {
|
||||
let autoderef = this.read_struct_field("autoderef", 0, |this| {
|
||||
Decodable::decode(this)
|
||||
}).unwrap();
|
||||
Ok((autoderef, MethodCallee {
|
||||
origin: this.read_struct_field("origin", 1, |this| {
|
||||
Ok(this.read_method_origin(dcx))
|
||||
let autoderef = this.read_struct_field("autoderef", 0,
|
||||
Decodable::decode).unwrap();
|
||||
Ok((autoderef, ty::MethodCallee {
|
||||
def_id: this.read_struct_field("def_id", 1, |this| {
|
||||
Ok(this.read_def_id(dcx))
|
||||
}).unwrap(),
|
||||
ty: this.read_struct_field("ty", 2, |this| {
|
||||
Ok(this.read_ty(dcx))
|
||||
}).unwrap(),
|
||||
substs: this.read_struct_field("substs", 3, |this| {
|
||||
Ok(this.read_substs(dcx))
|
||||
Ok(dcx.tcx.mk_substs(this.read_substs(dcx)))
|
||||
}).unwrap()
|
||||
}))
|
||||
}).unwrap()
|
||||
|
|
@ -707,9 +706,6 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> {
|
|||
trait rbml_writer_helpers<'tcx> {
|
||||
fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
closure_type: &ty::ClosureTy<'tcx>);
|
||||
fn emit_method_origin<'a>(&mut self,
|
||||
ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
method_origin: &ty::MethodOrigin<'tcx>);
|
||||
fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
|
||||
fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
|
||||
fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
|
|
@ -741,73 +737,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
fn emit_method_origin<'b>(&mut self,
|
||||
ecx: &e::EncodeContext<'b, 'tcx>,
|
||||
method_origin: &ty::MethodOrigin<'tcx>)
|
||||
{
|
||||
use serialize::Encoder;
|
||||
|
||||
self.emit_enum("MethodOrigin", |this| {
|
||||
match *method_origin {
|
||||
ty::MethodStatic(def_id) => {
|
||||
this.emit_enum_variant("MethodStatic", 0, 1, |this| {
|
||||
Ok(this.emit_def_id(def_id))
|
||||
})
|
||||
}
|
||||
|
||||
ty::MethodStaticClosure(def_id) => {
|
||||
this.emit_enum_variant("MethodStaticClosure", 1, 1, |this| {
|
||||
Ok(this.emit_def_id(def_id))
|
||||
})
|
||||
}
|
||||
|
||||
ty::MethodTypeParam(ref p) => {
|
||||
this.emit_enum_variant("MethodTypeParam", 2, 1, |this| {
|
||||
this.emit_struct("MethodParam", 2, |this| {
|
||||
try!(this.emit_struct_field("trait_ref", 0, |this| {
|
||||
Ok(this.emit_trait_ref(ecx, &p.trait_ref))
|
||||
}));
|
||||
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(())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ty::MethodTraitObject(ref o) => {
|
||||
this.emit_enum_variant("MethodTraitObject", 3, 1, |this| {
|
||||
this.emit_struct("MethodObject", 2, |this| {
|
||||
try!(this.emit_struct_field("trait_ref", 0, |this| {
|
||||
Ok(this.emit_trait_ref(ecx, &o.trait_ref))
|
||||
}));
|
||||
try!(this.emit_struct_field("object_trait_id", 0, |this| {
|
||||
Ok(this.emit_def_id(o.object_trait_id))
|
||||
}));
|
||||
try!(this.emit_struct_field("method_num", 0, |this| {
|
||||
this.emit_uint(o.method_num)
|
||||
}));
|
||||
try!(this.emit_struct_field("vtable_index", 0, |this| {
|
||||
this.emit_uint(o.vtable_index)
|
||||
}));
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) {
|
||||
self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
|
||||
}
|
||||
|
|
@ -1077,7 +1006,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||
})
|
||||
}
|
||||
|
||||
let method_call = MethodCall::expr(id);
|
||||
let method_call = ty::MethodCall::expr(id);
|
||||
if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
|
||||
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
|
|
@ -1089,7 +1018,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||
match *adjustment {
|
||||
ty::AdjustDerefRef(ref adj) => {
|
||||
for autoderef in 0..adj.autoderefs {
|
||||
let method_call = MethodCall::autoderef(id, autoderef as u32);
|
||||
let method_call = ty::MethodCall::autoderef(id, autoderef as u32);
|
||||
if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
|
||||
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
|
|
@ -1150,8 +1079,6 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> {
|
|||
}
|
||||
|
||||
trait rbml_decoder_decoder_helpers<'tcx> {
|
||||
fn read_method_origin<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::MethodOrigin<'tcx>;
|
||||
fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
|
||||
fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
|
||||
fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
|
|
@ -1235,88 +1162,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_method_origin<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::MethodOrigin<'tcx>
|
||||
{
|
||||
self.read_enum("MethodOrigin", |this| {
|
||||
let variants = &["MethodStatic", "MethodStaticClosure",
|
||||
"MethodTypeParam", "MethodTraitObject"];
|
||||
this.read_enum_variant(variants, |this, i| {
|
||||
Ok(match i {
|
||||
0 => {
|
||||
let def_id = this.read_def_id(dcx);
|
||||
ty::MethodStatic(def_id)
|
||||
}
|
||||
|
||||
1 => {
|
||||
let def_id = this.read_def_id(dcx);
|
||||
ty::MethodStaticClosure(def_id)
|
||||
}
|
||||
|
||||
2 => {
|
||||
this.read_struct("MethodTypeParam", 2, |this| {
|
||||
Ok(ty::MethodTypeParam(
|
||||
ty::MethodParam {
|
||||
trait_ref: {
|
||||
this.read_struct_field("trait_ref", 0, |this| {
|
||||
Ok(this.read_trait_ref(dcx))
|
||||
}).unwrap()
|
||||
},
|
||||
method_num: {
|
||||
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()
|
||||
}
|
||||
|
||||
3 => {
|
||||
this.read_struct("MethodTraitObject", 2, |this| {
|
||||
Ok(ty::MethodTraitObject(
|
||||
ty::MethodObject {
|
||||
trait_ref: {
|
||||
this.read_struct_field("trait_ref", 0, |this| {
|
||||
Ok(this.read_trait_ref(dcx))
|
||||
}).unwrap()
|
||||
},
|
||||
object_trait_id: {
|
||||
this.read_struct_field("object_trait_id", 1, |this| {
|
||||
Ok(this.read_def_id(dcx))
|
||||
}).unwrap()
|
||||
},
|
||||
method_num: {
|
||||
this.read_struct_field("method_num", 2, |this| {
|
||||
this.read_uint()
|
||||
}).unwrap()
|
||||
},
|
||||
vtable_index: {
|
||||
this.read_struct_field("vtable_index", 3, |this| {
|
||||
this.read_uint()
|
||||
}).unwrap()
|
||||
},
|
||||
}))
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
_ => panic!("..")
|
||||
})
|
||||
})
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
|
||||
fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
|
||||
// Note: regions types embed local node ids. In principle, we
|
||||
// should translate these node ids into the new decode
|
||||
|
|
@ -1663,7 +1508,7 @@ fn decode_side_tables(dcx: &DecodeContext,
|
|||
}
|
||||
c::tag_table_method_map => {
|
||||
let (autoderef, method) = val_dsr.read_method_callee(dcx);
|
||||
let method_call = MethodCall {
|
||||
let method_call = ty::MethodCall {
|
||||
expr_id: id,
|
||||
autoderef: autoderef
|
||||
};
|
||||
|
|
|
|||
|
|
@ -696,13 +696,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
ast::ExprMethodCall(..) => {
|
||||
let method_did = match v.tcx.tables.borrow().method_map[&method_call].origin {
|
||||
ty::MethodStatic(did) => Some(did),
|
||||
_ => None
|
||||
};
|
||||
let is_const = match method_did {
|
||||
Some(did) => v.handle_const_fn_call(e, did, node_ty),
|
||||
None => false
|
||||
let method = v.tcx.tables.borrow().method_map[&method_call];
|
||||
let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
|
||||
ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
|
||||
ty::TraitContainer(_) => false
|
||||
};
|
||||
if !is_const {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
|
|
|
|||
|
|
@ -93,40 +93,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
fn lookup_and_handle_method(&mut self, id: ast::NodeId,
|
||||
span: codemap::Span) {
|
||||
fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
|
||||
let method_call = ty::MethodCall::expr(id);
|
||||
match self.tcx.tables.borrow().method_map.get(&method_call) {
|
||||
Some(method) => {
|
||||
match method.origin {
|
||||
ty::MethodStatic(def_id) => {
|
||||
match self.tcx.provided_source(def_id) {
|
||||
Some(p_did) => self.check_def_id(p_did),
|
||||
None => self.check_def_id(def_id)
|
||||
}
|
||||
}
|
||||
ty::MethodStaticClosure(_) => {}
|
||||
ty::MethodTypeParam(ty::MethodParam {
|
||||
ref trait_ref,
|
||||
method_num: index,
|
||||
..
|
||||
}) |
|
||||
ty::MethodTraitObject(ty::MethodObject {
|
||||
ref trait_ref,
|
||||
method_num: index,
|
||||
..
|
||||
}) => {
|
||||
let trait_item = self.tcx.trait_item(trait_ref.def_id, index);
|
||||
self.check_def_id(trait_item.def_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.tcx.sess.span_bug(span,
|
||||
"method call expression not \
|
||||
in method map?!")
|
||||
}
|
||||
}
|
||||
let method = self.tcx.tables.borrow().method_map[&method_call];
|
||||
self.check_def_id(method.def_id);
|
||||
}
|
||||
|
||||
fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) {
|
||||
|
|
@ -262,7 +232,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
|
|||
fn visit_expr(&mut self, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprMethodCall(..) => {
|
||||
self.lookup_and_handle_method(expr.id, expr.span);
|
||||
self.lookup_and_handle_method(expr.id);
|
||||
}
|
||||
ast::ExprField(ref lhs, ref ident) => {
|
||||
self.handle_field_access(&**lhs, ident.node.name);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
|
|||
match expr.node {
|
||||
ast::ExprMethodCall(_, _, _) => {
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let base_type = self.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
|
||||
let base_type = self.tcx.tables.borrow().method_map[&method_call].ty;
|
||||
debug!("effect: method call case, base type is {:?}",
|
||||
base_type);
|
||||
if type_is_unsafe_function(base_type) {
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@ use self::OverloadedCallType::*;
|
|||
use middle::{def, region, pat_util};
|
||||
use middle::infer;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::ty::{self};
|
||||
use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
|
||||
use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
|
||||
use middle::ty::{MethodStatic, MethodStaticClosure};
|
||||
use middle::ty;
|
||||
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::ptr::P;
|
||||
|
|
@ -229,57 +226,8 @@ impl OverloadedCallType {
|
|||
|
||||
fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
|
||||
-> OverloadedCallType {
|
||||
let method_descriptor = match tcx.impl_or_trait_item(method_id) {
|
||||
ty::MethodTraitItem(ref method_descriptor) => {
|
||||
(*method_descriptor).clone()
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug("overloaded call method wasn't in method map")
|
||||
}
|
||||
};
|
||||
let impl_id = match method_descriptor.container {
|
||||
ty::TraitContainer(_) => {
|
||||
tcx.sess.bug("statically resolved overloaded call method \
|
||||
belonged to a trait?!")
|
||||
}
|
||||
ty::ImplContainer(impl_id) => impl_id,
|
||||
};
|
||||
let trait_ref = match tcx.impl_trait_ref(impl_id) {
|
||||
None => {
|
||||
tcx.sess.bug("statically resolved overloaded call impl \
|
||||
didn't implement a trait?!")
|
||||
}
|
||||
Some(ref trait_ref) => (*trait_ref).clone(),
|
||||
};
|
||||
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
|
||||
}
|
||||
|
||||
fn from_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
|
||||
-> OverloadedCallType {
|
||||
let trait_did =
|
||||
tcx.tables
|
||||
.borrow()
|
||||
.closure_kinds
|
||||
.get(&closure_did)
|
||||
.expect("OverloadedCallType::from_closure: didn't find closure id")
|
||||
.trait_did(tcx);
|
||||
OverloadedCallType::from_trait_id(tcx, trait_did)
|
||||
}
|
||||
|
||||
fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
|
||||
-> OverloadedCallType {
|
||||
match *origin {
|
||||
MethodStatic(def_id) => {
|
||||
OverloadedCallType::from_method_id(tcx, def_id)
|
||||
}
|
||||
MethodStaticClosure(def_id) => {
|
||||
OverloadedCallType::from_closure(tcx, def_id)
|
||||
}
|
||||
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
|
||||
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
|
||||
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
|
||||
}
|
||||
}
|
||||
let method = tcx.impl_or_trait_item(method_id);
|
||||
OverloadedCallType::from_trait_id(tcx, method.container().id())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -629,11 +577,9 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
|||
ty::TyError => { }
|
||||
_ => {
|
||||
let overloaded_call_type =
|
||||
match self.typer.node_method_origin(MethodCall::expr(call.id)) {
|
||||
Some(method_origin) => {
|
||||
OverloadedCallType::from_method_origin(
|
||||
self.tcx(),
|
||||
&method_origin)
|
||||
match self.typer.node_method_id(ty::MethodCall::expr(call.id)) {
|
||||
Some(method_id) => {
|
||||
OverloadedCallType::from_method_id(self.tcx(), method_id)
|
||||
}
|
||||
None => {
|
||||
self.tcx().sess.span_bug(
|
||||
|
|
|
|||
|
|
@ -1327,7 +1327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn node_method_ty(&self, method_call: ty::MethodCall)
|
||||
-> Option<Ty<'tcx>> {
|
||||
-> Option<Ty<'tcx>> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
|
|
@ -1336,14 +1336,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.map(|ty| self.resolve_type_vars_if_possible(&ty))
|
||||
}
|
||||
|
||||
pub fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>
|
||||
{
|
||||
pub fn node_method_id(&self, method_call: ty::MethodCall)
|
||||
-> Option<ast::DefId> {
|
||||
self.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.origin.clone())
|
||||
.map(|method| method.def_id)
|
||||
}
|
||||
|
||||
pub fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
|
|
|
|||
|
|
@ -1148,7 +1148,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
ast::ExprMethodCall(_, _, ref args) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let method_ty = self.ir.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
|
||||
let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
|
||||
let succ = if method_ty.fn_ret().diverges() {
|
||||
self.s.exit_ln
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -128,8 +128,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
|
|||
}
|
||||
ast::ExprMethodCall(..) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
match self.tcx.tables.borrow().method_map.get(&method_call).unwrap().origin {
|
||||
ty::MethodStatic(def_id) => {
|
||||
let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
|
||||
match self.tcx.impl_or_trait_item(def_id).container() {
|
||||
ty::ImplContainer(_) => {
|
||||
if is_local(def_id) {
|
||||
if self.def_id_represents_local_inlined_item(def_id) {
|
||||
self.worklist.push(def_id.node)
|
||||
|
|
@ -137,7 +138,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
|
|||
self.reachable_symbols.insert(def_id.node);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
ty::TraitContainer(_) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -406,31 +406,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
|
|||
ast::ExprMethodCall(i, _, _) => {
|
||||
span = i.span;
|
||||
let method_call = ty::MethodCall::expr(e.id);
|
||||
match tcx.tables.borrow().method_map.get(&method_call) {
|
||||
Some(method) => {
|
||||
match method.origin {
|
||||
ty::MethodStatic(def_id) => {
|
||||
def_id
|
||||
}
|
||||
ty::MethodStaticClosure(def_id) => {
|
||||
def_id
|
||||
}
|
||||
ty::MethodTypeParam(ty::MethodParam {
|
||||
ref trait_ref,
|
||||
method_num: index,
|
||||
..
|
||||
}) |
|
||||
ty::MethodTraitObject(ty::MethodObject {
|
||||
ref trait_ref,
|
||||
method_num: index,
|
||||
..
|
||||
}) => {
|
||||
tcx.trait_item(trait_ref.def_id, index).def_id()
|
||||
}
|
||||
}
|
||||
}
|
||||
None => return
|
||||
}
|
||||
tcx.tables.borrow().method_map[&method_call].def_id
|
||||
}
|
||||
ast::ExprField(ref base_e, ref field) => {
|
||||
span = field.span;
|
||||
|
|
|
|||
|
|
@ -141,19 +141,25 @@ impl<'tcx> Substs<'tcx> {
|
|||
{
|
||||
let Substs { types, regions } = self;
|
||||
let types = types.with_vec(FnSpace, m_types);
|
||||
let regions = regions.map(m_regions,
|
||||
|r, m_regions| r.with_vec(FnSpace, m_regions));
|
||||
let regions = regions.map(|r| r.with_vec(FnSpace, m_regions));
|
||||
Substs { types: types, regions: regions }
|
||||
}
|
||||
|
||||
pub fn method_to_trait(self) -> Substs<'tcx> {
|
||||
let Substs { mut types, regions } = self;
|
||||
types.truncate(FnSpace, 0);
|
||||
let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
|
||||
Substs { types: types, regions: regions }
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionSubsts {
|
||||
fn map<A, F>(self, a: A, op: F) -> RegionSubsts where
|
||||
F: FnOnce(VecPerParamSpace<ty::Region>, A) -> VecPerParamSpace<ty::Region>,
|
||||
fn map<F>(self, op: F) -> RegionSubsts where
|
||||
F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
|
||||
{
|
||||
match self {
|
||||
ErasedRegions => ErasedRegions,
|
||||
NonerasedRegions(r) => NonerasedRegions(op(r, a))
|
||||
NonerasedRegions(r) => NonerasedRegions(op(r))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,11 +291,13 @@ pub struct VtableBuiltinData<N> {
|
|||
/// for the object type `Foo`.
|
||||
#[derive(PartialEq,Eq,Clone)]
|
||||
pub struct VtableObjectData<'tcx> {
|
||||
/// the object type `Foo`.
|
||||
pub object_ty: Ty<'tcx>,
|
||||
|
||||
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
|
||||
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// the base object trait and all supertraits; this is the start of
|
||||
/// `upcast_trait_ref`'s methods in that vtable.
|
||||
pub vtable_base: usize
|
||||
}
|
||||
|
||||
/// Creates predicate obligations from the generic bounds.
|
||||
|
|
|
|||
|
|
@ -629,9 +629,10 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
|
|||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
object_ty: Ty<'tcx>)
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let self_ty = obligation_trait_ref.self_ty();
|
||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||
debug!("assemble_candidates_from_object_type(object_ty={:?})",
|
||||
object_ty);
|
||||
let data = match object_ty.sty {
|
||||
|
|
@ -684,10 +685,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
|||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Impl(data));
|
||||
}
|
||||
super::VtableObject(data) => {
|
||||
super::VtableObject(_) => {
|
||||
assemble_candidates_from_object_type(
|
||||
selcx, obligation, obligation_trait_ref, candidate_set,
|
||||
data.object_ty);
|
||||
selcx, obligation, obligation_trait_ref, candidate_set);
|
||||
}
|
||||
super::VtableClosure(data) => {
|
||||
candidate_set.vec.push(
|
||||
|
|
|
|||
|
|
@ -1362,12 +1362,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
|
||||
poly_trait_ref);
|
||||
|
||||
// see whether the object trait can be upcast to the trait we are looking for
|
||||
let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
|
||||
if upcast_trait_refs.len() > 1 {
|
||||
// Count only those upcast versions that match the trait-ref
|
||||
// we are looking for. Specifically, do not only check for the
|
||||
// correct trait, but also the correct type parameters.
|
||||
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
|
||||
// but `Foo` is declared as `trait Foo : Bar<u32>`.
|
||||
let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
|
||||
.filter(|upcast_trait_ref| self.infcx.probe(|_| {
|
||||
let upcast_trait_ref = upcast_trait_ref.clone();
|
||||
self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok()
|
||||
})).count();
|
||||
|
||||
if upcast_trait_refs > 1 {
|
||||
// can be upcast in many ways; need more type information
|
||||
candidates.ambiguous = true;
|
||||
} else if upcast_trait_refs.len() == 1 {
|
||||
} else if upcast_trait_refs == 1 {
|
||||
candidates.vec.push(ObjectCandidate);
|
||||
}
|
||||
|
||||
|
|
@ -2305,20 +2314,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// be exactly one applicable trait-reference; if this were not
|
||||
// the case, we would have reported an ambiguity error rather
|
||||
// than successfully selecting one of the candidates.
|
||||
let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation);
|
||||
assert_eq!(upcast_trait_refs.len(), 1);
|
||||
let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap();
|
||||
let mut upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
|
||||
.map(|upcast_trait_ref| {
|
||||
(upcast_trait_ref.clone(), self.infcx.probe(|_| {
|
||||
self.match_poly_trait_ref(obligation, upcast_trait_ref)
|
||||
}).is_ok())
|
||||
});
|
||||
let mut upcast_trait_ref = None;
|
||||
let mut vtable_base = 0;
|
||||
|
||||
match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(()) => {
|
||||
self.tcx().sess.span_bug(obligation.cause.span,
|
||||
"failed to match trait refs");
|
||||
while let Some((supertrait, matches)) = upcast_trait_refs.next() {
|
||||
if matches {
|
||||
upcast_trait_ref = Some(supertrait);
|
||||
break;
|
||||
}
|
||||
vtable_base += util::count_own_vtable_entries(self.tcx(), supertrait);
|
||||
}
|
||||
assert!(upcast_trait_refs.all(|(_, matches)| !matches));
|
||||
|
||||
VtableObjectData { object_ty: self_ty,
|
||||
upcast_trait_ref: upcast_trait_ref }
|
||||
VtableObjectData {
|
||||
upcast_trait_ref: upcast_trait_ref.unwrap(),
|
||||
vtable_base: vtable_base
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate(&mut self,
|
||||
|
|
@ -2719,7 +2736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
/// Returns `Ok` if `poly_trait_ref` being true implies that the
|
||||
/// obligation is satisfied.
|
||||
fn match_poly_trait_ref(&mut self,
|
||||
fn match_poly_trait_ref(&self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(),()>
|
||||
|
|
@ -2930,32 +2947,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation.cause.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Upcasts an object trait-reference into those that match the obligation.
|
||||
fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
|
||||
-> Vec<ty::PolyTraitRef<'tcx>>
|
||||
{
|
||||
debug!("upcast(obj_trait_ref={:?}, obligation={:?})",
|
||||
obj_trait_ref,
|
||||
obligation);
|
||||
|
||||
let obligation_def_id = obligation.predicate.def_id();
|
||||
let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id);
|
||||
|
||||
// Retain only those upcast versions that match the trait-ref
|
||||
// we are looking for. In particular, we know that all of
|
||||
// `upcast_trait_refs` apply to the correct trait, but
|
||||
// possibly with incorrect type parameters. For example, we
|
||||
// may be trying to upcast `Foo` to `Bar<i32>`, but `Foo` is
|
||||
// declared as `trait Foo : Bar<u32>`.
|
||||
upcast_trait_refs.retain(|upcast_trait_ref| {
|
||||
let upcast_trait_ref = upcast_trait_ref.clone();
|
||||
self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok()
|
||||
});
|
||||
|
||||
debug!("upcast: upcast_trait_refs={:?}", upcast_trait_refs);
|
||||
upcast_trait_refs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> SelectionCache<'tcx> {
|
||||
|
|
|
|||
|
|
@ -396,52 +396,50 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Given an object of type `object_trait_ref`, returns the index of
|
||||
/// the method `n_method` found in the trait `trait_def_id` (which
|
||||
/// should be a supertrait of `object_trait_ref`) within the vtable
|
||||
/// for `object_trait_ref`.
|
||||
/// Given an trait `trait_ref`, returns the number of vtable entries
|
||||
/// that come from `trait_ref`, excluding its supertraits. Used in
|
||||
/// computing the vtable base for an upcast trait of a trait object.
|
||||
pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> usize {
|
||||
let mut entries = 0;
|
||||
// Count number of methods and add them to the total offset.
|
||||
// Skip over associated types and constants.
|
||||
for trait_item in &tcx.trait_items(trait_ref.def_id())[..] {
|
||||
if let ty::MethodTraitItem(_) = *trait_item {
|
||||
entries += 1;
|
||||
}
|
||||
}
|
||||
entries
|
||||
}
|
||||
|
||||
/// Given an upcast trait object described by `object`, returns the
|
||||
/// index of the method `method_def_id` (which should be part of
|
||||
/// `object.upcast_trait_ref`) within the vtable for `object`.
|
||||
pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
method_offset_in_trait: usize) -> usize {
|
||||
// We need to figure the "real index" of the method in a
|
||||
// listing of all the methods of an object. We do this by
|
||||
// iterating down the supertraits of the object's trait until
|
||||
// we find the trait the method came from, counting up the
|
||||
// methods from them.
|
||||
let mut method_count = 0;
|
||||
object: &super::VtableObjectData<'tcx>,
|
||||
method_def_id: ast::DefId) -> usize {
|
||||
// Count number of methods preceding the one we are selecting and
|
||||
// add them to the total offset.
|
||||
// Skip over associated types and constants.
|
||||
let mut entries = object.vtable_base;
|
||||
for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] {
|
||||
if trait_item.def_id() == method_def_id {
|
||||
// The item with the ID we were given really ought to be a method.
|
||||
assert!(match *trait_item {
|
||||
ty::MethodTraitItem(_) => true,
|
||||
_ => false
|
||||
});
|
||||
|
||||
for bound_ref in transitive_bounds(tcx, &[object_trait_ref]) {
|
||||
if bound_ref.def_id() == trait_def_id {
|
||||
break;
|
||||
return entries;
|
||||
}
|
||||
|
||||
let trait_items = tcx.trait_items(bound_ref.def_id());
|
||||
for trait_item in trait_items.iter() {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(_) => method_count += 1,
|
||||
_ => {}
|
||||
}
|
||||
if let ty::MethodTraitItem(_) = *trait_item {
|
||||
entries += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// count number of methods preceding the one we are selecting and
|
||||
// add them to the total offset; skip over associated types.
|
||||
let trait_items = tcx.trait_items(trait_def_id);
|
||||
for trait_item in trait_items.iter().take(method_offset_in_trait) {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(_) => method_count += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// the item at the offset we were given really ought to be a method
|
||||
assert!(match trait_items[method_offset_in_trait] {
|
||||
ty::MethodTraitItem(_) => true,
|
||||
_ => false
|
||||
});
|
||||
|
||||
method_count
|
||||
tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found",
|
||||
method_def_id));
|
||||
}
|
||||
|
||||
pub enum TupleArgumentsFlag { Yes, No }
|
||||
|
|
@ -490,7 +488,7 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> {
|
|||
write!(f, "VtableFnPointer({:?})", d),
|
||||
|
||||
super::VtableObject(ref d) =>
|
||||
write!(f, "VtableObject({:?})", d),
|
||||
write!(f, "{:?}", d),
|
||||
|
||||
super::VtableParam(ref n) =>
|
||||
write!(f, "VtableParam({:?})", n),
|
||||
|
|
@ -535,7 +533,9 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData<N> {
|
|||
|
||||
impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "VtableObject(object_ty={:?})", self.object_ty)
|
||||
write!(f, "VtableObject(upcast={:?}, vtable_base={})",
|
||||
self.upcast_trait_ref,
|
||||
self.vtable_base)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ pub use self::ImplOrTraitItem::*;
|
|||
pub use self::BoundRegion::*;
|
||||
pub use self::TypeVariants::*;
|
||||
pub use self::IntVarValue::*;
|
||||
pub use self::MethodOrigin::*;
|
||||
pub use self::CopyImplementationError::*;
|
||||
|
||||
pub use self::BuiltinBound::Send as BoundSend;
|
||||
|
|
@ -330,7 +329,7 @@ impl IntTypeExt for attr::IntType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum ImplOrTraitItemContainer {
|
||||
TraitContainer(ast::DefId),
|
||||
ImplContainer(ast::DefId),
|
||||
|
|
@ -626,68 +625,12 @@ pub enum CustomCoerceUnsized {
|
|||
Struct(usize)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MethodOrigin<'tcx> {
|
||||
// fully statically resolved method
|
||||
MethodStatic(ast::DefId),
|
||||
|
||||
// fully statically resolved closure invocation
|
||||
MethodStaticClosure(ast::DefId),
|
||||
|
||||
// method invoked on a type parameter with a bounded trait
|
||||
MethodTypeParam(MethodParam<'tcx>),
|
||||
|
||||
// method invoked on a trait instance
|
||||
MethodTraitObject(MethodObject<'tcx>),
|
||||
|
||||
}
|
||||
|
||||
// details for a method invoked with a receiver whose type is a type parameter
|
||||
// with a bounded trait.
|
||||
#[derive(Clone)]
|
||||
pub struct MethodParam<'tcx> {
|
||||
// the precise trait reference that occurs as a bound -- this may
|
||||
// be a supertrait of what the user actually typed. Note that it
|
||||
// never contains bound regions; those regions should have been
|
||||
// instantiated with fresh variables at this point.
|
||||
pub trait_ref: ty::TraitRef<'tcx>,
|
||||
|
||||
// index of usize in the list of trait items. Note that this is NOT
|
||||
// the index into the vtable, because the list of trait items
|
||||
// includes associated types.
|
||||
pub method_num: usize,
|
||||
|
||||
/// 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
|
||||
#[derive(Clone)]
|
||||
pub struct MethodObject<'tcx> {
|
||||
// the (super)trait containing the method to be invoked
|
||||
pub trait_ref: TraitRef<'tcx>,
|
||||
|
||||
// the actual base trait id of the object
|
||||
pub object_trait_id: ast::DefId,
|
||||
|
||||
// index of the method to be invoked amongst the trait's items
|
||||
pub method_num: usize,
|
||||
|
||||
// index into the actual runtime vtable.
|
||||
// the vtable is formed by concatenating together the method lists of
|
||||
// the base object trait and all supertraits; this is the index into
|
||||
// that vtable
|
||||
pub vtable_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MethodCallee<'tcx> {
|
||||
pub origin: MethodOrigin<'tcx>,
|
||||
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
|
||||
pub def_id: ast::DefId,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub substs: subst::Substs<'tcx>
|
||||
pub substs: &'tcx subst::Substs<'tcx>
|
||||
}
|
||||
|
||||
/// With method calls, we store some extra information in
|
||||
|
|
@ -5595,11 +5538,6 @@ impl<'tcx> ctxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trait_item(&self, trait_did: ast::DefId, idx: usize) -> ImplOrTraitItem<'tcx> {
|
||||
let method_def_id = self.trait_item_def_ids(trait_did)[idx].def_id();
|
||||
self.impl_or_trait_item(method_def_id)
|
||||
}
|
||||
|
||||
pub fn trait_items(&self, trait_did: ast::DefId) -> Rc<Vec<ImplOrTraitItem<'tcx>>> {
|
||||
let mut trait_items = self.trait_items_cache.borrow_mut();
|
||||
match trait_items.get(&trait_did).cloned() {
|
||||
|
|
@ -6443,10 +6381,9 @@ impl<'tcx> ctxt<'tcx> {
|
|||
let name = impl_item.name();
|
||||
match self.trait_of_item(def_id) {
|
||||
Some(trait_did) => {
|
||||
let trait_items = self.trait_items(trait_did);
|
||||
trait_items.iter()
|
||||
.position(|m| m.name() == name)
|
||||
.map(|idx| self.trait_item(trait_did, idx).id())
|
||||
self.trait_items(trait_did).iter()
|
||||
.find(|item| item.name() == name)
|
||||
.map(|item| item.id())
|
||||
}
|
||||
None => None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,34 +310,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::MethodOrigin<'tcx> {
|
||||
match *self {
|
||||
ty::MethodStatic(def_id) => {
|
||||
ty::MethodStatic(def_id)
|
||||
}
|
||||
ty::MethodStaticClosure(def_id) => {
|
||||
ty::MethodStaticClosure(def_id)
|
||||
}
|
||||
ty::MethodTypeParam(ref param) => {
|
||||
ty::MethodTypeParam(ty::MethodParam {
|
||||
trait_ref: param.trait_ref.fold_with(folder),
|
||||
method_num: param.method_num,
|
||||
impl_def_id: param.impl_def_id,
|
||||
})
|
||||
}
|
||||
ty::MethodTraitObject(ref object) => {
|
||||
ty::MethodTraitObject(ty::MethodObject {
|
||||
trait_ref: object.trait_ref.fold_with(folder),
|
||||
object_trait_id: object.object_trait_id,
|
||||
method_num: object.method_num,
|
||||
vtable_index: object.vtable_index,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
|
||||
*self
|
||||
|
|
@ -520,8 +492,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
|
|||
impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
|
||||
traits::VtableObjectData {
|
||||
object_ty: self.object_ty.fold_with(folder),
|
||||
upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
|
||||
vtable_base: self.vtable_base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,38 +494,6 @@ impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::MethodOrigin<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ty::MethodStatic(def_id) => {
|
||||
write!(f, "MethodStatic({:?})", def_id)
|
||||
}
|
||||
ty::MethodStaticClosure(def_id) => {
|
||||
write!(f, "MethodStaticClosure({:?})", def_id)
|
||||
}
|
||||
ty::MethodTypeParam(ref p) => write!(f, "{:?}", p),
|
||||
ty::MethodTraitObject(ref p) => write!(f, "{:?}", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::MethodParam<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MethodParam({:?},{})",
|
||||
self.trait_ref,
|
||||
self.method_num)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::MethodObject<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MethodObject({:?},{},{})",
|
||||
self.trait_ref,
|
||||
self.method_num,
|
||||
self.vtable_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ExistentialBounds<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut empty = true;
|
||||
|
|
|
|||
|
|
@ -33,8 +33,10 @@
|
|||
|
||||
use metadata::{csearch, decoder};
|
||||
use middle::def::*;
|
||||
use middle::infer;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::traits;
|
||||
use middle::{def, pat_util, stability};
|
||||
use middle::const_eval::{eval_const_expr_partial, ConstVal};
|
||||
use middle::cfg;
|
||||
|
|
@ -1863,24 +1865,18 @@ impl LintPass for UnconditionalRecursion {
|
|||
|
||||
fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
|
||||
blk: &ast::Block, sp: Span, id: ast::NodeId) {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
|
||||
type F = for<'tcx> fn(&ty::ctxt<'tcx>,
|
||||
ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
|
||||
|
||||
let (name, checker) = match fn_kind {
|
||||
visit::FkItemFn(name, _, _, _, _, _) => (name, id_refers_to_this_fn as F),
|
||||
visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F),
|
||||
let method = match fn_kind {
|
||||
visit::FkItemFn(..) => None,
|
||||
visit::FkMethod(..) => {
|
||||
cx.tcx.impl_or_trait_item(local_def(id)).as_opt_method()
|
||||
}
|
||||
// closures can't recur, so they don't matter.
|
||||
visit::FkFnBlock => return
|
||||
};
|
||||
|
||||
let impl_def_id = cx.tcx.impl_of_method(local_def(id))
|
||||
.unwrap_or(local_def(ast::DUMMY_NODE_ID));
|
||||
assert!(ast_util::is_local(impl_def_id));
|
||||
let impl_node_id = impl_def_id.node;
|
||||
|
||||
// Walk through this function (say `f`) looking to see if
|
||||
// every possible path references itself, i.e. the function is
|
||||
// called recursively unconditionally. This is done by trying
|
||||
|
|
@ -1931,7 +1927,17 @@ impl LintPass for UnconditionalRecursion {
|
|||
let node_id = cfg.graph.node_data(idx).id();
|
||||
|
||||
// is this a recursive call?
|
||||
if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
|
||||
let self_recursive = if node_id != ast::DUMMY_NODE_ID {
|
||||
match method {
|
||||
Some(ref method) => {
|
||||
expr_refers_to_this_method(cx.tcx, method, node_id)
|
||||
}
|
||||
None => expr_refers_to_this_fn(cx.tcx, id, node_id)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if self_recursive {
|
||||
self_call_spans.push(cx.tcx.map.span(node_id));
|
||||
// this is a self call, so we shouldn't explore past
|
||||
// this node in the CFG.
|
||||
|
|
@ -1970,15 +1976,12 @@ impl LintPass for UnconditionalRecursion {
|
|||
// all done
|
||||
return;
|
||||
|
||||
// Functions for identifying if the given NodeId `id`
|
||||
// represents a call to the function `fn_id`/method
|
||||
// `method_id`.
|
||||
// Functions for identifying if the given Expr NodeId `id`
|
||||
// represents a call to the function `fn_id`/method `method`.
|
||||
|
||||
fn id_refers_to_this_fn<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
_: ast::NodeId,
|
||||
fn_id: ast::NodeId,
|
||||
_: ast::Ident,
|
||||
id: ast::NodeId) -> bool {
|
||||
fn expr_refers_to_this_fn(tcx: &ty::ctxt,
|
||||
fn_id: ast::NodeId,
|
||||
id: ast::NodeId) -> bool {
|
||||
match tcx.map.get(id) {
|
||||
ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => {
|
||||
tcx.def_map.borrow().get(&callee.id)
|
||||
|
|
@ -1988,64 +1991,68 @@ impl LintPass for UnconditionalRecursion {
|
|||
}
|
||||
}
|
||||
|
||||
// check if the method call `id` refers to method `method_id`
|
||||
// (with name `method_name` contained in impl `impl_id`).
|
||||
fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_id: ast::NodeId,
|
||||
method_id: ast::NodeId,
|
||||
method_name: ast::Ident,
|
||||
id: ast::NodeId) -> bool {
|
||||
let did = match tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)) {
|
||||
None => return false,
|
||||
Some(m) => match m.origin {
|
||||
// There's no way to know if a method call via a
|
||||
// vtable is recursion, so we assume it's not.
|
||||
ty::MethodTraitObject(_) => return false,
|
||||
// Check if the method call `id` refers to method `method`.
|
||||
fn expr_refers_to_this_method(tcx: &ty::ctxt,
|
||||
method: &ty::Method,
|
||||
id: ast::NodeId) -> bool {
|
||||
let method_call = ty::MethodCall::expr(id);
|
||||
let callee = match tcx.tables.borrow().method_map.get(&method_call) {
|
||||
Some(&m) => m,
|
||||
None => return false
|
||||
};
|
||||
let callee_item = tcx.impl_or_trait_item(callee.def_id);
|
||||
|
||||
// This `did` refers directly to the method definition.
|
||||
ty::MethodStatic(did) | ty::MethodStaticClosure(did) => did,
|
||||
match callee_item.container() {
|
||||
// This is an inherent method, so the `def_id` refers
|
||||
// directly to the method definition.
|
||||
ty::ImplContainer(_) => {
|
||||
callee.def_id == method.def_id
|
||||
}
|
||||
|
||||
// MethodTypeParam are methods from traits:
|
||||
// A trait method, from any number of possible sources.
|
||||
// Attempt to select a concrete impl before checking.
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
let trait_substs = callee.substs.clone().method_to_trait();
|
||||
let trait_substs = tcx.mk_substs(trait_substs);
|
||||
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
|
||||
let trait_ref = ty::Binder(trait_ref);
|
||||
let span = tcx.map.span(id);
|
||||
let obligation =
|
||||
traits::Obligation::new(traits::ObligationCause::misc(span, id),
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
|
||||
// The `impl ... for ...` of this method call
|
||||
// isn't known, e.g. it might be a default method
|
||||
// in a trait, so we get the def-id of the trait
|
||||
// method instead.
|
||||
ty::MethodTypeParam(
|
||||
ty::MethodParam { ref trait_ref, method_num, impl_def_id: None, }) => {
|
||||
|
||||
let on_self = m.substs.self_ty().map_or(false, |t| t.is_self());
|
||||
if !on_self {
|
||||
// we can only be recurring in a default
|
||||
let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node);
|
||||
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
match selcx.select(&obligation) {
|
||||
// The method comes from a `T: Trait` bound.
|
||||
// If `T` is `Self`, then this call is inside
|
||||
// a default method definition.
|
||||
Ok(Some(traits::VtableParam(_))) => {
|
||||
let self_ty = callee.substs.self_ty();
|
||||
let on_self = self_ty.map_or(false, |t| t.is_self());
|
||||
// We can only be recurring in a default
|
||||
// method if we're being called literally
|
||||
// on the `Self` type.
|
||||
return false
|
||||
on_self && callee.def_id == method.def_id
|
||||
}
|
||||
|
||||
tcx.trait_item(trait_ref.def_id, method_num).def_id()
|
||||
}
|
||||
// The `impl` is known, so we check that with a
|
||||
// special case:
|
||||
Ok(Some(traits::VtableImpl(vtable_impl))) => {
|
||||
let container = ty::ImplContainer(vtable_impl.impl_def_id);
|
||||
// It matches if it comes from the same impl,
|
||||
// and has the same method name.
|
||||
container == method.container
|
||||
&& callee_item.name() == method.name
|
||||
}
|
||||
|
||||
// The `impl` is known, so we check that with a
|
||||
// special case:
|
||||
ty::MethodTypeParam(
|
||||
ty::MethodParam { impl_def_id: Some(impl_def_id), .. }) => {
|
||||
|
||||
let name = match tcx.map.expect_expr(id).node {
|
||||
ast::ExprMethodCall(ref sp_ident, _, _) => sp_ident.node,
|
||||
_ => tcx.sess.span_bug(
|
||||
tcx.map.span(id),
|
||||
"non-method call expr behaving like a method call?")
|
||||
};
|
||||
// It matches if it comes from the same impl,
|
||||
// and has the same method name.
|
||||
return ast_util::is_local(impl_def_id)
|
||||
&& impl_def_id.node == impl_id
|
||||
&& method_name.name == name.name
|
||||
// There's no way to know if this call is
|
||||
// recursive, so we assume it's not.
|
||||
_ => return false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ast_util::is_local(did) && did.node == method_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,10 +40,6 @@ use rustc::middle::privacy::ImportUse::*;
|
|||
use rustc::middle::privacy::LastPrivate::*;
|
||||
use rustc::middle::privacy::PrivateDep::*;
|
||||
use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
|
||||
use rustc::middle::ty::{MethodTypeParam, MethodStatic};
|
||||
use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam};
|
||||
use rustc::middle::ty::{MethodStaticClosure, MethodObject};
|
||||
use rustc::middle::ty::MethodTraitObject;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet};
|
||||
|
||||
|
|
@ -53,7 +49,7 @@ use syntax::codemap::Span;
|
|||
use syntax::parse::token;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap);
|
||||
type Context<'a, 'tcx> = (&'a ty::MethodMap<'tcx>, &'a def::ExportMap);
|
||||
|
||||
/// Result of a checking operation - None => no errors were found. Some => an
|
||||
/// error and contains the span and message for reporting that error and
|
||||
|
|
@ -848,18 +844,16 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Checks that a method is in scope.
|
||||
fn check_method(&mut self, span: Span, origin: &MethodOrigin,
|
||||
fn check_method(&mut self, span: Span, method_def_id: ast::DefId,
|
||||
name: ast::Name) {
|
||||
match *origin {
|
||||
MethodStatic(method_id) => {
|
||||
self.check_static_method(span, method_id, name)
|
||||
match self.tcx.impl_or_trait_item(method_def_id).container() {
|
||||
ty::ImplContainer(_) => {
|
||||
self.check_static_method(span, method_def_id, name)
|
||||
}
|
||||
MethodStaticClosure(_) => {}
|
||||
// Trait methods are always all public. The only controlling factor
|
||||
// is whether the trait itself is accessible or not.
|
||||
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
|
||||
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
|
||||
self.report_error(self.ensure_public(span, trait_ref.def_id,
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
self.report_error(self.ensure_public(span, trait_def_id,
|
||||
None, "source trait"));
|
||||
}
|
||||
}
|
||||
|
|
@ -903,18 +897,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ast::ExprMethodCall(ident, _, _) => {
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
match self.tcx.tables.borrow().method_map.get(&method_call) {
|
||||
None => {
|
||||
self.tcx.sess.span_bug(expr.span,
|
||||
"method call not in \
|
||||
method map");
|
||||
}
|
||||
Some(method) => {
|
||||
debug!("(privacy checking) checking impl method");
|
||||
self.check_method(expr.span, &method.origin, ident.node.name);
|
||||
}
|
||||
}
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let method = self.tcx.tables.borrow().method_map[&method_call];
|
||||
debug!("(privacy checking) checking impl method");
|
||||
self.check_method(expr.span, method.def_id, ident.node.name);
|
||||
}
|
||||
ast::ExprStruct(_, ref fields, _) => {
|
||||
match self.tcx.expr_ty(expr).sty {
|
||||
|
|
|
|||
|
|
@ -886,43 +886,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
fn process_method_call(&mut self,
|
||||
ex: &ast::Expr,
|
||||
args: &Vec<P<ast::Expr>>) {
|
||||
let method_map = &self.tcx.tables.borrow().method_map;
|
||||
let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
|
||||
let (def_id, decl_id) = match method_callee.origin {
|
||||
ty::MethodStatic(def_id) |
|
||||
ty::MethodStaticClosure(def_id) => {
|
||||
// method invoked on an object with a concrete type (not a static method)
|
||||
let decl_id =
|
||||
match self.tcx.trait_item_of_item(def_id) {
|
||||
None => None,
|
||||
Some(decl_id) => Some(decl_id.def_id()),
|
||||
};
|
||||
|
||||
// This incantation is required if the method referenced is a
|
||||
// trait's default implementation.
|
||||
let def_id = match self.tcx.impl_or_trait_item(def_id) {
|
||||
ty::MethodTraitItem(method) => {
|
||||
method.provided_source.unwrap_or(def_id)
|
||||
}
|
||||
_ => self.sess
|
||||
.span_bug(ex.span,
|
||||
"save::process_method_call: non-method \
|
||||
DefId in MethodStatic or MethodStaticClosure"),
|
||||
};
|
||||
(Some(def_id), decl_id)
|
||||
}
|
||||
ty::MethodTypeParam(ref mp) => {
|
||||
// method invoked on a type parameter
|
||||
let trait_item = self.tcx.trait_item(mp.trait_ref.def_id,
|
||||
mp.method_num);
|
||||
(None, Some(trait_item.def_id()))
|
||||
}
|
||||
ty::MethodTraitObject(ref mo) => {
|
||||
// method invoked on a trait instance
|
||||
let trait_item = self.tcx.trait_item(mo.trait_ref.def_id,
|
||||
mo.method_num);
|
||||
(None, Some(trait_item.def_id()))
|
||||
}
|
||||
let method_call = ty::MethodCall::expr(ex.id);
|
||||
let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
|
||||
let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
|
||||
ty::ImplContainer(_) => (Some(method_id), None),
|
||||
ty::TraitContainer(_) => (None, Some(method_id))
|
||||
};
|
||||
let sub_span = self.span.sub_span_for_meth_name(ex.span);
|
||||
self.fmt.meth_call_str(ex.span,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use arena::TypedArena;
|
|||
use back::link;
|
||||
use session;
|
||||
use llvm::{self, ValueRef, get_params};
|
||||
use metadata::csearch;
|
||||
use middle::def;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
|
|
@ -66,7 +65,7 @@ pub struct MethodData {
|
|||
pub enum CalleeData<'tcx> {
|
||||
// Constructor for enum variant/tuple-like-struct
|
||||
// i.e. Some, Ok
|
||||
NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr),
|
||||
NamedTupleConstructor(ty::Disr),
|
||||
|
||||
// Represents a (possibly monomorphized) top-level fn item or method
|
||||
// item. Note that this is just the fn-ptr and is not a Rust closure
|
||||
|
|
@ -81,6 +80,7 @@ pub enum CalleeData<'tcx> {
|
|||
pub struct Callee<'blk, 'tcx: 'blk> {
|
||||
pub bcx: Block<'blk, 'tcx>,
|
||||
pub data: CalleeData<'tcx>,
|
||||
pub ty: Ty<'tcx>
|
||||
}
|
||||
|
||||
fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
||||
|
|
@ -104,11 +104,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
|||
let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
|
||||
match datum.ty.sty {
|
||||
ty::TyBareFn(..) => {
|
||||
let llval = datum.to_llscalarish(bcx);
|
||||
return Callee {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llval),
|
||||
};
|
||||
ty: datum.ty,
|
||||
data: Fn(datum.to_llscalarish(bcx))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
|
|
@ -119,12 +119,13 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
|||
}
|
||||
}
|
||||
|
||||
fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef)
|
||||
fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
return Callee {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
};
|
||||
data: Fn(datum.val),
|
||||
ty: datum.ty
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
|
@ -143,12 +144,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
|||
_ => false
|
||||
}
|
||||
} => {
|
||||
let substs = common::node_id_substs(bcx.ccx(),
|
||||
ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: NamedTupleConstructor(substs, 0)
|
||||
data: NamedTupleConstructor(0),
|
||||
ty: expr_ty
|
||||
}
|
||||
}
|
||||
def::DefFn(did, _) if match expr_ty.sty {
|
||||
|
|
@ -159,40 +158,36 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
|||
ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs);
|
||||
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
|
||||
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
|
||||
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty }
|
||||
}
|
||||
def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => {
|
||||
fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs).val)
|
||||
bcx.fcx.param_substs))
|
||||
}
|
||||
def::DefMethod(meth_did, def::FromTrait(trait_did)) => {
|
||||
fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
|
||||
meth_did,
|
||||
trait_did,
|
||||
ref_expr.id,
|
||||
bcx.fcx.param_substs).val)
|
||||
bcx.fcx.param_substs))
|
||||
}
|
||||
def::DefVariant(tid, vid, _) => {
|
||||
let vinfo = bcx.tcx().enum_variant_with_id(tid, vid);
|
||||
let substs = common::node_id_substs(bcx.ccx(),
|
||||
ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs);
|
||||
|
||||
// Nullary variants are not callable
|
||||
assert!(!vinfo.args.is_empty());
|
||||
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: NamedTupleConstructor(substs, vinfo.disr_val)
|
||||
data: NamedTupleConstructor(vinfo.disr_val),
|
||||
ty: expr_ty
|
||||
}
|
||||
}
|
||||
def::DefStruct(_) => {
|
||||
let substs = common::node_id_substs(bcx.ccx(),
|
||||
ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: NamedTupleConstructor(substs, 0)
|
||||
data: NamedTupleConstructor(0),
|
||||
ty: expr_ty
|
||||
}
|
||||
}
|
||||
def::DefStatic(..) |
|
||||
|
|
@ -232,21 +227,6 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
|
||||
}
|
||||
|
||||
fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
def_id: ast::DefId,
|
||||
ref_id: ast::NodeId,
|
||||
substs: subst::Substs<'tcx>)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
|
||||
def_id,
|
||||
ExprId(ref_id),
|
||||
bcx.fcx.param_substs,
|
||||
substs).val),
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates an adapter that implements the `Fn` trait for a fn
|
||||
/// pointer. This is basically the equivalent of something like:
|
||||
///
|
||||
|
|
@ -356,12 +336,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||
expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
|
||||
);
|
||||
|
||||
bcx = trans_call_inner(bcx,
|
||||
DebugLoc::None,
|
||||
bare_fn_ty,
|
||||
|bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
|
||||
ArgVals(&llargs[(self_idx + 1)..]),
|
||||
dest).bcx;
|
||||
bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfnpointer),
|
||||
ty: bare_fn_ty
|
||||
}
|
||||
}, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
|
||||
|
||||
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
||||
|
||||
|
|
@ -518,7 +499,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
|
|||
let ref_ty = match node {
|
||||
ExprId(id) => tcx.node_id_to_type(id),
|
||||
MethodCallKey(method_call) => {
|
||||
tcx.tables.borrow().method_map.get(&method_call).unwrap().ty
|
||||
tcx.tables.borrow().method_map[&method_call].ty
|
||||
}
|
||||
};
|
||||
let ref_ty = monomorphize::apply_param_substs(tcx,
|
||||
|
|
@ -586,17 +567,16 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
|
|||
// ______________________________________________________________________
|
||||
// Translating calls
|
||||
|
||||
pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
|
||||
pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
call_expr: &ast::Expr,
|
||||
f: &ast::Expr,
|
||||
args: CallArgs<'a, 'tcx>,
|
||||
dest: expr::Dest)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("trans_call");
|
||||
trans_call_inner(in_cx,
|
||||
trans_call_inner(bcx,
|
||||
call_expr.debug_loc(),
|
||||
common::expr_ty_adjusted(in_cx, f),
|
||||
|cx, _| trans(cx, f),
|
||||
|bcx, _| trans(bcx, f),
|
||||
args,
|
||||
Some(dest)).bcx
|
||||
}
|
||||
|
|
@ -610,22 +590,9 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let _icx = push_ctxt("trans_method_call");
|
||||
debug!("trans_method_call(call_expr={:?})", call_expr);
|
||||
let method_call = MethodCall::expr(call_expr.id);
|
||||
let method_ty = match bcx.tcx().tables.borrow().method_map.get(&method_call) {
|
||||
Some(method) => match method.origin {
|
||||
ty::MethodTraitObject(_) => match method.ty.sty {
|
||||
ty::TyBareFn(_, ref fty) => {
|
||||
bcx.tcx().mk_fn(None, meth::opaque_method_ty(bcx.tcx(), fty))
|
||||
}
|
||||
_ => method.ty
|
||||
},
|
||||
_ => method.ty
|
||||
},
|
||||
None => panic!("method not found in trans_method_call")
|
||||
};
|
||||
trans_call_inner(
|
||||
bcx,
|
||||
call_expr.debug_loc(),
|
||||
common::monomorphize_type(bcx, method_ty),
|
||||
|cx, arg_cleanup_scope| {
|
||||
meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
|
||||
},
|
||||
|
|
@ -639,22 +606,18 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
dest: Option<expr::Dest>,
|
||||
debug_loc: DebugLoc)
|
||||
-> Result<'blk, 'tcx> {
|
||||
let fty = if did.krate == ast::LOCAL_CRATE {
|
||||
bcx.tcx().node_id_to_type(did.node)
|
||||
} else {
|
||||
csearch::get_type(bcx.tcx(), did).ty
|
||||
};
|
||||
callee::trans_call_inner(bcx,
|
||||
debug_loc,
|
||||
fty,
|
||||
|bcx, _| {
|
||||
trans_fn_ref_with_substs_to_callee(bcx,
|
||||
did,
|
||||
0,
|
||||
subst::Substs::trans_empty())
|
||||
},
|
||||
ArgVals(args),
|
||||
dest)
|
||||
callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
|
||||
let datum = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
did,
|
||||
ExprId(0),
|
||||
bcx.fcx.param_substs,
|
||||
subst::Substs::trans_empty());
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(datum.val),
|
||||
ty: datum.ty
|
||||
}
|
||||
}, ArgVals(args), dest)
|
||||
}
|
||||
|
||||
/// This behemoth of a function translates function calls. Unfortunately, in order to generate more
|
||||
|
|
@ -669,7 +632,6 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
/// somewhere. Nonetheless we return the actual return value of the function.
|
||||
pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
debug_loc: DebugLoc,
|
||||
callee_ty: Ty<'tcx>,
|
||||
get_callee: F,
|
||||
args: CallArgs<'a, 'tcx>,
|
||||
dest: Option<expr::Dest>)
|
||||
|
|
@ -690,7 +652,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
|
||||
let mut bcx = callee.bcx;
|
||||
|
||||
let (abi, ret_ty) = match callee_ty.sty {
|
||||
let (abi, ret_ty) = match callee.ty.sty {
|
||||
ty::TyBareFn(_, ref f) => {
|
||||
let output = bcx.tcx().erase_late_bound_regions(&f.sig.output());
|
||||
(f.abi, output)
|
||||
|
|
@ -698,12 +660,12 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
_ => panic!("expected bare rust fn or closure in trans_call_inner")
|
||||
};
|
||||
|
||||
let (llfn, llenv, llself) = match callee.data {
|
||||
let (llfn, llself) = match callee.data {
|
||||
Fn(llfn) => {
|
||||
(llfn, None, None)
|
||||
(llfn, None)
|
||||
}
|
||||
TraitItem(d) => {
|
||||
(d.llfn, None, Some(d.llself))
|
||||
(d.llfn, Some(d.llself))
|
||||
}
|
||||
Intrinsic(node, substs) => {
|
||||
assert!(abi == synabi::RustIntrinsic);
|
||||
|
|
@ -716,18 +678,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
};
|
||||
|
||||
return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
|
||||
return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
|
||||
arg_cleanup_scope, args,
|
||||
dest.unwrap(), substs,
|
||||
call_info);
|
||||
}
|
||||
NamedTupleConstructor(substs, disr) => {
|
||||
NamedTupleConstructor(disr) => {
|
||||
assert!(dest.is_some());
|
||||
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
|
||||
|
||||
let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
|
||||
return base::trans_named_tuple_constructor(bcx,
|
||||
ctor_ty,
|
||||
callee.ty,
|
||||
disr,
|
||||
args,
|
||||
dest.unwrap(),
|
||||
|
|
@ -794,17 +755,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
// Push the environment (or a trait object's self).
|
||||
match (llenv, llself) {
|
||||
(Some(llenv), None) => llargs.push(llenv),
|
||||
(None, Some(llself)) => llargs.push(llself),
|
||||
_ => {}
|
||||
// Push a trait object's self.
|
||||
if let Some(llself) = llself {
|
||||
llargs.push(llself);
|
||||
}
|
||||
|
||||
// Push the arguments.
|
||||
bcx = trans_args(bcx,
|
||||
args,
|
||||
callee_ty,
|
||||
callee.ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(arg_cleanup_scope),
|
||||
llself.is_some(),
|
||||
|
|
@ -816,7 +775,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
let (llret, b) = base::invoke(bcx,
|
||||
llfn,
|
||||
&llargs[..],
|
||||
callee_ty,
|
||||
callee.ty,
|
||||
debug_loc);
|
||||
bcx = b;
|
||||
llresult = llret;
|
||||
|
|
@ -845,7 +804,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
};
|
||||
bcx = trans_args(bcx,
|
||||
args,
|
||||
callee_ty,
|
||||
callee.ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(arg_cleanup_scope),
|
||||
false,
|
||||
|
|
@ -853,7 +812,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
|
||||
|
||||
bcx = foreign::trans_native_call(bcx,
|
||||
callee_ty,
|
||||
callee.ty,
|
||||
llfn,
|
||||
opt_llretslot.unwrap(),
|
||||
&llargs[..],
|
||||
|
|
@ -894,11 +853,11 @@ pub enum CallArgs<'a, 'tcx> {
|
|||
// value.
|
||||
ArgVals(&'a [ValueRef]),
|
||||
|
||||
// For overloaded operators: `(lhs, Vec(rhs, rhs_id), autoref)`. `lhs`
|
||||
// For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
|
||||
// is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
|
||||
// the right-hand-side arguments (if any). `autoref` indicates whether the `rhs`
|
||||
// the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
|
||||
// arguments should be auto-referenced
|
||||
ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
|
||||
ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
|
||||
|
||||
// Supply value of arguments as a list of expressions that must be
|
||||
// translated, for overloaded call operators.
|
||||
|
|
@ -1077,12 +1036,14 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
DontAutorefArg,
|
||||
llargs);
|
||||
|
||||
assert_eq!(arg_tys.len(), 1 + rhs.len());
|
||||
for (rhs, rhs_id) in rhs {
|
||||
if let Some((rhs, rhs_id)) = rhs {
|
||||
assert_eq!(arg_tys.len(), 2);
|
||||
bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
|
||||
arg_cleanup_scope,
|
||||
if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
|
||||
llargs);
|
||||
} else {
|
||||
assert_eq!(arg_tys.len(), 1);
|
||||
}
|
||||
}
|
||||
ArgVals(vs) => {
|
||||
|
|
|
|||
|
|
@ -429,12 +429,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||
let callee_data = TraitItem(MethodData { llfn: llreffn,
|
||||
llself: env_datum.val });
|
||||
|
||||
bcx = callee::trans_call_inner(bcx,
|
||||
DebugLoc::None,
|
||||
llref_fn_ty,
|
||||
|bcx, _| Callee { bcx: bcx, data: callee_data },
|
||||
ArgVals(&llargs[(self_idx + 1)..]),
|
||||
dest).bcx;
|
||||
bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: callee_data,
|
||||
ty: llref_fn_ty
|
||||
}
|
||||
}, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
|
||||
|
||||
fcx.pop_custom_cleanup_scope(self_scope);
|
||||
|
||||
|
|
|
|||
|
|
@ -874,7 +874,6 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
|
||||
trait_ref, trait_ref.def_id());
|
||||
|
||||
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
|
|
@ -1026,7 +1025,7 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
tcx.node_id_item_substs(id).substs
|
||||
}
|
||||
MethodCallKey(method_call) => {
|
||||
tcx.tables.borrow().method_map.get(&method_call).unwrap().substs.clone()
|
||||
tcx.tables.borrow().method_map[&method_call].substs.clone()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -894,10 +894,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
ast::ExprMethodCall(_, _, ref args) => {
|
||||
let arg_vals = map_list(args);
|
||||
let method_call = ty::MethodCall::expr(e.id);
|
||||
let method_did = match cx.tcx().tables.borrow().method_map[&method_call].origin {
|
||||
ty::MethodStatic(did) => did,
|
||||
_ => cx.sess().span_bug(e.span, "expected a const method def")
|
||||
};
|
||||
let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id;
|
||||
const_fn_call(cx, MethodCallKey(method_call),
|
||||
method_did, &arg_vals, param_substs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -805,7 +805,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
index_expr,
|
||||
method_call,
|
||||
base_datum,
|
||||
vec![(ix_datum, idx.id)],
|
||||
Some((ix_datum, idx.id)),
|
||||
Some(SaveIn(scratch.val)),
|
||||
false));
|
||||
let datum = scratch.to_expr_datum();
|
||||
|
|
@ -1175,21 +1175,21 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
|
||||
let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
|
||||
vec![(rhs_datum, rhs.id)], Some(dest),
|
||||
Some((rhs_datum, rhs.id)), Some(dest),
|
||||
!ast_util::is_by_value_binop(op.node)).bcx
|
||||
}
|
||||
ast::ExprUnary(op, ref subexpr) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
|
||||
arg, Vec::new(), Some(dest), !ast_util::is_by_value_unop(op)).bcx
|
||||
arg, None, Some(dest), !ast_util::is_by_value_unop(op)).bcx
|
||||
}
|
||||
ast::ExprIndex(ref base, ref idx) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
let base = unpack_datum!(bcx, trans(bcx, &**base));
|
||||
let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
|
||||
vec![(idx_datum, idx.id)], Some(dest), true).bcx
|
||||
Some((idx_datum, idx.id)), Some(dest), true).bcx
|
||||
}
|
||||
ast::ExprCast(..) => {
|
||||
// Trait casts used to come this way, now they should be coercions.
|
||||
|
|
@ -1943,19 +1943,12 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
expr: &ast::Expr,
|
||||
method_call: MethodCall,
|
||||
lhs: Datum<'tcx, Expr>,
|
||||
rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>,
|
||||
rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
|
||||
dest: Option<Dest>,
|
||||
autoref: bool)
|
||||
-> Result<'blk, 'tcx> {
|
||||
let method_ty = bcx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call).unwrap().ty;
|
||||
|
||||
callee::trans_call_inner(bcx,
|
||||
expr.debug_loc(),
|
||||
monomorphize_type(bcx, method_ty),
|
||||
|bcx, arg_cleanup_scope| {
|
||||
meth::trans_method_callee(bcx,
|
||||
method_call,
|
||||
|
|
@ -1974,20 +1967,11 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
-> Block<'blk, 'tcx> {
|
||||
debug!("trans_overloaded_call {}", expr.id);
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let method_type = bcx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.unwrap()
|
||||
.ty;
|
||||
let mut all_args = vec!(callee);
|
||||
all_args.extend(args.iter().map(|e| &**e));
|
||||
unpack_result!(bcx,
|
||||
callee::trans_call_inner(bcx,
|
||||
expr.debug_loc(),
|
||||
monomorphize_type(bcx,
|
||||
method_type),
|
||||
|bcx, arg_cleanup_scope| {
|
||||
meth::trans_method_callee(
|
||||
bcx,
|
||||
|
|
@ -2259,7 +2243,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
|
||||
|
||||
unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
|
||||
datum, Vec::new(), Some(SaveIn(scratch.val)),
|
||||
datum, None, Some(SaveIn(scratch.val)),
|
||||
false));
|
||||
scratch.to_expr_datum()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ use trans::type_of::*;
|
|||
use middle::ty::{self, Ty, HasTypeFlags};
|
||||
use middle::ty::MethodCall;
|
||||
|
||||
use syntax::abi::{Rust, RustCall};
|
||||
use syntax::parse::token;
|
||||
use syntax::{ast, attr, visit};
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
|
@ -107,34 +106,28 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_method_callee");
|
||||
|
||||
let (origin, method_ty) =
|
||||
bcx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| (method.origin.clone(), method.ty))
|
||||
.unwrap();
|
||||
let method = bcx.tcx().tables.borrow().method_map[&method_call];
|
||||
|
||||
match origin {
|
||||
ty::MethodStatic(did) |
|
||||
ty::MethodStaticClosure(did) => {
|
||||
debug!("trans_method_callee: static, {:?}", did);
|
||||
match bcx.tcx().impl_or_trait_item(method.def_id).container() {
|
||||
ty::ImplContainer(_) => {
|
||||
debug!("trans_method_callee: static, {:?}", method.def_id);
|
||||
let datum = callee::trans_fn_ref(bcx.ccx(),
|
||||
method.def_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(callee::trans_fn_ref(bcx.ccx(),
|
||||
did,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs).val),
|
||||
data: Fn(datum.val),
|
||||
ty: datum.ty
|
||||
}
|
||||
}
|
||||
|
||||
ty::MethodTypeParam(ty::MethodParam {
|
||||
ref trait_ref,
|
||||
method_num,
|
||||
impl_def_id: _
|
||||
}) => {
|
||||
let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
let trait_substs = method.substs.clone().method_to_trait();
|
||||
let trait_substs = bcx.tcx().mk_substs(trait_substs);
|
||||
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
|
||||
|
||||
let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
|
||||
let span = bcx.tcx().map.span(method_call.expr_id);
|
||||
debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
|
||||
method_call,
|
||||
|
|
@ -147,25 +140,12 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
debug!("origin = {:?}", origin);
|
||||
trans_monomorphized_callee(bcx,
|
||||
method_call,
|
||||
trait_ref.def_id(),
|
||||
method_num,
|
||||
origin)
|
||||
}
|
||||
|
||||
ty::MethodTraitObject(ref mt) => {
|
||||
let self_expr = match self_expr {
|
||||
Some(self_expr) => self_expr,
|
||||
None => {
|
||||
bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id),
|
||||
"self expr wasn't provided for trait object \
|
||||
callee (trying to call overloaded op?)")
|
||||
}
|
||||
};
|
||||
trans_trait_callee(bcx,
|
||||
monomorphize_type(bcx, method_ty),
|
||||
mt.vtable_index,
|
||||
self_expr,
|
||||
arg_cleanup_scope)
|
||||
self_expr,
|
||||
trait_def_id,
|
||||
method.def_id,
|
||||
method.ty,
|
||||
origin,
|
||||
arg_cleanup_scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -235,8 +215,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
Vec::new()));
|
||||
let trait_substs = tcx.mk_substs(trait_substs);
|
||||
debug!("trait_substs={:?}", trait_substs);
|
||||
let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
|
||||
substs: trait_substs });
|
||||
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
|
||||
let vtbl = fulfill_obligation(ccx,
|
||||
DUMMY_SP,
|
||||
trait_ref);
|
||||
|
|
@ -282,18 +261,11 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
callee_substs)
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let trait_item_def_ids =
|
||||
ccx.tcx().trait_item_def_ids(trait_id);
|
||||
let method_offset_in_trait =
|
||||
trait_item_def_ids.iter()
|
||||
.position(|item| item.def_id() == method_id)
|
||||
.unwrap();
|
||||
let (llfn, ty) =
|
||||
trans_object_shim(ccx,
|
||||
data.object_ty,
|
||||
data.upcast_trait_ref.clone(),
|
||||
method_offset_in_trait);
|
||||
immediate_rvalue(llfn, ty)
|
||||
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
|
||||
trans_object_shim(ccx,
|
||||
data.upcast_trait_ref.clone(),
|
||||
method_id,
|
||||
idx)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
|
||||
|
|
@ -326,16 +298,19 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name)
|
|||
|
||||
fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
method_call: MethodCall,
|
||||
self_expr: Option<&ast::Expr>,
|
||||
trait_id: ast::DefId,
|
||||
n_method: usize,
|
||||
vtable: traits::Vtable<'tcx, ()>)
|
||||
method_id: ast::DefId,
|
||||
method_ty: Ty<'tcx>,
|
||||
vtable: traits::Vtable<'tcx, ()>,
|
||||
arg_cleanup_scope: cleanup::ScopeId)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_monomorphized_callee");
|
||||
match vtable {
|
||||
traits::VtableImpl(vtable_impl) => {
|
||||
let ccx = bcx.ccx();
|
||||
let impl_did = vtable_impl.impl_def_id;
|
||||
let mname = match ccx.tcx().trait_item(trait_id, n_method) {
|
||||
let mname = match ccx.tcx().impl_or_trait_item(method_id) {
|
||||
ty::MethodTraitItem(method) => method.name,
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("can't monomorphize a non-method trait \
|
||||
|
|
@ -351,13 +326,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
bcx, MethodCallKey(method_call), vtable_impl.substs);
|
||||
|
||||
// translate the function
|
||||
let llfn = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
mth_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs,
|
||||
callee_substs).val;
|
||||
let datum = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
mth_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs,
|
||||
callee_substs);
|
||||
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
|
||||
}
|
||||
traits::VtableClosure(vtable_closure) => {
|
||||
// The substitutions should have no type parameters remaining
|
||||
|
|
@ -372,19 +347,31 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
ty: monomorphize_type(bcx, method_ty)
|
||||
}
|
||||
}
|
||||
traits::VtableFnPointer(fn_ty) => {
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
ty: monomorphize_type(bcx, method_ty)
|
||||
}
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let (llfn, _) = trans_object_shim(bcx.ccx(),
|
||||
data.object_ty,
|
||||
data.upcast_trait_ref.clone(),
|
||||
n_method);
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id);
|
||||
if let Some(self_expr) = self_expr {
|
||||
if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty {
|
||||
let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty));
|
||||
return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope);
|
||||
}
|
||||
}
|
||||
let datum = trans_object_shim(bcx.ccx(),
|
||||
data.upcast_trait_ref.clone(),
|
||||
method_id,
|
||||
idx);
|
||||
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
|
||||
}
|
||||
traits::VtableBuiltin(..) |
|
||||
traits::VtableDefaultImpl(..) |
|
||||
|
|
@ -438,7 +425,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
/// object. Objects are represented as a pair, so we first evaluate the self expression and then
|
||||
/// extract the self data and vtable out of the pair.
|
||||
fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
method_ty: Ty<'tcx>,
|
||||
opaque_fn_ty: Ty<'tcx>,
|
||||
vtable_index: usize,
|
||||
self_expr: &ast::Expr,
|
||||
arg_cleanup_scope: cleanup::ScopeId)
|
||||
|
|
@ -471,51 +458,39 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR]));
|
||||
let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA]));
|
||||
trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable)
|
||||
trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable)
|
||||
}
|
||||
|
||||
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
|
||||
/// pair.
|
||||
pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
callee_ty: Ty<'tcx>,
|
||||
vtable_index: usize,
|
||||
llself: ValueRef,
|
||||
llvtable: ValueRef)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
opaque_fn_ty: Ty<'tcx>,
|
||||
vtable_index: usize,
|
||||
llself: ValueRef,
|
||||
llvtable: ValueRef)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_trait_callee");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Load the data pointer from the object.
|
||||
debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
|
||||
callee_ty,
|
||||
opaque_fn_ty,
|
||||
vtable_index,
|
||||
bcx.val_to_string(llself),
|
||||
bcx.val_to_string(llvtable));
|
||||
|
||||
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
let llcallee_ty = match callee_ty.sty {
|
||||
ty::TyBareFn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
|
||||
let fake_sig =
|
||||
ty::Binder(ty::FnSig {
|
||||
inputs: f.sig.0.inputs[1..].to_vec(),
|
||||
output: f.sig.0.output,
|
||||
variadic: f.sig.0.variadic,
|
||||
});
|
||||
type_of_rust_fn(ccx, Some(Type::i8p(ccx)), &fake_sig, f.abi)
|
||||
}
|
||||
_ => {
|
||||
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
|
||||
}
|
||||
};
|
||||
let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
|
||||
let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty);
|
||||
|
||||
return Callee {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: TraitItem(MethodData {
|
||||
llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()),
|
||||
llself: PointerCast(bcx, llself, Type::i8p(ccx)),
|
||||
})
|
||||
};
|
||||
}),
|
||||
ty: opaque_fn_ty
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a shim function that allows an object type like `SomeTrait` to
|
||||
|
|
@ -540,32 +515,19 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
///
|
||||
/// In fact, all virtual calls can be thought of as normal trait calls
|
||||
/// that go through this shim function.
|
||||
pub fn trans_object_shim<'a, 'tcx>(
|
||||
fn trans_object_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
object_ty: Ty<'tcx>,
|
||||
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
method_offset_in_trait: usize)
|
||||
-> (ValueRef, Ty<'tcx>)
|
||||
method_id: ast::DefId,
|
||||
vtable_index: usize)
|
||||
-> Datum<'tcx, Rvalue>
|
||||
{
|
||||
let _icx = push_ctxt("trans_object_shim");
|
||||
let tcx = ccx.tcx();
|
||||
let trait_id = upcast_trait_ref.def_id();
|
||||
|
||||
debug!("trans_object_shim(object_ty={:?}, upcast_trait_ref={:?}, method_offset_in_trait={})",
|
||||
object_ty,
|
||||
debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})",
|
||||
upcast_trait_ref,
|
||||
method_offset_in_trait);
|
||||
|
||||
let object_trait_ref =
|
||||
match object_ty.sty {
|
||||
ty::TyTrait(ref data) => {
|
||||
data.principal_trait_ref_with_self_ty(tcx, object_ty)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("trans_object_shim() called on non-object: {:?}",
|
||||
object_ty));
|
||||
}
|
||||
};
|
||||
method_id);
|
||||
|
||||
// Upcast to the trait in question and extract out the substitutions.
|
||||
let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref);
|
||||
|
|
@ -573,7 +535,7 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
debug!("trans_object_shim: object_substs={:?}", object_substs);
|
||||
|
||||
// Lookup the type of this method as declared in the trait and apply substitutions.
|
||||
let method_ty = match tcx.trait_item(trait_id, method_offset_in_trait) {
|
||||
let method_ty = match tcx.impl_or_trait_item(method_id) {
|
||||
ty::MethodTraitItem(method) => method,
|
||||
_ => {
|
||||
tcx.sess.bug("can't create a method shim for a non-method item")
|
||||
|
|
@ -622,27 +584,21 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
fcx.llretslotptr.get().map(
|
||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
|
||||
|
||||
let method_offset_in_vtable =
|
||||
traits::get_vtable_index_of_object_method(bcx.tcx(),
|
||||
object_trait_ref.clone(),
|
||||
trait_id,
|
||||
method_offset_in_trait);
|
||||
debug!("trans_object_shim: method_offset_in_vtable={}",
|
||||
method_offset_in_vtable);
|
||||
vtable_index);
|
||||
|
||||
bcx = trans_call_inner(bcx,
|
||||
DebugLoc::None,
|
||||
method_bare_fn_ty,
|
||||
|bcx, _| trans_trait_callee_from_llval(bcx,
|
||||
method_bare_fn_ty,
|
||||
method_offset_in_vtable,
|
||||
vtable_index,
|
||||
llself, llvtable),
|
||||
ArgVals(&llargs[(self_idx + 2)..]),
|
||||
dest).bcx;
|
||||
|
||||
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
||||
|
||||
(llfn, method_bare_fn_ty)
|
||||
immediate_rvalue(llfn, shim_fn_ty)
|
||||
}
|
||||
|
||||
/// Creates a returns a dynamic vtable for the given type and vtable origin.
|
||||
|
|
@ -825,8 +781,8 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
/// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
|
||||
-> &'tcx ty::BareFnTy<'tcx> {
|
||||
fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
|
||||
-> &'tcx ty::BareFnTy<'tcx> {
|
||||
let mut inputs = method_ty.sig.0.inputs.clone();
|
||||
inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8));
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let item_ty = ccx.tcx().lookup_item_type(fn_id).ty;
|
||||
|
||||
debug!("monomorphic_fn about to subst into {:?}", item_ty);
|
||||
let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
|
||||
let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty);
|
||||
debug!("mono_ty = {:?} (post-substitution)", mono_ty);
|
||||
|
||||
match ccx.monomorphized().borrow().get(&hash_id) {
|
||||
Some(&val) => {
|
||||
|
|
@ -96,11 +97,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
debug!("mono_ty = {:?} (post-substitution)", mono_ty);
|
||||
|
||||
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
|
||||
debug!("mono_ty = {:?} (post-normalization)", mono_ty);
|
||||
|
||||
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
|
||||
|
||||
let depth;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ use check::UnresolvedTypeAction;
|
|||
use middle::subst::{self};
|
||||
use middle::traits;
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin,
|
||||
MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::infer;
|
||||
use middle::infer::InferCtxt;
|
||||
|
|
@ -52,7 +50,7 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> MethodCallee<'tcx>
|
||||
-> ty::MethodCallee<'tcx>
|
||||
{
|
||||
debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
|
||||
unadjusted_self_ty,
|
||||
|
|
@ -77,7 +75,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> MethodCallee<'tcx>
|
||||
-> ty::MethodCallee<'tcx>
|
||||
{
|
||||
// Adjust the self expression the user provided and obtain the adjusted type.
|
||||
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
|
||||
|
|
@ -86,8 +84,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
self.enforce_illegal_method_limitations(&pick);
|
||||
|
||||
// Create substitutions for the method's type parameters.
|
||||
let (rcvr_substs, method_origin) =
|
||||
self.fresh_receiver_substs(self_ty, &pick);
|
||||
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
|
||||
let (method_types, method_regions) =
|
||||
self.instantiate_method_substs(&pick, supplied_method_types);
|
||||
let all_substs = rcvr_substs.with_method(method_types, method_regions);
|
||||
|
|
@ -112,10 +109,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
let callee = MethodCallee {
|
||||
origin: method_origin,
|
||||
let callee = ty::MethodCallee {
|
||||
def_id: pick.item.def_id(),
|
||||
ty: fty,
|
||||
substs: all_substs
|
||||
substs: self.tcx().mk_substs(all_substs)
|
||||
};
|
||||
|
||||
// If this is an `&mut self` method, bias the receiver
|
||||
|
|
@ -194,18 +191,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
fn fresh_receiver_substs(&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
pick: &probe::Pick<'tcx>)
|
||||
-> (subst::Substs<'tcx>, MethodOrigin<'tcx>)
|
||||
-> subst::Substs<'tcx>
|
||||
{
|
||||
match pick.kind {
|
||||
probe::InherentImplPick(impl_def_id) => {
|
||||
probe::InherentImplPick => {
|
||||
let impl_def_id = pick.item.container().id();
|
||||
assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(),
|
||||
"impl {:?} is not an inherent impl", impl_def_id);
|
||||
let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
|
||||
|
||||
(impl_polytype.substs, MethodStatic(pick.item.def_id()))
|
||||
check::impl_self_ty(self.fcx, self.span, impl_def_id).substs
|
||||
}
|
||||
|
||||
probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
|
||||
probe::ObjectPick => {
|
||||
let trait_def_id = pick.item.container().id();
|
||||
self.extract_trait_ref(self_ty, |this, object_ty, data| {
|
||||
// The object data has no entry for the Self
|
||||
// Type. For the purposes of this method call, we
|
||||
|
|
@ -227,18 +224,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
original_poly_trait_ref,
|
||||
upcast_trait_ref,
|
||||
trait_def_id);
|
||||
let substs = upcast_trait_ref.substs.clone();
|
||||
let origin = MethodTraitObject(MethodObject {
|
||||
trait_ref: upcast_trait_ref,
|
||||
object_trait_id: trait_def_id,
|
||||
method_num: method_num,
|
||||
vtable_index: vtable_index,
|
||||
});
|
||||
(substs, origin)
|
||||
upcast_trait_ref.substs.clone()
|
||||
})
|
||||
}
|
||||
|
||||
probe::ExtensionImplPick(impl_def_id, method_num) => {
|
||||
probe::ExtensionImplPick(impl_def_id) => {
|
||||
// The method being invoked is the method as defined on the trait,
|
||||
// so return the substitutions from the trait. Consider:
|
||||
//
|
||||
|
|
@ -254,13 +244,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
self.span,
|
||||
&impl_polytype.substs,
|
||||
&self.tcx().impl_trait_ref(impl_def_id).unwrap());
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
|
||||
method_num: method_num,
|
||||
impl_def_id: Some(impl_def_id) });
|
||||
(impl_trait_ref.substs.clone(), origin)
|
||||
impl_trait_ref.substs.clone()
|
||||
}
|
||||
|
||||
probe::TraitPick(trait_def_id, method_num) => {
|
||||
probe::TraitPick => {
|
||||
let trait_def_id = pick.item.container().id();
|
||||
let trait_def = self.tcx().lookup_trait_def(trait_def_id);
|
||||
|
||||
// Make a trait reference `$0 : Trait<$1...$n>`
|
||||
|
|
@ -268,27 +256,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// the process we will unify the transformed-self-type
|
||||
// of the method with the actual type in order to
|
||||
// unify some of these variables.
|
||||
let substs = self.infcx().fresh_substs_for_trait(self.span,
|
||||
&trait_def.generics,
|
||||
self.infcx().next_ty_var());
|
||||
|
||||
let trait_ref =
|
||||
ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs.clone()));
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
|
||||
method_num: method_num,
|
||||
impl_def_id: None });
|
||||
(substs, origin)
|
||||
self.infcx().fresh_substs_for_trait(self.span,
|
||||
&trait_def.generics,
|
||||
self.infcx().next_ty_var())
|
||||
}
|
||||
|
||||
probe::WhereClausePick(ref poly_trait_ref, method_num) => {
|
||||
probe::WhereClausePick(ref poly_trait_ref) => {
|
||||
// Where clauses can have bound regions in them. We need to instantiate
|
||||
// those to convert from a poly-trait-ref to a trait-ref.
|
||||
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,
|
||||
impl_def_id: None });
|
||||
(substs, origin)
|
||||
self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref).substs.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -450,7 +426,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
/// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
|
||||
/// respectively.
|
||||
fn fixup_derefs_on_method_receiver_if_necessary(&self,
|
||||
method_callee: &MethodCallee) {
|
||||
method_callee: &ty::MethodCallee) {
|
||||
let sig = match method_callee.ty.sty {
|
||||
ty::TyBareFn(_, ref f) => f.sig.clone(),
|
||||
_ => return,
|
||||
|
|
@ -570,7 +546,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
|
||||
let result = check::try_index_step(
|
||||
self.fcx,
|
||||
MethodCall::expr(expr.id),
|
||||
ty::MethodCall::expr(expr.id),
|
||||
expr,
|
||||
&**base_expr,
|
||||
adjusted_base_ty,
|
||||
|
|
@ -589,7 +565,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
ast::ExprUnary(ast::UnDeref, ref base_expr) => {
|
||||
// if this is an overloaded deref, then re-evaluate with
|
||||
// a preference for mut
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
|
||||
check::try_overloaded_deref(
|
||||
self.fcx,
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ pub enum CandidateSource {
|
|||
TraitSource(/* trait id */ ast::DefId),
|
||||
}
|
||||
|
||||
type ItemIndex = usize; // just for doc purposes
|
||||
|
||||
/// Determines whether the type `self_ty` supports a method name `method_name` or not.
|
||||
pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
|
|
@ -204,14 +202,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
// Trait must have a method named `m_name` and it should not have
|
||||
// type parameters or early-bound regions.
|
||||
let tcx = fcx.tcx();
|
||||
let (method_num, method_ty) = trait_item(tcx, trait_def_id, m_name)
|
||||
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
|
||||
.unwrap();
|
||||
let method_item = trait_item(tcx, trait_def_id, m_name).unwrap();
|
||||
let method_ty = method_item.as_opt_method().unwrap();
|
||||
assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
|
||||
assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
|
||||
|
||||
debug!("lookup_in_trait_adjusted: method_num={} method_ty={:?}",
|
||||
method_num, method_ty);
|
||||
debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
|
||||
method_item, method_ty);
|
||||
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
|
|
@ -309,11 +306,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
let callee = ty::MethodCallee {
|
||||
origin: ty::MethodTypeParam(ty::MethodParam{trait_ref: trait_ref.clone(),
|
||||
method_num: method_num,
|
||||
impl_def_id: None}),
|
||||
def_id: method_item.def_id(),
|
||||
ty: fty,
|
||||
substs: trait_ref.substs.clone()
|
||||
substs: trait_ref.substs
|
||||
};
|
||||
|
||||
debug!("callee = {:?}", callee);
|
||||
|
|
@ -332,14 +327,15 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
|
||||
let def_id = pick.item.def_id();
|
||||
let mut lp = LastMod(AllPublic);
|
||||
let container_def_id = pick.item.container().id();
|
||||
let provenance = match pick.kind {
|
||||
probe::InherentImplPick(impl_def_id) => {
|
||||
probe::InherentImplPick => {
|
||||
if pick.item.vis() != ast::Public {
|
||||
lp = LastMod(DependsOn(def_id));
|
||||
}
|
||||
def::FromImpl(impl_def_id)
|
||||
def::FromImpl(container_def_id)
|
||||
}
|
||||
_ => def::FromTrait(pick.item.container().id())
|
||||
_ => def::FromTrait(container_def_id)
|
||||
};
|
||||
let def_result = match pick.item {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
|
||||
|
|
@ -352,19 +348,17 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
|
||||
/// Find item with name `item_name` defined in `trait_def_id` and return it, along with its
|
||||
/// index (or `None`, if no such item).
|
||||
/// Find item with name `item_name` defined in `trait_def_id`
|
||||
/// and return it, or `None`, if no such item.
|
||||
fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
let trait_items = tcx.trait_items(trait_def_id);
|
||||
trait_items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, ref item)| item.name() == item_name)
|
||||
.map(|(num, item)| (num, (*item).clone()))
|
||||
trait_items.iter()
|
||||
.find(|item| item.name() == item_name)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
use super::MethodError;
|
||||
use super::NoMatchData;
|
||||
use super::ItemIndex;
|
||||
use super::{CandidateSource, ImplSource, TraitSource};
|
||||
use super::suggest;
|
||||
|
||||
|
|
@ -70,15 +69,13 @@ struct Candidate<'tcx> {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum CandidateKind<'tcx> {
|
||||
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
|
||||
InherentImplCandidate(subst::Substs<'tcx>,
|
||||
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
|
||||
ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>,
|
||||
subst::Substs<'tcx>, ItemIndex,
|
||||
ExtensionImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
|
||||
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||
ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
|
||||
ProjectionCandidate(ast::DefId, ItemIndex),
|
||||
ObjectCandidate,
|
||||
TraitCandidate,
|
||||
WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -106,11 +103,11 @@ pub struct Pick<'tcx> {
|
|||
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum PickKind<'tcx> {
|
||||
InherentImplPick(/* Impl */ ast::DefId),
|
||||
ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
|
||||
ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
|
||||
TraitPick(/* Trait */ ast::DefId, ItemIndex),
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
|
||||
InherentImplPick,
|
||||
ExtensionImplPick(/* Impl */ ast::DefId),
|
||||
ObjectPick,
|
||||
TraitPick,
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>),
|
||||
}
|
||||
|
||||
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
|
||||
|
|
@ -430,7 +427,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item,
|
||||
kind: InherentImplCandidate(impl_def_id, impl_substs, obligations)
|
||||
kind: InherentImplCandidate(impl_substs, obligations)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -440,8 +437,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
|
||||
self_ty);
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
||||
// It is illegal to invoke a method on a trait instance that
|
||||
// refers to the `Self` type. An error will be reported by
|
||||
// `enforce_object_limitations()` if the method refers to the
|
||||
|
|
@ -450,15 +445,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
// itself. Hence, a `&self` method will wind up with an
|
||||
// argument type like `&Trait`.
|
||||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
|
||||
self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
|
||||
self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
|
||||
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
|
||||
|
||||
let vtable_index =
|
||||
traits::get_vtable_index_of_object_method(tcx,
|
||||
trait_ref.clone(),
|
||||
new_trait_ref.def_id,
|
||||
item_num);
|
||||
|
||||
let xform_self_ty = this.xform_self_ty(&item,
|
||||
new_trait_ref.self_ty(),
|
||||
new_trait_ref.substs);
|
||||
|
|
@ -466,7 +455,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item,
|
||||
kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
|
||||
kind: ObjectCandidate
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -499,7 +488,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
|
||||
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| {
|
||||
let trait_ref =
|
||||
this.erase_late_bound_regions(&poly_trait_ref);
|
||||
|
||||
|
|
@ -533,7 +522,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item,
|
||||
kind: WhereClauseCandidate(poly_trait_ref, item_num)
|
||||
kind: WhereClauseCandidate(poly_trait_ref)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -549,16 +538,15 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
&mut ProbeContext<'b, 'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::ImplOrTraitItem<'tcx>,
|
||||
usize,
|
||||
),
|
||||
{
|
||||
debug!("elaborate_bounds(bounds={:?})", bounds);
|
||||
|
||||
let tcx = self.tcx();
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
let (pos, item) = match trait_item(tcx,
|
||||
bound_trait_ref.def_id(),
|
||||
self.item_name) {
|
||||
let item = match trait_item(tcx,
|
||||
bound_trait_ref.def_id(),
|
||||
self.item_name) {
|
||||
Some(v) => v,
|
||||
None => { continue; }
|
||||
};
|
||||
|
|
@ -566,7 +554,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
if !self.has_applicable_self(&item) {
|
||||
self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
|
||||
} else {
|
||||
mk_cand(self, bound_trait_ref, item, pos);
|
||||
mk_cand(self, bound_trait_ref, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -607,14 +595,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
let trait_items =
|
||||
self.tcx().trait_items(trait_def_id);
|
||||
let matching_index =
|
||||
let maybe_item =
|
||||
trait_items.iter()
|
||||
.position(|item| item.name() == self.item_name);
|
||||
let matching_index = match matching_index {
|
||||
.find(|item| item.name() == self.item_name);
|
||||
let item = match maybe_item {
|
||||
Some(i) => i,
|
||||
None => { return Ok(()); }
|
||||
};
|
||||
let ref item = (&*trait_items)[matching_index];
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
if !self.has_applicable_self(item) {
|
||||
|
|
@ -623,29 +610,20 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
self.assemble_extension_candidates_for_trait_impls(trait_def_id,
|
||||
item.clone(),
|
||||
matching_index);
|
||||
self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
|
||||
|
||||
try!(self.assemble_closure_candidates(trait_def_id,
|
||||
item.clone(),
|
||||
matching_index));
|
||||
try!(self.assemble_closure_candidates(trait_def_id, item.clone()));
|
||||
|
||||
self.assemble_projection_candidates(trait_def_id,
|
||||
item.clone(),
|
||||
matching_index);
|
||||
self.assemble_projection_candidates(trait_def_id, item.clone());
|
||||
|
||||
self.assemble_where_clause_candidates(trait_def_id,
|
||||
item.clone(),
|
||||
matching_index);
|
||||
self.assemble_where_clause_candidates(trait_def_id, item.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assemble_extension_candidates_for_trait_impls(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
let trait_def = self.tcx().lookup_trait_def(trait_def_id);
|
||||
|
||||
|
|
@ -690,11 +668,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item.clone(),
|
||||
kind: ExtensionImplCandidate(impl_def_id,
|
||||
impl_trait_ref,
|
||||
impl_substs,
|
||||
item_index,
|
||||
obligations)
|
||||
kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -717,8 +691,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_closure_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
-> Result<(), MethodError<'tcx>>
|
||||
{
|
||||
// Check if this is one of the Fn,FnMut,FnOnce traits.
|
||||
|
|
@ -770,7 +743,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item.clone(),
|
||||
kind: ClosureCandidate(trait_def_id, item_index)
|
||||
kind: TraitCandidate
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -779,16 +752,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_projection_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
debug!("assemble_projection_candidates(\
|
||||
trait_def_id={:?}, \
|
||||
item={:?}, \
|
||||
item_index={})",
|
||||
item={:?})",
|
||||
trait_def_id,
|
||||
item,
|
||||
item_index);
|
||||
item);
|
||||
|
||||
for step in self.steps.iter() {
|
||||
debug!("assemble_projection_candidates: step={:?}",
|
||||
|
|
@ -830,7 +800,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item.clone(),
|
||||
kind: ProjectionCandidate(trait_def_id, item_index)
|
||||
kind: TraitCandidate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -839,8 +809,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_where_clause_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
debug!("assemble_where_clause_candidates(trait_def_id={:?})",
|
||||
trait_def_id);
|
||||
|
|
@ -862,7 +831,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item.clone(),
|
||||
kind: WhereClauseCandidate(poly_bound, item_index)
|
||||
kind: WhereClauseCandidate(poly_bound)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1048,8 +1017,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
}
|
||||
|
||||
applicable_candidates.pop().map(|probe| {
|
||||
let pick = probe.to_unadjusted_pick();
|
||||
Ok(pick)
|
||||
Ok(probe.to_unadjusted_pick())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1073,48 +1041,52 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
// clauses) that must be considered. Make sure that those
|
||||
// match as well (or at least may match, sometimes we
|
||||
// don't have enough information to fully evaluate).
|
||||
match probe.kind {
|
||||
InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) |
|
||||
ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => {
|
||||
let selcx = &mut traits::SelectionContext::new(self.infcx());
|
||||
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_bounds = self.tcx().lookup_predicates(impl_def_id);
|
||||
let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
|
||||
let traits::Normalized { value: impl_bounds,
|
||||
obligations: norm_obligations } =
|
||||
traits::normalize(selcx, cause.clone(), &impl_bounds);
|
||||
|
||||
// Convert the bounds into obligations.
|
||||
let obligations =
|
||||
traits::predicates_for_generics(cause.clone(),
|
||||
&impl_bounds);
|
||||
debug!("impl_obligations={:?}", obligations);
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
let mut all_true = true;
|
||||
for o in obligations.iter()
|
||||
.chain(norm_obligations.iter())
|
||||
.chain(ref_obligations.iter()) {
|
||||
if !selcx.evaluate_obligation(o) {
|
||||
all_true = false;
|
||||
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
|
||||
possibly_unsatisfied_predicates.push(pred.0.trait_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
all_true
|
||||
let (impl_def_id, substs, ref_obligations) = match probe.kind {
|
||||
InherentImplCandidate(ref substs, ref ref_obligations) => {
|
||||
(probe.item.container().id(), substs, ref_obligations)
|
||||
}
|
||||
|
||||
ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => {
|
||||
(impl_def_id, substs, ref_obligations)
|
||||
}
|
||||
|
||||
ProjectionCandidate(..) |
|
||||
ObjectCandidate(..) |
|
||||
ClosureCandidate(..) |
|
||||
TraitCandidate |
|
||||
WhereClauseCandidate(..) => {
|
||||
// These have no additional conditions to check.
|
||||
true
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
let selcx = &mut traits::SelectionContext::new(self.infcx());
|
||||
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_bounds = self.tcx().lookup_predicates(impl_def_id);
|
||||
let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
|
||||
let traits::Normalized { value: impl_bounds,
|
||||
obligations: norm_obligations } =
|
||||
traits::normalize(selcx, cause.clone(), &impl_bounds);
|
||||
|
||||
// Convert the bounds into obligations.
|
||||
let obligations =
|
||||
traits::predicates_for_generics(cause.clone(),
|
||||
&impl_bounds);
|
||||
debug!("impl_obligations={:?}", obligations);
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
let mut all_true = true;
|
||||
for o in obligations.iter()
|
||||
.chain(norm_obligations.iter())
|
||||
.chain(ref_obligations.iter()) {
|
||||
if !selcx.evaluate_obligation(o) {
|
||||
all_true = false;
|
||||
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
|
||||
possibly_unsatisfied_predicates.push(pred.0.trait_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
all_true
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1139,20 +1111,19 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
probes: &[&Candidate<'tcx>])
|
||||
-> Option<Pick<'tcx>> {
|
||||
// Do all probes correspond to the same trait?
|
||||
let trait_data = match probes[0].to_trait_data() {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
if probes[1..].iter().any(|p| p.to_trait_data() != Some(trait_data)) {
|
||||
let container = probes[0].item.container();
|
||||
match container {
|
||||
ty::TraitContainer(_) => {}
|
||||
ty::ImplContainer(_) => return None
|
||||
}
|
||||
if probes[1..].iter().any(|p| p.item.container() != container) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// If so, just use this trait and call it a day.
|
||||
let (trait_def_id, item_num) = trait_data;
|
||||
let item = probes[0].item.clone();
|
||||
Some(Pick {
|
||||
item: item,
|
||||
kind: TraitPick(trait_def_id, item_num),
|
||||
item: probes[0].item.clone(),
|
||||
kind: TraitPick,
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
|
|
@ -1317,20 +1288,18 @@ fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
.find(|item| item.name() == item_name)
|
||||
}
|
||||
|
||||
/// Find item with name `item_name` defined in `trait_def_id` and return it,
|
||||
/// along with its index (or `None`, if no such item).
|
||||
/// Find item with name `item_name` defined in `trait_def_id`
|
||||
/// and return it, or `None`, if no such item.
|
||||
fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
let trait_items = tcx.trait_items(trait_def_id);
|
||||
debug!("trait_method; items: {:?}", trait_items);
|
||||
trait_items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, ref item)| item.name() == item_name)
|
||||
.map(|(num, ref item)| (num, (*item).clone()))
|
||||
trait_items.iter()
|
||||
.find(|item| item.name() == item_name)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
impl<'tcx> Candidate<'tcx> {
|
||||
|
|
@ -1338,19 +1307,13 @@ impl<'tcx> Candidate<'tcx> {
|
|||
Pick {
|
||||
item: self.item.clone(),
|
||||
kind: match self.kind {
|
||||
InherentImplCandidate(def_id, _, _) => {
|
||||
InherentImplPick(def_id)
|
||||
InherentImplCandidate(_, _) => InherentImplPick,
|
||||
ExtensionImplCandidate(def_id, _, _) => {
|
||||
ExtensionImplPick(def_id)
|
||||
}
|
||||
ObjectCandidate(def_id, item_num, real_index) => {
|
||||
ObjectPick(def_id, item_num, real_index)
|
||||
}
|
||||
ExtensionImplCandidate(def_id, _, _, index, _) => {
|
||||
ExtensionImplPick(def_id, index)
|
||||
}
|
||||
ClosureCandidate(trait_def_id, index) => {
|
||||
TraitPick(trait_def_id, index)
|
||||
}
|
||||
WhereClauseCandidate(ref trait_ref, index) => {
|
||||
ObjectCandidate => ObjectPick,
|
||||
TraitCandidate => TraitPick,
|
||||
WhereClauseCandidate(ref trait_ref) => {
|
||||
// Only trait derived from where-clauses should
|
||||
// appear here, so they should not contain any
|
||||
// inference variables or other artifacts. This
|
||||
|
|
@ -1358,10 +1321,7 @@ impl<'tcx> Candidate<'tcx> {
|
|||
// `WhereClausePick`.
|
||||
assert!(!trait_ref.substs().types.needs_infer());
|
||||
|
||||
WhereClausePick((*trait_ref).clone(), index)
|
||||
}
|
||||
ProjectionCandidate(def_id, index) => {
|
||||
TraitPick(def_id, index)
|
||||
WhereClausePick(trait_ref.clone())
|
||||
}
|
||||
},
|
||||
autoderefs: 0,
|
||||
|
|
@ -1372,35 +1332,13 @@ impl<'tcx> Candidate<'tcx> {
|
|||
|
||||
fn to_source(&self) -> CandidateSource {
|
||||
match self.kind {
|
||||
InherentImplCandidate(def_id, _, _) => ImplSource(def_id),
|
||||
ObjectCandidate(def_id, _, _) => TraitSource(def_id),
|
||||
ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id),
|
||||
ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
|
||||
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
|
||||
match self.kind {
|
||||
InherentImplCandidate(..) => {
|
||||
None
|
||||
}
|
||||
ObjectCandidate(trait_def_id, item_num, _) => {
|
||||
Some((trait_def_id, item_num))
|
||||
}
|
||||
ClosureCandidate(trait_def_id, item_num) => {
|
||||
Some((trait_def_id, item_num))
|
||||
}
|
||||
ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => {
|
||||
Some((trait_ref.def_id, item_num))
|
||||
}
|
||||
WhereClauseCandidate(ref trait_ref, item_num) => {
|
||||
Some((trait_ref.def_id(), item_num))
|
||||
}
|
||||
ProjectionCandidate(trait_def_id, item_num) => {
|
||||
Some((trait_def_id, item_num))
|
||||
InherentImplCandidate(_, _) => {
|
||||
ImplSource(self.item.container().id())
|
||||
}
|
||||
ExtensionImplCandidate(def_id, _, _) => ImplSource(def_id),
|
||||
ObjectCandidate |
|
||||
TraitCandidate |
|
||||
WhereClauseCandidate(_) => TraitSource(self.item.container().id()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
impl_ty);
|
||||
}
|
||||
CandidateSource::TraitSource(trait_did) => {
|
||||
let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
|
||||
let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
|
||||
let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
|
||||
span_note!(fcx.sess(), item_span,
|
||||
"candidate #{} is defined in the trait `{}`",
|
||||
|
|
|
|||
|
|
@ -302,9 +302,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
method_call,
|
||||
method);
|
||||
let new_method = MethodCallee {
|
||||
origin: self.resolve(&method.origin, reason),
|
||||
def_id: method.def_id,
|
||||
ty: self.resolve(&method.ty, reason),
|
||||
substs: self.resolve(&method.substs, reason),
|
||||
substs: self.tcx().mk_substs(self.resolve(method.substs, reason)),
|
||||
};
|
||||
|
||||
Some(new_method)
|
||||
|
|
|
|||
40
src/test/run-pass/traits-issue-26339.rs
Normal file
40
src/test/run-pass/traits-issue-26339.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Test that the right implementation is called through a trait
|
||||
// object when supertraits include multiple references to the
|
||||
// same trait, with different type parameters.
|
||||
|
||||
trait A: PartialEq<Foo> + PartialEq<Bar> { }
|
||||
|
||||
struct Foo;
|
||||
struct Bar;
|
||||
|
||||
struct Aimpl;
|
||||
|
||||
impl PartialEq<Foo> for Aimpl {
|
||||
fn eq(&self, _rhs: &Foo) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Bar> for Aimpl {
|
||||
fn eq(&self, _rhs: &Bar) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl A for Aimpl { }
|
||||
|
||||
fn main() {
|
||||
let a = &Aimpl as &A;
|
||||
|
||||
assert!(*a == Foo);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue