]> git.lizzy.rs Git - rust.git/commitdiff
Implement automatic overloaded dereference.
authorEduard Burtescu <edy.burt@gmail.com>
Thu, 6 Mar 2014 17:24:11 +0000 (19:24 +0200)
committerEduard Burtescu <edy.burt@gmail.com>
Thu, 13 Mar 2014 12:21:45 +0000 (14:21 +0200)
Closes #7141.

33 files changed:
src/libnum/complex.rs
src/librustc/middle/astencode.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/gather_loans/mod.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/check_const.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/dataflow.rs
src/librustc/middle/dead.rs
src/librustc/middle/effect.rs
src/librustc/middle/kind.rs
src/librustc/middle/lint.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/moves.rs
src/librustc/middle/privacy.rs
src/librustc/middle/reachable.rs
src/librustc/middle/trans/asm.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/cleanup.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/check/writeback.rs
src/librustc/middle/typeck/mod.rs
src/librustc/util/nodemap.rs
src/test/run-pass/overloaded-autoderef.rs [new file with mode: 0644]

index 5ffd23aa3462150b01fcadb8951490e5d5553270..b226e773dbb880f6a9f87f44b0a948aa967a5116 100644 (file)
@@ -101,7 +101,7 @@ pub fn to_polar(&self) -> (T, T) {
     /// 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())
     }
 }
 
index 06aec8c050e0d58a24fe653516991446eb868eb6..fed35922a90c0ffbc02d73df78da0d16b094d981 100644 (file)
@@ -21,7 +21,7 @@
 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;
@@ -1039,7 +1039,8 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         }
     }
 
-    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| {
@@ -1385,7 +1386,8 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
                     }
                     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 =
index 5972625caad0771fc2ee94122cdfca4ec82d6ca7..e50d24560701ee25da81b481bba6873da5646432 100644 (file)
@@ -22,6 +22,7 @@
 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;
@@ -838,11 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
         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) => {
index 135783f510ff0cbacecbfd91b816acf1edc26bdf..d2fcee79fc03189fc3bbdd1acdca9fbc949dc5a5 100644 (file)
@@ -23,6 +23,7 @@
 use middle::pat_util;
 use middle::ty::{ty_region};
 use middle::ty;
+use middle::typeck::MethodCall;
 use util::common::indenter;
 use util::ppaux::{Repr};
 
@@ -242,7 +243,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
 
       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
index 654203bf0776bf0a3e682d81898d6c377aa9d019..44a5acc7f1b54dabdc0194f5bf0b33ab9858ed1d 100644 (file)
@@ -556,7 +556,8 @@ pub fn report_use_of_moved_value(&self,
             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))
@@ -582,7 +583,8 @@ pub fn report_use_of_moved_value(&self,
             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))
@@ -922,8 +924,8 @@ fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
         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> {
@@ -932,7 +934,7 @@ 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> {
index ec1ddd99cc6bff8cb8f671ab9ae2f81bc5917c57..0100a82a9d5aa56aad2ce3dbf0b55e239acd8619 100644 (file)
@@ -523,7 +523,7 @@ fn find_scope(&self,
     }
 
     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)
     }
 }
index 680caf101bf72e5ec1a980294fcdf0f52dbb541e..6841e09f7f2db661e2296cda0677c918f418695a 100644 (file)
@@ -117,8 +117,8 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
           }
           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");
             }
index 7c46f05f1c1a68c83e696b4d500e0c91e9a650df..1f675b7bb4a688e0400b6809970e8ef7d848649c 100644 (file)
@@ -16,7 +16,7 @@
 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;
@@ -136,7 +136,7 @@ fn variant_expr(variants: &[ast::P<ast::Variant>], id: ast::NodeId) -> Option<@E
         }
         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())
         };
@@ -186,7 +186,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, def_id: ast::DefId)
         }
         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())
         };
