diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index c1c195852f9..2246621f83c 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -412,8 +412,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { pred: CFGIndex, func_or_rcvr: &hir::Expr, args: I) -> CFGIndex { - let method_call = ty::MethodCall::expr(call_expr.id); - let fn_ty = match self.tables.method_map.get(&method_call) { + let fn_ty = match self.tables.method_map.get(&call_expr.id) { Some(method) => method.ty, None => self.tables.expr_ty_adjusted(func_or_rcvr), }; diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 3bbac8d6a64..0575bfcf926 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -102,7 +102,7 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { autoderefs.hash_stable(hcx, hasher); autoref.hash_stable(hcx, hasher); unsize.hash_stable(hcx, hasher); @@ -112,7 +112,6 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad } impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); -impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); @@ -626,17 +625,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ich::hash_stable_nodemap(hcx, hasher, node_types); ich::hash_stable_nodemap(hcx, hasher, item_substs); ich::hash_stable_nodemap(hcx, hasher, adjustments); - - ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { - let ty::MethodCall { - expr_id, - autoderef - } = *method_call; - - let def_id = hcx.tcx().hir.local_def_id(expr_id); - (hcx.def_path_hash(def_id), autoderef) - }); - + ich::hash_stable_nodemap(hcx, hasher, method_map); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { var_id, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a6dbbee79a4..f05f4119450 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -564,13 +564,14 @@ impl<'tcx, T> InferOk<'tcx, T> { } #[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot { +pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot, int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, was_in_snapshot: bool, + _in_progress_tables: Option>>, } /// Helper trait for shortening the lifetimes inside a @@ -888,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result } - fn start_snapshot(&self) -> CombinedSnapshot { + fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> { debug!("start_snapshot()"); let in_snapshot = self.in_snapshot.get(); @@ -901,6 +902,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), was_in_snapshot: in_snapshot, + // Borrow tables "in progress" (i.e. during typeck) + // to ban writes from within a snapshot to them. + _in_progress_tables: match self.tables { + InferTables::InProgress(ref tables) => tables.try_borrow().ok(), + _ => None + } } } @@ -911,7 +918,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - was_in_snapshot } = snapshot; + was_in_snapshot, + _in_progress_tables } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -938,7 +946,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - was_in_snapshot } = snapshot; + was_in_snapshot, + _in_progress_tables } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -1645,29 +1654,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { !traits::type_known_to_meet_bound(self, ty, copy_def_id, span) } - pub fn node_method_ty(&self, method_call: ty::MethodCall) - -> Option> { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.ty) - .map(|ty| self.resolve_type_vars_if_possible(&ty)) - } - - pub fn node_method_id(&self, method_call: ty::MethodCall) - -> Option { - self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.def_id) - } - - pub fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) - } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 84ead6506c8..ebae3933bdd 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,9 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_method(&mut self, id: ast::NodeId) { - let method_call = ty::MethodCall::expr(id); - let method = self.tables.method_map[&method_call]; - self.check_def_id(method.def_id); + self.check_def_id(self.tables.method_map[&id].def_id); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 2261f296454..1d3f8e426e7 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -13,7 +13,6 @@ use self::RootUnsafeContext::*; use ty::{self, Ty, TyCtxt}; -use ty::MethodCall; use lint; use syntax::ast; @@ -174,8 +173,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let method_call = MethodCall::expr(expr.id); - let base_type = self.tables.method_map[&method_call].ty; + let base_type = self.tables.method_map[&expr.id].ty; debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 99b140f690a..64880bf4fad 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -563,19 +563,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let overloaded_call_type = - match self.mc.infcx.node_method_id(ty::MethodCall::expr(call.id)) { - Some(method_id) => { - OverloadedCallType::from_method_id(self.tcx(), method_id) - } - None => { - span_bug!( - callee.span, - "unexpected callee type {}", - callee_ty) - } - }; - match overloaded_call_type { + let method = self.mc.infcx.tables.borrow().method_map[&call.id]; + match OverloadedCallType::from_method_id(self.tcx(), method.def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, @@ -717,7 +706,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_adjustment(&mut self, expr: &hir::Expr) { let infcx = self.mc.infcx; //NOTE(@jroesch): mixed RefCell borrow causes crash - let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone()); + let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned(); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); if let Some(adjustment) = adj { match adjustment.kind { adjustment::Adjust::NeverToAny | @@ -728,17 +719,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. debug!("walk_adjustment: trivial adjustment"); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize } => { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); - self.walk_autoderefs(expr, autoderefs); - let cmt_derefd = - return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs)); + return_if_err!(self.walk_autoderefs(expr, cmt_unadjusted, autoderefs)); let cmt_refd = self.walk_autoref(expr, cmt_derefd, autoref); @@ -757,30 +744,30 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// `deref()` is declared with `&self`, this is an autoref of `x`. fn walk_autoderefs(&mut self, expr: &hir::Expr, - autoderefs: usize) { - debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs); - - for i in 0..autoderefs { - let deref_id = ty::MethodCall::autoderef(expr.id, i as u32); - if let Some(method_ty) = self.mc.infcx.node_method_ty(deref_id) { - let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i)); + mut cmt: mc::cmt<'tcx>, + autoderefs: &[Option>]) + -> mc::McResult> { + debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs); + for &overloaded in autoderefs { + if let Some(method) = overloaded { // the method call infrastructure should have // replaced all late-bound regions with variables: - let self_ty = method_ty.fn_sig().input(0); + let self_ty = method.ty.fn_sig().input(0); + let self_ty = self.mc.infcx.resolve_type_vars_if_possible(&self_ty); let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap(); let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), - _ => span_bug!(expr.span, - "bad overloaded deref type {:?}", - method_ty) + _ => span_bug!(expr.span, "bad overloaded deref type {:?}", self_ty) }; let bk = ty::BorrowKind::from_mutbl(m); - self.delegate.borrow(expr.id, expr.span, cmt, + self.delegate.borrow(expr.id, expr.span, cmt.clone(), r, bk, AutoRef); } + cmt = self.mc.cat_deref(expr, cmt, overloaded)?; } + Ok(cmt) } /// Walks the autoref `opt_autoref` applied to the autoderef'd @@ -863,7 +850,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pass_args: PassArgs) -> bool { - if !self.mc.infcx.is_method_call(expr.id) { + if !self.mc.infcx.tables.borrow().is_method_call(expr.id) { return false; } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ecd350d1273..d5c0a67f71c 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1084,8 +1084,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprMethodCall(.., ref args) => { - let method_call = ty::MethodCall::expr(expr.id); - let method_ty = self.tables.method_map[&method_call].ty; + let method_ty = self.tables.method_map[&expr.id].ty; // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if method_ty.fn_ret().0.is_never() { self.s.exit_ln diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 13647d420c3..4e2150dc2c6 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -480,14 +480,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Some(adjustment) => { + debug!("cat_expr({:?}): {:?}", adjustment, expr); match adjustment.kind { adjustment::Adjust::DerefRef { - autoderefs, + ref autoderefs, autoref: None, unsize: false } => { // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) + let mut cmt = self.cat_expr_unadjusted(expr)?; + debug!("cat_expr: autoderefs={:?}, cmt={:?}", + autoderefs, cmt); + for &overloaded in autoderefs { + cmt = self.cat_deref(expr, cmt, overloaded)?; + } + return Ok(cmt); } adjustment::Adjust::NeverToAny | @@ -496,9 +503,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | adjustment::Adjust::DerefRef {..} => { - debug!("cat_expr({:?}): {:?}", - adjustment, - expr); // Result is an rvalue. let expr_ty = self.expr_ty_adjusted(expr)?; Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) @@ -508,20 +512,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - pub fn cat_expr_autoderefd(&self, - expr: &hir::Expr, - autoderefs: usize) - -> McResult> { - let mut cmt = self.cat_expr_unadjusted(expr)?; - debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}", - autoderefs, - cmt); - for deref in 1..autoderefs + 1 { - cmt = self.cat_deref(expr, cmt, deref)?; - } - return Ok(cmt); - } - pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { debug!("cat_expr: id={} expr={:?}", expr.id, expr); @@ -529,7 +519,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { let base_cmt = self.cat_expr(&e_base)?; - self.cat_deref(expr, base_cmt, 0) + let method = self.infcx.tables.borrow().method_map + .get(&expr.id).cloned(); + self.cat_deref(expr, base_cmt, method) } hir::ExprField(ref base, f_name) => { @@ -547,12 +539,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - let method_call = ty::MethodCall::expr(expr.id()); - match self.infcx.node_method_ty(method_call) { - Some(method_ty) => { + let method = self.infcx.tables.borrow().method_map.get(&expr.id()).cloned(); + match method { + Some(method) => { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. - let ret_ty = self.overloaded_method_return_ty(method_ty); + let ret_ty = self.overloaded_method_return_ty(method); // The index method always returns an `&T`, so // dereference it to find the result type. @@ -932,24 +924,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - deref_cnt: usize) - -> McResult> { - let method_call = ty::MethodCall { - expr_id: node.id(), - autoderef: deref_cnt as u32 - }; - let method_ty = self.infcx.node_method_ty(method_call); + pub fn cat_deref(&self, + node: &N, + base_cmt: cmt<'tcx>, + overloaded: Option>) + -> McResult> { + debug!("cat_deref: overloaded={:?}", overloaded); - debug!("cat_deref: method_call={:?} method_ty={:?}", - method_call, method_ty.map(|ty| ty)); - - let base_cmt = match method_ty { - Some(method_ty) => { - let ref_ty = - self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + let base_cmt = match overloaded { + Some(method) => { + let ref_ty = self.overloaded_method_return_ty(method); self.cat_rvalue_node(node.id(), node.span(), ref_ty) } None => base_cmt @@ -1020,12 +1004,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - let method_call = ty::MethodCall::expr(elt.id()); - let method_ty = self.infcx.node_method_ty(method_call); - - let (element_ty, element_kind) = match method_ty { - Some(method_ty) => { - let ref_ty = self.overloaded_method_return_ty(method_ty); + let method = self.infcx.tables.borrow().method_map.get(&elt.id()).cloned(); + let (element_ty, element_kind) = match method { + Some(method) => { + let ref_ty = self.overloaded_method_return_ty(method); base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, @@ -1234,7 +1216,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, 0)?; + let method = self.infcx.tables.borrow().method_map + .get(&pat.id).cloned(); + let subcmt = self.cat_deref(pat, cmt, method)?; self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1262,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn overloaded_method_return_ty(&self, - method_ty: Ty<'tcx>) + method: ty::MethodCallee<'tcx>) -> Ty<'tcx> { // When we process an overloaded `*` or `[]` etc, we often @@ -1270,8 +1254,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // types are generated by method resolution and always have // all late-bound regions fully instantiated, so we just want // to skip past the binder. - self.tcx().no_late_bound_regions(&method_ty.fn_ret()) - .unwrap() + let ret_ty = method.ty.fn_ret(); + let ret_ty = self.infcx.resolve_type_vars_if_possible(&ret_ty); + self.tcx().no_late_bound_regions(&ret_ty).unwrap() } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 939d7364d9e..e5cc7aae4e9 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -110,8 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { Some(self.tables.qpath_def(qpath, expr.id)) } hir::ExprMethodCall(..) => { - let method_call = ty::MethodCall::expr(expr.id); - let def_id = self.tables.method_map[&method_call].def_id; + let def_id = self.tables.method_map[&expr.id].def_id; Some(Def::Method(def_id)) } _ => None diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 9aa700e2b44..629f94609aa 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -9,10 +9,6 @@ // except according to those terms. use ty::{self, Ty, TyCtxt, TypeAndMut}; -use ty::LvaluePreference::{NoPreference}; - -use syntax::ast; -use syntax_pos::Span; use hir; @@ -43,10 +39,10 @@ pub enum Adjust<'tcx> { /// here means either or both of raw vs borrowed vs unique and fat vs thin. /// /// We transform pointers by following the following steps in order: - /// 1. Deref the pointer `self.autoderefs` times (may be 0). + /// 1. Deref the pointer through `self.autoderefs` steps (may be no steps). /// 2. If `autoref` is `Some(_)`, then take the address and produce either a /// `&` or `*` pointer. - /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, + /// 3. If `unsize` is `true`, then apply the unsize transformation, /// which will do things like convert thin pointers to fat /// pointers, or convert structs containing thin pointers to /// structs containing fat pointers, or convert between fat @@ -61,23 +57,26 @@ pub enum Adjust<'tcx> { /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. /// Here the pointer will be dereferenced N times (where a dereference can /// happen to raw or borrowed pointers or any smart pointer which implements - /// Deref, including Box<_>). The number of dereferences is given by + /// Deref, including Box<_>). The types of dereferences is given by /// `autoderefs`. It can then be auto-referenced zero or one times, indicated /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is - /// None. + /// `false`. /// /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start /// with a thin pointer, deref a number of times, unsize the underlying data, /// then autoref. The 'unsize' phase may change a fixed length array to a /// dynamically sized one, a concrete object to a trait object, or statically - /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is + /// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is /// represented by: /// /// ``` - /// Adjust::DerefRef { - /// autoderefs: 1, // &[i32; 4] -> [i32; 4] - /// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32] - /// unsize: Some([i32]), // [i32; 4] -> [i32] + /// Adjustment { + /// kind: Adjust::DerefRef { + /// autoderefs: vec![None], // &[i32; 4] -> [i32; 4] + /// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] + /// unsize: true, // &[i32; 4] -> &[i32] + /// }, + /// target: `[i32]`, /// } /// ``` /// @@ -95,15 +94,18 @@ pub enum Adjust<'tcx> { /// Box<[i32]> is represented by: /// /// ``` - /// Adjust::DerefRef { - /// autoderefs: 0, - /// autoref: None, - /// unsize: Some(Box<[i32]>), + /// Adjustment { + /// Adjust::DerefRef { + /// autoderefs: vec![], + /// autoref: None, + /// unsize: true, + /// }, + /// target: `Box<[i32]>`, /// } /// ``` DerefRef { /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: usize, + autoderefs: Vec>>, /// Step 2. Optionally produce a pointer/reference from the value. autoref: Option>, @@ -119,7 +121,11 @@ impl<'tcx> Adjustment<'tcx> { match self.kind { Adjust::NeverToAny => self.target.is_never(), - Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true, + Adjust::DerefRef { + ref autoderefs, + autoref: None, + unsize: false + } if autoderefs.is_empty() => true, Adjust::ReifyFnPointer | Adjust::UnsafeFnPointer | @@ -161,35 +167,6 @@ pub enum CustomCoerceUnsized { } impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { - pub fn adjust_for_autoderef(&'tcx self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - expr_id: ast::NodeId, - expr_span: Span, - autoderef: u32, // how many autoderefs so far? - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - let method_call = ty::MethodCall::autoderef(expr_id, autoderef); - let mut adjusted_ty = self; - if let Some(method_ty) = method_type(method_call) { - // Method calls always have all late-bound regions - // fully instantiated. - adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - } - match adjusted_ty.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => { - span_bug!( - expr_span, - "the {}th autoderef for {} failed: {}", - autoderef, - expr_id, - adjusted_ty); - } - } - } - pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, autoref: Option>) -> Ty<'tcx> { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e3d7aeb22e1..76882b94315 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -222,7 +222,7 @@ pub struct TypeckTables<'tcx> { pub adjustments: NodeMap>, - pub method_map: ty::MethodMap<'tcx>, + pub method_map: NodeMap>, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -358,11 +358,7 @@ impl<'tcx> TypeckTables<'tcx> { } pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.method_map.contains_key(&ty::MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { - self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs)) + self.method_map.contains_key(&expr_id) } pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index aeffd71a096..08016ac91bf 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -398,44 +398,6 @@ pub struct MethodCallee<'tcx> { pub substs: &'tcx Substs<'tcx> } -/// With method calls, we store some extra information in -/// side tables (i.e method_map). We use -/// MethodCall as a key to index into these tables instead of -/// just directly using the expression's NodeId. The reason -/// for this being that we may apply adjustments (coercions) -/// with the resulting expression also needing to use the -/// side tables. The problem with this is that we don't -/// assign a separate NodeId to this new expression -/// and so it would clash with the base expression if both -/// needed to add to the side tables. Thus to disambiguate -/// we also keep track of whether there's an adjustment in -/// our key. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct MethodCall { - pub expr_id: NodeId, - pub autoderef: u32 -} - -impl MethodCall { - pub fn expr(id: NodeId) -> MethodCall { - MethodCall { - expr_id: id, - autoderef: 0 - } - } - - pub fn autoderef(expr_id: 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<'tcx> = FxHashMap>; - // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. #[derive(Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f1d014692a4..13c69d10530 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -882,19 +882,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { use rustc::ty::adjustment::*; // Check for method calls and overloaded operators. - let opt_m = cx.tables.method_map.get(&ty::MethodCall::expr(id)).cloned(); - if let Some(m) = opt_m { + if let Some(m) = cx.tables.method_map.get(&id).cloned() { if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { return true; } } // Check for overloaded autoderef method calls. - let opt_adj = cx.tables.adjustments.get(&id).cloned(); - if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj { - for i in 0..autoderefs { - let method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = cx.tables.method_map.get(&method_call).cloned() { + if let Some(Adjustment { + kind: Adjust::DerefRef { ref autoderefs, .. }, .. + }) = cx.tables.adjustments.get(&id).cloned() { + for &overloaded in autoderefs { + if let Some(m) = overloaded { if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { return true; } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b180d982e86..6c48e0120ba 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -31,16 +31,16 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let mut expr = make_mirror_unadjusted(cx, self); - let adj = cx.tables().adjustments.get(&self.id).cloned(); + let adj = cx.tables().adjustments.get(&self.id); debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", expr, adj); // Now apply adjustments, if any. - match adj.map(|adj| (adj.kind, adj.target)) { + match adj.map(|adj| (&adj.kind, adj.target)) { None => {} - Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -49,7 +49,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -58,7 +58,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -67,7 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ClosureFnPointer { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -76,7 +76,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::NeverToAny { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { + Some((&ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -85,25 +85,18 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize }, + Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize }, adjusted_ty)) => { - for i in 0..autoderefs { - let i = i as u32; - let adjusted_ty = - expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| { - cx.tables().method_map.get(&mc).map(|m| m.ty) - }); - debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", - i, - adjusted_ty); - let method_key = ty::MethodCall::autoderef(self.id, i); - let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty); - let kind = if let Some(meth_ty) = meth_ty { - debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty); + for &overloaded in autoderefs { + let mut ref_ty = expr.ty; + let kind = if let Some(method) = overloaded { + debug!("make_mirror: overloaded autoderef (method={:?})", method); - let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret()); - let (region, mutbl) = match ref_ty { - Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl), + // Method calls always have all late-bound regions + // fully instantiated. + ref_ty = cx.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap(); + let (region, mutbl) = match ref_ty.sty { + ty::TyRef(region, mt) => (region, mt.mutbl), _ => span_bug!(expr.span, "autoderef returned bad type"), }; @@ -125,7 +118,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { overloaded_lvalue(cx, self, - method_key, + method, PassArgs::ByRef, expr.to_ref(), vec![]) @@ -133,6 +126,14 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("make_mirror: built-in autoderef"); ExprKind::Deref { arg: expr.to_ref() } }; + let adjusted_ty = match ref_ty.builtin_deref(true, + ty::LvaluePreference::NoPreference) { + Some(mt) => mt.ty, + None => { + span_bug!(self.span, "autoderef for {} failed: {}", self.id, ref_ty); + } + }; + debug!("make_mirror: autoderef adjusted_ty={:?}", adjusted_ty); expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, @@ -243,7 +244,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Here comes the interesting stuff: hir::ExprMethodCall(.., ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) - let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + let method = cx.tables().method_map[&expr.id]; + let expr = method_callee(cx, expr, method); let args = args.iter() .map(|e| e.to_ref()) .collect(); @@ -255,7 +257,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprCall(ref fun, ref args) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the @@ -263,7 +265,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + let method = method_callee(cx, expr, method); let sig = method.ty.fn_sig(); @@ -352,7 +354,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -360,7 +362,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, pass_args, lhs.to_ref(), vec![rhs]) @@ -376,7 +378,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, hir::ExprBinary(op, ref lhs, ref rhs) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -384,7 +386,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, pass_args, lhs.to_ref(), vec![rhs]) @@ -436,10 +438,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprIndex(ref lhs, ref index) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, lhs.to_ref(), vec![index]) @@ -452,10 +454,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_lvalue(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -465,10 +467,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -481,10 +483,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if cx.tables().is_method_call(expr.id) { + if let Some(&method) = cx.tables().method_map.get(&expr.id) { overloaded_operator(cx, expr, - ty::MethodCall::expr(expr.id), + method, PassArgs::ByValue, arg.to_ref(), vec![]) @@ -703,9 +705,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, - method_call: ty::MethodCall) + callee: ty::MethodCallee<'tcx>) -> Expr<'tcx> { - let callee = cx.tables().method_map[&method_call]; let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); Expr { temp_lifetime: temp_lifetime, @@ -948,7 +949,7 @@ enum PassArgs { fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, + method: ty::MethodCallee<'tcx>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -991,7 +992,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } // now create the call itself - let fun = method_callee(cx, expr, method_call); + let fun = method_callee(cx, expr, method); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), @@ -1001,7 +1002,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, + method: ty::MethodCallee<'tcx>, pass_args: PassArgs, receiver: ExprRef<'tcx>, args: Vec<&'tcx P>) @@ -1011,14 +1012,14 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // line up (this is because `*x` and `x[y]` represent lvalues): // to find the type &T of the content returned by the method; - let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret(); + let ref_ty = method.ty.fn_ret(); let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); // callees always have all late-bound regions fully instantiated, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); - let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args); + let ref_kind = overloaded_operator(cx, expr, method, pass_args, receiver, args); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 09e90b78d60..712f5f7ad39 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -280,11 +280,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node _ => {} } - let method_call = ty::MethodCall::expr(e.id); match e.node { hir::ExprUnary(..) | hir::ExprBinary(..) | - hir::ExprIndex(..) if v.tables.method_map.contains_key(&method_call) => { + hir::ExprIndex(..) if v.tables.method_map.contains_key(&e.id) => { v.promotable = false; } hir::ExprBox(_) => { @@ -381,7 +380,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tables.method_map[&method_call]; + let method = v.tables.method_map[&e.id]; match v.tcx.associated_item(method.def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty), ty::TraitContainer(_) => v.promotable = false @@ -450,9 +449,8 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp Some(&Adjust::ClosureFnPointer) | Some(&Adjust::MutToConstPointer) => {} - Some(&Adjust::DerefRef { autoderefs, .. }) => { - if (0..autoderefs as u32) - .any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) { + Some(&Adjust::DerefRef { ref autoderefs, .. }) => { + if autoderefs.iter().any(|overloaded| overloaded.is_some()) { v.promotable = false; } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d83740936d5..d0809f0f642 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -564,8 +564,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::MethodCall(..) => { - let method_call = ty::MethodCall::expr(expr.id); - let method_id = self.tables.method_map[&method_call].def_id; + let method_id = self.tables.method_map[&expr.id].def_id; let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index f03451c04ed..098674519b4 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,14 +12,12 @@ use astconv::AstConv; use super::{FnCtxt, LvalueOp}; -use check::coercion::AsCoercionSite; use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; -use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::{LvaluePreference, NoPreference}; -use rustc::hir; +use rustc::ty::adjustment::AutoBorrow; use syntax_pos::Span; use syntax::symbol::Symbol; @@ -149,52 +147,45 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) { - let fcx = self.fcx; - fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr])); + pub fn step_count(&self) -> usize { + self.steps.len() } - pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) - -> InferOk<'tcx, ()> - where E: AsCoercionSite - { - let Autoderef { fcx, span, mut obligations, steps, .. } = self; - let methods: Vec<_> = steps - .iter() - .map(|&(ty, kind)| { - if let AutoderefKind::Overloaded = kind { - fcx.try_overloaded_deref(span, None, ty, pref) - .map(|InferOk { value, obligations: o }| { - obligations.extend(o); - value - }) - } else { - None - } - }) - .collect(); + /// Returns the steps required in adjustments (overloaded deref calls). + pub fn adjust_steps(&self, pref: LvaluePreference) + -> Vec>> { + self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) + } - debug!("finalize({:?}) - {:?},{:?}", - pref, - methods, - obligations); - - for expr in exprs { - let expr = expr.as_coercion_site(); - debug!("finalize - finalizing #{} - {:?}", expr.id, expr); - for (n, method) in methods.iter().enumerate() { - if let &Some(method) = method { - let method_call = MethodCall::autoderef(expr.id, n as u32); - fcx.tables.borrow_mut().method_map.insert(method_call, method); - } + pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference) + -> InferOk<'tcx, Vec>>> { + let mut obligations = vec![]; + let steps: Vec<_> = self.steps.iter().map(|&(ty, kind)| { + if let AutoderefKind::Overloaded = kind { + self.fcx.try_overloaded_deref(self.span, ty, pref) + .map(|InferOk { value: (_, method), obligations: o }| { + obligations.extend(o); + method + }) + } else { + None } - } + }).collect(); InferOk { - value: (), - obligations + obligations, + value: steps } } + + pub fn finalize(self) { + let fcx = self.fcx; + fcx.register_predicates(self.into_obligations()); + } + + pub fn into_obligations(self) -> Vec> { + self.obligations + } } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -211,14 +202,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn try_overloaded_deref(&self, span: Span, - base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, pref: LvaluePreference) - -> Option>> { - let rcvr = base_expr.map(|base_expr| super::AdjustedRcvr { - rcvr_expr: base_expr, autoderefs: 0, unsize: false - }); - - self.try_overloaded_lvalue_op(span, rcvr, base_ty, &[], pref, LvalueOp::Deref) + -> Option>, + ty::MethodCallee<'tcx>)>> { + self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index dde5f598a68..ce3dbf8c23e 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; +use super::{Expectation, FnCtxt, TupleArgumentsFlag}; +use super::autoderef::Autoderef; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, LvaluePreference, Ty}; use rustc::ty::subst::Subst; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use syntax::abi; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -33,7 +35,7 @@ pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefI } enum CallStep<'tcx> { - Builtin, + Builtin(Ty<'tcx>), DeferredClosure(ty::FnSig<'tcx>), Overloaded(ty::MethodCallee<'tcx>), } @@ -49,13 +51,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); - let result = autoderef.by_ref() - .flat_map(|(adj_ty, idx)| { - self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) - }) - .next(); - let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, callee_expr); + let mut result = None; + while result.is_none() && autoderef.next().is_some() { + result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef); + } + autoderef.finalize(); let output = match result { None => { @@ -63,7 +63,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected) } - Some(CallStep::Builtin) => { + Some(CallStep::Builtin(callee_ty)) => { self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected) } @@ -89,19 +89,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_call_step(&self, call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) + autoderef: &Autoderef<'a, 'gcx, 'tcx>) -> Option> { - debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", + let adjusted_ty = autoderef.unambiguous_final_ty(); + debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", call_expr, - adjusted_ty, - autoderefs); + adjusted_ty); // If the callee is a bare function or a closure, then we're all set. - match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { + match adjusted_ty.sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); - return Some(CallStep::Builtin); + return Some(CallStep::Builtin(adjusted_ty)); } ty::TyClosure(def_id, substs) => { @@ -116,15 +116,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { infer::FnCall, &closure_ty) .0; - self.record_deferred_call_resolution(def_id, - Box::new(CallResolution { - call_expr: call_expr, - callee_expr: callee_expr, - adjusted_ty: adjusted_ty, - autoderefs: autoderefs, - fn_sig: fn_sig.clone(), - closure_def_id: def_id, - })); + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.record_deferred_call_resolution(def_id, DeferredCallResolution { + call_expr: call_expr, + callee_expr: callee_expr, + adjusted_ty: adjusted_ty, + autoderefs: autoderefs, + fn_sig: fn_sig.clone(), + closure_def_id: def_id, + }); return Some(CallStep::DeferredClosure(fn_sig)); } } @@ -137,23 +137,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // over the top. The simplest fix by far is to just ignore // this case and deref again, so we wind up with // `FnMut::call_mut(&mut *x, ())`. - ty::TyRef(..) if autoderefs == 0 => { + ty::TyRef(..) if autoderef.step_count() == 0 => { return None; } _ => {} } - self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs) - .map(|method_callee| CallStep::Overloaded(method_callee)) + self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.apply_adjustment(callee_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs, + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + CallStep::Overloaded(method) + }) } fn try_overloaded_call_traits(&self, call_expr: &hir::Expr, - callee_expr: &hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> { + adjusted_ty: Ty<'tcx>) + -> Option<(Option>, + ty::MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name) in &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")), @@ -165,20 +174,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; match self.lookup_method_in_trait_adjusted(call_expr.span, - Some(super::AdjustedRcvr { - rcvr_expr: callee_expr, - autoderefs, - unsize: false - }), method_name, trait_def_id, adjusted_ty, None) { None => continue, - Some(ok) => { - let method_callee = self.register_infer_ok_obligations(ok); - return Some(method_callee); - } + Some(ok) => return Some(self.register_infer_ok_obligations(ok)) } } @@ -313,30 +314,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::TupleArguments, expected); - self.write_overloaded_call_method_map(call_expr, method_callee); + self.tables.borrow_mut().method_map.insert(call_expr.id, method_callee); output_type } - - fn write_overloaded_call_method_map(&self, - call_expr: &hir::Expr, - method_callee: ty::MethodCallee<'tcx>) { - let method_call = ty::MethodCall::expr(call_expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method_callee); - } } #[derive(Debug)] -struct CallResolution<'gcx: 'tcx, 'tcx> { +pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, adjusted_ty: Ty<'tcx>, - autoderefs: usize, + autoderefs: Vec>>, fn_sig: ty::FnSig<'tcx>, closure_def_id: DefId, } -impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { +impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { + pub fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been @@ -345,10 +339,8 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc // We may now know enough to figure out fn vs fnmut etc. match fcx.try_overloaded_call_traits(self.call_expr, - self.callee_expr, - self.adjusted_ty, - self.autoderefs) { - Some(method_callee) => { + self.adjusted_ty) { + Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature // from the call trait. This has to be reconciled with @@ -370,7 +362,16 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); - fcx.write_overloaded_call_method_map(self.call_expr, method_callee); + fcx.apply_adjustment(self.callee_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: self.autoderefs, + autoref, + unsize: false + }, + target: method_sig.inputs()[0] + }); + + fcx.tables.borrow_mut().method_map.insert(self.call_expr.id, method_callee); } None => { span_bug!(self.call_expr.span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2d8126225be..78559e470ae 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -110,7 +110,7 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, fn identity<'tcx>() -> Adjust<'tcx> { Adjust::DerefRef { - autoderefs: 0, + autoderefs: vec![], autoref: None, unsize: false, } @@ -157,13 +157,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce(&self, - exprs: &[E], - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CoerceResult<'tcx> - where E: AsCoercionSite - { + fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -210,7 +204,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } ty::TyRef(r_b, mt_b) => { - return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b); + return self.coerce_borrowed_pointer(a, b, r_b, mt_b); } _ => {} @@ -245,15 +239,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer(&self, - exprs: &[E], - a: Ty<'tcx>, - b: Ty<'tcx>, - r_b: ty::Region<'tcx>, - mt_b: TypeAndMut<'tcx>) - -> CoerceResult<'tcx> - where E: AsCoercionSite - { + fn coerce_borrowed_pointer(&self, + a: Ty<'tcx>, + b: Ty<'tcx>, + r_b: ty::Region<'tcx>, + mt_b: TypeAndMut<'tcx>) + -> CoerceResult<'tcx> { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -375,7 +366,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }); match self.unify(derefd_ty_a, b) { Ok(ok) => { - found = Some((ok, autoderefs)); + found = Some(ok); break; } Err(err) => { @@ -391,7 +382,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (InferOk { value: ty, mut obligations }, autoderefs) = match found { + let InferOk { value: ty, mut obligations } = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -400,7 +391,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { + if ty == a && mt_a.mutbl == hir::MutImmutable && autoderef.step_count() == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as // we started with. In that case, just skip it @@ -423,17 +414,21 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + let InferOk { value: autoderefs, obligations: o } + = autoderef.adjust_steps_as_infer_ok(pref); + obligations.extend(o); + obligations.extend(autoderef.into_obligations()); + debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", ty, autoderefs, autoref); - let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations); - success(Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, + autoderefs, + autoref, unsize: false, }, ty, obligations) } @@ -477,7 +472,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); let adjust = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoderefs: if reborrow.is_some() { vec![None] } else { vec![] }, autoref: reborrow, unsize: true, }; @@ -668,7 +663,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // regionck knows that the region for `a` must be valid here. self.unify_and(a_unsafe, b, if is_ref { Adjust::DerefRef { - autoderefs: 1, + autoderefs: vec![None], autoref: Some(AutoBorrow::RawPtr(mutbl_b)), unsize: false, } @@ -703,7 +698,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?; + let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; let adjustment = self.register_infer_ok_obligations(ok); self.apply_adjustment(expr.id, adjustment); @@ -721,7 +716,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - self.probe(|_| coerce.coerce::(&[], source, target)).is_ok() + self.probe(|_| coerce.coerce(source, target)).is_ok() } /// Given some expressions, their known unified type and another expression, @@ -796,7 +791,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); @@ -815,10 +810,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr = expr.as_coercion_site(); let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| &adj.kind) { Some(&Adjust::DerefRef { - autoderefs: 1, + ref autoderefs, autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), unsize: false - }) => { + }) if autoderefs.len() == 1 => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore, because @@ -842,7 +837,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a9e82a0601f..b6cd1dfc3d0 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -136,8 +136,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap(); assert_eq!(n, pick.autoderefs); + let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); + autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); + autoderef.finalize(); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -145,8 +147,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Write out the final adjustment. self.apply_adjustment(self.self_expr.id, Adjustment { kind: Adjust::DerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, + autoderefs, + autoref, unsize: pick.unsize.is_some(), }, target: target @@ -436,19 +438,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded lvalue ops, and will be fixed by them in order to get // the correct region. - let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs, - Some(_) | None => 0 - }; - - if autoderefs > 0 { - let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); - autoderef.nth(autoderefs).unwrap_or_else(|| { - span_bug!(expr.span, - "expr was deref-able {} times but now isn't?", - autoderefs); - }); - autoderef.finalize(PreferMutLvalue, expr); + let expr_ty = self.node_ty(expr.id); + if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { + if let Adjust::DerefRef { ref mut autoderefs, .. } = adj.kind { + let mut autoderef = self.autoderef(expr.span, expr_ty); + autoderef.nth(autoderefs.len()).unwrap_or_else(|| { + span_bug!(expr.span, + "expr was deref-able as {:?} but now isn't?", + autoderefs); + }); + *autoderefs = autoderef.adjust_steps(LvaluePreference::PreferMutLvalue); + autoderef.finalize(); + } } match expr.node { @@ -474,8 +475,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); - let method_call = ty::MethodCall::expr(expr.id); - if !self.tables.borrow().method_map.contains_key(&method_call) { + if !self.tables.borrow().method_map.contains_key(&expr.id) { debug!("convert_lvalue_op_to_mutable - builtin, nothing to do"); return } @@ -490,14 +490,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { .ty; let method = self.try_overloaded_lvalue_op( - expr.span, None, base_ty, arg_tys, PreferMutLvalue, op); + expr.span, base_ty, arg_tys, PreferMutLvalue, op); let ok = match method { Some(method) => method, None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; - let method = self.register_infer_ok_obligations(ok); + let (_, method) = self.register_infer_ok_obligations(ok); debug!("convert_lvalue_op_to_mutable: method={:?}", method); - self.tables.borrow_mut().method_map.insert(method_call, method); + self.tables.borrow_mut().method_map.insert(expr.id, method); // Convert the autoref in the base expr to mutable with the correct // region and mutability. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 43bf702935a..7397c3d48e7 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,13 +10,13 @@ //! Method lookup: the secret sauce of Rust. See `README.md`. -use check::{FnCtxt, AdjustedRcvr}; +use check::FnCtxt; use hir::def::Def; use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; +use rustc::ty::adjustment::AutoBorrow; use rustc::ty::subst::Subst; use rustc::infer::{self, InferOk}; @@ -166,16 +166,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// this method is basically the same as confirmation. pub fn lookup_method_in_trait_adjusted(&self, span: Span, - self_info: Option, m_name: ast::Name, trait_def_id: DefId, self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option>> { - debug!("lookup_in_trait_adjusted(self_ty={:?}, self_info={:?}, \ + opt_input_types: Option<&[ty::Ty<'tcx>]>) + -> Option>, + ty::MethodCallee<'tcx>)>> { + debug!("lookup_in_trait_adjusted(self_ty={:?}, \ m_name={}, trait_def_id={:?})", self_ty, - self_info, m_name, trait_def_id); @@ -237,7 +237,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value } }; - let transformed_self_ty = fn_sig.inputs()[0]; let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", @@ -267,36 +266,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Also add an obligation for the method type being well-formed. obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); - // Insert any adjustments needed (always an autoref of some mutability). - if let Some(AdjustedRcvr { rcvr_expr, autoderefs, unsize }) = self_info { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, fty={:?})", - rcvr_expr.id, autoderefs, unsize, original_method_ty); - - let original_sig = original_method_ty.fn_sig(); - let autoref = match (&original_sig.input(0).skip_binder().sty, - &transformed_self_ty.sty) { - (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - Some(AutoBorrow::Ref(region, mutbl)) - } - _ => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - None - } - }; - - self.apply_adjustment(rcvr_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: unsize - }, - target: transformed_self_ty - }); - } + let autoref = match (&original_method_ty.fn_sig().input(0).skip_binder().sty, + &method_ty.fn_sig().input(0).skip_binder().sty) { + (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + Some(AutoBorrow::Ref(region, mutbl)) + } + _ => { + // Trait method is fn(self), no transformation needed. + None + } + }; let callee = ty::MethodCallee { def_id: def_id, @@ -308,7 +289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(InferOk { obligations, - value: callee + value: (autoref, callee) }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bee4a18523e..ed37b55d030 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,6 +77,8 @@ type parameter). */ pub use self::Expectation::*; +use self::autoderef::Autoderef; +use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -93,7 +95,7 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; -use rustc::ty::{MethodCall, MethodCallee}; +use rustc::ty::{MethodCallee}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; @@ -168,7 +170,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // decision. We keep these deferred resolutions grouped by the // def-id of the closure, so that once we decide, we can easily go // back and process them. - deferred_call_resolutions: RefCell>>>, + deferred_call_resolutions: RefCell>>>, deferred_cast_checks: RefCell>>, @@ -194,12 +196,6 @@ impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { } } -trait DeferredCallResolution<'gcx, 'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>); -} - -type DeferredCallResolutionHandler<'gcx, 'tcx> = Box+'tcx>; - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. #[derive(Copy, Clone, Debug)] @@ -375,13 +371,6 @@ pub enum LvalueOp { Index } -#[derive(Copy, Clone, Debug)] -pub struct AdjustedRcvr<'a> { - pub rcvr_expr: &'a hir::Expr, - pub autoderefs: usize, - pub unsize: bool -} - /// Tracks whether executing a node may exit normally (versus /// return/break/panic, which "diverge", leaving dead code in their /// wake). Tracked semi-automatically (through type variables marked @@ -1729,17 +1718,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn record_deferred_call_resolution(&self, closure_def_id: DefId, - r: DeferredCallResolutionHandler<'gcx, 'tcx>) { + r: DeferredCallResolution<'gcx, 'tcx>) { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r); } fn remove_deferred_call_resolutions(&self, closure_def_id: DefId) - -> Vec> + -> Vec> { let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new()) + deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) } pub fn tag(&self) -> String { @@ -1782,11 +1771,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn apply_autoderef_adjustment(&self, node_id: ast::NodeId, - derefs: usize, + autoderefs: Vec>>, adjusted_ty: Ty<'tcx>) { self.apply_adjustment(node_id, Adjustment { kind: Adjust::DerefRef { - autoderefs: derefs, + autoderefs, autoref: None, unsize: false }, @@ -1805,18 +1794,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - let composed_kind = match (&entry.get().kind, &adj.kind) { + match (&entry.get().kind, &adj.kind) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (&Adjust::NeverToAny, _) => Adjust::NeverToAny, + (&Adjust::NeverToAny, _) => return, (&Adjust::DerefRef { - autoderefs: 1, + autoderefs: ref old, autoref: Some(AutoBorrow::Ref(..)), unsize: false - }, &Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { + }, &Adjust::DerefRef { + autoderefs: ref new, .. + }) if old.len() == 1 && new.len() >= 1 => { // A reborrow has no effect before a dereference. - adj.kind } // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. @@ -1824,10 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bug!("while adjusting {}, can't compose {:?} and {:?}", node_id, entry.get(), adj) }; - *entry.get_mut() = Adjustment { - kind: composed_kind, - target: adj.target - }; + *entry.get_mut() = adj; } } } @@ -2189,32 +2176,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // consolidated. let mut autoderef = self.autoderef(base_expr.span, base_ty); - - while let Some((adj_ty, autoderefs)) = autoderef.next() { - if let Some(final_mt) = self.try_index_step( - MethodCall::expr(expr.id), expr, Some(AdjustedRcvr { - rcvr_expr: base_expr, - autoderefs, - unsize: false - }), base_expr.span, adj_ty, lvalue_pref, idx_ty) - { - autoderef.finalize(lvalue_pref, base_expr); - return Some(final_mt); - } - - if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, base_expr); - let adj_ty = self.tcx.mk_slice(element_ty); - return self.try_index_step( - MethodCall::expr(expr.id), expr, Some(AdjustedRcvr { - rcvr_expr: base_expr, - autoderefs, - unsize: true - }), base_expr.span, adj_ty, lvalue_pref, idx_ty) - } + let mut result = None; + while result.is_none() && autoderef.next().is_some() { + result = self.try_index_step(expr, base_expr, &autoderef, lvalue_pref, idx_ty); } - autoderef.unambiguous_final_ty(); - None + autoderef.finalize(); + result } /// To type-check `base_expr[index_expr]`, we progressively autoderef @@ -2223,16 +2190,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This loop implements one step in that search; the autoderef loop /// is implemented by `lookup_indexing`. fn try_index_step(&self, - method_call: MethodCall, expr: &hir::Expr, - base_expr: Option, - base_span: Span, - adjusted_ty: Ty<'tcx>, + base_expr: &hir::Expr, + autoderef: &Autoderef<'a, 'gcx, 'tcx>, lvalue_pref: LvaluePreference, index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let tcx = self.tcx; + let mut adjusted_ty = autoderef.unambiguous_final_ty(); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", expr, @@ -2240,35 +2205,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjusted_ty, index_ty); - let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_span)); // First, try built-in indexing. match (adjusted_ty.builtin_index(), &index_ty.sty) { (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); - // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. - if let Some(base_expr) = base_expr { - assert!(!base_expr.unsize); - self.apply_autoderef_adjustment( - base_expr.rcvr_expr.id, base_expr.autoderefs, adjusted_ty); - } - return Some((tcx.types.usize, ty)); + let autoderefs = autoderef.adjust_steps(lvalue_pref); + self.apply_autoderef_adjustment( + base_expr.id, autoderefs, adjusted_ty); + return Some((self.tcx.types.usize, ty)); } _ => {} } - // If some lookup succeeds, write callee into table and extract index/element - // type from the method signature. - // If some lookup succeeded, install method in table - let method = self.try_overloaded_lvalue_op( - expr.span, base_expr, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index); + for &unsize in &[false, true] { + if unsize { + // We only unsize arrays here. + if let ty::TyArray(element_ty, _) = adjusted_ty.sty { + adjusted_ty = self.tcx.mk_slice(element_ty); + } else { + continue; + } + } - method.map(|ok| { - debug!("try_index_step: success, using overloaded indexing"); - let method = self.register_infer_ok_obligations(ok); - self.tables.borrow_mut().method_map.insert(method_call, method); - (input_ty, self.make_overloaded_lvalue_return_type(method).ty) - }) + // If some lookup succeeds, write callee into table and extract index/element + // type from the method signature. + // If some lookup succeeded, install method in table + let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); + let method = self.try_overloaded_lvalue_op( + expr.span, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index); + + let result = method.map(|ok| { + debug!("try_index_step: success, using overloaded indexing"); + let (autoref, method) = self.register_infer_ok_obligations(ok); + + let autoderefs = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustment(base_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs, + autoref, + unsize + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + + self.tables.borrow_mut().method_map.insert(expr.id, method); + (input_ty, self.make_overloaded_lvalue_return_type(method).ty) + }); + if result.is_some() { + return result; + } + } + + None } fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option, Symbol) { @@ -2287,16 +2276,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn try_overloaded_lvalue_op(&self, span: Span, - base_expr: Option, base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], lvalue_pref: LvaluePreference, op: LvalueOp) - -> Option>> + -> Option>, + ty::MethodCallee<'tcx>)>> { - debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?},{:?})", + debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})", span, - base_expr, base_ty, lvalue_pref, op); @@ -2306,11 +2295,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match (lvalue_pref, mut_tr) { (PreferMutLvalue, Some(trait_did)) => { self.lookup_method_in_trait_adjusted(span, - base_expr, mut_op, trait_did, base_ty, - Some(arg_tys.to_owned())) + Some(arg_tys)) } _ => None, }; @@ -2320,11 +2308,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match (method, imm_tr) { (None, Some(trait_did)) => { self.lookup_method_in_trait_adjusted(span, - base_expr, imm_op, trait_did, base_ty, - Some(arg_tys.to_owned())) + Some(arg_tys)) } (method, _) => method, }; @@ -2802,10 +2789,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, rcvr) { Ok(method) => { - let method_ty = method.ty; - let method_call = MethodCall::expr(expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method); - method_ty + self.tables.borrow_mut().method_map.insert(expr.id, method); + method.ty } Err(error) => { if method_name.node != keywords::Invalid.name() { @@ -2912,7 +2897,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, autoderefs)) = autoderef.next() { + while let Some((base_t, _)) = autoderef.next() { match base_t.sty { ty::TyAdt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); @@ -2922,8 +2907,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(def_scope, self.tcx) { - autoderef.finalize(lvalue_pref, base); + let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + autoderef.finalize(); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3020,7 +3006,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut private_candidate = None; let mut tuple_like = false; let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, autoderefs)) = autoderef.next() { + while let Some((base_t, _)) = autoderef.next() { let field = match base_t.sty { ty::TyAdt(base_def, substs) if base_def.is_struct() => { tuple_like = base_def.struct_variant().ctor_kind == CtorKind::Fn; @@ -3055,8 +3041,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, base); + let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + autoderef.finalize(); return field_ty; } } @@ -3470,11 +3457,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; } else if let Some(ok) = self.try_overloaded_deref( - expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { - let method = self.register_infer_ok_obligations(ok); + expr.span, oprnd_t, lvalue_pref) { + let (autoref, method) = self.register_infer_ok_obligations(ok); + self.apply_adjustment(oprnd.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: vec![], + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), - method); + self.tables.borrow_mut().method_map.insert(expr.id, method); } else { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 3709260acc9..0ac568f2090 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -14,6 +14,7 @@ use super::FnCtxt; use hir::def_id::DefId; use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; +use rustc::ty::adjustment::{Adjustment, Adjust}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; use syntax::ast; @@ -184,7 +185,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var], Symbol::intern(name), trait_def_id, lhs_expr); @@ -214,7 +215,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty], + self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty], Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.note( @@ -313,7 +314,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { assert!(op.is_by_value()); let mname = Symbol::intern(mname); - match self.lookup_op_method(ex, operand_ty, vec![], mname, trait_did, operand_expr) { + match self.lookup_op_method(ex, operand_ty, &[], mname, trait_did, operand_expr) { Ok(t) => t, Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); @@ -382,7 +383,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn lookup_op_method(&self, expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, - other_tys: Vec>, + other_tys: &[Ty<'tcx>], opname: ast::Name, trait_did: Option, lhs_expr: &'a hir::Expr) @@ -398,11 +399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match trait_did { Some(trait_did) => { - let lhs_expr = Some(super::AdjustedRcvr { - rcvr_expr: lhs_expr, autoderefs: 0, unsize: false - }); self.lookup_method_in_trait_adjusted(expr.span, - lhs_expr, opname, trait_did, lhs_ty, @@ -413,18 +410,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method { Some(ok) => { - let method = self.register_infer_ok_obligations(ok); + let (autoref, method) = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(); - let method_ty = method.ty; - - // HACK(eddyb) Fully qualified path to work around a resolve bug. - let method_call = ::rustc::ty::MethodCall::expr(expr.id); - self.tables.borrow_mut().method_map.insert(method_call, method); + self.apply_adjustment(lhs_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: vec![], + autoref, + unsize: false + }, + target: *method.ty.fn_sig().input(0).skip_binder() + }); + self.tables.borrow_mut().method_map.insert(expr.id, method); // extract return type for method; all late bound regions // should have been instantiated by now - let ret_ty = method_ty.fn_ret(); + let ret_ty = method.ty.fn_ret(); Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap()) } None => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2c4188e392d..6cb9375c5de 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::region::{CodeExtent, RegionMaps}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; -use rustc::ty::{self, Ty, MethodCall, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use rustc::ty::adjustment; use rustc::ty::wf::ImpliedBound; @@ -520,8 +520,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, expr_region); - let method_call = MethodCall::expr(expr.id); - let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned(); + let opt_method_callee = self.tables.borrow().method_map.get(&expr.id).cloned(); let has_method_map = opt_method_callee.is_some(); // If we are calling a method (either explicitly or via an @@ -548,11 +547,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment.kind { - adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => { - let expr_ty = self.resolve_node_type(expr.id); - self.constrain_autoderefs(expr, autoderefs, expr_ty); + adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, .. } => { + let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs)); if let Some(ref autoref) = *autoref { - self.link_autoref(expr, autoderefs, autoref); + self.link_autoref(expr, cmt, autoref); // Require that the resulting region encompasses // the current node. @@ -690,8 +688,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - let method_call = MethodCall::expr(expr.id); - let base_ty = match self.tables.borrow().method_map.get(&method_call) { + let base_ty = match self.tables.borrow().method_map.get(&expr.id) { Some(method) => { self.constrain_call(expr, Some(&base), None::.iter(), true); @@ -914,79 +911,68 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// dereferenced, the lifetime of the pointer includes the deref expr. fn constrain_autoderefs(&mut self, deref_expr: &hir::Expr, - derefs: usize, - mut derefd_ty: Ty<'tcx>) + autoderefs: &[Option>]) + -> mc::McResult> { - debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})", + debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})", deref_expr, - derefs, - derefd_ty); + autoderefs); + + let mut cmt = { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + mc.cat_expr_unadjusted(deref_expr)? + }; let r_deref_expr = self.tcx.node_scope_region(deref_expr.id); - for i in 0..derefs { - let method_call = MethodCall::autoderef(deref_expr.id, i as u32); - debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); + for &overloaded in autoderefs { + if let Some(method) = overloaded { + debug!("constrain_autoderefs: overloaded, method={:?}", method); - let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); + let origin = infer::ParameterOrigin::OverloadedDeref; + self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - derefd_ty = match method { - Some(method) => { - debug!("constrain_autoderefs: #{} is overloaded, method={:?}", - i, method); - - let origin = infer::ParameterOrigin::OverloadedDeref; - self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - - // Treat overloaded autoderefs as if an AutoBorrow adjustment - // was applied on the base type, as that is always the case. - let fn_sig = method.ty.fn_sig(); - let fn_sig = // late-bound regions should have been instantiated - self.tcx.no_late_bound_regions(&fn_sig).unwrap(); - let self_ty = fn_sig.inputs()[0]; - let (m, r) = match self_ty.sty { - ty::TyRef(r, ref m) => (m.mutbl, r), - _ => { - span_bug!( - deref_expr.span, - "bad overloaded deref type {:?}", - method.ty) - } - }; - - debug!("constrain_autoderefs: receiver r={:?} m={:?}", - r, m); - - { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); - debug!("constrain_autoderefs: self_cmt={:?}", - self_cmt); - self.link_region(deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), self_cmt); + // Treat overloaded autoderefs as if an AutoBorrow adjustment + // was applied on the base type, as that is always the case. + let fn_sig = method.ty.fn_sig(); + let fn_sig = // late-bound regions should have been instantiated + self.tcx.no_late_bound_regions(&fn_sig).unwrap(); + let self_ty = fn_sig.inputs()[0]; + let (m, r) = match self_ty.sty { + ty::TyRef(r, ref m) => (m.mutbl, r), + _ => { + span_bug!( + deref_expr.span, + "bad overloaded deref type {:?}", + method.ty) } + }; - // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); - self.type_must_outlive(infer::CallReturn(deref_expr.span), - fn_sig.output(), r_deref_expr); - fn_sig.output() - } - None => derefd_ty - }; + debug!("constrain_autoderefs: receiver r={:?} m={:?}", + r, m); - if let ty::TyRef(r_ptr, _) = derefd_ty.sty { + debug!("constrain_autoderefs: self_cmt={:?}", cmt); + self.link_region(deref_expr.span, r, + ty::BorrowKind::from_mutbl(m), cmt.clone()); + + // Specialized version of constrain_call. + self.type_must_outlive(infer::CallRcvr(deref_expr.span), + self_ty, r_deref_expr); + self.type_must_outlive(infer::CallReturn(deref_expr.span), + fn_sig.output(), r_deref_expr); + } + + { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + cmt = mc.cat_deref(deref_expr, cmt, overloaded)?; + } + + if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { self.mk_subregion_due_to_dereference(deref_expr.span, r_deref_expr, r_ptr); } - - match derefd_ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => derefd_ty = mt.ty, - /* if this type can't be dereferenced, then there's already an error - in the session saying so. Just bail out for now */ - None => break - } } + + Ok(cmt) } pub fn mk_subregion_due_to_dereference(&mut self, @@ -1151,13 +1137,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// autoref'd. fn link_autoref(&self, expr: &hir::Expr, - autoderefs: usize, + expr_cmt: mc::cmt<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { - debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref); - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); - debug!("expr_cmt={:?}", expr_cmt); + debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 799d6186653..286d0ad1b35 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -216,9 +216,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); - let mut deferred_call_resolutions = + let deferred_call_resolutions = self.fcx.remove_deferred_call_resolutions(closure_def_id); - for deferred_call_resolution in &mut deferred_call_resolutions { + for deferred_call_resolution in deferred_call_resolutions { deferred_call_resolution.resolve(self.fcx); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b43e2423757..5fa5bb8f7af 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,7 +16,7 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; -use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; +use rustc::ty::{self, Ty, TyCtxt, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::util::nodemap::DefIdSet; @@ -106,7 +106,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty); if inner_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); + self.fcx.tables.borrow_mut().method_map.remove(&e.id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | @@ -118,7 +118,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { - self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); + self.fcx.tables.borrow_mut().method_map.remove(&e.id); // weird but true: the by-ref binops put an // adjustment on the lhs but not the rhs; the @@ -164,7 +164,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.fix_scalar_builtin_expr(e); self.visit_node_id(e.span, e.id); - self.visit_method_map_entry(e.span, MethodCall::expr(e.id)); + self.visit_method_map_entry(e.span, e.id); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); @@ -335,13 +335,16 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { - for autoderef in 0..autoderefs { - let method_call = MethodCall::autoderef(node_id, autoderef as u32); - self.visit_method_map_entry(span, method_call); - } - adjustment::Adjust::DerefRef { - autoderefs: autoderefs, + autoderefs: autoderefs.iter().map(|overloaded| { + overloaded.map(|method| { + MethodCallee { + def_id: method.def_id, + ty: self.resolve(&method.ty, &span), + substs: self.resolve(&method.substs, &span), + } + }) + }).collect(), autoref: self.resolve(&autoref, &span), unsize: unsize, } @@ -359,27 +362,22 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_method_map_entry(&mut self, method_span: Span, - method_call: MethodCall) { + node_id: ast::NodeId) { // Resolve any method map entry - let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) { + let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&node_id) { Some(method) => { - debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})", - method_call, - method); - let new_method = MethodCallee { + Some(MethodCallee { def_id: method.def_id, ty: self.resolve(&method.ty, &method_span), substs: self.resolve(&method.substs, &method_span), - }; - - Some(new_method) + }) } None => None }; //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE if let Some(method) = new_method { - self.tables.method_map.insert(method_call, method); + self.tables.method_map.insert(node_id, method); } }