Closes #7141.
/// Convert a polar representation into a complex number.
#[inline]
pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
- Cmplx::new(r * theta.cos(), r * theta.sin())
+ Cmplx::new(*r * theta.cos(), *r * theta.sin())
}
}
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
-use middle::typeck::{MethodCallee, MethodOrigin};
+use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck, moves};
use middle;
use util::ppaux::ty_to_str;
}
}
- for &method in maps.method_map.borrow().get().find(&id).iter() {
+ let method_call = MethodCall::expr(id);
+ for &method in maps.method_map.borrow().get().find(&method_call).iter() {
ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
}
c::tag_table_method_map => {
let method = val_dsr.read_method_callee(xcx);
- dcx.maps.method_map.borrow_mut().get().insert(id, method);
+ let method_call = MethodCall::expr(id);
+ dcx.maps.method_map.borrow_mut().get().insert(method_call, method);
}
c::tag_table_vtable_map => {
let vtable_res =
use middle::borrowck::*;
use middle::moves;
use middle::ty;
+use middle::typeck::MethodCall;
use std::vec_ng::Vec;
use syntax::ast;
use syntax::ast_util;
this.check_call(expr, None, expr.span, args.as_slice());
}
ast::ExprIndex(_, rval) | ast::ExprBinary(_, _, rval)
- if method_map.get().contains_key(&expr.id) => {
+ if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, [rval]);
}
ast::ExprUnary(_, _) | ast::ExprIndex(_, _)
- if method_map.get().contains_key(&expr.id) => {
+ if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, []);
}
ast::ExprInlineAsm(ref ia) => {
use middle::pat_util;
use middle::ty::{ty_region};
use middle::ty;
+use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::{Repr};
ast::ExprIndex(_, arg) |
ast::ExprBinary(_, _, arg)
- if method_map.get().contains_key(&ex.id) => {
+ if method_map.get().contains_key(&MethodCall::expr(ex.id)) => {
// Arguments in method calls are always passed by ref.
//
// Currently these do not use adjustments, so we have to
move_data::MoveExpr => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
- (ty::expr_ty_adjusted(self.tcx, expr), expr.span)
+ (ty::expr_ty_adjusted(self.tcx, expr,
+ self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
move.id, r))
move_data::Captured => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
- (ty::expr_ty_adjusted(self.tcx, expr), expr.span)
+ (ty::expr_ty_adjusted(self.tcx, expr,
+ self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
move.id, r))
Ok(ty::node_id_to_type(self.tcx, id))
}
- fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
- self.method_map.borrow().get().find(&id).map(|method| method.ty)
+ fn node_method_ty(&mut self, method_call: typeck::MethodCall) -> Option<ty::t> {
+ self.method_map.borrow().get().find(&method_call).map(|method| method.ty)
}
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
}
fn is_method_call(&mut self, id: ast::NodeId) -> bool {
- self.method_map.borrow().get().contains_key(&id)
+ self.method_map.borrow().get().contains_key(&typeck::MethodCall::expr(id))
}
fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
}
fn is_method_call(&self, expr: &ast::Expr) -> bool {
- let method_map = self.method_map.borrow();
- method_map.get().contains_key(&expr.id)
+ let method_call = typeck::MethodCall::expr(expr.id);
+ self.method_map.borrow().get().contains_key(&method_call)
}
}
}
ExprLit(lit) if ast_util::lit_is_str(lit) => {}
ExprBinary(..) | ExprUnary(..) => {
- let method_map = method_map.borrow();
- if method_map.get().contains_key(&e.id) {
+ let method_call = typeck::MethodCall::expr(e.id);
+ if method_map.borrow().get().contains_key(&method_call) {
sess.span_err(e.span, "user-defined operators are not \
allowed in constant expressions");
}
use middle::ty;
use middle::typeck::astconv;
use middle;
-use util::nodemap::{DefIdMap, NodeMap};
+use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use syntax::ast::*;
use syntax::parse::token::InternedString;
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
- method_map: @RefCell::new(NodeMap::new()),
+ method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
- method_map: @RefCell::new(NodeMap::new()),
+ method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};
}
fn is_method_call(&self, expr: &ast::Expr) -> bool {
- let method_map = self.dfcx.method_map.borrow();
- method_map.get().contains_key(&expr.id)
+ let method_call = typeck::MethodCall::expr(expr.id);
+ self.dfcx.method_map.borrow().get().contains_key(&method_call)
}
fn reset(&mut self, bits: &mut [uint]) {
}
}
- fn lookup_and_handle_method(&mut self, id: &ast::NodeId,
+ fn lookup_and_handle_method(&mut self, id: ast::NodeId,
span: codemap::Span) {
- match self.method_map.borrow().get().find(id) {
+ let method_call = typeck::MethodCall::expr(id);
+ match self.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
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, expr.span);
}
_ => ()
}
/// `unsafe`.
use middle::ty;
-use middle::typeck::MethodMap;
+use middle::typeck::{MethodCall, MethodMap};
use util::ppaux;
use syntax::ast;
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
match expr.node {
ast::ExprMethodCall(_, _, _) => {
- let base_type = self.method_map.borrow().get().get(&expr.id).ty;
+ let method_call = MethodCall::expr(expr.id);
+ let base_type = self.method_map.borrow().get().get(&method_call).ty;
debug!("effect: method call case, base type is {}",
ppaux::ty_to_str(self.tcx, base_type));
if type_is_unsafe_function(base_type) {
// Handle any kind bounds on type parameters
{
let method_map = cx.method_map.borrow();
- let method = method_map.get().find(&e.id);
+ let method = method_map.get().find(&typeck::MethodCall::expr(e.id));
let node_type_substs = cx.tcx.node_type_substs.borrow();
let r = match method {
Some(method) => Some(&method.substs.tps),
match **adjustment {
ty::AutoObject(..) => {
let source_ty = ty::expr_ty(cx.tcx, e);
- let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
+ let target_ty = ty::expr_ty_adjusted(cx.tcx, e,
+ cx.method_map.borrow().get());
check_trait_cast(cx, source_ty, target_ty, e.span);
}
ty::AutoAddEnv(..) |
}
}
ast::ExprMethodCall(..) => {
- match cx.method_map.borrow().get().find(&e.id) {
+ let method_call = typeck::MethodCall::expr(e.id);
+ match cx.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
#[allow(non_camel_case_types)];
use middle::ty;
+use middle::typeck;
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
use std::vec_ng::Vec;
pub trait Typer {
fn tcx(&self) -> ty::ctxt;
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t>;
- fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t>;
+ fn node_method_ty(&mut self, method_call: typeck::MethodCall) -> Option<ty::t>;
fn adjustment(&mut self, node_id: ast::NodeId) -> Option<@ty::AutoAdjustment>;
fn is_method_call(&mut self, id: ast::NodeId) -> bool;
fn temporary_scope(&mut self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
fn expr_ty_adjusted(&mut self, expr: &ast::Expr) -> McResult<ty::t> {
let unadjusted_ty = if_ok!(self.expr_ty(expr));
let adjustment = self.adjustment(expr.id);
- Ok(ty::adjust_ty(self.tcx(), expr.span, unadjusted_ty, adjustment))
+ Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, adjustment,
+ |method_call| self.typer.node_method_ty(method_call)))
}
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t> {
let expr_ty = if_ok!(self.expr_ty(expr));
match expr.node {
ast::ExprUnary(ast::UnDeref, e_base) => {
- let base_cmt = match self.typer.node_method_ty(expr.id) {
- Some(method_ty) => {
- let ref_ty = ty::ty_fn_ret(method_ty);
- self.cat_rvalue_node(expr.id(), expr.span(), ref_ty)
- }
- None => if_ok!(self.cat_expr(e_base))
- };
+ let base_cmt = if_ok!(self.cat_expr(e_base));
Ok(self.cat_deref(expr, base_cmt, 0))
}
ast::ExprField(base, f_name, _) => {
- // Method calls are now a special syntactic form,
- // so `a.b` should always be a field.
- assert!(!self.typer.is_method_call(expr.id));
-
let base_cmt = if_ok!(self.cat_expr(base));
Ok(self.cat_field(expr, base_cmt, f_name, expr_ty))
}
// `()` (the empty tuple).
let opaque_ty = ty::mk_tup(self.tcx(), Vec::new());
- return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
+ self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty)
}
- pub fn cat_deref<N:ast_node>(&mut self,
- node: &N,
- base_cmt: cmt,
- deref_cnt: uint)
- -> cmt {
- let mt = match ty::deref(base_cmt.ty, true) {
- Some(mt) => mt,
+ fn cat_deref<N:ast_node>(&mut self,
+ node: &N,
+ base_cmt: cmt,
+ deref_cnt: uint)
+ -> cmt {
+ let method_call = typeck::MethodCall {
+ expr_id: node.id(),
+ autoderef: deref_cnt as u32
+ };
+ let method_ty = self.typer.node_method_ty(method_call);
+
+ debug!("cat_deref: method_call={:?} method_ty={}",
+ method_call, method_ty.map(|ty| ty.repr(self.tcx())));
+
+ let base_cmt = match method_ty {
+ Some(method_ty) => {
+ let ref_ty = ty::ty_fn_ret(method_ty);
+ self.cat_rvalue_node(node.id(), node.span(), ref_ty)
+ }
+ None => base_cmt
+ };
+ match ty::deref(base_cmt.ty, true) {
+ Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty),
None => {
self.tcx().sess.span_bug(
node.span(),
format!("Explicit deref of non-derefable type: {}",
base_cmt.ty.repr(self.tcx())));
}
- };
-
- return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
+ }
}
- pub fn cat_deref_common<N:ast_node>(&mut self,
- node: &N,
- base_cmt: cmt,
- deref_cnt: uint,
- deref_ty: ty::t)
- -> cmt {
- match deref_kind(self.tcx(), base_cmt.ty) {
+ fn cat_deref_common<N:ast_node>(&mut self,
+ node: &N,
+ base_cmt: cmt,
+ deref_cnt: uint,
+ deref_ty: ty::t)
+ -> cmt {
+ let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
- let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl,
- ptr);
-
- @cmt_ {
- id:node.id(),
- span:node.span(),
- cat:cat_deref(base_cmt, deref_cnt, ptr),
- mutbl:m,
- ty:deref_ty
- }
+ (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
+ cat_deref(base_cmt, deref_cnt, ptr))
}
-
deref_interior(interior) => {
- let m = base_cmt.mutbl.inherit();
- @cmt_ {
- id:node.id(),
- span:node.span(),
- cat:cat_interior(base_cmt, interior),
- mutbl:m,
- ty:deref_ty
- }
+ (base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
}
+ };
+ @cmt_ {
+ id: node.id(),
+ span: node.span(),
+ cat: cat,
+ mutbl: m,
+ ty: deref_ty
}
}
use middle::pat_util::{pat_bindings};
use middle::freevars;
use middle::ty;
-use middle::typeck::MethodMap;
+use middle::typeck::{MethodCall, MethodMap};
use util::ppaux;
use util::ppaux::Repr;
use util::common::indenter;
debug!("consume_expr(expr={})",
expr.repr(self.tcx));
- let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
+ let expr_ty = ty::expr_ty_adjusted(self.tcx, expr,
+ self.method_map.borrow().get());
if ty::type_moves_by_default(self.tcx, expr_ty) {
- {
- let mut moves_map = self.move_maps.moves_map.borrow_mut();
- moves_map.get().insert(expr.id);
- }
+ self.move_maps.moves_map.borrow_mut().get().insert(expr.id);
self.use_expr(expr, Move);
} else {
self.use_expr(expr, Read);
receiver_expr: @Expr,
arg_exprs: &[@Expr])
-> bool {
- let method_map = self.method_map.borrow();
- if !method_map.get().contains_key(&expr.id) {
+ let method_call = MethodCall::expr(expr.id);
+ if !self.method_map.borrow().get().contains_key(&method_call) {
return false;
}
use middle::lint;
use middle::resolve;
use middle::ty;
-use middle::typeck::{MethodMap, MethodOrigin, MethodParam};
+use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic, MethodObject};
use util::nodemap::{NodeMap, NodeSet};
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
match expr.node {
ast::ExprField(base, ident, _) => {
- // Method calls are now a special syntactic form,
- // so `a.b` should always be a field.
- let method_map = self.method_map.borrow();
- assert!(!method_map.get().contains_key(&expr.id));
-
- // With type_autoderef, make sure we don't
- // allow pointers to violate privacy
- let t = ty::type_autoderef(ty::expr_ty(self.tcx, base));
- match ty::get(t).sty {
+ match ty::get(ty::expr_ty_adjusted(self.tcx, base,
+ self.method_map.borrow().get())).sty {
ty::ty_struct(id, _) => {
self.check_field(expr.span, id, ident, None);
}
_ => {}
}
}
- ast::ExprMethodCall(ident, _, ref args) => {
- // see above
- let t = ty::type_autoderef(ty::expr_ty(self.tcx,
- *args.get(0)));
- match ty::get(t).sty {
- ty::ty_enum(_, _) | ty::ty_struct(_, _) => {
- match self.method_map.borrow().get().find(&expr.id) {
- 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);
- }
- }
+ ast::ExprMethodCall(ident, _, _) => {
+ let method_call = MethodCall::expr(expr.id);
+ match self.method_map.borrow().get().find(&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);
}
- _ => {}
}
}
ast::ExprStruct(_, ref fields, _) => {
}
}
ast::ExprMethodCall(..) => {
- match self.method_map.borrow().get().get(&expr.id).origin {
+ let method_call = typeck::MethodCall::expr(expr.id);
+ match self.method_map.borrow().get().get(&method_call).origin {
typeck::MethodStatic(def_id) => {
if is_local(def_id) {
if ReachableContext::
def_id_represents_local_inlined_item(
self.tcx,
def_id) {
- {
- let mut worklist = self.worklist
- .borrow_mut();
- worklist.get().push(def_id.node)
- }
- }
- {
- let mut reachable_symbols =
- self.reachable_symbols.borrow_mut();
- reachable_symbols.get().insert(def_id.node);
+ self.worklist.borrow_mut().get().push(def_id.node)
}
+ self.reachable_symbols.borrow_mut().get().insert(def_id.node);
}
}
_ => {}
let inputs = ia.inputs.map(|&(ref c, input)| {
constraints.push((*c).clone());
+ let in_datum = unpack_datum!(bcx, expr::trans(bcx, input));
unpack_result!(bcx, {
- callee::trans_arg_expr(bcx,
+ callee::trans_arg_datum(bcx,
expr_ty(bcx, input),
- input,
+ in_datum,
cleanup::CustomScope(temp_scope),
callee::DontAutorefArg)
})
use middle::subst::Subst;
use middle::typeck;
use middle::typeck::coherence::make_substs_for_receiver_types;
+use middle::typeck::MethodCall;
use util::ppaux::Repr;
use middle::trans::type_::Type;
match def {
ast::DefFn(did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
- fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id, false))
+ fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id)))
}
ast::DefStaticMethod(impl_did,
ast::FromTrait(trait_did),
assert!(ty::enum_variant_with_id(bcx.tcx(),
tid,
vid).args.len() > 0u);
- fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id, false))
+ fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
}
ast::DefStruct(def_id) => {
- fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id, false))
+ fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
}
ast::DefStatic(..) |
ast::DefArg(..) |
}
}
-pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId,
- ref_id: ast::NodeId, is_method: bool)
- -> ValueRef {
+pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef {
/*!
*
* Translates a reference (with id `ref_id`) to the fn/method
let _icx = push_ctxt("trans_fn_ref");
- let type_params = node_id_type_params(bcx, ref_id, is_method);
- let vtables = node_vtables(bcx, ref_id);
- debug!("trans_fn_ref(def_id={}, ref_id={:?}, type_params={}, vtables={})",
- def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()),
+ let type_params = node_id_type_params(bcx, node);
+ let vtables = match node {
+ ExprId(id) => node_vtables(bcx, id),
+ MethodCall(method_call) if method_call.autoderef == 0 => {
+ node_vtables(bcx, method_call.expr_id)
+ }
+ _ => None
+ };
+ debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})",
+ def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()),
vtables.repr(bcx.tcx()));
- trans_fn_ref_with_vtables(bcx,
- def_id,
- ref_id,
- is_method,
+ trans_fn_ref_with_vtables(bcx, def_id, node,
type_params.as_slice(),
vtables)
}
vtables: Option<typeck::vtable_res>)
-> Callee<'a> {
Callee {bcx: bcx,
- data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ref_id, false,
+ data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id),
type_params, vtables))}
}
pub fn trans_fn_ref_with_vtables(
bcx: &Block, //
def_id: ast::DefId, // def id of fn
- ref_id: ast::NodeId, // node id of use of fn; may be zero if N/A
- is_method: bool,
+ node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> ValueRef {
*
* - `bcx`: the current block where the reference to the fn occurs
* - `def_id`: def id of the fn or method item being referenced
- * - `ref_id`: node id of the reference to the fn/method, if applicable.
+ * - `node`: node id of the reference to the fn/method, if applicable.
* This parameter may be zero; but, if so, the resulting value may not
* have the right type, so it must be cast before being used.
* - `type_params`: values for each of the fn/method's type parameters
let ccx = bcx.ccx();
let tcx = ccx.tcx;
- debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, ref_id={:?}, \
+ debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, node={:?}, \
type_params={}, vtables={})",
bcx.to_str(),
def_id.repr(bcx.tcx()),
- ref_id,
+ node,
type_params.repr(bcx.tcx()),
vtables.repr(bcx.tcx()));
// Should be either intra-crate or inlined.
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
+ let ref_id = match node {
+ ExprId(id) if id != 0 => Some(id),
+ _ => None
+ };
+
let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, self_vtables,
- Some(ref_id));
+ ref_id);
let mut val = val;
- if must_cast && ref_id != 0 {
+ if must_cast && node != ExprId(0) {
// Monotype of the REFERENCE to the function (type params
// are subst'd)
- let ref_ty = if is_method {
- let t = bcx.ccx().maps.method_map.borrow().get().get(&ref_id).ty;
- monomorphize_type(bcx, t)
- } else {
- node_id_type(bcx, ref_id)
+ let ref_ty = match node {
+ ExprId(id) => node_id_type(bcx, id),
+ MethodCall(method_call) => {
+ let t = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
+ monomorphize_type(bcx, t)
+ }
};
val = PointerCast(
-> &'a Block<'a> {
let _icx = push_ctxt("trans_method_call");
debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx()));
- let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&call_ex.id).ty;
+ let method_call = MethodCall::expr(call_ex.id);
+ let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
trans_call_inner(
bcx,
Some(common::expr_info(call_ex)),
monomorphize_type(bcx, method_ty),
|cx, arg_cleanup_scope| {
- meth::trans_method_callee(cx, call_ex.id, rcvr, arg_cleanup_scope)
+ meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
},
args,
Some(dest)).bcx
assert!(dest.is_some());
let mut llargs = Vec::new();
- bcx = trans_args(bcx, args, callee_ty, &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope), false);
- fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
let arg_tys = match args {
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
_ => fail!("expected arg exprs.")
};
- bcx = foreign::trans_native_call(bcx,
- callee_ty,
- llfn,
- opt_llretslot.unwrap(),
- llargs.as_slice(),
- arg_tys);
+ bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope), false);
+ fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
+ bcx = foreign::trans_native_call(bcx, callee_ty,
+ llfn, opt_llretslot.unwrap(),
+ llargs.as_slice(), arg_tys);
}
// If the caller doesn't care about the result of this fn call,
pub enum CallArgs<'a> {
ArgExprs(&'a [@ast::Expr]),
- // HACK used only by trans_overloaded_op.
- ArgAutorefSecond(&'a ast::Expr, Option<&'a ast::Expr>),
+ ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
ArgVals(&'a [ValueRef])
}
match args {
ArgExprs(arg_exprs) => {
let num_formal_args = arg_tys.len();
- for (i, arg_expr) in arg_exprs.iter().enumerate() {
+ for (i, &arg_expr) in arg_exprs.iter().enumerate() {
if i == 0 && ignore_self {
continue;
}
let arg_ty = if i >= num_formal_args {
assert!(variadic);
- expr_ty_adjusted(cx, *arg_expr)
+ expr_ty_adjusted(cx, arg_expr)
} else {
*arg_tys.get(i)
};
+
+ let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_expr));
llargs.push(unpack_result!(bcx, {
- trans_arg_expr(bcx, arg_ty, *arg_expr,
- arg_cleanup_scope,
- DontAutorefArg)
+ trans_arg_datum(bcx, arg_ty, arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg)
}));
}
}
- ArgAutorefSecond(arg_expr, arg2) => {
+ ArgOverloadedOp(lhs, rhs) => {
assert!(!variadic);
llargs.push(unpack_result!(bcx, {
- trans_arg_expr(bcx, *arg_tys.get(0), arg_expr,
- arg_cleanup_scope,
- DontAutorefArg)
+ trans_arg_datum(bcx, *arg_tys.get(0), lhs,
+ arg_cleanup_scope,
+ DontAutorefArg)
}));
- match arg2 {
- Some(arg2_expr) => {
+ match rhs {
+ Some((rhs, rhs_id)) => {
assert_eq!(arg_tys.len(), 2);
llargs.push(unpack_result!(bcx, {
- trans_arg_expr(bcx, *arg_tys.get(1), arg2_expr,
- arg_cleanup_scope,
- DoAutorefArg)
+ trans_arg_datum(bcx, *arg_tys.get(1), rhs,
+ arg_cleanup_scope,
+ DoAutorefArg(rhs_id))
}));
}
None => assert_eq!(arg_tys.len(), 1)
pub enum AutorefArg {
DontAutorefArg,
- DoAutorefArg
+ DoAutorefArg(ast::NodeId)
}
-pub fn trans_arg_expr<'a>(
+pub fn trans_arg_datum<'a>(
bcx: &'a Block<'a>,
formal_arg_ty: ty::t,
- arg_expr: &ast::Expr,
+ arg_datum: Datum<Expr>,
arg_cleanup_scope: cleanup::ScopeId,
autoref_arg: AutorefArg)
-> Result<'a> {
- let _icx = push_ctxt("trans_arg_expr");
+ let _icx = push_ctxt("trans_arg_datum");
let mut bcx = bcx;
let ccx = bcx.ccx();
- debug!("trans_arg_expr(formal_arg_ty=({}), arg_expr={})",
- formal_arg_ty.repr(bcx.tcx()),
- arg_expr.repr(bcx.tcx()));
+ debug!("trans_arg_datum({})",
+ formal_arg_ty.repr(bcx.tcx()));
- // translate the arg expr to a datum
- let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_expr));
let arg_datum_ty = arg_datum.ty;
debug!(" arg datum: {}", arg_datum.to_str(bcx.ccx()));
} else {
// FIXME(#3548) use the adjustments table
match autoref_arg {
- DoAutorefArg => {
+ DoAutorefArg(arg_id) => {
// We will pass argument by reference
// We want an lvalue, so that we can pass by reference and
let arg_datum = unpack_datum!(
- bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_expr.id));
+ bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
val = arg_datum.val;
}
DontAutorefArg => {
}
}
- debug!("--- trans_arg_expr passing {}", bcx.val_to_str(val));
- return rslt(bcx, val);
+ debug!("--- trans_arg_datum passing {}", bcx.val_to_str(val));
+ rslt(bcx, val)
}
use middle::trans::build;
use middle::trans::callee;
use middle::trans::common;
-use middle::trans::common::{Block, FunctionContext};
+use middle::trans::common::{Block, FunctionContext, ExprId};
use middle::trans::glue;
use middle::trans::type_::Type;
use middle::ty;
// The exception handling personality function.
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
- let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0, false);
+ let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, ExprId(0));
// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t {
let tcx = bcx.tcx();
- let t = ty::expr_ty_adjusted(tcx, ex);
+ let t = ty::expr_ty_adjusted(tcx, ex, bcx.ccx().maps.method_map.borrow().get());
monomorphize_type(bcx, t)
}
-pub fn node_id_type_params(bcx: &Block, id: ast::NodeId, is_method: bool) -> Vec<ty::t> {
+#[deriving(Eq)]
+pub enum ExprOrMethodCall {
+ ExprId(ast::NodeId),
+ MethodCall(typeck::MethodCall)
+}
+
+pub fn node_id_type_params(bcx: &Block, node: ExprOrMethodCall) -> Vec<ty::t> {
let tcx = bcx.tcx();
- let params = if is_method {
- bcx.ccx().maps.method_map.borrow().get().get(&id).substs.tps.clone()
- } else {
- ty::node_id_to_type_params(tcx, id)
+ let params = match node {
+ ExprId(id) => ty::node_id_to_type_params(tcx, id),
+ MethodCall(method_call) => {
+ bcx.ccx().maps.method_map.borrow().get().get(&method_call).substs.tps.clone()
+ }
};
if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
bcx.sess().bug(
- format!("type parameters for node {} include inference types: {}",
- id, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
+ format!("type parameters for node {:?} include inference types: {}",
+ node, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
}
match bcx.fcx.param_substs {
let mut llconst = llconst;
let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
- let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
+ let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e,
+ cx.maps.method_map.borrow().get());
let adjustment = {
let adjustments = cx.tcx.adjustments.borrow();
adjustments.get().find_copy(&e.id)
}, true)
}
ast::ExprField(base, field, _) => {
- let bt = ty::expr_ty_adjusted(cx.tcx, base);
+ let bt = ty::expr_ty_adjusted(cx.tcx, base,
+ cx.maps.method_map.borrow().get());
let brepr = adt::represent_type(cx, bt);
let (bv, inlineable) = const_expr(cx, base, is_local);
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
}
ast::ExprIndex(base, index) => {
- let bt = ty::expr_ty_adjusted(cx.tcx, base);
+ let bt = ty::expr_ty_adjusted(cx.tcx, base,
+ cx.maps.method_map.borrow().get());
let (bv, inlineable) = const_expr(cx, base, is_local);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
use middle::ty;
+use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
}
Some(AutoBorrowFn(..)) => {
- let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
- datum.ty, Some(adjustment));
+ let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span, expr.id, datum.ty,
+ Some(adjustment), |method_call| {
+ bcx.ccx().maps.method_map.borrow().get()
+ .find(&method_call).map(|method| method.ty)
+ });
unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
}
Some(AutoBorrowObj(..)) => {
};
}
AutoObject(..) => {
- let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
+ let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr,
+ bcx.ccx().maps.method_map.borrow().get());
let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
bcx = meth::trans_trait_cast(
bcx, datum, expr.id, SaveIn(scratch.val));
debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
return DatumBlock {bcx: bcx, datum: datum};
- fn auto_ref<'a>(bcx: &'a Block<'a>,
- datum: Datum<Expr>,
- expr: &ast::Expr)
- -> DatumBlock<'a, Expr> {
- let mut bcx = bcx;
-
- // Ensure cleanup of `datum` if not already scheduled and obtain
- // a "by ref" pointer.
- let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
-
- // Compute final type. Note that we are loose with the region and
- // mutability, since those things don't matter in trans.
- let referent_ty = lv_datum.ty;
- let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
-
- // Get the pointer.
- let llref = lv_datum.to_llref();
-
- // Construct the resulting datum, using what was the "by ref"
- // ValueRef of type `referent_ty` to be the "by value" ValueRef
- // of type `&referent_ty`.
- DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
- }
-
fn auto_borrow_fn<'a>(
bcx: &'a Block<'a>,
adjusted_ty: ty::t,
}
ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
ast::ExprBinary(op, lhs, rhs) => {
- // if overloaded, would be RvalueDpsExpr
- assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&expr.id));
-
trans_binary(bcx, expr, op, lhs, rhs)
}
ast::ExprUnary(op, x) => {
- trans_unary_datum(bcx, expr, op, x)
+ trans_unary(bcx, expr, op, x)
}
ast::ExprAddrOf(_, x) => {
trans_addr_of(bcx, expr, x)
}
ast::ExprBinary(_, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr
- trans_overloaded_op(bcx, expr, lhs, Some(&*rhs), Some(dest)).bcx
+ 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,
+ Some((rhs_datum, rhs.id)), Some(dest)).bcx
}
ast::ExprUnary(_, subexpr) => {
// if not overloaded, would be RvalueDatumExpr
- trans_overloaded_op(bcx, expr, subexpr, None, Some(dest)).bcx
+ let arg = unpack_datum!(bcx, trans(bcx, subexpr));
+ trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
+ arg, None, Some(dest)).bcx
}
ast::ExprIndex(base, idx) => {
// if not overloaded, would be RvalueDatumExpr
- trans_overloaded_op(bcx, expr, base, Some(&*idx), Some(dest)).bcx
+ 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,
+ Some((idx_datum, idx.id)), Some(dest)).bcx
}
ast::ExprCast(val, _) => {
// DPS output mode means this is a trait cast:
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
- let llfn = callee::trans_fn_ref(bcx, vid, ref_expr.id, false);
+ let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
Store(bcx, llfn, lldest);
return bcx;
} else {
ast::DefFn(did, _) |
ast::DefStruct(did) | ast::DefVariant(_, did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
- callee::trans_fn_ref(bcx, did, ref_expr.id, false)
+ callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
}
ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
meth::trans_static_method_callee(bcx, impl_did,
immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
}
-fn trans_unary_datum<'a>(
- bcx: &'a Block<'a>,
- un_expr: &ast::Expr,
- op: ast::UnOp,
- sub_expr: &ast::Expr)
- -> DatumBlock<'a, Expr> {
+fn trans_unary<'a>(bcx: &'a Block<'a>,
+ expr: &ast::Expr,
+ op: ast::UnOp,
+ sub_expr: &ast::Expr)
+ -> DatumBlock<'a, Expr> {
let mut bcx = bcx;
let _icx = push_ctxt("trans_unary_datum");
- let overloaded = {
- let method_map = bcx.ccx().maps.method_map.borrow();
- method_map.get().contains_key(&un_expr.id)
- };
+ let method_call = MethodCall::expr(expr.id);
+ let overloaded = bcx.ccx().maps.method_map.borrow().get().contains_key(&method_call);
// if overloaded, would be RvalueDpsExpr
assert!(!overloaded || op == ast::UnDeref);
- let un_ty = expr_ty(bcx, un_expr);
+ let un_ty = expr_ty(bcx, expr);
- return match op {
+ match op {
ast::UnNot => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
let llresult = if ty::type_is_bool(un_ty) {
trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_exchange)
}
ast::UnDeref => {
- if overloaded {
- let r = trans_overloaded_op(bcx, un_expr, sub_expr, None, None);
- DatumBlock(r.bcx, Datum(r.val, un_ty, LvalueExpr))
- } else {
- let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
- deref_once(bcx, un_expr, datum, 0)
- }
+ let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
+ deref_once(bcx, expr, datum, 0)
}
- };
+ }
}
fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
}
-fn trans_binary<'a>(
- bcx: &'a Block<'a>,
- binop_expr: &ast::Expr,
- op: ast::BinOp,
- lhs: &ast::Expr,
- rhs: &ast::Expr)
- -> DatumBlock<'a, Expr> {
+fn trans_binary<'a>(bcx: &'a Block<'a>,
+ expr: &ast::Expr,
+ op: ast::BinOp,
+ lhs: &ast::Expr,
+ rhs: &ast::Expr)
+ -> DatumBlock<'a, Expr> {
let _icx = push_ctxt("trans_binary");
let ccx = bcx.ccx();
+ // if overloaded, would be RvalueDpsExpr
+ assert!(!ccx.maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
+
match op {
ast::BiAnd => {
- trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
+ trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
}
ast::BiOr => {
- trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
+ trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
}
_ => {
let mut bcx = bcx;
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
- let binop_ty = expr_ty(bcx, binop_expr);
+ let binop_ty = expr_ty(bcx, expr);
debug!("trans_binary (expr {}): lhs_datum={}",
- binop_expr.id,
+ expr.id,
lhs_datum.to_str(ccx));
let lhs_ty = lhs_datum.ty;
let lhs = lhs_datum.to_llscalarish(bcx);
debug!("trans_binary (expr {}): rhs_datum={}",
- binop_expr.id,
+ expr.id,
rhs_datum.to_str(ccx));
let rhs_ty = rhs_datum.ty;
let rhs = rhs_datum.to_llscalarish(bcx);
- trans_eager_binop(bcx, binop_expr, binop_ty, op,
+ trans_eager_binop(bcx, expr, binop_ty, op,
lhs_ty, lhs, rhs_ty, rhs)
}
}
fn trans_overloaded_op<'a, 'b>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
- rcvr: &'b ast::Expr,
- arg: Option<&'b ast::Expr>,
+ method_call: MethodCall,
+ lhs: Datum<Expr>,
+ rhs: Option<(Datum<Expr>, ast::NodeId)>,
dest: Option<Dest>)
-> Result<'a> {
- let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&expr.id).ty;
+ let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
monomorphize_type(bcx, method_ty),
|bcx, arg_cleanup_scope| {
meth::trans_method_callee(bcx,
- expr.id,
- rcvr,
+ method_call,
+ None,
arg_cleanup_scope)
},
- callee::ArgAutorefSecond(rcvr, arg),
+ callee::ArgOverloadedOp(lhs, rhs),
dest)
}
debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
// User-defined operator methods cannot be used with `+=` etc right now
- assert!({
- let method_map = bcx.ccx().maps.method_map.borrow();
- !method_map.get().find(&expr.id).is_some()
- });
+ assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
// Evaluate LHS (destination), which should be an lvalue
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32()).to_expr_datumblock()
}
+fn auto_ref<'a>(bcx: &'a Block<'a>,
+ datum: Datum<Expr>,
+ expr: &ast::Expr)
+ -> DatumBlock<'a, Expr> {
+ let mut bcx = bcx;
+
+ // Ensure cleanup of `datum` if not already scheduled and obtain
+ // a "by ref" pointer.
+ let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
+
+ // Compute final type. Note that we are loose with the region and
+ // mutability, since those things don't matter in trans.
+ let referent_ty = lv_datum.ty;
+ let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
+
+ // Get the pointer.
+ let llref = lv_datum.to_llref();
+
+ // Construct the resulting datum, using what was the "by ref"
+ // ValueRef of type `referent_ty` to be the "by value" ValueRef
+ // of type `&referent_ty`.
+ DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
+}
+
fn deref_multiple<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>,
let mut bcx = bcx;
+ let method_call = MethodCall {
+ expr_id: expr.id,
+ autoderef: derefs as u32
+ };
+ let method_ty = ccx.maps.method_map.borrow().get()
+ .find(&method_call).map(|method| method.ty);
+ let datum = match method_ty {
+ Some(method_ty) => {
+ let datum = if derefs == 0 {
+ datum
+ } else {
+ // Always perform an AutoPtr when applying an overloaded auto-deref.
+ unpack_datum!(bcx, auto_ref(bcx, datum, expr))
+ };
+ let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
+ datum, None, None));
+ let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
+ Datum(val, ref_ty, RvalueExpr(Rvalue(ByValue)))
+ }
+ None => datum
+ };
+
let r = match ty::get(datum.ty).sty {
ty::ty_uniq(content_ty) => {
deref_owned_pointer(bcx, expr, datum, content_ty)
DatumBlock(bcx, Datum(ptr, content_ty, LvalueExpr))
}
- ty::ty_enum(..) |
- ty::ty_struct(..) => {
- // Subtle efficiency note: In the case where we have a
- // newtype struct where the struct itself does not have a
- // dtor, but the contents do, we could avoid forcing the
- // data into Lvalue and instead return an Rvalue. But it
- // doesn't seem worth the trouble.
- let datum = unpack_datum!(bcx, ensure_cleanup(bcx, expr, datum));
-
- // Unlike the pointer case above, we generate an
- // rvalue datum if we are given an rvalue. There are
- // two reasons that this makes sense here:
- //
- // 1. dereferencing a struct does not actually perform a
- // pointer load and hence the resulting value is not
- // naturally by reference, as would be required by an
- // lvalue result.
- //
- // 2. the struct always owns its contents, and hence and does not
- // itself have a dtor (else it would be in lvalue mode).
- let repr = adt::represent_type(ccx, datum.ty);
- let ty = adt::deref_ty(ccx, repr);
- let Datum { val, kind, .. } = datum;
- let r = match kind {
- LvalueExpr => {
- Datum {
- val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
- ty: ty,
- kind: LvalueExpr
- }
- }
- RvalueExpr(Rvalue { mode: ByRef }) => {
- Datum {
- val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
- ty: ty,
- kind: RvalueExpr(Rvalue(ByValue))
- }
- }
- RvalueExpr(Rvalue { mode: ByValue }) => {
- Datum {
- val: ExtractValue(bcx, val, 0),
- ty: ty,
- kind: RvalueExpr(Rvalue(ByValue))
- }
- }
- };
- DatumBlock(bcx, r)
- }
-
_ => {
bcx.tcx().sess.span_bug(
expr.span,
return r;
- fn ensure_cleanup<'a>(mut bcx: &'a Block<'a>,
- expr: &ast::Expr,
- datum: Datum<Expr>)
- -> DatumBlock<'a, Expr> {
- /*!
- * If the datum contains data that needs to be dropped,
- * convert it to an lvalue, thus ensuring that cleanup
- * is scheduled.
- */
-
- if ty::type_needs_drop(bcx.tcx(), datum.ty) {
- let lv_datum = unpack_datum!(
- bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
- DatumBlock(bcx, lv_datum.to_expr_datum())
- } else {
- DatumBlock(bcx, datum)
- }
- }
-
fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>,
use middle::trans::type_of::*;
use middle::ty;
use middle::typeck;
+use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::Repr;
pub fn trans_method_callee<'a>(
bcx: &'a Block<'a>,
- expr_id: ast::NodeId,
- this: &ast::Expr,
+ method_call: MethodCall,
+ self_expr: Option<&ast::Expr>,
arg_cleanup_scope: cleanup::ScopeId)
-> Callee<'a> {
let _icx = push_ctxt("meth::trans_method_callee");
let (origin, method_ty) = match bcx.ccx().maps.method_map
- .borrow().get().find(&expr_id) {
+ .borrow().get().find(&method_call) {
Some(method) => {
- debug!("trans_method_callee(expr_id={:?}, method={})",
- expr_id, method.repr(bcx.tcx()));
+ debug!("trans_method_callee({:?}, method={})",
+ method_call, method.repr(bcx.tcx()));
(method.origin, method.ty)
}
None => {
- bcx.tcx().sess.span_bug(this.span, "method call expr wasn't in method map")
+ bcx.tcx().sess.span_bug(bcx.tcx().map.span(method_call.expr_id),
+ "method call expr wasn't in method map")
}
};
typeck::MethodStatic(did) => {
Callee {
bcx: bcx,
- data: Fn(callee::trans_fn_ref(bcx, did, expr_id, true))
+ data: Fn(callee::trans_fn_ref(bcx, did, MethodCall(method_call)))
}
}
typeck::MethodParam(typeck::MethodParam {
trait_id);
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
- trans_monomorphized_callee(bcx, expr_id,
+ trans_monomorphized_callee(bcx, method_call,
trait_id, off, vtbl)
}
// how to get rid of this?
}
typeck::MethodObject(ref mt) => {
+ let self_expr = match self_expr {
+ Some(self_expr) => self_expr,
+ None => {
+ bcx.tcx().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.real_index,
- this,
+ self_expr,
arg_cleanup_scope)
}
}
let mth_id = method_with_name(ccx, impl_did, mname);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
- bcx, mth_id, expr_id, false,
+ bcx, mth_id, ExprId(expr_id),
rcvr_substs.as_slice(), rcvr_origins);
- let llfn = trans_fn_ref_with_vtables(bcx,
- mth_id,
- expr_id,
- false,
+ let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id),
callee_substs.as_slice(),
Some(callee_origins));
}
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
- expr_id: ast::NodeId,
+ method_call: MethodCall,
trait_id: ast::DefId,
n_method: uint,
vtbl: typeck::vtable_origin)
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
- bcx, mth_id, expr_id, true,
+ bcx, mth_id, MethodCall(method_call),
rcvr_substs.as_slice(), rcvr_origins);
// translate the function
let llfn = trans_fn_ref_with_vtables(bcx,
mth_id,
- expr_id,
- true,
+ MethodCall(method_call),
callee_substs.as_slice(),
Some(callee_origins));
fn combine_impl_and_methods_tps(bcx: &Block,
mth_did: ast::DefId,
- expr_id: ast::NodeId,
- is_method: bool,
+ node: ExprOrMethodCall,
rcvr_substs: &[ty::t],
rcvr_origins: typeck::vtable_res)
-> (Vec<ty::t> , typeck::vtable_res) {
let ccx = bcx.ccx();
let method = ty::method(ccx.tcx, mth_did);
let n_m_tps = method.generics.type_param_defs().len();
- let node_substs = node_id_type_params(bcx, expr_id, is_method);
+ let node_substs = node_id_type_params(bcx, node);
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx));
let ty_substs
= vec_ng::append(Vec::from_slice(rcvr_substs),
// Now, do the same work for the vtables. The vtables might not
// exist, in which case we need to make them.
- let r_m_origins = match node_vtables(bcx, expr_id) {
+ let vtables = match node {
+ ExprId(id) => node_vtables(bcx, id),
+ MethodCall(method_call) if method_call.autoderef == 0 => {
+ node_vtables(bcx, method_call.expr_id)
+ }
+ _ => None
+ };
+ let r_m_origins = match vtables {
Some(vt) => vt,
None => @Vec::from_elem(node_substs.len(), @Vec::new())
};
token::get_ident(ident));
C_null(Type::nil().ptr_to())
} else {
- trans_fn_ref_with_vtables(bcx, m_id, 0, false, substs, Some(vtables))
+ trans_fn_ref_with_vtables(bcx, m_id, ExprId(0), substs, Some(vtables))
}
})
}
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
+use middle::typeck::{MethodCall, MethodCallee, MethodMap};
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle;
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
use util::ppaux::{Repr, UserString};
use util::common::{indenter};
-use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
+use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet, FnvHashMap};
use std::cast;
use std::cell::{Cell, RefCell};
diag: @syntax::diagnostic::SpanHandler,
// Specifically use a speedy hash algorithm for this hash map, it's used
// quite often.
- #[cfg(stage0)]
- interner: RefCell<HashMap<intern_key, ~t_box_>>,
- #[cfg(not(stage0))]
- interner: RefCell<HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher>>,
+ interner: RefCell<FnvHashMap<intern_key, ~t_box_>>,
next_id: Cell<uint>,
cstore: @metadata::cstore::CStore,
sess: session::Session,
region_maps: middle::region::RegionMaps,
lang_items: @middle::lang_items::LanguageItems)
-> ctxt {
- #[cfg(stage0)]
- fn hasher() -> HashMap<intern_key, ~t_box_> {
- HashMap::new()
- }
- #[cfg(not(stage0))]
- fn hasher() -> HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher> {
- HashMap::with_hasher(::util::nodemap::FnvHasher)
- }
@ctxt_ {
named_region_map: named_region_map,
item_variance_map: RefCell::new(DefIdMap::new()),
diag: s.diagnostic(),
- interner: RefCell::new(hasher()),
+ interner: RefCell::new(FnvHashMap::new()),
next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
cstore: s.cstore,
sess: s,
// The parameter `explicit` indicates if this is an *explicit* dereference.
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
pub fn deref(t: t, explicit: bool) -> Option<mt> {
- deref_sty(&get(t).sty, explicit)
-}
-
-pub fn deref_sty(sty: &sty, explicit: bool) -> Option<mt> {
- match *sty {
- ty_box(typ) | ty_uniq(typ) => {
- Some(mt {
- ty: typ,
- mutbl: ast::MutImmutable,
- })
- }
-
- ty_rptr(_, mt) => {
- Some(mt)
- }
-
- ty_ptr(mt) if explicit => {
- Some(mt)
- }
-
+ match get(t).sty {
+ ty_box(typ) | ty_uniq(typ) => Some(mt {
+ ty: typ,
+ mutbl: ast::MutImmutable,
+ }),
+ ty_rptr(_, mt) => Some(mt),
+ ty_ptr(mt) if explicit => Some(mt),
_ => None
}
}
-pub fn type_autoderef(t: t) -> t {
- let mut t = t;
- loop {
- match deref(t, false) {
- None => return t,
- Some(mt) => t = mt.ty
- }
- }
-}
-
// Returns the type and mutability of t[i]
pub fn index(t: t) -> Option<mt> {
- index_sty(&get(t).sty)
-}
-
-pub fn index_sty(sty: &sty) -> Option<mt> {
- match *sty {
- ty_vec(mt, _) => Some(mt),
- ty_str(_) => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
- _ => None
+ match get(t).sty {
+ ty_vec(mt, _) => Some(mt),
+ ty_str(_) => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
+ _ => None
}
}
return node_id_to_type_opt(cx, expr.id);
}
-pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
+pub fn expr_ty_adjusted(cx: ctxt,
+ expr: &ast::Expr,
+ method_map: &FnvHashMap<MethodCall, MethodCallee>)
+ -> t {
/*!
*
* Returns the type of `expr`, considering any `AutoAdjustment`
*/
let unadjusted_ty = expr_ty(cx, expr);
- let adjustment = {
- let adjustments = cx.adjustments.borrow();
- adjustments.get().find_copy(&expr.id)
- };
- adjust_ty(cx, expr.span, unadjusted_ty, adjustment)
+ let adjustment = cx.adjustments.borrow().get().find_copy(&expr.id);
+ adjust_ty(cx, expr.span, expr.id, unadjusted_ty, adjustment, |method_call| {
+ method_map.find(&method_call).map(|method| method.ty)
+ })
}
pub fn expr_span(cx: ctxt, id: NodeId) -> Span {
pub fn adjust_ty(cx: ctxt,
span: Span,
+ expr_id: ast::NodeId,
unadjusted_ty: ty::t,
- adjustment: Option<@AutoAdjustment>)
+ adjustment: Option<@AutoAdjustment>,
+ method_type: |MethodCall| -> Option<ty::t>)
-> ty::t {
/*! See `expr_ty_adjusted` */
return match adjustment {
- None => unadjusted_ty,
-
Some(adjustment) => {
match *adjustment {
AutoAddEnv(r, s) => {
if !ty::type_is_error(adjusted_ty) {
for i in range(0, adj.autoderefs) {
- match ty::deref(adjusted_ty, true) {
+ match method_type(MethodCall::autoderef(expr_id, i as u32)) {
+ Some(method_ty) => {
+ adjusted_ty = ty_fn_ret(method_ty);
+ }
+ None => {}
+ }
+ match deref(adjusted_ty, true) {
Some(mt) => { adjusted_ty = mt.ty; }
None => {
cx.sess.span_bug(
}
}
}
+ None => unadjusted_ty
};
fn borrow_vec(cx: ctxt, span: Span,
}
pub fn expr_is_lval(tcx: ctxt,
- method_map: typeck::MethodMap,
+ method_map: MethodMap,
e: &ast::Expr) -> bool {
match expr_kind(tcx, method_map, e) {
LvalueExpr => true,
}
pub fn expr_kind(tcx: ctxt,
- method_map: typeck::MethodMap,
+ method_map: MethodMap,
expr: &ast::Expr) -> ExprKind {
- {
- let method_map = method_map.borrow();
- if method_map.get().contains_key(&expr.id) {
- // Overloaded operations are generally calls, and hence they are
- // generated via DPS. However, assign_op (e.g., `x += y`) is an
- // exception, as its result is always unit.
- return match expr.node {
- ast::ExprAssignOp(..) => RvalueStmtExpr,
- ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
- _ => RvalueDpsExpr
- };
- }
+ if method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)) {
+ // Overloaded operations are generally calls, and hence they are
+ // generated via DPS. However, assign_op (e.g., `x += y`) is an
+ // exception, as its result is always unit.
+ return match expr.node {
+ ast::ExprAssignOp(..) => RvalueStmtExpr,
+ ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
+ _ => RvalueDpsExpr
+ };
}
match expr.node {
use middle::ty::*;
use middle::ty;
use middle::typeck::astconv::AstConv;
-use middle::typeck::check::{FnCtxt, impl_self_ty};
-use middle::typeck::check::{structurally_resolved_type};
-use middle::typeck::check::vtable;
+use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
use middle::typeck::check;
use middle::typeck::infer;
use middle::typeck::MethodCallee;
use syntax::ast::{SelfUniq, SelfStatic};
use syntax::ast::{MutMutable, MutImmutable};
use syntax::ast;
+use syntax::codemap::Span;
use syntax::parse::token;
#[deriving(Eq)]
DontAutoderefReceiver,
}
-pub fn lookup(
+pub fn lookup<'a>(
fcx: @FnCtxt,
// In a call `a.b::<X, Y, ...>(...)`:
expr: &ast::Expr, // The expression `a.b(...)`.
- self_expr: &ast::Expr, // The expression `a`.
+ self_expr: &'a ast::Expr, // The expression `a`.
m_name: ast::Name, // The name `b`.
self_ty: ty::t, // The type of `a`.
- supplied_tps: &[ty::t], // The list of types X, Y, ... .
+ supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
deref_args: check::DerefArgs, // Whether we autopointer first.
check_traits: CheckTraitsFlag, // Whether we check traits only.
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
fcx: fcx,
- expr: expr,
- self_expr: self_expr,
+ span: expr.span,
+ self_expr: Some(self_expr),
m_name: m_name,
supplied_tps: supplied_tps,
impl_dups: @RefCell::new(HashSet::new()),
autoderef_receiver: autoderef_receiver,
};
- let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
self_expr.repr(fcx.tcx()));
debug!("searching extension candidates");
lcx.reset_candidates();
lcx.push_bound_candidates(self_ty, None);
- lcx.push_extension_candidates();
+ lcx.push_extension_candidates(expr.id);
return lcx.search(self_ty);
}
-pub fn lookup_in_trait(
+pub fn lookup_in_trait<'a>(
fcx: @FnCtxt,
// In a call `a.b::<X, Y, ...>(...)`:
- expr: &ast::Expr, // The expression `a.b(...)`.
- self_expr: &ast::Expr, // The expression `a`.
+ span: Span, // The expression `a.b(...)`'s span.
+ self_expr: Option<&'a ast::Expr>, // The expression `a`, if available.
m_name: ast::Name, // The name `b`.
trait_did: DefId, // The trait to limit the lookup to.
self_ty: ty::t, // The type of `a`.
- supplied_tps: &[ty::t], // The list of types X, Y, ... .
+ supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
fcx: fcx,
- expr: expr,
+ span: span,
self_expr: self_expr,
m_name: m_name,
supplied_tps: supplied_tps,
autoderef_receiver: autoderef_receiver,
};
- let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
- debug!("method lookup_in_trait(self_ty={}, expr={}, self_expr={})",
- self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
- self_expr.repr(fcx.tcx()));
+ debug!("method lookup_in_trait(self_ty={}, self_expr={})",
+ self_ty.repr(fcx.tcx()), self_expr.map(|e| e.repr(fcx.tcx())));
lcx.push_bound_candidates(self_ty, Some(trait_did));
lcx.push_extension_candidate(trait_did);
lcx.search(self_ty)
}
-pub struct LookupContext<'a> {
+struct LookupContext<'a> {
fcx: @FnCtxt,
- expr: &'a ast::Expr,
- self_expr: &'a ast::Expr,
+ span: Span,
+ self_expr: Option<&'a ast::Expr>,
m_name: ast::Name,
supplied_tps: &'a [ty::t],
impl_dups: @RefCell<HashSet<DefId>>,
* is of a suitable type.
*/
#[deriving(Clone)]
-pub struct Candidate {
+struct Candidate {
rcvr_match_condition: RcvrMatchCondition,
rcvr_substs: ty::substs,
method_ty: @ty::Method,
impl<'a> LookupContext<'a> {
fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
- let mut self_ty = self_ty;
- let mut autoderefs = 0;
- loop {
+ let span = self.self_expr.map_or(self.span, |e| e.span);
+ let self_expr_id = self.self_expr.map(|e| e.id);
+ let (self_ty, autoderefs, result) =
+ check::autoderef(self.fcx, span, self_ty, self_expr_id,
+ PreferMutLvalue, |self_ty, autoderefs| {
+
debug!("loop: self_ty={} autoderefs={}",
self.ty_to_str(self_ty), autoderefs);
match self.deref_args {
check::DontDerefArgs => {
- match self.search_for_autoderefd_method(self_ty,
- autoderefs) {
- Some(mme) => { return Some(mme); }
+ match self.search_for_autoderefd_method(self_ty, autoderefs) {
+ Some(result) => return Some(Some(result)),
None => {}
}
- match self.search_for_autoptrd_method(self_ty,
- autoderefs) {
- Some(mme) => { return Some(mme); }
+ match self.search_for_autoptrd_method(self_ty, autoderefs) {
+ Some(result) => return Some(Some(result)),
None => {}
}
}
check::DoDerefArgs => {
- match self.search_for_autoptrd_method(self_ty,
- autoderefs) {
- Some(mme) => { return Some(mme); }
+ match self.search_for_autoptrd_method(self_ty, autoderefs) {
+ Some(result) => return Some(Some(result)),
None => {}
}
- match self.search_for_autoderefd_method(self_ty,
- autoderefs) {
- Some(mme) => { return Some(mme); }
+ match self.search_for_autoderefd_method(self_ty, autoderefs) {
+ Some(result) => return Some(Some(result)),
None => {}
}
}
// Don't autoderef if we aren't supposed to.
if self.autoderef_receiver == DontAutoderefReceiver {
- break;
- }
-
- // Otherwise, perform autoderef.
- match self.deref(self_ty) {
- None => { break; }
- Some(ty) => {
- self_ty = ty;
- autoderefs += 1;
- }
+ Some(None)
+ } else {
+ None
}
- }
-
- self.search_for_autosliced_method(self_ty, autoderefs)
- }
+ });
- fn deref(&self, ty: ty::t) -> Option<ty::t> {
- match ty::deref(ty, false) {
- None => None,
- Some(t) => {
- Some(structurally_resolved_type(self.fcx,
- self.self_expr.span,
- t.ty))
- }
+ match result {
+ Some(Some(result)) => Some(result),
+ _ => self.search_for_autosliced_method(self_ty, autoderefs)
}
}
* we'll want to find the inherent impls for `C`.
*/
- let mut self_ty = self_ty;
- loop {
+ let span = self.self_expr.map_or(self.span, |e| e.span);
+ check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
ty_trait(did, ref substs, _, _, _) => {
self.push_inherent_candidates_from_object(did, substs);
_ => { /* No inherent methods in these types */ }
}
- // n.b.: Generally speaking, we only loop if we hit the
- // fallthrough case in the match above. The exception
- // would be newtype enums.
- self_ty = match self.deref(self_ty) {
- None => { return; }
- Some(ty) => { ty }
+ // Don't autoderef if we aren't supposed to.
+ if self.autoderef_receiver == DontAutoderefReceiver {
+ Some(())
+ } else {
+ None
}
- }
+ });
}
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
- let mut self_ty = self_ty;
- loop {
+ let span = self.self_expr.map_or(self.span, |e| e.span);
+ check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
_ => { /* No bound methods in these types */ }
}
- self_ty = match self.deref(self_ty) {
- None => { return; }
- Some(ty) => { ty }
+ // Don't autoderef if we aren't supposed to.
+ if self.autoderef_receiver == DontAutoderefReceiver {
+ Some(())
+ } else {
+ None
}
- }
+ });
}
fn push_extension_candidate(&self, trait_did: DefId) {
}
}
- fn push_extension_candidates(&self) {
+ fn push_extension_candidates(&self, expr_id: ast::NodeId) {
// If the method being called is associated with a trait, then
// find all the impls of that trait. Each of those are
// candidates.
- let opt_applicable_traits = self.fcx.ccx.trait_map.find(&self.expr.id);
+ let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
for applicable_traits in opt_applicable_traits.move_iter() {
for trait_did in applicable_traits.iter() {
self.push_extension_candidate(*trait_did);
}
fn push_candidates_from_impl(&self,
- candidates: &mut Vec<Candidate> ,
- impl_info: &ty::Impl) {
+ candidates: &mut Vec<Candidate>,
+ impl_info: &ty::Impl) {
{
let mut impl_dups = self.impl_dups.borrow_mut();
if !impl_dups.get().insert(impl_info.did) {
// determine the `self` of the impl with fresh
// variables for each parameter:
- let location_info = &vtable::location_info_for_expr(self.self_expr);
+ let span = self.self_expr.map_or(self.span, |e| e.span);
let vcx = self.fcx.vtable_context();
let ty::ty_param_substs_and_ty {
substs: impl_substs,
ty: impl_ty
- } = impl_self_ty(&vcx, location_info, impl_info.did);
+ } = impl_self_ty(&vcx, span, impl_info.did);
candidates.push(Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
// Candidate selection (see comment at start of file)
fn search_for_autoderefd_method(&self,
- self_ty: ty::t,
- autoderefs: uint)
- -> Option<MethodCallee> {
- let (self_ty, autoadjust) =
+ self_ty: ty::t,
+ autoderefs: uint)
+ -> Option<MethodCallee> {
+ let (self_ty, auto_deref_ref) =
self.consider_reborrow(self_ty, autoderefs);
+
+ // HACK(eddyb) only overloaded auto-deref calls should be missing
+ // adjustments, because we imply an AutoPtr adjustment for them.
+ let adjustment = match auto_deref_ref {
+ ty::AutoDerefRef {
+ autoderefs: 0,
+ autoref: Some(ty::AutoPtr(..))
+ } => None,
+ _ => match self.self_expr {
+ Some(expr) => Some((expr.id, @ty::AutoDerefRef(auto_deref_ref))),
+ None => return None
+ }
+ };
+
match self.search_for_method(self_ty) {
None => None,
- Some(mme) => {
+ Some(method) => {
debug!("(searching for autoderef'd method) writing \
- adjustment ({}) to {}",
- autoderefs,
- self.self_expr.id);
- self.fcx.write_adjustment(self.self_expr.id, @autoadjust);
- Some(mme)
+ adjustment {:?}", adjustment);
+ match adjustment {
+ Some((self_expr_id, adj)) => {
+ self.fcx.write_adjustment(self_expr_id, adj);
+ }
+ None => {}
+ }
+ Some(method)
}
}
}
fn consider_reborrow(&self,
- self_ty: ty::t,
- autoderefs: uint)
- -> (ty::t, ty::AutoAdjustment) {
+ self_ty: ty::t,
+ autoderefs: uint)
+ -> (ty::t, ty::AutoDerefRef) {
/*!
* In the event that we are invoking a method with a receiver
* of a borrowed type like `&T`, `&mut T`, or `&mut [T]`,
return match ty::get(self_ty).sty {
ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => {
(self_ty,
- ty::AutoDerefRef(ty::AutoDerefRef {
+ ty::AutoDerefRef {
autoderefs: autoderefs,
- autoref: None}))
+ autoref: None})
}
ty::ty_rptr(_, self_mt) => {
let region =
- self.infcx().next_region_var(
- infer::Autoref(self.expr.span));
+ self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_rptr(tcx, region, self_mt),
- ty::AutoDerefRef(ty::AutoDerefRef {
+ ty::AutoDerefRef {
autoderefs: autoderefs+1,
- autoref: Some(ty::AutoPtr(region, self_mt.mutbl))}))
+ autoref: Some(ty::AutoPtr(region, self_mt.mutbl))})
}
ty::ty_vec(self_mt, vstore_slice(_)) => {
let region =
- self.infcx().next_region_var(
- infer::Autoref(self.expr.span));
+ self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_vec(tcx, self_mt, vstore_slice(region)),
- ty::AutoDerefRef(ty::AutoDerefRef {
+ ty::AutoDerefRef {
autoderefs: autoderefs,
- autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))}))
+ autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))})
}
- ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
+ ty::ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
let region =
- self.infcx().next_region_var(
- infer::Autoref(self.expr.span));
+ self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_trait(tcx, did, substs.clone(),
ty::RegionTraitStore(region),
mutbl, bounds),
- ty::AutoDerefRef(ty::AutoDerefRef {
+ ty::AutoDerefRef {
autoderefs: autoderefs,
- autoref: Some(ty::AutoBorrowObj(region, mutbl))}))
+ autoref: Some(ty::AutoBorrowObj(region, mutbl))})
}
_ => {
(self_ty,
- ty::AutoDerefRef(ty::AutoDerefRef {
+ ty::AutoDerefRef {
autoderefs: autoderefs,
- autoref: None}))
+ autoref: None})
}
};
mutbls: &[ast::Mutability],
mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
-> Option<MethodCallee> {
+ // HACK(eddyb) only overloaded auto-deref calls should be missing
+ // adjustments, because we imply an AutoPtr adjustment for them.
+ let self_expr_id = match self.self_expr {
+ Some(expr) => Some(expr.id),
+ None => match kind(ty::ReEmpty, ast::MutImmutable) {
+ ty::AutoPtr(..) if autoderefs == 0 => None,
+ _ => return None
+ }
+ };
// This is hokey. We should have mutability inference as a
// variable. But for now, try &const, then &, then &mut:
let region =
- self.infcx().next_region_var(
- infer::Autoref(self.expr.span));
+ self.infcx().next_region_var(infer::Autoref(self.span));
for mutbl in mutbls.iter() {
let autoref_ty = mk_autoref_ty(*mutbl, region);
match self.search_for_method(autoref_ty) {
None => {}
- Some(mme) => {
- self.fcx.write_adjustment(
- self.self_expr.id,
- @ty::AutoDerefRef(ty::AutoDerefRef {
- autoderefs: autoderefs,
- autoref: Some(kind(region, *mutbl))}));
- return Some(mme);
+ Some(method) => {
+ match self_expr_id {
+ Some(self_expr_id) => {
+ self.fcx.write_adjustment(
+ self_expr_id,
+ @ty::AutoDerefRef(ty::AutoDerefRef {
+ autoderefs: autoderefs,
+ autoref: Some(kind(region, *mutbl))
+ }));
+ }
+ None => {}
+ }
+ return Some(method);
}
}
}
- return None;
+ None
}
- fn search_for_method(&self, rcvr_ty: ty::t)
- -> Option<MethodCallee> {
+ fn search_for_method(&self, rcvr_ty: ty::t) -> Option<MethodCallee> {
debug!("search_for_method(rcvr_ty={})", self.ty_to_str(rcvr_ty));
let _indenter = indenter();
}
}
- fn consider_candidates(&self,
- rcvr_ty: ty::t,
- candidates: &mut Vec<Candidate> )
+ fn consider_candidates(&self, rcvr_ty: ty::t,
+ candidates: &mut Vec<Candidate>)
-> Option<MethodCallee> {
// FIXME(pcwalton): Do we need to clone here?
let relevant_candidates: Vec<Candidate> =
if relevant_candidates.len() > 1 {
self.tcx().sess.span_err(
- self.expr.span,
+ self.span,
"multiple applicable methods in scope");
for (idx, candidate) in relevant_candidates.iter().enumerate() {
self.report_candidate(idx, &candidate.origin);
let tcx = self.tcx();
- debug!("confirm_candidate(expr={}, rcvr_ty={}, candidate={})",
- self.expr.repr(tcx),
+ debug!("confirm_candidate(rcvr_ty={}, candidate={})",
self.ty_to_str(rcvr_ty),
candidate.repr(self.tcx()));
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_method_tps == 0u {
tcx.sess.span_err(
- self.expr.span,
+ self.span,
"this method does not take type parameters");
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_supplied_tps != num_method_tps {
tcx.sess.span_err(
- self.expr.span,
+ self.span,
"incorrect number of type \
parameters given for this method");
self.fcx.infcx().next_ty_vars(num_method_tps)
// FIXME -- permit users to manually specify lifetimes
let mut all_regions = match candidate.rcvr_substs.regions {
NonerasedRegions(ref v) => v.clone(),
- ErasedRegions => tcx.sess.span_bug(self.expr.span, "ErasedRegions")
+ ErasedRegions => tcx.sess.span_bug(self.span, "ErasedRegions")
};
let m_regions =
self.fcx.infcx().region_vars_for_defs(
- self.expr.span,
+ self.span,
candidate.method_ty.generics.region_param_defs.deref().as_slice());
for &r in m_regions.iter() {
all_regions.push(r);
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
tcx, &fn_sig,
|br| self.fcx.infcx().next_region_var(
- infer::LateBoundRegion(self.expr.span, br)));
+ infer::LateBoundRegion(self.span, br)));
let transformed_self_ty = *fn_sig.inputs.get(0);
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
sig: fn_sig,
// variables to unify etc). Since we checked beforehand, and
// nothing has changed in the meantime, this unification
// should never fail.
- match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span),
+ let span = self.self_expr.map_or(self.span, |e| e.span);
+ match self.fcx.mk_subty(false, infer::Misc(span),
rcvr_ty, transformed_self_ty) {
result::Ok(_) => {}
result::Err(_) => {
&self,
trait_def_id: ast::DefId,
rcvr_substs: &ty::substs,
- method_ty: &ty::Method) -> ty::t
- {
+ method_ty: &ty::Method) -> ty::t {
/*!
* This is a bit tricky. We have a match against a trait method
* being invoked on an object, and we want to generate the
tps: rcvr_substs.tps.clone()};
match method_ty.explicit_self {
ast::SelfStatic => {
- self.bug(~"static method for object type receiver");
+ self.bug("static method for object type receiver");
}
ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
match candidate.method_ty.explicit_self {
ast::SelfStatic => { // reason (a) above
self.tcx().sess.span_err(
- self.expr.span,
+ self.span,
"cannot call a method without a receiver \
through an object");
}
ast::SelfValue => { // reason (a) above
self.tcx().sess.span_err(
- self.expr.span,
+ self.span,
"cannot call a method with a by-value receiver \
through an object");
}
let check_for_self_ty = |ty| {
if ty::type_has_self(ty) {
self.tcx().sess.span_err(
- self.expr.span,
+ self.span,
"cannot call a method whose type contains a \
self-type through an object");
true
if candidate.method_ty.generics.has_type_params() { // reason (b) above
self.tcx().sess.span_err(
- self.expr.span,
+ self.span,
"cannot call a generic method through an object");
}
}
}
if bad {
- self.tcx().sess.span_err(self.expr.span,
+ self.tcx().sess.span_err(self.span,
"explicit call to destructor");
}
}
let span = if did.krate == ast::LOCAL_CRATE {
self.tcx().map.span(did.node)
} else {
- self.expr.span
+ self.span
};
self.tcx().sess.span_note(
span,
fn report_param_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
- self.expr.span,
+ self.span,
format!("candidate \\#{} derives from the bound `{}`",
idx+1u,
ty::item_path_str(self.tcx(), did)));
fn report_trait_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
- self.expr.span,
+ self.span,
format!("candidate \\#{} derives from the type of the receiver, \
which is the trait `{}`",
idx+1u,
ty::item_path_str(self.tcx(), did)
}
- fn bug(&self, s: ~str) -> ! {
- self.tcx().sess.span_bug(self.self_expr.span, s)
+ fn bug(&self, s: &str) -> ! {
+ let span = self.self_expr.map_or(self.span, |e| e.span);
+ self.tcx().sess.span_bug(span, s)
}
}
use middle::typeck::check::method::{DontAutoderefReceiver};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::relate_free_regions;
-use middle::typeck::check::vtable::{LocationInfo, VtableContext};
+use middle::typeck::check::vtable::VtableContext;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
use middle::typeck::rscope::RegionScope;
use middle::typeck::{lookup_def_ccx};
use middle::typeck::no_params;
-use middle::typeck::{require_same_types, MethodMap, vtable_map};
+use middle::typeck::{require_same_types, vtable_map};
+use middle::typeck::{MethodCall, MethodMap};
use middle::lang_items::TypeIdLangItem;
use util::common::{block_query, indenter, loop_query};
use util::ppaux;
use util::ppaux::{UserString, Repr};
-use util::nodemap::NodeMap;
+use util::nodemap::{FnvHashMap, NodeMap};
use std::cell::{Cell, RefCell};
use collections::HashMap;
node_types: RefCell::new(NodeMap::new()),
node_type_substs: RefCell::new(NodeMap::new()),
adjustments: RefCell::new(NodeMap::new()),
- method_map: @RefCell::new(NodeMap::new()),
+ method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
upvar_borrow_map: RefCell::new(HashMap::new()),
}
}
}
- pub fn method_ty(&self, id: ast::NodeId) -> ty::t {
- match self.inh.method_map.borrow().get().find(&id) {
- Some(method) => method.ty,
- None => {
- self.tcx().sess.bug(
- format!("no method entry for node {}: {} in fcx {}",
- id, self.tcx().map.node_to_str(id),
- self.tag()));
- }
- }
- }
-
pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
match self.inh.node_type_substs.borrow().get().find(&id) {
Some(ts) => (*ts).clone(),
}
pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
- match self.inh.method_map.borrow().get().find(&id) {
+ match self.inh.method_map.borrow().get().find(&MethodCall::expr(id)) {
Some(method) => method.substs.clone(),
None => {
self.tcx().sess.bug(
NoPreference
}
-pub fn do_autoderef(fcx: @FnCtxt, sp: Span, t: ty::t) -> (ty::t, uint) {
+pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
+ expr_id: Option<ast::NodeId>,
+ mut lvalue_pref: LvaluePreference,
+ should_stop: |ty::t, uint| -> Option<T>)
+ -> (ty::t, uint, Option<T>) {
/*!
*
- * Autoderefs the type `t` as many times as possible, returning
- * a new type and a counter for how many times the type was
- * deref'd. If the counter is non-zero, the receiver is responsible
- * for inserting an AutoAdjustment record into `tcx.adjustments`
+ * Autoderefs the type `t` as many times as possible, returning a new type
+ * and an autoderef count. If the count is not zero, the receiver is
+ * responsible for inserting an AutoAdjustment record into `tcx.adjustments`
* so that trans/borrowck/etc know about this autoderef. */
- let mut t1 = t;
- let mut enum_dids = Vec::new();
+ let mut t = t;
let mut autoderefs = 0;
loop {
- let sty = structure_of(fcx, sp, t1);
+ let resolved_t = structurally_resolved_type(fcx, sp, t);
// Some extra checks to detect weird cycles and so forth:
- match *sty {
- ty::ty_box(inner) | ty::ty_uniq(inner) => {
- match ty::get(t1).sty {
+ match ty::get(resolved_t).sty {
+ ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
+ match ty::get(t).sty {
ty::ty_infer(ty::TyVar(v1)) => {
- ty::occurs_check(fcx.ccx.tcx, sp, v1,
- ty::mk_box(fcx.ccx.tcx, inner));
+ ty::occurs_check(fcx.ccx.tcx, sp, v1, resolved_t);
}
- _ => ()
- }
- }
- ty::ty_rptr(_, inner) => {
- match ty::get(t1).sty {
- ty::ty_infer(ty::TyVar(v1)) => {
- ty::occurs_check(fcx.ccx.tcx, sp, v1,
- ty::mk_box(fcx.ccx.tcx, inner.ty));
- }
- _ => ()
- }
- }
- ty::ty_enum(ref did, _) => {
- // Watch out for a type like `enum t = @t`. Such a
- // type would otherwise infinitely auto-deref. Only
- // autoderef loops during typeck (basically, this one
- // and the loops in typeck::check::method) need to be
- // concerned with this, as an error will be reported
- // on the enum definition as well because the enum is
- // not instantiable.
- if enum_dids.contains(did) {
- return (t1, autoderefs);
+ _ => {}
}
- enum_dids.push(*did);
}
_ => { /*ok*/ }
}
+ match should_stop(resolved_t, autoderefs) {
+ Some(x) => return (resolved_t, autoderefs, Some(x)),
+ None => {}
+ }
+
// Otherwise, deref if type is derefable:
- match ty::deref_sty(sty, false) {
+ let mt = match ty::deref(resolved_t, false) {
+ Some(mt) => Some(mt),
None => {
- return (t1, autoderefs);
+ let method_call =
+ expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
+ try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
}
+ };
+ match mt {
Some(mt) => {
+ t = mt.ty;
+ if mt.mutbl == ast::MutImmutable {
+ lvalue_pref = NoPreference;
+ }
autoderefs += 1;
- t1 = mt.ty
}
+ None => return (resolved_t, autoderefs, None)
}
- };
+ }
}
fn try_overloaded_deref(fcx: @FnCtxt,
- expr: &ast::Expr,
- base_expr: &ast::Expr,
+ span: Span,
+ method_call: Option<MethodCall>,
+ base_expr: Option<&ast::Expr>,
base_ty: ty::t,
lvalue_pref: LvaluePreference)
-> Option<ty::mt> {
// Try DerefMut first, if preferred.
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
(PreferMutLvalue, Some(trait_did)) => {
- method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref_mut"),
- trait_did, base_ty, [], DontAutoderefReceiver)
+ method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
+ token::intern("deref_mut"), trait_did,
+ base_ty, [], DontAutoderefReceiver)
}
_ => None
};
// Otherwise, fall back to Deref.
let method = match (method, fcx.tcx().lang_items.deref_trait()) {
(None, Some(trait_did)) => {
- method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref"),
- trait_did, base_ty, [], DontAutoderefReceiver)
+ method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
+ token::intern("deref"), trait_did,
+ base_ty, [], DontAutoderefReceiver)
}
(method, _) => method
};
match method {
Some(method) => {
let ref_ty = ty::ty_fn_ret(method.ty);
- fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
+ match method_call {
+ Some(method_call) => {
+ fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
+ }
+ None => {}
+ }
ty::deref(ref_ty, true)
}
None => None
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
pub fn impl_self_ty(vcx: &VtableContext,
- location_info: &LocationInfo, // (potential) receiver for
- // this impl
+ span: Span, // (potential) receiver for this impl
did: ast::DefId)
-> ty_param_substs_and_ty {
let tcx = vcx.tcx();
ity.generics.region_param_defs(),
ity.ty);
- let rps = vcx.infcx.region_vars_for_defs(location_info.span, rps);
+ let rps = vcx.infcx.region_vars_for_defs(span, rps);
let tps = vcx.infcx.next_ty_vars(n_tps);
let substs = substs {
AutoderefReceiver) {
Some(method) => {
let method_ty = method.ty;
- fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
+ let method_call = MethodCall::expr(expr.id);
+ fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
method_ty
}
None => {
unbound_method: ||) -> ty::t {
let method = match trait_did {
Some(trait_did) => {
- method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
- self_t, [], autoderef_receiver)
+ method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
+ trait_did, self_t, [], autoderef_receiver)
}
None => None
};
match method {
Some(method) => {
let method_ty = method.ty;
- fcx.inh.method_map.borrow_mut().get().insert(op_ex.id, method);
+ // HACK(eddyb) Fully qualified path to work around a resolve bug.
+ let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
+ fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
check_method_argument_types(fcx, op_ex.span,
method_ty, op_ex,
args, DoDerefArgs)
field: ast::Name,
tys: &[ast::P<ast::Ty>]) {
let tcx = fcx.ccx.tcx;
- let bot = check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
+ check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
- let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
-
- match *structure_of(fcx, expr.span, base_t) {
- ty::ty_struct(base_id, ref substs) => {
- // This is just for fields -- the same code handles
- // methods in both classes and traits
-
- // (1) verify that the class id actually has a field called
- // field
- debug!("class named {}", ppaux::ty_to_str(tcx, base_t));
- let cls_items = ty::lookup_struct_fields(tcx, base_id);
- match lookup_field_ty(tcx, base_id, cls_items.as_slice(),
- field, &(*substs)) {
- Some(field_ty) => {
- // (2) look up what field's type is, and return it
- fcx.write_ty(expr.id, field_ty);
- fcx.write_autoderef_adjustment(base.id, derefs);
- return bot;
- }
- None => ()
+ // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
+ let (_, autoderefs, field_ty) =
+ autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
+ match ty::get(base_t).sty {
+ ty::ty_struct(base_id, ref substs) => {
+ debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
+ let fields = ty::lookup_struct_fields(tcx, base_id);
+ lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
}
+ _ => None
+ }
+ });
+ match field_ty {
+ Some(field_ty) => {
+ fcx.write_ty(expr.id, field_ty);
+ fcx.write_autoderef_adjustment(base.id, autoderefs);
+ return;
}
- _ => ()
+ None => {}
}
let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
oprnd_t = match ty::deref(oprnd_t, true) {
Some(mt) => mt.ty,
- None => match try_overloaded_deref(fcx, expr, oprnd,
- oprnd_t, lvalue_pref) {
+ None => match try_overloaded_deref(fcx, expr.span,
+ Some(MethodCall::expr(expr.id)),
+ Some(&*oprnd), oprnd_t, lvalue_pref) {
Some(mt) => mt.ty,
None => {
let is_newtype = match ty::get(oprnd_t).sty {
} else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
fcx.write_ty(id, idx_t);
} else {
- let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
- let base_sty = structure_of(fcx, expr.span, base_t);
- match ty::index_sty(base_sty) {
+ let (base_t, autoderefs, field_ty) =
+ autoderef(fcx, expr.span, raw_base_t, Some(base.id),
+ lvalue_pref, |base_t, _| ty::index(base_t));
+ match field_ty {
Some(mt) => {
require_integral(fcx, idx.span, idx_t);
fcx.write_ty(id, mt.ty);
- fcx.write_autoderef_adjustment(base.id, derefs);
+ fcx.write_autoderef_adjustment(base.id, autoderefs);
}
None => {
let resolved = structurally_resolved_type(fcx,
expr.span,
raw_base_t);
- let error_message = || {
+ let ret_ty = lookup_op_method(fcx,
+ expr,
+ resolved,
+ token::intern("index"),
+ tcx.lang_items.index_trait(),
+ [base, idx],
+ AutoderefReceiver,
+ || {
fcx.type_error_message(expr.span,
|actual| {
format!("cannot index a value \
},
base_t,
None);
- };
- let ret_ty = lookup_op_method(fcx,
- expr,
- resolved,
- token::intern("index"),
- tcx.lang_items.index_trait(),
- [base, idx],
- AutoderefReceiver,
- error_message);
+ });
fcx.write_ty(id, ret_ty);
}
}
use middle::typeck::infer::resolve_and_force_all_but_regions;
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
+use middle::typeck::MethodCall;
use middle::pat_util;
use util::ppaux::{ty_to_str, region_to_str, Repr};
}
/// Try to resolve the type for the given node.
- pub fn resolve_node_type(&mut self, id: ast::NodeId) -> ty::t {
+ fn resolve_node_type(&mut self, id: ast::NodeId) -> ty::t {
let t = self.fcx.node_ty(id);
self.resolve_type(t)
}
+ fn resolve_method_type(&mut self, method_call: MethodCall) -> Option<ty::t> {
+ let method_ty = self.fcx.inh.method_map.borrow().get()
+ .find(&method_call).map(|method| method.ty);
+ method_ty.map(|method_ty| self.resolve_type(method_ty))
+ }
+
/// Try to resolve the type for the given node.
pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
let ty_unadjusted = self.resolve_node_type(expr.id);
ty_unadjusted
} else {
let tcx = self.fcx.tcx();
- let adjustment = {
- let adjustments = self.fcx.inh.adjustments.borrow();
- adjustments.get().find_copy(&expr.id)
- };
- ty::adjust_ty(tcx, expr.span, ty_unadjusted, adjustment)
+ let adjustment = self.fcx.inh.adjustments.borrow().get().find_copy(&expr.id);
+ ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, adjustment,
+ |method_call| self.resolve_method_type(method_call))
}
}
}
if ty::type_is_error(t) {Err(())} else {Ok(t)}
}
- fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
- self.fcx.inh.method_map.borrow().get().find(&id).map(|method| {
- self.resolve_type(method.ty)
- })
+ fn node_method_ty(&mut self, method_call: MethodCall) -> Option<ty::t> {
+ self.resolve_method_type(method_call)
}
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
}
fn is_method_call(&mut self, id: ast::NodeId) -> bool {
- self.fcx.inh.method_map.borrow().get().contains_key(&id)
+ self.fcx.inh.method_map.borrow().get().contains_key(&MethodCall::expr(id))
}
fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
- let has_method_map = rcx.fcx.inh.method_map.get().contains_key(&expr.id);
+ let method_call = MethodCall::expr(expr.id);
+ let has_method_map = rcx.fcx.inh.method_map.get().contains_key(&method_call);
// Check any autoderefs or autorefs that appear.
- {
- let adjustments = rcx.fcx.inh.adjustments.borrow();
- let r = adjustments.get().find(&expr.id);
- for &adjustment in r.iter() {
- debug!("adjustment={:?}", adjustment);
- match **adjustment {
- ty::AutoDerefRef(
- ty::AutoDerefRef {autoderefs: autoderefs, autoref: opt_autoref}) =>
- {
- let expr_ty = rcx.resolve_node_type(expr.id);
- constrain_derefs(rcx, expr, autoderefs, expr_ty);
- for autoref in opt_autoref.iter() {
- link_autoref(rcx, expr, autoderefs, autoref);
-
- // Require that the resulting region encompasses
- // the current node.
- //
- // FIXME(#6268) remove to support nested method calls
- constrain_regions_in_type_of_node(
- rcx, expr.id, ty::ReScope(expr.id),
- infer::AutoBorrow(expr.span));
- }
- }
- ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
- // Determine if we are casting `expr` to an trait
- // instance. If so, we have to be sure that the type of
- // the source obeys the trait's region bound.
+ for &adjustment in rcx.fcx.inh.adjustments.borrow().get().find(&expr.id).iter() {
+ debug!("adjustment={:?}", adjustment);
+ match **adjustment {
+ ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
+ let expr_ty = rcx.resolve_node_type(expr.id);
+ constrain_derefs(rcx, expr, autoderefs, expr_ty);
+ for autoref in opt_autoref.iter() {
+ link_autoref(rcx, expr, autoderefs, autoref);
+
+ // Require that the resulting region encompasses
+ // the current node.
//
- // Note: there is a subtle point here concerning type
- // parameters. It is possible that the type of `source`
- // contains type parameters, which in turn may contain
- // regions that are not visible to us (only the caller
- // knows about them). The kind checker is ultimately
- // responsible for guaranteeing region safety in that
- // particular case. There is an extensive comment on the
- // function check_cast_for_escaping_regions() in kind.rs
- // explaining how it goes about doing that.
-
- let source_ty = rcx.fcx.expr_ty(expr);
- constrain_regions_in_type(rcx, trait_region,
- infer::RelateObjectBound(expr.span), source_ty);
+ // FIXME(#6268) remove to support nested method calls
+ constrain_regions_in_type_of_node(
+ rcx, expr.id, ty::ReScope(expr.id),
+ infer::AutoBorrow(expr.span));
}
- _ => {}
}
+ ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
+ // Determine if we are casting `expr` to an trait
+ // instance. If so, we have to be sure that the type of
+ // the source obeys the trait's region bound.
+ //
+ // Note: there is a subtle point here concerning type
+ // parameters. It is possible that the type of `source`
+ // contains type parameters, which in turn may contain
+ // regions that are not visible to us (only the caller
+ // knows about them). The kind checker is ultimately
+ // responsible for guaranteeing region safety in that
+ // particular case. There is an extensive comment on the
+ // function check_cast_for_escaping_regions() in kind.rs
+ // explaining how it goes about doing that.
+
+ let source_ty = rcx.fcx.expr_ty(expr);
+ constrain_regions_in_type(rcx, trait_region,
+ infer::RelateObjectBound(expr.span), source_ty);
+ }
+ _ => {}
}
}
ast::ExprUnary(ast::UnDeref, base) => {
// For *a, the lifetime of a must enclose the deref
- let base_ty = match rcx.fcx.inh.method_map.get().find(&expr.id) {
+ let method_call = MethodCall::expr(expr.id);
+ let base_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
Some(method) => {
constrain_call(rcx, None, expr, Some(base), [], true);
ty::ty_fn_ret(method.ty)
implicitly_ref_args);
let callee_ty = match fn_expr_id {
Some(id) => rcx.resolve_node_type(id),
- None => rcx.resolve_type(rcx.fcx.method_ty(call_expr.id))
+ None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
+ .expect("call should have been to a method")
};
if ty::type_is_error(callee_ty) {
// Bail, as function type is unknown
// is going to fail anyway, so just stop here and let typeck
// report errors later on in the writeback phase.
let ty0 = rcx.resolve_node_type(id);
- let adjustment = {
- let adjustments = rcx.fcx.inh.adjustments.borrow();
- adjustments.get().find_copy(&id)
- };
- let ty = ty::adjust_ty(tcx, origin.span(), ty0, adjustment);
+ let adjustment = rcx.fcx.inh.adjustments.borrow().get().find_copy(&id);
+ let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, adjustment,
+ |method_call| rcx.resolve_method_type(method_call));
debug!("constrain_regions_in_type_of_node(\
ty={}, ty0={}, id={}, minimum_lifetime={:?}, adjustment={:?})",
ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
use middle::typeck::{vtable_static, vtable_param, impl_res};
use middle::typeck::{param_numbered, param_self, param_index};
+use middle::typeck::MethodCall;
use middle::subst::Subst;
use util::common::indenter;
use util::ppaux;
// It may be better to do something more clever, like processing fully
// resolved types first.
-
-/// Location info records the span and ID of the expression or item that is
-/// responsible for this vtable instantiation. (This may not be an expression
-/// if the vtable instantiation is being performed as part of "deriving".)
-pub struct LocationInfo {
- span: Span,
- id: ast::NodeId
-}
-
/// A vtable context includes an inference context, a crate context, and a
/// callback function to call in case of type error.
pub struct VtableContext<'a> {
}
fn lookup_vtables(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
type_param_defs: &[ty::TypeParameterDef],
substs: &ty::substs,
is_early: bool) -> vtable_res {
- debug!("lookup_vtables(location_info={:?}, \
+ debug!("lookup_vtables(span={:?}, \
type_param_defs={}, \
substs={}",
- location_info,
+ span,
type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()));
substs.tps.rev_iter()
.zip(type_param_defs.rev_iter())
.map(|(ty, def)|
- lookup_vtables_for_param(vcx, location_info, Some(substs),
- &*def.bounds, *ty, is_early))
+ lookup_vtables_for_param(vcx, span, Some(substs),
+ &*def.bounds, *ty, is_early))
.collect();
result.reverse();
assert_eq!(substs.tps.len(), result.len());
debug!("lookup_vtables result(\
- location_info={:?}, \
+ span={:?}, \
type_param_defs={}, \
substs={}, \
result={})",
- location_info,
+ span,
type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()),
result.repr(vcx.tcx()));
}
fn lookup_vtables_for_param(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
// None for substs means the identity
substs: Option<&ty::substs>,
type_param_bounds: &ty::ParamBounds,
debug!("after subst: {}", trait_ref.repr(tcx));
- match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) {
+ match lookup_vtable(vcx, span, ty, trait_ref, is_early) {
Some(vtable) => param_result.push(vtable),
None => {
- vcx.tcx().sess.span_fatal(
- location_info.span,
+ vcx.tcx().sess.span_fatal(span,
format!("failed to find an implementation of \
trait {} for {}",
vcx.infcx.trait_ref_to_str(trait_ref),
});
debug!("lookup_vtables_for_param result(\
- location_info={:?}, \
+ span={:?}, \
type_param_bounds={}, \
ty={}, \
result={})",
- location_info,
+ span,
type_param_bounds.repr(vcx.tcx()),
ty.repr(vcx.tcx()),
param_result.repr(vcx.tcx()));
}
fn relate_trait_refs(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
act_trait_ref: @ty::TraitRef,
- exp_trait_ref: @ty::TraitRef)
-{
+ exp_trait_ref: @ty::TraitRef) {
/*!
*
* Checks that an implementation of `act_trait_ref` is suitable
match infer::mk_sub_trait_refs(vcx.infcx,
false,
- infer::RelateTraitRefs(location_info.span),
+ infer::RelateTraitRefs(span),
act_trait_ref,
- exp_trait_ref)
- {
+ exp_trait_ref) {
result::Ok(()) => {} // Ok.
result::Err(ref err) => {
// There is an error, but we need to do some work to make
!ty::trait_ref_contains_error(&r_exp_trait_ref)
{
let tcx = vcx.tcx();
- tcx.sess.span_err(
- location_info.span,
+ tcx.sess.span_err(span,
format!("expected {}, but found {} ({})",
ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref),
ppaux::trait_ref_to_str(tcx, &r_act_trait_ref),
// Look up the vtable implementing the trait `trait_ref` at type `t`
fn lookup_vtable(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
ty: ty::t,
trait_ref: @ty::TraitRef,
is_early: bool)
- -> Option<vtable_origin>
-{
+ -> Option<vtable_origin> {
debug!("lookup_vtable(ty={}, trait_ref={})",
vcx.infcx.ty_to_str(ty),
vcx.infcx.trait_ref_to_str(trait_ref));
let _i = indenter();
- let ty = match fixup_ty(vcx, location_info, ty, is_early) {
+ let ty = match fixup_ty(vcx, span, ty, is_early) {
Some(ty) => ty,
None => {
// fixup_ty can only fail if this is early resolution
.get(n)
.trait_bounds
.as_slice();
- lookup_vtable_from_bounds(vcx,
- location_info,
+ lookup_vtable_from_bounds(vcx, span,
type_param_bounds,
param_numbered(n),
trait_ref)
ty::ty_self(_) => {
let self_param_bound = vcx.param_env.self_param_bound.unwrap();
- lookup_vtable_from_bounds(vcx,
- location_info,
+ lookup_vtable_from_bounds(vcx, span,
[self_param_bound],
param_self,
trait_ref)
// If we aren't a self type or param, or it was, but we didn't find it,
// do a search.
- return search_for_vtable(vcx, location_info,
- ty, trait_ref, is_early)
+ search_for_vtable(vcx, span, ty, trait_ref, is_early)
}
// Given a list of bounds on a type, search those bounds to see if any
// of them are the vtable we are looking for.
fn lookup_vtable_from_bounds(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
bounds: &[@ty::TraitRef],
param: param_index,
trait_ref: @ty::TraitRef)
bound_trait_ref.repr(vcx.tcx()));
if bound_trait_ref.def_id == trait_ref.def_id {
- relate_trait_refs(vcx,
- location_info,
- bound_trait_ref,
- trait_ref);
+ relate_trait_refs(vcx, span, bound_trait_ref, trait_ref);
let vtable = vtable_param(param, n_bound);
debug!("found param vtable: {:?}",
vtable);
}
fn search_for_vtable(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
ty: ty::t,
trait_ref: @ty::TraitRef,
is_early: bool)
let ty::ty_param_substs_and_ty {
substs: substs,
ty: for_ty
- } = impl_self_ty(vcx, location_info, im.did);
+ } = impl_self_ty(vcx, span, im.did);
match infer::mk_subty(vcx.infcx,
false,
- infer::RelateSelfType(
- location_info.span),
+ infer::RelateSelfType(span),
ty,
for_ty) {
result::Err(_) => continue,
vcx.infcx.trait_ref_to_str(of_trait_ref));
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
- relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
+ relate_trait_refs(vcx, span, of_trait_ref, trait_ref);
// Recall that trait_ref -- the trait type we're casting to --
// process of looking up bounds might constrain some of them.
let im_generics =
ty::lookup_item_type(tcx, im.did).generics;
- let subres = lookup_vtables(vcx, location_info,
+ let subres = lookup_vtables(vcx, span,
im_generics.type_param_defs(), &substs,
is_early);
// substs might contain type variables, so we call
// fixup_substs to resolve them.
- let substs_f = match fixup_substs(vcx,
- location_info,
+ let substs_f = match fixup_substs(vcx, span,
trait_ref.def_id,
substs,
is_early) {
// I am a little confused about this, since it seems to be
// very similar to the relate_trait_refs we already do,
// but problems crop up if it is removed, so... -sully
- connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
+ connect_trait_tps(vcx, span, &substs_f, trait_ref, im.did);
// Finally, we register that we found a matching impl, and
// record the def ID of the impl as well as the resolved list
1 => return Some(found.get(0).clone()),
_ => {
if !is_early {
- vcx.tcx().sess.span_err(
- location_info.span,
- "multiple applicable methods in scope");
+ vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
}
return Some(found.get(0).clone());
}
fn fixup_substs(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
id: ast::DefId,
substs: ty::substs,
is_early: bool)
ty::RegionTraitStore(ty::ReStatic),
ast::MutImmutable,
ty::EmptyBuiltinBounds());
- fixup_ty(vcx, location_info, t, is_early).map(|t_f| {
+ fixup_ty(vcx, span, t, is_early).map(|t_f| {
match ty::get(t_f).sty {
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
_ => fail!("t_f should be a trait")
}
fn fixup_ty(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
ty: ty::t,
is_early: bool)
-> Option<ty::t> {
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
Ok(new_type) => Some(new_type),
Err(e) if !is_early => {
- tcx.sess.span_fatal(
- location_info.span,
+ tcx.sess.span_fatal(span,
format!("cannot determine a type \
for this bounded type parameter: {}",
fixup_err_to_str(e)))
}
fn connect_trait_tps(vcx: &VtableContext,
- location_info: &LocationInfo,
+ span: Span,
impl_substs: &ty::substs,
trait_ref: @ty::TraitRef,
impl_did: ast::DefId) {
let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
Some(t) => t,
- None => vcx.tcx().sess.span_bug(location_info.span,
+ None => vcx.tcx().sess.span_bug(span,
"connect_trait_tps invoked on a type impl")
};
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
- relate_trait_refs(vcx, location_info, impl_trait_ref, trait_ref);
+ relate_trait_refs(vcx, span, impl_trait_ref, trait_ref);
}
fn insert_vtables(fcx: &FnCtxt, expr_id: ast::NodeId, vtables: vtable_res) {
fcx.inh.vtable_map.borrow_mut().get().insert(expr_id, vtables);
}
-pub fn location_info_for_expr(expr: &ast::Expr) -> LocationInfo {
- LocationInfo {
- span: expr.span,
- id: expr.id
- }
-}
-pub fn location_info_for_item(item: &ast::Item) -> LocationInfo {
- LocationInfo {
- span: item.span,
- id: item.id
- }
-}
-
pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
ex.id, is_early, expr_to_str(ex));
_ => fail!("shouldn't get here"),
};
- let location_info =
- &location_info_for_expr(ex);
let vcx = fcx.vtable_context();
let target_trait_ref = @ty::TraitRef {
def_id: target_def_id,
};
let vtables =
lookup_vtables_for_param(&vcx,
- location_info,
+ ex.span,
None,
¶m_bounds,
typ,
debug!("early_resolve_expr: looking up vtables for type params {}",
item_ty.generics.type_param_defs().repr(fcx.tcx()));
let vcx = fcx.vtable_context();
- let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
+ let vtbls = lookup_vtables(&vcx, ex.span,
item_ty.generics.type_param_defs(),
substs, is_early);
if !is_early {
ast::ExprAssignOp(_, _, _) |
ast::ExprIndex(_, _) |
ast::ExprMethodCall(_, _, _) => {
- match fcx.inh.method_map.borrow().get().find(&ex.id) {
+ match fcx.inh.method_map.borrow().get().find(&MethodCall::expr(ex.id)) {
Some(method) => {
debug!("vtable resolution on parameter bounds for method call {}",
ex.repr(fcx.tcx()));
if has_trait_bounds(type_param_defs.deref().as_slice()) {
let substs = fcx.method_ty_substs(ex.id);
let vcx = fcx.vtable_context();
- let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
+ let vtbls = lookup_vtables(&vcx, ex.span,
type_param_defs.deref()
.as_slice(),
&substs, is_early);
let infcx = &infer::new_infer_ctxt(tcx);
let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
- let loc_info = location_info_for_item(impl_item);
// First, check that the impl implements any trait bounds
// on the trait.
let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
- let vtbls = lookup_vtables(&vcx,
- &loc_info,
+ let vtbls = lookup_vtables(&vcx, impl_item.span,
trait_def.generics.type_param_defs(),
&impl_trait_ref.substs,
false);
// We will need to make one so we can use this information
// for compiling default methods that refer to supertraits.
let self_vtable_res =
- lookup_vtables_for_param(&vcx, &loc_info, None,
+ lookup_vtables_for_param(&vcx, impl_item.span, None,
¶m_bounds, t, false);
infcx: &infer::new_infer_ctxt(tcx),
param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id)
};
- let loc_info = LocationInfo {
- id: id,
- span: tcx.map.span(id)
- };
Some(lookup_vtables(&vcx,
- &loc_info,
+ tcx.map.span(id),
type_param_defs.as_slice(),
substs,
false))
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
-use middle::typeck::MethodCallee;
+use middle::typeck::{MethodCall, MethodCallee};
use middle::typeck::{vtable_res, vtable_origin};
use middle::typeck::{vtable_static, vtable_param};
use middle::typeck::write_substs_to_tcx;
}).collect()
}
-fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
+fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall) {
let fcx = wbcx.fcx;
let tcx = fcx.ccx.tcx;
// Resolve any method map entry
- match fcx.inh.method_map.borrow().get().find(&id) {
+ match fcx.inh.method_map.borrow().get().find(&method_call) {
Some(method) => {
- debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})",
- id, method.repr(tcx));
+ debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
+ method_call, method.repr(tcx));
let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
Some(t) => t,
None => {
self_ty: None
}
};
- fcx.ccx.method_map.borrow_mut().get().insert(id, new_method);
+ fcx.ccx.method_map.borrow_mut().get().insert(method_call, new_method);
}
None => {}
}
let tcx = fcx.ccx.tcx;
// Resolve any borrowings for the node with id `id`
- let adjustment = {
- let adjustments = fcx.inh.adjustments.borrow();
- adjustments.get().find_copy(&id)
- };
+ let adjustment = fcx.inh.adjustments.borrow().get().find_copy(&id);
match adjustment {
None => (),
// FIXME(eddyb) #2190 Allow only statically resolved
// bare functions to coerce to a closure to avoid
// constructing (slower) indirect call wrappers.
- {
- let def_map = tcx.def_map.borrow();
- match def_map.get().find(&id) {
- Some(&ast::DefFn(..)) |
- Some(&ast::DefStaticMethod(..)) |
- Some(&ast::DefVariant(..)) |
- Some(&ast::DefStruct(_)) => {}
- _ => tcx.sess.span_err(sp,
- "cannot coerce non-statically resolved bare fn")
- }
+ match tcx.def_map.borrow().get().find(&id) {
+ Some(&ast::DefFn(..)) |
+ Some(&ast::DefStaticMethod(..)) |
+ Some(&ast::DefVariant(..)) |
+ Some(&ast::DefStruct(_)) => {}
+ _ => tcx.sess.span_err(sp,
+ "cannot coerce non-statically resolved bare fn")
}
let resolved_adj = @ty::AutoAddEnv(r1, s);
debug!("Adjustments for node {}: {:?}",
- id,
- resolved_adj);
- let mut adjustments = tcx.adjustments
- .borrow_mut();
- adjustments.get().insert(id, resolved_adj);
+ id, resolved_adj);
+ tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
}
}
}
ty::AutoDerefRef(adj) => {
+ for autoderef in range(0, adj.autoderefs) {
+ let method_call = MethodCall::autoderef(id, autoderef as u32);
+ resolve_method_map_entry(wbcx, sp, method_call);
+ }
+
let fixup_region = |r| {
match resolve_region(fcx.infcx(),
r,
autoref: resolved_autoref,
});
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
- let mut adjustments = tcx.adjustments.borrow_mut();
- adjustments.get().insert(id, resolved_adj);
+ tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
}
ty::AutoObject(..) => {
debug!("Adjustments for node {}: {:?}", id, adjustment);
- let mut adjustments = tcx.adjustments.borrow_mut();
- adjustments.get().insert(id, adjustment);
+ tcx.adjustments.borrow_mut().get().insert(id, adjustment);
}
}
}
}
resolve_type_vars_for_node(wbcx, e.span, e.id);
- resolve_method_map_entry(wbcx, e.span, e.id);
+ resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id));
resolve_vtable_map_entry(wbcx.fcx, e.span, e.id);
match e.node {
use util::common::time;
use util::ppaux::Repr;
use util::ppaux;
-use util::nodemap::{DefIdMap, NodeMap};
+use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use std::cell::RefCell;
use std::rc::Rc;
substs: ty::substs
}
+#[deriving(Clone, Eq, Hash)]
+pub struct MethodCall {
+ expr_id: ast::NodeId,
+ autoderef: u32
+}
+
+impl MethodCall {
+ pub fn expr(id: ast::NodeId) -> MethodCall {
+ MethodCall {
+ expr_id: id,
+ autoderef: 0
+ }
+ }
+
+ pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall {
+ MethodCall {
+ expr_id: expr_id,
+ autoderef: 1 + autoderef
+ }
+ }
+}
+
// maps from an expression id that corresponds to a method call to the details
// of the method to be invoked
-pub type MethodMap = @RefCell<NodeMap<MethodCallee>>;
+pub type MethodMap = @RefCell<FnvHashMap<MethodCall, MethodCallee>>;
pub type vtable_param_res = @Vec<vtable_origin> ;
// Resolutions for bounds of all parameters, left to right, for a given path.
let time_passes = tcx.sess.time_passes();
let ccx = @CrateCtxt {
trait_map: trait_map,
- method_map: @RefCell::new(NodeMap::new()),
+ method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
tcx: tcx
};
use syntax::ast;
#[cfg(not(stage0))]
-pub type NodeMap<T> = HashMap<ast::NodeId, T, FnvHasher>;
-#[cfg(not(stage0))]
-pub type DefIdMap<T> = HashMap<ast::DefId, T, FnvHasher>;
+pub type FnvHashMap<K, V> = HashMap<K, V, FnvHasher>;
+
+pub type NodeMap<T> = FnvHashMap<ast::NodeId, T>;
+pub type DefIdMap<T> = FnvHashMap<ast::DefId, T>;
+
#[cfg(not(stage0))]
pub type NodeSet = HashSet<ast::NodeId, FnvHasher>;
#[cfg(not(stage0))]
// Hacks to get good names
#[cfg(not(stage0))]
-pub mod NodeMap {
+pub mod FnvHashMap {
+ use std::hash::Hash;
use collections::HashMap;
- pub fn new<T>() -> super::NodeMap<T> {
+ pub fn new<K: Hash<super::FnvState> + Eq, V>() -> super::FnvHashMap<K, V> {
HashMap::with_hasher(super::FnvHasher)
}
}
+pub mod NodeMap {
+ pub fn new<T>() -> super::NodeMap<T> {
+ super::FnvHashMap::new()
+ }
+}
+pub mod DefIdMap {
+ pub fn new<T>() -> super::DefIdMap<T> {
+ super::FnvHashMap::new()
+ }
+}
#[cfg(not(stage0))]
pub mod NodeSet {
use collections::HashSet;
}
}
#[cfg(not(stage0))]
-pub mod DefIdMap {
- use collections::HashMap;
- pub fn new<T>() -> super::DefIdMap<T> {
- HashMap::with_hasher(super::FnvHasher)
- }
-}
-#[cfg(not(stage0))]
pub mod DefIdSet {
use collections::HashSet;
pub fn new() -> super::DefIdSet {
}
#[cfg(stage0)]
-pub type NodeMap<T> = HashMap<ast::NodeId, T>;
-#[cfg(stage0)]
-pub type DefIdMap<T> = HashMap<ast::DefId, T>;
+pub type FnvHashMap<K, V> = HashMap<K, V>;
+
#[cfg(stage0)]
pub type NodeSet = HashSet<ast::NodeId>;
#[cfg(stage0)]
// Hacks to get good names
#[cfg(stage0)]
-pub mod NodeMap {
+pub mod FnvHashMap {
+ use std::hash::Hash;
use collections::HashMap;
- pub fn new<T>() -> super::NodeMap<T> {
+ pub fn new<K: Hash + Eq, V>() -> super::FnvHashMap<K, V> {
HashMap::new()
}
}
}
}
#[cfg(stage0)]
-pub mod DefIdMap {
- use collections::HashMap;
- pub fn new<T>() -> super::DefIdMap<T> {
- HashMap::new()
- }
-}
-#[cfg(stage0)]
pub mod DefIdSet {
use collections::HashSet;
pub fn new() -> super::DefIdSet {
--- /dev/null
+// Copyright 2014 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.
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+#[deriving(Eq, Show)]
+struct Point {
+ x: int,
+ y: int
+}
+
+pub fn main() {
+ assert_eq!(Rc::new(5u).to_uint(), Some(5));
+ assert_eq!((~&~&Rc::new(~~&~5u)).to_uint(), Some(5));
+ let point = Rc::new(Point {x: 2, y: 4});
+ assert_eq!(point.x, 2);
+ assert_eq!(point.y, 4);
+
+ let i = Rc::new(RefCell::new(2));
+ let i_value = *i.borrow();
+ *i.borrow_mut() = 5;
+ assert_eq!((i_value, *i.borrow()), (2, 5));
+
+ let s = Rc::new(~"foo");
+ assert!(s.equiv(&("foo")));
+ assert_eq!(s.as_slice(), "foo");
+
+ let mut_s = Rc::new(RefCell::new(~"foo"));
+ mut_s.borrow_mut().push_str("bar");
+ // HACK assert_eq! would fail here because it stores the LHS and RHS in two locals.
+ assert!(mut_s.borrow().as_slice() == "foobar");
+ assert!(mut_s.borrow_mut().as_slice() == "foobar");
+
+ let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
+ p.borrow_mut().x = 3;
+ p.borrow_mut().y += 3;
+ assert_eq!(*p.borrow(), Point {x: 3, y: 5});
+
+ let v = Rc::new(RefCell::new(~[1, 2, 3]));
+ v.borrow_mut()[0] = 3;
+ v.borrow_mut()[1] += 3;
+ assert_eq!((v.borrow()[0], v.borrow()[1], v.borrow()[2]), (3, 5, 3));
+}