index ba3fc34023d1828917b192a3dde7fef5970a95fc..57b5be4e96069b5742dde20c524c170cfbbf92fe 100644 (file)
@@ -810,8 +810,8 @@ fn find_scope<'a,'b>(
     }
 
     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]) {
index d226f2561b7bdae0d4e5dea031fa5f112f08e288..310feb88892d71e43ea6b5d02b583d2af8d8cb74 100644 (file)
@@ -92,9 +92,10 @@ fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
         }
     }
 
-    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) => {
@@ -179,7 +180,7 @@ impl Visitor<()> for MarkSymbolVisitor {
     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);
             }
             _ => ()
         }
index bac706e5a866005d093837e655e96a9126a10cbd..d3ec7044040ccabf513cdd09d0d034dff2c28b4d 100644 (file)
@@ -12,7 +12,7 @@
 /// `unsafe`.
 
 use middle::ty;
-use middle::typeck::MethodMap;
+use middle::typeck::{MethodCall, MethodMap};
 use util::ppaux;
 
 use syntax::ast;
@@ -138,7 +138,8 @@ fn visit_block(&mut self, block: &ast::Block, _:()) {
     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) {
index 97aff130dfbfc369dc6d945ab1a25a970a64935a..7771cb0ab3c14d1b6775dcfde9cde2fca26c4fe3 100644 (file)
@@ -267,7 +267,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
     // 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),
@@ -341,7 +341,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
             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(..) |
index 3e3a94f7f0f66472badc76cef9be48d09d1fc0b9..31d705dc6aa933e9330975d727a684165d870166 100644 (file)
@@ -1491,7 +1491,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
             }
         }
         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) => {
index ba93e52bc48eced6ad2a2c2c86f0433ec5db7bc1..c07cd2570a30b3b08e4e65f234384aaddc21a06e 100644 (file)
@@ -63,6 +63,7 @@
 #[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;
@@ -268,7 +269,7 @@ pub struct MemCategorizationContext<TYPER> {
 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>;
@@ -365,7 +366,8 @@ fn expr_ty(&mut self, expr: &ast::Expr) -> McResult<ty::t> {
     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> {
@@ -435,21 +437,11 @@ pub fn cat_expr_unadjusted(&mut self, expr: &ast::Expr) -> McResult<cmt> {
         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))
           }
@@ -725,59 +717,64 @@ pub fn cat_deref_fn_or_obj<N:ast_node>(&mut self,
         // `()` (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
         }
     }
 
index 16655474d3a85ef4834c487c4815f95536444ce4..b52ec7be631143b24e4d59a77bb1c027c1e81465 100644 (file)
@@ -130,7 +130,7 @@ struct Foo { a: int, b: ~int }
 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;
@@ -281,12 +281,10 @@ pub fn consume_expr(&mut self, expr: &Expr) {
         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);
@@ -608,8 +606,8 @@ pub fn use_overloaded_operator(&mut self,
                                    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;
         }
 
index 5cee3e1a20dd9414f6a34e7f44720df479f0a9c9..b8a40f623d947088a56ebe9eb98b7d28e1299aba 100644 (file)
@@ -19,7 +19,7 @@
 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};
 
@@ -772,40 +772,26 @@ fn visit_item(&mut self, item: &ast::Item, _: ()) {
     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, _) => {
index fac7e7a36e69cbb38c1199cee408e2c8c53fd08b..e9d01713e1c271942601b8cf8dc1b173cbd48db3 100644 (file)
@@ -149,24 +149,17 @@ fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
                 }
             }
             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);
                         }
                     }
                     _ => {}
index adcef0278f8b474f199a21d39bdc8dca6f7a95e7..1a398a7377100a7cc097e11ecd06c74414f63947 100644 (file)
@@ -50,10 +50,11 @@ pub fn trans_inline_asm<'a>(bcx: &'a Block<'a>, ia: &ast::InlineAsm)
     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)
         })
index 1ede187245e6dff0620c6d090dbecb99eb52974e..5e2a8792abf86fd3321a2c23aa12da709a9ce64d 100644 (file)
@@ -44,6 +44,7 @@
 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;
@@ -120,7 +121,7 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: ast::Def, ref_expr: &ast::Expr)
         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),
@@ -134,10 +135,10 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: ast::Def, ref_expr: &ast::Expr)
                 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(..) |
@@ -160,9 +161,7 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: ast::Def, ref_expr: &ast::Expr)
     }
 }
 
-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
@@ -171,15 +170,18 @@ pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId,
 
     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)
 }
@@ -191,7 +193,7 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
                                            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))}
 }
 
@@ -241,8 +243,7 @@ fn resolve_default_method_vtables(bcx: &Block,
 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 {
@@ -254,7 +255,7 @@ pub fn trans_fn_ref_with_vtables(
      *
      * - `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
@@ -265,11 +266,11 @@ pub fn trans_fn_ref_with_vtables(
     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()));
 
@@ -380,19 +381,25 @@ pub fn trans_fn_ref_with_vtables(
         // 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(
@@ -472,13 +479,14 @@ pub fn trans_method_call<'a>(
                          -> &'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
@@ -717,19 +725,16 @@ pub fn trans_call_inner<'a>(
         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,
@@ -754,8 +759,7 @@ pub fn trans_call_inner<'a>(
 
 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])
 }
 
@@ -778,40 +782,42 @@ fn trans_args<'a>(cx: &'a Block<'a>,
     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)
@@ -827,26 +833,23 @@ fn trans_args<'a>(cx: &'a Block<'a>,
 
 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()));
@@ -864,11 +867,11 @@ pub fn trans_arg_expr<'a>(
     } 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 => {
@@ -898,6 +901,6 @@ pub fn trans_arg_expr<'a>(
         }
     }
 
-    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)
 }
index be5eab0e8eca735b8d3fc6a8097b15f4a0349be9..d249bd8a894cc8be40d43a9049a3c2f4d3770d43 100644 (file)
@@ -19,7 +19,7 @@
 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;
@@ -673,7 +673,7 @@ fn get_or_create_landing_pad(&'a self) -> BasicBlockRef {
 
         // 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);
index 4194f3ff57c06c8b5409b76d690fd7ebc815cc74..759e5e872d4be85236dc0e837e929f012a27f289 100644 (file)
@@ -805,22 +805,29 @@ pub fn expr_ty(bcx: &Block, ex: &ast::Expr) -> ty::t {
 
 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 {
index c9317f18168f2f0aafd1d33198c8d96a0ce4b1bf..9d55084c7f4e7ed95db6b8a859e909a8de4c3f1e 100644 (file)
@@ -190,7 +190,8 @@ pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef
     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)
@@ -422,7 +423,8 @@ fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
             }, 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| {
@@ -432,7 +434,8 @@ fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
           }
 
           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,
index be0faf2b6445d6f38791225912d65d2579570475..056ac62183f90d560fa42d1fcf474cb93af293e1 100644 (file)
@@ -64,6 +64,7 @@
 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;
@@ -211,8 +212,11 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
                     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(..)) => {
@@ -221,7 +225,8 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
             };
         }
         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));
@@ -231,30 +236,6 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
     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,
@@ -462,13 +443,10 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
         }
         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)
@@ -789,15 +767,23 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
         }
         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:
@@ -848,7 +834,7 @@ fn trans_def_dps_unadjusted<'a>(
             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 {
@@ -888,7 +874,7 @@ fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
         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,
@@ -1165,25 +1151,22 @@ fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
     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) {
@@ -1218,15 +1201,10 @@ fn trans_unary_datum<'a>(
             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>,
@@ -1451,41 +1429,43 @@ fn trans_lazy_binop<'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)
         }
     }
@@ -1494,21 +1474,22 @@ fn trans_binary<'a>(
 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)
 }
 
@@ -1666,10 +1647,7 @@ fn trans_assign_op<'a>(
     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"));
@@ -1748,6 +1726,30 @@ fn trans_log_level<'a>(bcx: &'a Block<'a>) -> DatumBlock<'a, Expr> {
     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>,
@@ -1777,6 +1779,28 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
 
     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)
@@ -1805,55 +1829,6 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
             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,
@@ -1867,25 +1842,6 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
 
     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>,
index cfc88d163c0b05d240cd9ac158dd75b00e9806c1..b3d69043d33e397ddcda5506d3cbba927416bfa9 100644 (file)
@@ -29,6 +29,7 @@
 use middle::trans::type_of::*;
 use middle::ty;
 use middle::typeck;
+use middle::typeck::MethodCall;
 use util::common::indenter;
 use util::ppaux::Repr;
 
@@ -93,21 +94,22 @@ pub fn trans_method(ccx: @CrateContext, method: &ast::Method,
 
 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")
         }
     };
 
@@ -115,7 +117,7 @@ pub fn trans_method_callee<'a>(
         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 {
@@ -131,7 +133,7 @@ pub fn trans_method_callee<'a>(
                         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?
@@ -140,10 +142,18 @@ pub fn trans_method_callee<'a>(
         }
 
         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)
         }
     }
@@ -209,13 +219,10 @@ pub fn trans_static_method_callee(bcx: &Block,
             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));
 
@@ -254,7 +261,7 @@ pub fn method_with_name(ccx: &CrateContext,
 }
 
 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)
@@ -270,14 +277,13 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
           // 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));
 
@@ -291,8 +297,7 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
 
 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) {
@@ -316,7 +321,7 @@ fn combine_impl_and_methods_tps(bcx: &Block,
     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),
@@ -328,7 +333,14 @@ fn combine_impl_and_methods_tps(bcx: &Block,
 
     // 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())
     };
@@ -555,7 +567,7 @@ fn emit_vtable_methods(bcx: &Block,
                    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))
         }
     })
 }
index 7193f6576584b1b62a3f086adbcb8b5ded57fdc2..33b246539341b3ff210730c75aef95e73f6d8108 100644 (file)
@@ -23,6 +23,7 @@
 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;
@@ -30,7 +31,7 @@
 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};
@@ -258,10 +259,7 @@ pub struct ctxt_ {
     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,
@@ -1091,19 +1089,11 @@ pub fn mk_ctxt(s: 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,
@@ -2710,50 +2700,23 @@ pub fn type_param(ty: t) -> Option<uint> {
 // 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
     }
 }
 
@@ -2964,7 +2927,10 @@ pub fn expr_ty_opt(cx: ctxt, expr: &ast::Expr) -> Option<t> {
     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`
@@ -2979,11 +2945,10 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
      */
 
     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 {
@@ -3026,14 +2991,14 @@ pub fn local_var_name_str(cx: ctxt, id: NodeId) -> InternedString {
 
 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) => {
@@ -3062,7 +3027,13 @@ pub fn adjust_ty(cx: ctxt,
 
                     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(
@@ -3130,6 +3101,7 @@ pub fn adjust_ty(cx: ctxt,
                 }
             }
         }
+        None => unadjusted_ty
     };
 
     fn borrow_vec(cx: ctxt, span: Span,
@@ -3274,7 +3246,7 @@ pub fn resolve_expr(tcx: ctxt, expr: &ast::Expr) -> ast::Def {
 }
 
 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,
@@ -3295,20 +3267,17 @@ pub enum ExprKind {
 }
 
 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 {
index 114c385b5a0c4db23e4d607f75427e01b61a1be5..89658b32be89a9764b23b2dd49000e163ca89c95 100644 (file)
@@ -84,9 +84,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 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;
@@ -106,6 +104,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 use syntax::ast::{SelfUniq, SelfStatic};
 use syntax::ast::{MutMutable, MutImmutable};
 use syntax::ast;
+use syntax::codemap::Span;
 use syntax::parse::token;
 
 #[deriving(Eq)]
@@ -120,23 +119,23 @@ pub enum AutoderefReceiverFlag {
     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()),
@@ -147,7 +146,6 @@ pub fn lookup(
         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()));
@@ -162,25 +160,25 @@ pub fn lookup(
     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,
@@ -192,20 +190,18 @@ pub fn lookup_in_trait(
         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>>,
@@ -221,7 +217,7 @@ pub struct LookupContext<'a> {
  * is of a suitable type.
  */
 #[deriving(Clone)]
-pub struct Candidate {
+struct Candidate {
     rcvr_match_condition: RcvrMatchCondition,
     rcvr_substs: ty::substs,
     method_ty: @ty::Method,
@@ -244,36 +240,35 @@ pub enum RcvrMatchCondition {
 
 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 => {}
                     }
                 }
@@ -281,30 +276,15 @@ fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
 
             // 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)
         }
     }
 
@@ -326,8 +306,8 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
          * 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);
@@ -341,19 +321,18 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
                 _ => { /* 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);
@@ -366,11 +345,13 @@ fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
                 _ => { /* 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) {
@@ -386,11 +367,11 @@ 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);
@@ -591,8 +572,8 @@ fn push_inherent_impl_candidates_for_type(&self, did: DefId) {
     }
 
     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) {
@@ -619,12 +600,12 @@ fn push_candidates_from_impl(&self,
 
         // 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),
@@ -638,28 +619,45 @@ fn push_candidates_from_impl(&self,
     // 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]`,
@@ -681,44 +679,41 @@ fn consider_reborrow(&self,
         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})
             }
         };
 
@@ -848,30 +843,43 @@ fn search_for_some_kind_of_autorefd_method(
             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();
 
@@ -900,9 +908,8 @@ fn search_for_method(&self, rcvr_ty: ty::t)
         }
     }
 
-    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> =
@@ -918,7 +925,7 @@ fn consider_candidates(&self,
 
         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);
@@ -986,8 +993,7 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
 
         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()));
 
@@ -1007,12 +1013,12 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
                 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)
@@ -1025,11 +1031,11 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
         // 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);
@@ -1077,7 +1083,7 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
         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,
@@ -1091,7 +1097,8 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
         // 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(_) => {
@@ -1112,8 +1119,7 @@ fn construct_transformed_self_ty_for_object(
         &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
@@ -1140,7 +1146,7 @@ fn construct_transformed_self_ty_for_object(
                                  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()`
@@ -1187,14 +1193,14 @@ fn enforce_object_limitations(&self, candidate: &Candidate) {
         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");
             }
@@ -1206,7 +1212,7 @@ fn enforce_object_limitations(&self, candidate: &Candidate) {
         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
@@ -1228,7 +1234,7 @@ fn enforce_object_limitations(&self, candidate: &Candidate) {
 
         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");
         }
     }
@@ -1253,7 +1259,7 @@ fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
         }
 
         if bad {
-            self.tcx().sess.span_err(self.expr.span,
+            self.tcx().sess.span_err(self.span,
                                      "explicit call to destructor");
         }
     }
@@ -1364,7 +1370,7 @@ fn report_static_candidate(&self, idx: uint, did: DefId) {
         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,
@@ -1375,7 +1381,7 @@ fn report_static_candidate(&self, idx: uint, did: DefId) {
 
     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)));
@@ -1383,7 +1389,7 @@ fn report_param_candidate(&self, idx: uint, did: DefId) {
 
     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,
@@ -1406,8 +1412,9 @@ fn did_to_str(&self, did: DefId) -> ~str {
         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)
     }
 }
 
index d032f0f841fc7f4f11c1273397a9cde550684021..7a51a2cc23177b0daea1f96a1e9a064eaa684e8e 100644 (file)
 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;
@@ -266,7 +267,7 @@ fn new(tcx: ty::ctxt,
             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()),
         }
@@ -1108,18 +1109,6 @@ pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
         }
     }
 
-    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(),
@@ -1133,7 +1122,7 @@ pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
     }
 
     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(
@@ -1252,81 +1241,76 @@ pub enum LvaluePreference {
     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
     };
@@ -1334,8 +1318,9 @@ fn try_overloaded_deref(fcx: @FnCtxt,
     // 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
     };
@@ -1343,7 +1328,12 @@ fn try_overloaded_deref(fcx: @FnCtxt,
     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
@@ -1434,8 +1424,7 @@ fn check_expr_with_lvalue_pref(fcx: @FnCtxt, expr: &ast::Expr,
 // 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();
@@ -1446,7 +1435,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
          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 {
@@ -1921,7 +1910,8 @@ fn check_method_call(fcx: @FnCtxt,
                                          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 => {
@@ -2001,15 +1991,17 @@ fn lookup_op_method(fcx: @FnCtxt,
                         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)
@@ -2293,32 +2285,28 @@ fn check_field(fcx: @FnCtxt,
                    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();
@@ -2738,8 +2726,9 @@ fn check_struct_enum_variant(fcx: @FnCtxt,
                     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 {
@@ -3175,19 +3164,27 @@ fn types_compatible(fcx: @FnCtxt, sp: Span,
           } 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 \
@@ -3196,15 +3193,7 @@ fn types_compatible(fcx: @FnCtxt, sp: Span,
                                                },
                                                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);
                   }
               }
index 381ff141bfbb4e18b0631a55c316c30517a0d0c0..169a7cfc90e71a08c0f7c099f65ce881406445db 100644 (file)
@@ -129,6 +129,7 @@ fn get_i(x: &'a Bar) -> &'a int {
 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};
 
@@ -221,11 +222,17 @@ pub fn resolve_type(&mut self, unresolved_ty: ty::t) -> ty::t {
     }
 
     /// 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);
@@ -233,11 +240,9 @@ pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
             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))
         }
     }
 }
@@ -252,10 +257,8 @@ fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
         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> {
@@ -264,7 +267,7 @@ 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> {
@@ -383,53 +386,48 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     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);
+            }
+            _ => {}
         }
     }
 
@@ -488,7 +486,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
 
         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)
@@ -769,7 +768,8 @@ fn constrain_call(rcx: &mut Rcx,
             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
@@ -904,11 +904,9 @@ fn constrain_regions_in_type_of_node(
     // 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),
index 70fe3cfde50b837ade8370df4d3464826491f174..3fee30bc4988cc93aeed1641304bf9b1a45e475f 100644 (file)
@@ -21,6 +21,7 @@
 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> {
@@ -88,14 +80,14 @@ fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool {
 }
 
 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()));
 
@@ -105,18 +97,18 @@ fn lookup_vtables(vcx: &VtableContext,
         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()));
@@ -124,7 +116,7 @@ fn lookup_vtables(vcx: &VtableContext,
 }
 
 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,
@@ -155,11 +147,10 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
 
         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),
@@ -170,11 +161,11 @@ trait {} for {}",
     });
 
     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()));
@@ -183,10 +174,9 @@ trait {} for {}",
 }
 
 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
@@ -196,10 +186,9 @@ fn relate_trait_refs(vcx: &VtableContext,
 
     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
@@ -215,8 +204,7 @@ fn relate_trait_refs(vcx: &VtableContext,
                 !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),
@@ -228,18 +216,17 @@ fn relate_trait_refs(vcx: &VtableContext,
 
 // 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
@@ -261,8 +248,7 @@ fn lookup_vtable(vcx: &VtableContext,
                    .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)
@@ -270,8 +256,7 @@ fn lookup_vtable(vcx: &VtableContext,
 
         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)
@@ -285,14 +270,13 @@ fn lookup_vtable(vcx: &VtableContext,
 
     // 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)
@@ -306,10 +290,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
                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);
@@ -324,7 +305,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
 }
 
 fn search_for_vtable(vcx: &VtableContext,
-                     location_info: &LocationInfo,
+                     span: Span,
                      ty: ty::t,
                      trait_ref: @ty::TraitRef,
                      is_early: bool)
@@ -385,11 +366,10 @@ fn search_for_vtable(vcx: &VtableContext,
         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,
@@ -418,7 +398,7 @@ fn search_for_vtable(vcx: &VtableContext,
                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 --
@@ -430,15 +410,14 @@ fn search_for_vtable(vcx: &VtableContext,
         // 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) {
@@ -463,7 +442,7 @@ fn search_for_vtable(vcx: &VtableContext,
         // 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
@@ -476,9 +455,7 @@ fn search_for_vtable(vcx: &VtableContext,
         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());
         }
@@ -487,7 +464,7 @@ fn search_for_vtable(vcx: &VtableContext,
 
 
 fn fixup_substs(vcx: &VtableContext,
-                location_info: &LocationInfo,
+                span: Span,
                 id: ast::DefId,
                 substs: ty::substs,
                 is_early: bool)
@@ -499,7 +476,7 @@ fn fixup_substs(vcx: &VtableContext,
                          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")
@@ -508,7 +485,7 @@ fn fixup_substs(vcx: &VtableContext,
 }
 
 fn fixup_ty(vcx: &VtableContext,
-            location_info: &LocationInfo,
+            span: Span,
             ty: ty::t,
             is_early: bool)
             -> Option<ty::t> {
@@ -516,8 +493,7 @@ fn fixup_ty(vcx: &VtableContext,
     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)))
@@ -529,7 +505,7 @@ fn fixup_ty(vcx: &VtableContext,
 }
 
 fn connect_trait_tps(vcx: &VtableContext,
-                     location_info: &LocationInfo,
+                     span: Span,
                      impl_substs: &ty::substs,
                      trait_ref: @ty::TraitRef,
                      impl_did: ast::DefId) {
@@ -537,12 +513,12 @@ fn connect_trait_tps(vcx: &VtableContext,
 
     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) {
@@ -551,19 +527,6 @@ 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));
@@ -608,8 +571,6 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
                         _ => 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,
@@ -626,7 +587,7 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
                       };
                       let vtables =
                             lookup_vtables_for_param(&vcx,
-                                                     location_info,
+                                                     ex.span,
                                                      None,
                                                      &param_bounds,
                                                      typ,
@@ -687,7 +648,7 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
                 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 {
@@ -704,7 +665,7 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
       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()));
@@ -712,7 +673,7 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
             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);
@@ -782,13 +743,11 @@ pub fn resolve_impl(tcx: ty::ctxt,
 
     let infcx = &infer::new_infer_ctxt(tcx);
     let vcx = VtableContext { infcx: infcx, param_env: &param_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);
@@ -808,7 +767,7 @@ pub fn resolve_impl(tcx: ty::ctxt,
     // 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,
                                  &param_bounds, t, false);
 
 
@@ -833,13 +792,9 @@ pub fn trans_resolve_method(tcx: ty::ctxt, id: ast::NodeId,
             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))
index ced9db069545beb8301b0ca5407bc070793f9953..7659842aff4119e3b4055fcf3c6cf081ed1e992f 100644 (file)
@@ -20,7 +20,7 @@
 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;
@@ -63,15 +63,15 @@ fn resolve_type_vars_in_types(fcx: @FnCtxt, sp: Span, tys: &[ty::t])
     }).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 => {
@@ -95,7 +95,7 @@ fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
                     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 => {}
     }
@@ -142,10 +142,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
     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 => (),
 
@@ -167,30 +164,29 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
                             // 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,
@@ -218,14 +214,12 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
                         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);
                 }
             }
         }
@@ -280,7 +274,7 @@ fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) {
     }
 
     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 {
index 86f642a228d89104926daf3e460faaa0f45ee1b7..726f89048984c9f9f8954f89a6075158407febe1 100644 (file)
@@ -68,7 +68,7 @@
 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;
@@ -149,9 +149,31 @@ pub struct MethodCallee {
     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.
@@ -442,7 +464,7 @@ pub fn check_crate(tcx: ty::ctxt,
     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
     };
index 05b3b10598127af3f2025e68a5385b97f7a37291..7507fd579ebc174e02a5a0e592cf45bb230281a9 100644 (file)
 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;
@@ -40,13 +53,6 @@ pub fn new() -> super::NodeSet {
     }
 }
 #[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 {
@@ -55,9 +61,8 @@ 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)]
@@ -65,9 +70,10 @@ pub fn new() -> super::DefIdSet {
 
 // 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()
     }
 }
@@ -79,13 +85,6 @@ pub fn new() -> super::NodeSet {
     }
 }
 #[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 {
diff --git a/src/test/run-pass/overloaded-autoderef.rs b/src/test/run-pass/overloaded-autoderef.rs
new file mode 100644 (file)
index 0000000..6b347b3
--- /dev/null
@@ -0,0 +1,51 @@
+// 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));
+}