diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index af18cddaddb01..06d585f8ea82f 100644 --- a/src/libcollections/tests/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -134,22 +134,22 @@ fn test_push() { fn test_push_unique() { let mut heap = BinaryHeap::>::from(vec![box 2, box 4, box 9]); assert_eq!(heap.len(), 3); - assert!(*heap.peek().unwrap() == box 9); + assert!(**heap.peek().unwrap() == 9); heap.push(box 11); assert_eq!(heap.len(), 4); - assert!(*heap.peek().unwrap() == box 11); + assert!(**heap.peek().unwrap() == 11); heap.push(box 5); assert_eq!(heap.len(), 5); - assert!(*heap.peek().unwrap() == box 11); + assert!(**heap.peek().unwrap() == 11); heap.push(box 27); assert_eq!(heap.len(), 6); - assert!(*heap.peek().unwrap() == box 27); + assert!(**heap.peek().unwrap() == 27); heap.push(box 3); assert_eq!(heap.len(), 7); - assert!(*heap.peek().unwrap() == box 27); + assert!(**heap.peek().unwrap() == 27); heap.push(box 103); assert_eq!(heap.len(), 8); - assert!(*heap.peek().unwrap() == box 103); + assert!(**heap.peek().unwrap() == 103); } fn check_to_vec(mut data: Vec) { diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index c1c195852f949..85b1858c875bc 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -355,11 +355,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => { + hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr) => { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => { + hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr) => { self.call(expr, pred, &e, None::.iter()) } @@ -412,16 +412,10 @@ 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) { - Some(method) => method.ty, - None => self.tables.expr_ty_adjusted(func_or_rcvr), - }; - let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); let ret = self.straightline(call_expr, func_or_rcvr_exit, args); // FIXME(canndrew): This is_never should probably be an is_uninhabited. - if fn_ty.fn_ret().0.is_never() { + if self.tables.expr_ty(call_expr).is_never() { self.add_unreachable_node() } else { ret diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index b43c516f317f2..a362dc31ff180 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -19,8 +19,6 @@ use std::mem; use syntax_pos::symbol::InternedString; use ty; -impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); - impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice where T: HashStable> { fn hash_stable(&self, @@ -101,19 +99,20 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Ad ty::adjustment::Adjust::ReifyFnPointer | ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | - ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { - autoderefs.hash_stable(hcx, hasher); + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => {} + ty::adjustment::Adjust::Deref(ref overloaded) => { + overloaded.hash_stable(hcx, hasher); + } + ty::adjustment::Adjust::Borrow(ref autoref) => { autoref.hash_stable(hcx, hasher); - unsize.hash_stable(hcx, hasher); } } } } 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::adjustment::OverloadedDeref<'tcx> { region, mutbl }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); @@ -601,11 +600,10 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { let ty::TypeckTables { - ref type_relative_path_defs, + ref type_dependent_defs, ref node_types, - ref item_substs, + ref node_substs, ref adjustments, - ref method_map, ref upvar_capture_map, ref closure_tys, ref closure_kinds, @@ -622,21 +620,10 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, type_dependent_defs); ich::hash_stable_nodemap(hcx, hasher, node_types); - ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, node_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_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 a6dbbee79a48c..f05f411945089 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 84ead6506c85c..6077b7863e2c3 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.type_dependent_defs[&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 2261f296454ef..74e1225f3948b 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,8 @@ 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 def_id = self.tables.type_dependent_defs[&expr.id].def_id(); + let base_type = self.tcx.type_of(def_id); 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 99b140f690a48..bb56439a157fe 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -263,12 +263,6 @@ macro_rules! return_if_err { ) } -/// Whether the elements of an overloaded operation are passed by value or by reference -enum PassArgs { - ByValue, - ByRef, -} - impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), region_maps: &'a RegionMaps, @@ -382,9 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprUnary(hir::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) { - self.select_from_expr(&base); - } + self.select_from_expr(&base); } hir::ExprField(ref base, _) => { // base.f @@ -396,13 +388,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, - &lhs, - vec![&rhs], - PassArgs::ByValue) { - self.select_from_expr(&lhs); - self.consume_expr(&rhs); - } + self.select_from_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprCall(ref callee, ref args) => { // callee(args) @@ -485,29 +472,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.walk_block(&blk); } - hir::ExprUnary(op, ref lhs) => { - let pass_args = if op.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) { - self.consume_expr(&lhs); - } + hir::ExprUnary(_, ref lhs) => { + self.consume_expr(&lhs); } - hir::ExprBinary(op, ref lhs, ref rhs) => { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) { - self.consume_expr(&lhs); - self.consume_expr(&rhs); - } + hir::ExprBinary(_, ref lhs, ref rhs) => { + self.consume_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprBlock(ref blk) => { @@ -529,14 +500,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - // NB All our assignment operations take the RHS by value - assert!(op.node.is_by_value()); - - if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { + hir::ExprAssignOp(_, ref lhs, ref rhs) => { + if self.mc.infcx.tables.borrow().is_method_call(expr) { + self.consume_expr(lhs); + } else { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); - self.consume_expr(&rhs); } + self.consume_expr(&rhs); } hir::ExprRepeat(ref base, _) => { @@ -563,19 +533,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 def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id(); + match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); self.borrow_expr(callee, @@ -715,102 +674,55 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // consumed or borrowed as part of the automatic adjustment // process. 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()); - if let Some(adjustment) = adj { + let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec(); + let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); + for adjustment in adjustments { + debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::ReifyFnPointer | adjustment::Adjust::UnsafeFnPointer | adjustment::Adjust::ClosureFnPointer | - adjustment::Adjust::MutToConstPointer => { + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::Unsize => { // 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); + self.delegate_consume(expr.id, expr.span, cmt.clone()); } - adjustment::Adjust::DerefRef { 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)); - - let cmt_refd = - self.walk_autoref(expr, cmt_derefd, autoref); - - if unsize { - // Unsizing consumes the thin pointer and produces a fat one. - self.delegate_consume(expr.id, expr.span, cmt_refd); - } + adjustment::Adjust::Deref(None) => {} + + // Autoderefs for overloaded Deref calls in fact reference + // their receiver. That is, if we have `(*x)` where `x` + // is of type `Rc`, then this in fact is equivalent to + // `x.deref()`. Since `deref()` is declared with `&self`, + // this is an autoref of `x`. + adjustment::Adjust::Deref(Some(ref deref)) => { + let bk = ty::BorrowKind::from_mutbl(deref.mutbl); + self.delegate.borrow(expr.id, expr.span, cmt.clone(), + deref.region, bk, AutoRef); } - } - } - } - /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have - /// `(*x)` where `x` is of type `Rc`, then this in fact is equivalent to `x.deref()`. Since - /// `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)); - - // 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 = 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) - }; - let bk = ty::BorrowKind::from_mutbl(m); - self.delegate.borrow(expr.id, expr.span, cmt, - r, bk, AutoRef); + adjustment::Adjust::Borrow(ref autoref) => { + self.walk_autoref(expr, cmt.clone(), autoref); + } } + cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); } } - /// Walks the autoref `opt_autoref` applied to the autoderef'd - /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` - /// after all relevant autoderefs have occurred. Because AutoRefs - /// can be recursive, this function is recursive: it first walks - /// deeply all the way down the autoref chain, and then processes - /// the autorefs on the way out. At each point, it returns the - /// `cmt` for the rvalue that will be produced by introduced an - /// autoref. + /// Walks the autoref `autoref` applied to the autoderef'd + /// `expr`. `cmt_base` is the mem-categorized form of `expr` + /// after all relevant autoderefs have occurred. fn walk_autoref(&mut self, expr: &hir::Expr, cmt_base: mc::cmt<'tcx>, - opt_autoref: Option>) - -> mc::cmt<'tcx> - { - debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", + autoref: &adjustment::AutoBorrow<'tcx>) { + debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})", expr.id, cmt_base, - opt_autoref); - - let cmt_base_ty = cmt_base.ty; - - let autoref = match opt_autoref { - Some(ref autoref) => autoref, - None => { - // No AutoRef. - return cmt_base; - } - }; + autoref); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { @@ -840,58 +752,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { AutoUnsafe); } } - - // Construct the categorization for the result of the autoref. - // This is always an rvalue, since we are producing a new - // (temporary) indirection. - - let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref); - - self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) - } - - - // When this returns true, it means that the expression *is* a - // method-call (i.e. via the operator-overload). This true result - // also implies that walk_overloaded_operator already took care of - // recursively processing the input arguments, and thus the caller - // should not do so. - fn walk_overloaded_operator(&mut self, - expr: &hir::Expr, - receiver: &hir::Expr, - rhs: Vec<&hir::Expr>, - pass_args: PassArgs) - -> bool - { - if !self.mc.infcx.is_method_call(expr.id) { - return false; - } - - match pass_args { - PassArgs::ByValue => { - self.consume_expr(receiver); - for &arg in &rhs { - self.consume_expr(arg); - } - - return true; - }, - PassArgs::ByRef => {}, - } - - self.walk_expr(receiver); - - // Arguments (but not receivers) to overloaded operator - // methods are implicitly autoref'd which sadly does not use - // adjustments, so we must hardcode the borrow here. - - let r = self.tcx().node_scope_region(expr.id); - let bk = ty::ImmBorrow; - - for &arg in &rhs { - self.borrow_expr(arg, r, bk, OverloadedOperator); - } - return true; } fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ecd350d127368..c6a42be6135cc 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1045,7 +1045,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAssignOp(_, ref l, ref r) => { // an overloaded assign op is like a method call - if self.tables.is_method_call(expr.id) { + if self.tables.is_method_call(expr) { let succ = self.propagate_through_expr(&l, succ); self.propagate_through_expr(&r, succ) } else { @@ -1072,9 +1072,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCall(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited - let diverges = !self.tables.is_method_call(expr.id) && - self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never(); - let succ = if diverges { + let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln } else { succ @@ -1084,10 +1082,8 @@ 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; // FIXME(canndrew): This is_never should really be an is_uninhabited - let succ = if method_ty.fn_ret().0.is_never() { + let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln } else { succ @@ -1370,7 +1366,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } hir::ExprAssignOp(_, ref l, _) => { - if !this.tables.is_method_call(expr.id) { + if !this.tables.is_method_call(expr) { this.check_lvalue(&l); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index d0adf51d79e68..53d8eecde5422 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -63,7 +63,6 @@ pub use self::PointerKind::*; pub use self::InteriorKind::*; pub use self::FieldName::*; -pub use self::ElementKind::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; @@ -94,7 +93,7 @@ pub enum Categorization<'tcx> { StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr + Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -129,7 +128,7 @@ pub enum PointerKind<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { InteriorField(FieldName), - InteriorElement(InteriorOffsetKind, ElementKind), + InteriorElement(InteriorOffsetKind), } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -144,12 +143,6 @@ pub enum InteriorOffsetKind { Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }` } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum ElementKind { - VecElement, - OtherElement, -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum MutabilityCategory { McImmutable, // Immutable. @@ -229,8 +222,8 @@ impl<'tcx> cmt_<'tcx> { pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => { // try to figure out where the immutable reference came from match base_cmt.cat { Categorization::Local(node_id) => @@ -255,13 +248,13 @@ impl<'tcx> cmt_<'tcx> { } Categorization::Rvalue(..) | Categorization::Upvar(..) | - Categorization::Deref(.., UnsafePtr(..)) => { + Categorization::Deref(_, UnsafePtr(..)) => { // This should not be reachable up to inference limitations. None } Categorization::Interior(ref base_cmt, _) | Categorization::Downcast(ref base_cmt, _) | - Categorization::Deref(ref base_cmt, _, _) => { + Categorization::Deref(ref base_cmt, _) => { base_cmt.immutability_blame() } Categorization::StaticItem => { @@ -473,53 +466,64 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_expr(&self, expr: &hir::Expr) -> McResult> { - match self.infcx.tables.borrow().adjustments.get(&expr.id) { - None => { - // No adjustments. - self.cat_expr_unadjusted(expr) - } - - Some(adjustment) => { - match adjustment.kind { - adjustment::Adjust::DerefRef { - autoderefs, - autoref: None, - unsize: false - } => { - // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) - } - - adjustment::Adjust::NeverToAny | - adjustment::Adjust::ReifyFnPointer | - adjustment::Adjust::UnsafeFnPointer | - 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)) - } + // This recursion helper avoids going through *too many* + // adjustments, since *only* non-overloaded deref recurses. + fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>, + expr: &hir::Expr, + adjustments: &[adjustment::Adjustment<'tcx>]) + -> McResult> { + match adjustments.split_last() { + None => mc.cat_expr_unadjusted(expr), + Some((adjustment, previous)) => { + mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment) } } } + + helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr)) + } + + pub fn cat_expr_adjusted(&self, expr: &hir::Expr, + previous: cmt<'tcx>, + adjustment: &adjustment::Adjustment<'tcx>) + -> McResult> { + self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) } - 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)?; + fn cat_expr_adjusted_with(&self, expr: &hir::Expr, + previous: F, + adjustment: &adjustment::Adjustment<'tcx>) + -> McResult> + where F: FnOnce() -> McResult> + { + debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); + let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target); + match adjustment.kind { + adjustment::Adjust::Deref(overloaded) => { + // Equivalent to *expr or something similar. + let base = if let Some(deref) = overloaded { + let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { + ty: target, + mutbl: deref.mutbl, + }); + self.cat_rvalue_node(expr.id, expr.span, ref_ty) + } else { + previous()? + }; + self.cat_deref(expr, base, false) + } + + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::ClosureFnPointer | + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::Borrow(_) | + adjustment::Adjust::Unsize => { + // Result is an rvalue. + Ok(self.cat_rvalue_node(expr.id, expr.span, target)) + } } - return Ok(cmt); } pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { @@ -528,8 +532,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; 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) + if self.infcx.tables.borrow().is_method_call(expr) { + self.cat_overloaded_lvalue(expr, e_base, false) + } else { + let base_cmt = self.cat_expr(&e_base)?; + self.cat_deref(expr, base_cmt, false) + } } hir::ExprField(ref base, f_name) => { @@ -547,33 +555,16 @@ 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) => { - // 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); - - // The index method always returns an `&T`, so - // dereference it to find the result type. - let elem_ty = match ret_ty.sty { - ty::TyRef(_, mt) => mt.ty, - _ => { - debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?", - ret_ty); - return Err(()); - } - }; - - // The call to index() returns a `&T` value, which - // is an rvalue. That is what we will be - // dereferencing. - let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty); - Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)) - } - None => { - self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index) - } + if self.infcx.tables.borrow().is_method_call(expr) { + // If this is an index implemented by a method call, then it + // will include an implicit deref of the result. + // The call to index() returns a `&T` value, which + // is an rvalue. That is what we will be + // dereferencing. + self.cat_overloaded_lvalue(expr, base, true) + } else { + let base_cmt = self.cat_expr(&base)?; + self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) } } @@ -763,7 +754,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cmt_ { id: id, span: span, - cat: Categorization::Deref(Rc::new(cmt_result), 0, ptr), + cat: Categorization::Deref(Rc::new(cmt_result), ptr), mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind), ty: var_ty, note: NoteUpvarRef(upvar_id) @@ -823,7 +814,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ret = cmt_ { id: id, span: span, - cat: Categorization::Deref(Rc::new(cmt_result), 0, env_ptr), + cat: Categorization::Deref(Rc::new(cmt_result), env_ptr), mutbl: deref_mutbl, ty: var_ty, note: NoteClosureEnv(upvar_id) @@ -932,51 +923,51 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - deref_cnt: usize) + fn cat_overloaded_lvalue(&self, + expr: &hir::Expr, + base: &hir::Expr, + implicit: bool) -> 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); + debug!("cat_overloaded_lvalue: implicit={}", implicit); - debug!("cat_deref: method_call={:?} method_ty={:?}", - method_call, method_ty.map(|ty| ty)); + // Reconstruct the output assuming it's a reference with the + // same region and mutability as the receiver. This holds for + // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + let lvalue_ty = self.expr_ty(expr)?; + let base_ty = self.expr_ty_adjusted(base)?; - let base_cmt = match method_ty { - Some(method_ty) => { - let ref_ty = - self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap(); - self.cat_rvalue_node(node.id(), node.span(), ref_ty) + let (region, mutbl) = match base_ty.sty { + ty::TyRef(region, mt) => (region, mt.mutbl), + _ => { + span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference") } - None => base_cmt }; + let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { + ty: lvalue_ty, + mutbl, + }); + + let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); + self.cat_deref(expr, base_cmt, implicit) + } + + pub fn cat_deref(&self, + node: &N, + base_cmt: cmt<'tcx>, + implicit: bool) + -> McResult> { + debug!("cat_deref: base_cmt={:?}", base_cmt); + let base_cmt_ty = base_cmt.ty; - match base_cmt_ty.builtin_deref(true, ty::NoPreference) { - Some(mt) => { - let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false); - debug!("cat_deref ret {:?}", ret); - Ok(ret) - } + let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) { + Some(mt) => mt.ty, None => { debug!("Explicit deref of non-derefable type: {:?}", base_cmt_ty); return Err(()); } - } - } + }; - fn cat_deref_common(&self, - node: &N, - base_cmt: cmt<'tcx>, - deref_cnt: usize, - deref_ty: Ty<'tcx>, - implicit: bool) - -> cmt<'tcx> - { let ptr = match base_cmt.ty.sty { ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), @@ -984,26 +975,27 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let bk = ty::BorrowKind::from_mutbl(mt.mutbl); if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } } - ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty) + ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; let ret = Rc::new(cmt_ { id: node.id(), span: node.span(), // For unique ptrs, we inherit mutability from the owning reference. mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), - cat: Categorization::Deref(base_cmt, deref_cnt, ptr), + cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, note: NoteNone }); - debug!("cat_deref_common ret {:?}", ret); - ret + debug!("cat_deref ret {:?}", ret); + Ok(ret) } - pub fn cat_index(&self, - elt: &N, - mut base_cmt: cmt<'tcx>, - context: InteriorOffsetKind) - -> McResult> { + fn cat_index(&self, + elt: &N, + base_cmt: cmt<'tcx>, + element_ty: Ty<'tcx>, + context: InteriorOffsetKind) + -> McResult> { //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be @@ -1021,31 +1013,9 @@ 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); - base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); - - (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty, - ElementKind::OtherElement) - } - None => { - match base_cmt.ty.builtin_index() { - Some(ty) => (ty, ElementKind::VecElement), - None => { - debug!("Explicit index of non-indexable type {:?}", base_cmt); - return Err(()); - } - } - } - }; - - let interior_elem = InteriorElement(context, element_kind); + let interior_elem = InteriorElement(context); let ret = - self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem); + self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); debug!("cat_index ret {:?}", ret); return Ok(ret); } @@ -1235,13 +1205,20 @@ 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 subcmt = self.cat_deref(pat, cmt, false)?; self.cat_pattern_(subcmt, &subpat, op)?; } PatKind::Slice(ref before, ref slice, ref after) => { + let element_ty = match cmt.ty.builtin_index() { + Some(ty) => ty, + None => { + debug!("Explicit index of non-indexable type {:?}", cmt); + return Err(()); + } + }; let context = InteriorOffsetKind::Pattern; - let elt_cmt = self.cat_index(pat, cmt, context)?; + let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?; for before_pat in before { self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; } @@ -1261,19 +1238,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(()) } - - fn overloaded_method_return_ty(&self, - method_ty: Ty<'tcx>) - -> Ty<'tcx> - { - // When we process an overloaded `*` or `[]` etc, we often - // need to extract the return type of the method. These method - // 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() - } } #[derive(Clone, Debug)] @@ -1300,15 +1264,15 @@ impl<'tcx> cmt_<'tcx> { Categorization::Rvalue(..) | Categorization::StaticItem | Categorization::Local(..) | - Categorization::Deref(.., UnsafePtr(..)) | - Categorization::Deref(.., BorrowedPtr(..)) | - Categorization::Deref(.., Implicit(..)) | + Categorization::Deref(_, UnsafePtr(..)) | + Categorization::Deref(_, BorrowedPtr(..)) | + Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { Rc::new((*self).clone()) } Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) | - Categorization::Deref(ref b, _, Unique) => { + Categorization::Deref(ref b, Unique) => { b.guarantor() } } @@ -1321,11 +1285,11 @@ impl<'tcx> cmt_<'tcx> { // aliased and eventually recused. match self.cat { - Categorization::Deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) | - Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | - Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, _, Unique) | + Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) | + Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) | + Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt @@ -1335,7 +1299,7 @@ impl<'tcx> cmt_<'tcx> { Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | - Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but... + Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but... NonAliasable } @@ -1347,8 +1311,8 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => { FreelyAliasable(AliasableBorrowed) } } @@ -1360,9 +1324,9 @@ impl<'tcx> cmt_<'tcx> { match self.note { NoteClosureEnv(..) | NoteUpvarRef(..) => { Some(match self.cat { - Categorization::Deref(ref inner, ..) => { + Categorization::Deref(ref inner, _) => { match inner.cat { - Categorization::Deref(ref inner, ..) => inner.clone(), + Categorization::Deref(ref inner, _) => inner.clone(), Categorization::Upvar(..) => inner.clone(), _ => bug!() } @@ -1390,7 +1354,7 @@ impl<'tcx> cmt_<'tcx> { "local variable".to_string() } } - Categorization::Deref(.., pk) => { + Categorization::Deref(_, pk) => { let upvar = self.upvar(); match upvar.as_ref().map(|i| &i.cat) { Some(&Categorization::Upvar(ref var)) => { @@ -1421,16 +1385,10 @@ impl<'tcx> cmt_<'tcx> { Categorization::Interior(_, InteriorField(PositionalField(_))) => { "anonymous field".to_string() } - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index, - VecElement)) | - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index, - OtherElement)) => { + Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => { "indexed content".to_string() } - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern, - VecElement)) | - Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern, - OtherElement)) => { + Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => { "pattern-bound indexed content".to_string() } Categorization::Upvar(ref var) => { @@ -1467,8 +1425,8 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> { Categorization::Upvar(upvar) => { write!(f, "upvar({:?})", upvar) } - Categorization::Deref(ref cmt, derefs, ptr) => { - write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs) + Categorization::Deref(ref cmt, ptr) => { + write!(f, "{:?}-{:?}->", cmt.cat, ptr) } Categorization::Interior(ref cmt, interior) => { write!(f, "{:?}.{:?}", cmt.cat, interior) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 939d7364d9e06..c2f69147e3a56 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -110,9 +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; - Some(Def::Method(def_id)) + Some(self.tables.type_dependent_defs[&expr.id]) } _ => None }; diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 385591e10f744..62d137475f90e 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -8,21 +8,59 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, Ty, TyCtxt, TypeAndMut}; -use ty::LvaluePreference::{NoPreference}; - -use syntax::ast; -use syntax_pos::Span; - use hir; +use hir::def_id::DefId; +use ty::{self, Ty, TyCtxt}; +use ty::subst::Substs; + -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +/// Represents coercing a value to a different type of value. +/// +/// We transform values by following a number of `Adjust` steps in order. +/// See the documentation on variants of `Adjust` for more details. +/// +/// Here are some common scenarios: +/// +/// 1. The simplest cases are where a 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 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 +/// `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 dynamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// Deref(None) -> [i32; 4], +/// Borrow(AutoBorrow::Ref) -> &[i32; 4], +/// Unsize -> &[i32], +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, - pub target: Ty<'tcx> + pub target: Ty<'tcx>, } -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, @@ -39,94 +77,45 @@ pub enum Adjust<'tcx> { /// Go from a mut raw pointer to a const raw pointer. MutToConstPointer, - /// Represents coercing a pointer to a different kind of pointer - where 'kind' - /// 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). - /// 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, - /// 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 - /// pointers. We don't store the details of how the transform is - /// done (in fact, we don't know that, because it might depend on - /// the precise type parameters). We just store the target - /// type. Trans figures out what has to be done at monomorphization - /// time based on the precise source/target type at hand. - /// - /// To make that more concrete, here are some common scenarios: - /// - /// 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 - /// `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. - /// - /// 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 - /// represented by: - /// - /// ``` - /// Adjust::DerefRef { - /// autoderefs: 1, // &[i32; 4] -> [i32; 4] - /// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32] - /// unsize: Some([i32]), // [i32; 4] -> [i32] - /// } - /// ``` - /// - /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. - /// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> - /// The autoderef and -ref are the same as in the above example, but the type - /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about - /// the underlying conversions from `[i32; 4]` to `[i32]`. - /// - /// 3. Coercing a `Box` to `Box` is an interesting special case. In - /// that case, we have the pointer we need coming in, so there are no - /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. - /// At some point, of course, `Box` should move out of the compiler, in which - /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> - /// Box<[i32]> is represented by: - /// - /// ``` - /// Adjust::DerefRef { - /// autoderefs: 0, - /// autoref: None, - /// unsize: Some(Box<[i32]>), - /// } - /// ``` - DerefRef { - /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: usize, - - /// Step 2. Optionally produce a pointer/reference from the value. - autoref: Option>, - - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - unsize: bool, - } + /// Dereference once, producing an lvalue. + Deref(Option>), + + /// Take the address and produce either a `&` or `*` pointer. + Borrow(AutoBorrow<'tcx>), + + /// Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + /// This 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 + /// pointers. We don't store the details of how the transform is + /// done (in fact, we don't know that, because it might depend on + /// the precise type parameters). We just store the target + /// type. Trans figures out what has to be done at monomorphization + /// time based on the precise source/target type at hand. + Unsize, } -impl<'tcx> Adjustment<'tcx> { - pub fn is_identity(&self) -> bool { - match self.kind { - Adjust::NeverToAny => self.target.is_never(), - - Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true, +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. +/// The target type is `U` in both cases, with the region and mutability +/// being those shared by both the receiver and the returned reference. +#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] +pub struct OverloadedDeref<'tcx> { + pub region: ty::Region<'tcx>, + pub mutbl: hir::Mutability, +} - Adjust::ReifyFnPointer | - Adjust::UnsafeFnPointer | - Adjust::ClosureFnPointer | - Adjust::MutToConstPointer | - Adjust::DerefRef {..} => false, - } +impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> { + pub fn method_call(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source: Ty<'tcx>) + -> (DefId, &'tcx Substs<'tcx>) { + let trait_def_id = match self.mutbl { + hir::MutImmutable => tcx.lang_items.deref_trait(), + hir::MutMutable => tcx.lang_items.deref_mut_trait() + }; + let method_def_id = tcx.associated_items(trait_def_id.unwrap()) + .find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id; + (method_def_id, tcx.mk_substs_trait(source, &[])) } } @@ -159,48 +148,3 @@ pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. Struct(usize) } - -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> { - match autoref { - None => self, - Some(AutoBorrow::Ref(r, m)) => { - tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) - } - Some(AutoBorrow::RawPtr(m)) => { - tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) - } - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8c801c6fa2b97..e0e195867131f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -206,8 +206,9 @@ pub struct CommonTypes<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct TypeckTables<'tcx> { - /// Resolved definitions for `::X` associated paths. - pub type_relative_path_defs: NodeMap, + /// Resolved definitions for `::X` associated paths and + /// method calls, including those of overloaded operators. + pub type_dependent_defs: NodeMap, /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See @@ -218,11 +219,9 @@ pub struct TypeckTables<'tcx> { /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or /// other items. - pub item_substs: NodeMap>, + pub node_substs: NodeMap<&'tcx Substs<'tcx>>, - pub adjustments: NodeMap>, - - pub method_map: ty::MethodMap<'tcx>, + pub adjustments: NodeMap>>, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -271,11 +270,10 @@ pub struct TypeckTables<'tcx> { impl<'tcx> TypeckTables<'tcx> { pub fn empty() -> TypeckTables<'tcx> { TypeckTables { - type_relative_path_defs: NodeMap(), + type_dependent_defs: NodeMap(), node_types: FxHashMap(), - item_substs: NodeMap(), + node_substs: NodeMap(), adjustments: NodeMap(), - method_map: FxHashMap(), upvar_capture_map: FxHashMap(), closure_tys: NodeMap(), closure_kinds: NodeMap(), @@ -294,7 +292,7 @@ impl<'tcx> TypeckTables<'tcx> { match *qpath { hir::QPath::Resolved(_, ref path) => path.def, hir::QPath::TypeRelative(..) => { - self.type_relative_path_defs.get(&id).cloned().unwrap_or(Def::Err) + self.type_dependent_defs.get(&id).cloned().unwrap_or(Def::Err) } } } @@ -313,8 +311,8 @@ impl<'tcx> TypeckTables<'tcx> { self.node_types.get(&id).cloned() } - pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> { - self.item_substs.get(&id).map(|ts| ts.substs) + pub fn node_substs(&self, id: NodeId) -> &'tcx Substs<'tcx> { + self.node_substs.get(&id).cloned().unwrap_or(Substs::empty()) } // Returns the type of a pattern as a monotype. Like @expr_ty, this function @@ -345,24 +343,37 @@ impl<'tcx> TypeckTables<'tcx> { self.node_id_to_type_opt(expr.id) } + pub fn expr_adjustments(&self, expr: &hir::Expr) + -> &[ty::adjustment::Adjustment<'tcx>] { + self.adjustments.get(&expr.id).map_or(&[], |a| &a[..]) + } + /// Returns the type of `expr`, considering any `Adjustment` /// entry recorded for that expression. pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.adjustments.get(&expr.id) + self.expr_adjustments(expr) + .last() .map_or_else(|| self.expr_ty(expr), |adj| adj.target) } pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { - self.adjustments.get(&expr.id) - .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) + self.expr_adjustments(expr) + .last() + .map(|adj| adj.target) + .or_else(|| self.expr_ty_opt(expr)) } - pub fn is_method_call(&self, expr_id: NodeId) -> bool { - self.method_map.contains_key(&ty::MethodCall::expr(expr_id)) - } + pub fn is_method_call(&self, expr: &hir::Expr) -> bool { + // Only paths and method calls/overloaded operators have + // entries in type_dependent_defs, ignore the former here. + if let hir::ExprPath(_) = expr.node { + return false; + } - pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { - self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs)) + match self.type_dependent_defs.get(&expr.id) { + Some(&Def::Method(_)) => true, + _ => false + } } pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index c17a54f4f69bb..bb13031a2b7c4 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,8 +39,6 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. -use ty::subst::Substs; -use ty::adjustment; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; @@ -138,34 +136,9 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { t.super_fold_with(self) } - fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> { - t.super_fold_with(self) - } - - fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> { - imp.super_fold_with(self) - } - - fn fold_substs(&mut self, - substs: &'tcx Substs<'tcx>) - -> &'tcx Substs<'tcx> { - substs.super_fold_with(self) - } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - sig.super_fold_with(self) - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } - - fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>) - -> adjustment::AutoBorrow<'tcx> { - ar.super_fold_with(self) - } } pub trait TypeVisitor<'tcx> : Sized { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 22fcc61953b2b..b495b5ee81a9a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -390,52 +390,6 @@ impl Variance { } } -#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)] -pub struct MethodCallee<'tcx> { - /// Impl method ID, for inherent methods, or trait method ID, otherwise. - pub def_id: DefId, - pub ty: Ty<'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)] @@ -1843,13 +1797,6 @@ impl<'a, 'gcx, 'tcx> FieldDef { } } -/// Records the substitutions used to translate the polytype for an -/// item into the monotype of an item reference. -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct ItemSubsts<'tcx> { - pub substs: &'tcx Substs<'tcx>, -} - #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen @@ -1927,12 +1874,6 @@ impl<'tcx> TyS<'tcx> { } } -impl<'tcx> ItemSubsts<'tcx> { - pub fn is_noop(&self) -> bool { - self.substs.is_noop() - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index c3ca679153759..3a6147f911cce 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -217,12 +217,50 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> { - type Lifted = ty::ItemSubsts<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { + type Lifted = ty::adjustment::Adjustment<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.substs).map(|substs| { - ty::ItemSubsts { - substs: substs + tcx.lift(&self.kind).and_then(|kind| { + tcx.lift(&self.target).map(|target| { + ty::adjustment::Adjustment { kind, target } + }) + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { + type Lifted = ty::adjustment::Adjust<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ty::adjustment::Adjust::NeverToAny => + Some(ty::adjustment::Adjust::NeverToAny), + ty::adjustment::Adjust::ReifyFnPointer => + Some(ty::adjustment::Adjust::ReifyFnPointer), + ty::adjustment::Adjust::UnsafeFnPointer => + Some(ty::adjustment::Adjust::UnsafeFnPointer), + ty::adjustment::Adjust::ClosureFnPointer => + Some(ty::adjustment::Adjust::ClosureFnPointer), + ty::adjustment::Adjust::MutToConstPointer => + Some(ty::adjustment::Adjust::MutToConstPointer), + ty::adjustment::Adjust::Unsize => + Some(ty::adjustment::Adjust::Unsize), + ty::adjustment::Adjust::Deref(ref overloaded) => { + tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow) + } + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { + type Lifted = ty::adjustment::OverloadedDeref<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.region).map(|region| { + ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, } }) } @@ -540,10 +578,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_mt(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.ty.visit_with(visitor) } @@ -560,10 +594,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_fn_sig(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.inputs().iter().any(|i| i.visit_with(visitor)) || self.output().visit_with(visitor) @@ -610,10 +640,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_impl_header(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.self_ty.visit_with(visitor) || self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) || @@ -651,15 +677,66 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ItemSubsts { - substs: self.substs.fold_with(folder), + ty::adjustment::Adjustment { + kind: self.kind.fold_with(folder), + target: self.target.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.substs.visit_with(visitor) + self.kind.visit_with(visitor) || + self.target.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => self.clone(), + ty::adjustment::Adjust::Deref(ref overloaded) => { + ty::adjustment::Adjust::Deref(overloaded.fold_with(folder)) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + ty::adjustment::Adjust::Borrow(autoref.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Unsize => false, + ty::adjustment::Adjust::Deref(ref overloaded) => { + overloaded.visit_with(visitor) + } + ty::adjustment::Adjust::Borrow(ref autoref) => { + autoref.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::adjustment::OverloadedDeref { + region: self.region.fold_with(folder), + mutbl: self.mutbl, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.region.visit_with(visitor) } } @@ -673,10 +750,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_autoref(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bbb399434d6ae..0925a4032fba3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -141,8 +141,6 @@ pub enum TypeVariants<'tcx> { TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>), /// A pointer to a function. Written as `fn() -> i32`. - /// FIXME: This is currently also used to represent the callee of a method; - /// see ty::MethodCallee etc. TyFnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. @@ -1338,15 +1336,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Type accessors for substructures of types - pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> { - self.fn_sig().inputs() - } - - pub fn fn_ret(&self) -> Binder> { - self.fn_sig().output() - } - pub fn is_fn(&self) -> bool { match self.sty { TyFnDef(..) | TyFnPtr(_) => true, diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e23003bf772f2..d0d61323392c7 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -320,10 +320,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_substs(self) - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { self.iter().any(|t| t.visit_with(visitor)) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 5a1b7393db312..15fbeb5108fdb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -363,12 +363,6 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ItemSubsts({:?})", self.substs) - } -} - impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // when printing out the debug representation, we don't need diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 722ec6424fece..0fe8865f4a268 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -805,7 +805,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.check_if_assigned_path_is_moved(id, span, use_kind, lp_base); } - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) | + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) | LpExtend(ref lp_base, _, LpDeref(_)) => { // assigning to `P[i]` requires `P` is initialized // assigning to `(*P)` requires `P` is initialized diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index f193588dd7d6c..3d98c2a23dc67 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -222,9 +222,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, cmt: &mc::cmt<'tcx>) -> Option> { match cmt.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { Some(cmt.clone()) } @@ -237,7 +237,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) | - Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { + Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => { match b.ty.sty { ty::TyAdt(def, _) => { if def.has_dtor(bccx.tcx) { @@ -253,12 +253,12 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } - Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => { + Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => { // Forbid move of arr[i] for arr: [T; 3]; see RFC 533. Some(cmt.clone()) } - Categorization::Deref(ref b, _, mc::Unique) => { + Categorization::Deref(ref b, mc::Unique) => { check_and_get_illegal_move_origin(bccx, b) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 5fc5682a60b45..0a6375ab187d6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -72,11 +72,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { match cmt.cat { Categorization::Rvalue(..) | - Categorization::Local(..) | // L-Local + Categorization::Local(..) | // L-Local Categorization::Upvar(..) | - Categorization::Deref(.., mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) => { self.check_scope(self.scope(cmt)) } @@ -85,8 +85,8 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } Categorization::Downcast(ref base, _) | - Categorization::Deref(ref base, _, mc::Unique) | // L-Deref-Send - Categorization::Interior(ref base, _) => { // L-Field + Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send + Categorization::Interior(ref base, _) => { // L-Field self.check(base, discr_scope) } } @@ -119,15 +119,15 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { self.bccx.region_maps.var_scope(local_id))) } Categorization::StaticItem | - Categorization::Deref(.., mc::UnsafePtr(..)) => { + Categorization::Deref(_, mc::UnsafePtr(..)) => { self.bccx.tcx.types.re_static } - Categorization::Deref(.., mc::BorrowedPtr(_, r)) | - Categorization::Deref(.., mc::Implicit(_, r)) => { + Categorization::Deref(_, mc::BorrowedPtr(_, r)) | + Categorization::Deref(_, mc::Implicit(_, r)) => { r } Categorization::Downcast(ref cmt, _) | - Categorization::Deref(ref cmt, _, mc::Unique) | + Categorization::Deref(ref cmt, mc::Unique) | Categorization::Interior(ref cmt, _) => { self.scope(cmt) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 1ee6d565d0d7d..cceb4a7b3cc21 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -138,9 +138,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_from: mc::cmt<'tcx>) -> DiagnosticBuilder<'a> { match move_from.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) | - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { let mut err = struct_span_err!(bccx, move_from.span, E0507, "cannot move out of {}", @@ -152,7 +152,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, err } - Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => { + Categorization::Interior(ref b, mc::InteriorElement(ik)) => { match (&b.ty.sty, ik) { (&ty::TySlice(..), _) | (_, Kind::Index) => { diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 7f90a8b19d4a1..b7965f81b8826 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { RestrictionResult::Safe } - Categorization::Deref(cmt_base, _, pk) => { + Categorization::Deref(cmt_base, pk) => { match pk { mc::Unique => { // R-Deref-Send-Pointer diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 9b084acc1938f..2b5bbe0e8a5df 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -284,7 +284,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { InteriorField(mc::FieldName), - InteriorElement(mc::ElementKind), + InteriorElement, } trait ToInteriorKind { fn cleaned(self) -> InteriorKind; } @@ -292,7 +292,7 @@ impl ToInteriorKind for mc::InteriorKind { fn cleaned(self) -> InteriorKind { match self { mc::InteriorField(name) => InteriorField(name), - mc::InteriorElement(_, elem_kind) => InteriorElement(elem_kind), + mc::InteriorElement(_) => InteriorElement, } } } @@ -426,7 +426,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { Some(new_lp(LpUpvar(id))) } - Categorization::Deref(ref cmt_base, _, pk) => { + Categorization::Deref(ref cmt_base, pk) => { opt_loan_path(cmt_base).map(|lp| { new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk))) }) @@ -1232,7 +1232,7 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ } } - LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => { self.append_autoderefd_loan_path_to_string(&lp_base, out); out.push_str("[..]"); } @@ -1318,7 +1318,7 @@ impl<'tcx> fmt::Debug for InteriorKind { match *self { InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld), InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i), - InteriorElement(..) => write!(f, "[]"), + InteriorElement => write!(f, "[]"), } } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 1b364596a23f7..0a31905c7928a 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -191,7 +191,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool { LpVar(_) | LpUpvar(_) => { true } - LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => { + LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => { // Paths involving element accesses a[i] do not refer to a unique // location, as there is no accurate tracking of the indices. // diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index e79f23aee1145..a6b39f22277de 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -286,8 +286,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprPath(ref qpath) => { - let substs = cx.tables.node_id_item_substs(e.id) - .unwrap_or_else(|| tcx.intern_substs(&[])); + let substs = cx.tables.node_substs(e.id); // Avoid applying substitutions if they're empty, that'd ICE. let substs = if cx.substs.is_empty() { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a2e0bb80d23dd..d175920e8a6ba 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -584,8 +584,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let tcx = self.tcx.global_tcx(); - let substs = self.tables.node_id_item_substs(id) - .unwrap_or_else(|| tcx.intern_substs(&[])); + let substs = self.tables.node_substs(id); match eval::lookup_const_by_id(tcx, def_id, substs) { Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f1d014692a4b8..12bfb1e02cf6f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -881,30 +881,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { -> bool { 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 method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { - return true; - } - } + // Ignore non-expressions. + let expr = if let hir_map::NodeExpr(e) = cx.tcx.hir.get(id) { + e + } else { + return false; + }; // 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 method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) { - return true; - } + let mut source = cx.tables.expr_ty(expr); + for adjustment in cx.tables.expr_adjustments(expr) { + if let Adjust::Deref(Some(deref)) = adjustment.kind { + let (def_id, substs) = deref.method_call(cx.tcx, source); + if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + return true; } } + source = adjustment.target; + } + + // Check for method calls and overloaded operators. + if cx.tables.is_method_call(expr) { + let def_id = cx.tables.type_dependent_defs[&id].def_id(); + let substs = cx.tables.node_substs(id); + if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + return true; + } } // Check for calls to methods via explicit paths (e.g. `T::method()`). - match cx.tcx.hir.get(id) { - hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { + match expr.node { + hir::ExprCall(ref callee, _) => { let def = if let hir::ExprPath(ref qpath) = callee.node { cx.tables.qpath_def(qpath, callee.id) } else { @@ -912,8 +919,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { }; match def { Def::Method(def_id) => { - let substs = cx.tables.node_id_item_substs(callee.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables.node_substs(callee.id); method_call_refers_to_method( cx.tcx, method, def_id, substs, id) } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 93ff609a280ae..0c82679c307d3 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -468,21 +468,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { _ => return, } - if let Some(adjustment) = cx.tables.adjustments.get(&e.id) { - if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind { - match autoref { - Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use & instead"); - } - Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { - cx.span_lint(UNUSED_ALLOCATION, - e.span, - "unnecessary allocation, use &mut instead"); - } - _ => (), - } + for adj in cx.tables.expr_adjustments(e) { + if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { + let msg = match m { + hir::MutImmutable => "unnecessary allocation, use & instead", + hir::MutMutable => "unnecessary allocation, use &mut instead" + }; + cx.span_lint(UNUSED_ALLOCATION, e.span, msg); } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 5982d3bdc81a4..d456bc3ded390 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -201,13 +201,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args } => { - let diverges = match ty.sty { - ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - f.output().skip_binder().is_never() - } - _ => false - }; + // FIXME(canndrew): This is_never should probably be an is_uninhabited + let diverges = expr.ty.is_never(); let intrinsic = match ty.sty { ty::TyFnDef(def_id, _, ref f) if f.abi() == Abi::RustIntrinsic || diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b180d982e86b6..2c3f51969267f 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,9 +17,10 @@ use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; +use rustc::ty::subst::Subst; use rustc::hir; -use syntax::ptr::P; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; @@ -31,175 +32,13 @@ 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(); - - debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", - expr, - adj); // Now apply adjustments, if any. - match adj.map(|adj| (adj.kind, adj.target)) { - None => {} - Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, - }; - } - Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, - }; - } - Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::ClosureFnPointer { source: expr.to_ref() }, - }; - } - Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::NeverToAny { source: expr.to_ref() }, - }; - } - Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() }, - }; - } - Some((ty::adjustment::Adjust::DerefRef { 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); - - 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), - _ => span_bug!(expr.span, "autoderef returned bad type"), - }; - - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: expr.ty, - mutbl: mutbl, - }), - span: expr.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: to_borrow_kind(mutbl), - arg: expr.to_ref(), - }, - }; - - overloaded_lvalue(cx, - self, - method_key, - PassArgs::ByRef, - expr.to_ref(), - vec![]) - } else { - debug!("make_mirror: built-in autoderef"); - ExprKind::Deref { arg: expr.to_ref() } - }; - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: kind, - }; - } - - if let Some(autoref) = autoref { - let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); - match autoref { - ty::adjustment::AutoBorrow::Ref(r, m) => { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Borrow { - region: r, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - } - ty::adjustment::AutoBorrow::RawPtr(m) => { - // Convert this to a suitable `&foo` and - // then an unsafe coercion. Limit the region to be just this - // expression. - let region = ty::ReScope(expr_extent); - let region = cx.tcx.mk_region(region); - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: expr.ty, - mutbl: m, - }), - span: self.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: to_borrow_kind(m), - arg: expr.to_ref(), - }, - }; - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Cast { source: expr.to_ref() }, - }; - } - } - } - - if unsize { - expr = Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: self.span, - kind: ExprKind::Unsize { source: expr.to_ref() }, - }; - } - } + for adjustment in cx.tables().expr_adjustments(self) { + debug!("make_mirror: expr={:?} applying adjustment={:?}", + expr, + adjustment); + expr = apply_adjustment(cx, self, expr, adjustment); } // Next, wrap this up in the expr's scope. @@ -233,6 +72,96 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } +fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + hir_expr: &'tcx hir::Expr, + mut expr: Expr<'tcx>, + adjustment: &Adjustment<'tcx>) + -> Expr<'tcx> { + let Expr { temp_lifetime, temp_lifetime_was_shrunk, span, .. } = expr; + let kind = match adjustment.kind { + Adjust::ReifyFnPointer => { + ExprKind::ReifyFnPointer { source: expr.to_ref() } + } + Adjust::UnsafeFnPointer => { + ExprKind::UnsafeFnPointer { source: expr.to_ref() } + } + Adjust::ClosureFnPointer => { + ExprKind::ClosureFnPointer { source: expr.to_ref() } + } + Adjust::NeverToAny => { + ExprKind::NeverToAny { source: expr.to_ref() } + } + Adjust::MutToConstPointer => { + ExprKind::Cast { source: expr.to_ref() } + } + Adjust::Deref(None) => { + ExprKind::Deref { arg: expr.to_ref() } + } + Adjust::Deref(Some(deref)) => { + let call = deref.method_call(cx.tcx, expr.ty); + + expr = Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: cx.tcx.mk_ref(deref.region, + ty::TypeAndMut { + ty: expr.ty, + mutbl: deref.mutbl, + }), + span, + kind: ExprKind::Borrow { + region: deref.region, + borrow_kind: to_borrow_kind(deref.mutbl), + arg: expr.to_ref(), + }, + }; + + overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) + } + Adjust::Borrow(AutoBorrow::Ref(r, m)) => { + ExprKind::Borrow { + region: r, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + } + } + Adjust::Borrow(AutoBorrow::RawPtr(m)) => { + // Convert this to a suitable `&foo` and + // then an unsafe coercion. Limit the region to be just this + // expression. + let region = ty::ReScope(CodeExtent::Misc(hir_expr.id)); + let region = cx.tcx.mk_region(region); + expr = Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: expr.ty, + mutbl: m, + }), + span, + kind: ExprKind::Borrow { + region: region, + borrow_kind: to_borrow_kind(m), + arg: expr.to_ref(), + }, + }; + ExprKind::Cast { source: expr.to_ref() } + } + Adjust::Unsize => { + ExprKind::Unsize { source: expr.to_ref() } + } + }; + + Expr { + temp_lifetime, + temp_lifetime_was_shrunk, + ty: adjustment.target, + span, + kind, + } +} + fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { @@ -243,7 +172,7 @@ 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 expr = method_callee(cx, expr, None); let args = args.iter() .map(|e| e.to_ref()) .collect(); @@ -255,7 +184,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 cx.tables().is_method_call(expr) { // 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,18 +192,11 @@ 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 sig = method.ty.fn_sig(); - - let sig = cx.tcx - .no_late_bound_regions(&sig) - .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions")); - - assert_eq!(sig.inputs().len(), 2); + let method = method_callee(cx, expr, None); + let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e)); let tupled_args = Expr { - ty: sig.inputs()[1], + ty: cx.tcx.mk_tup(arg_tys, false), temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, span: expr.span, @@ -302,8 +224,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, None }; if let Some((adt_def, index)) = adt_data { - let substs = cx.tables().node_id_item_substs(fun.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables().node_substs(fun.id); let field_refs = args.iter() .enumerate() .map(|(idx, e)| { @@ -352,18 +273,8 @@ 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) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - ty::MethodCall::expr(expr.id), - pass_args, - lhs.to_ref(), - vec![rhs]) + if cx.tables().is_method_call(expr) { + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { ExprKind::AssignOp { op: bin_op(op.node), @@ -376,18 +287,8 @@ 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) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - ty::MethodCall::expr(expr.id), - pass_args, - lhs.to_ref(), - vec![rhs]) + if cx.tables().is_method_call(expr) { + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { // FIXME overflow match (op.node, cx.constness) { @@ -436,13 +337,8 @@ 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) { - overloaded_lvalue(cx, - expr, - ty::MethodCall::expr(expr.id), - PassArgs::ByValue, - lhs.to_ref(), - vec![index]) + if cx.tables().is_method_call(expr) { + overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) } else { ExprKind::Index { lhs: lhs.to_ref(), @@ -452,26 +348,16 @@ 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) { - overloaded_lvalue(cx, - expr, - ty::MethodCall::expr(expr.id), - PassArgs::ByValue, - arg.to_ref(), - vec![]) + if cx.tables().is_method_call(expr) { + overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()]) } else { ExprKind::Deref { arg: arg.to_ref() } } } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tables().is_method_call(expr.id) { - overloaded_operator(cx, - expr, - ty::MethodCall::expr(expr.id), - PassArgs::ByValue, - arg.to_ref(), - vec![]) + if cx.tables().is_method_call(expr) { + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { ExprKind::Unary { op: UnOp::Not, @@ -481,13 +367,8 @@ 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) { - overloaded_operator(cx, - expr, - ty::MethodCall::expr(expr.id), - PassArgs::ByValue, - arg.to_ref(), - vec![]) + if cx.tables().is_method_call(expr) { + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { // FIXME runtime-overflow if let hir::ExprLit(_) = arg.node { @@ -703,18 +584,21 @@ 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) + custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>) -> Expr<'tcx> { - let callee = cx.tables().method_map[&method_call]; let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id); + let (def_id, substs) = custom_callee.unwrap_or_else(|| { + (cx.tables().type_dependent_defs[&expr.id].def_id(), + cx.tables().node_substs(expr.id)) + }); Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, - ty: callee.ty, + ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs), span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: ConstVal::Function(callee.def_id, callee.substs), + value: ConstVal::Function(def_id, substs), }, }, } @@ -739,8 +623,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) -> ExprKind<'tcx> { - let substs = cx.tables().node_id_item_substs(expr.id) - .unwrap_or_else(|| cx.tcx.intern_substs(&[])); + let substs = cx.tables().node_substs(expr.id); match def { // A regular function, constructor function or a constant. Def::Fn(def_id) | @@ -941,90 +824,59 @@ fn bin_op(op: hir::BinOp_) -> BinOp { } } -enum PassArgs { - ByValue, - ByRef, -} - fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P>) + args: Vec>) -> ExprKind<'tcx> { - // the receiver has all the adjustments that are needed, so we can - // just push a reference to it - let mut argrefs = vec![receiver]; - - // the arguments, unfortunately, do not, so if this is a ByRef - // operator, we have to gin up the autorefs (but by value is easy) - match pass_args { - PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())), - - PassArgs::ByRef => { - let region = cx.tcx.node_scope_region(expr.id); - let (temp_lifetime, was_shrunk) = - cx.region_maps.temporary_scope2(expr.id); - argrefs.extend(args.iter() - .map(|arg| { - let arg_ty = cx.tables().expr_ty_adjusted(arg); - let adjusted_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: arg_ty, - mutbl: hir::MutImmutable, - }); - Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: expr.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: BorrowKind::Shared, - arg: arg.to_ref(), - }, - } - .to_ref() - })) - } - } - - // now create the call itself - let fun = method_callee(cx, expr, method_call); + let fun = method_callee(cx, expr, None); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), - args: argrefs, + args, } } fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - method_call: ty::MethodCall, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P>) + lvalue_ty: Ty<'tcx>, + custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, + args: Vec>) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types // 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 = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); - // callees always have all late-bound regions fully instantiated, + let recv_ty = match args[0] { + ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), + ExprRef::Mirror(ref e) => e.ty + }; + + // Reconstruct the output assuming it's a reference with the + // same region and mutability as the receiver. This holds for + // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + let (region, mt) = match recv_ty.sty { + ty::TyRef(region, mt) => (region, mt), + _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"), + }; + let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { + ty: lvalue_ty, + mutbl: mt.mutbl, + }); // 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 fun = method_callee(cx, expr, custom_callee); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, ty: ref_ty, span: expr.span, - kind: ref_kind, + kind: ExprKind::Call { + ty: fun.ty, + fun: fun.to_ref(), + args, + }, }; // construct and return a deref wrapper `*foo()` diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 698850f0e9e7f..fecde3a636cda 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.is_method_call(e) => { v.promotable = false; } hir::ExprBox(_) => { @@ -381,9 +380,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tables.method_map[&method_call]; - match v.tcx.associated_item(method.def_id).container { - ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty), + let def_id = v.tables.type_dependent_defs[&e.id].def_id(); + match v.tcx.associated_item(def_id).container { + ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty), ty::TraitContainer(_) => v.promotable = false } } @@ -442,18 +441,21 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { use rustc::ty::adjustment::*; - match v.tables.adjustments.get(&e.id).map(|adj| adj.kind) { - None | - Some(Adjust::NeverToAny) | - Some(Adjust::ReifyFnPointer) | - Some(Adjust::UnsafeFnPointer) | - 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)) { - v.promotable = false; + for adjustment in v.tables.expr_adjustments(e) { + match adjustment.kind { + Adjust::NeverToAny | + Adjust::ReifyFnPointer | + Adjust::UnsafeFnPointer | + Adjust::ClosureFnPointer | + Adjust::MutToConstPointer | + Adjust::Borrow(_) | + Adjust::Unsize => {} + + Adjust::Deref(ref overloaded) => { + if overloaded.is_some() { + v.promotable = false; + break; + } } } } @@ -512,7 +514,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { Categorization::StaticItem => { break; } - Categorization::Deref(ref cmt, ..) | + Categorization::Deref(ref cmt, _) | Categorization::Downcast(ref cmt, _) | Categorization::Interior(ref cmt, _) => { cur = cmt; diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fa74e4d6ffccc..b74d3982d61c5 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.type_dependent_defs[&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/_match.rs b/src/librustc_typeck/check/_match.rs index bbe34f37950dc..33f0b0282d173 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -619,7 +619,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = tcx.no_late_bound_regions(&pat_ty.fn_ret()).expect("expected fn type"); + let pat_ty = pat_ty.fn_sig().output(); + let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type"); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 7d3a63263edbf..92017465f7d74 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -11,19 +11,20 @@ use astconv::AstConv; use super::{FnCtxt, LvalueOp}; +use super::method::MethodCallee; -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::{Adjustment, Adjust, OverloadedDeref}; use syntax_pos::Span; use syntax::symbol::Symbol; +use std::iter; + #[derive(Copy, Clone, Debug)] enum AutoderefKind { Builtin, @@ -150,52 +151,59 @@ 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() + } + + /// Returns the adjustment steps. + pub fn adjust_steps(&self, pref: LvaluePreference) + -> Vec> { + self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref)) } - 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(); - - 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 targets = self.steps.iter().skip(1).map(|&(ty, _)| ty) + .chain(iter::once(self.cur_ty)); + let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| { + if let AutoderefKind::Overloaded = kind { + self.fcx.try_overloaded_deref(self.span, source, pref) + .and_then(|InferOk { value: method, obligations: o }| { + obligations.extend(o); + if let ty::TyRef(region, mt) = method.sig.output().sty { + Some(OverloadedDeref { + region, + mutbl: mt.mutbl, + }) + } else { + None + } + }) + } else { + None } - } + }).zip(targets).map(|(autoderef, target)| { + Adjustment { + kind: Adjust::Deref(autoderef), + target + } + }).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> { @@ -212,14 +220,9 @@ 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) + 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 dde5f598a6832..d5ee66a2f0a07 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,13 +8,16 @@ // 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 super::method::MethodCallee; 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,9 +36,9 @@ 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>), + Overloaded(MethodCallee<'tcx>), } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -49,13 +52,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 +64,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) } @@ -72,11 +73,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Some(CallStep::Overloaded(method_callee)) => { - self.confirm_overloaded_call(call_expr, - callee_expr, - arg_exprs, - expected, - method_callee) + self.confirm_overloaded_call(call_expr, arg_exprs, expected, method_callee) } }; @@ -89,19 +86,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(_) => { - self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); - return Some(CallStep::Builtin); + let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.apply_adjustments(callee_expr, adjustments); + return Some(CallStep::Builtin(adjusted_ty)); } ty::TyClosure(def_id, substs) => { @@ -116,15 +113,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 adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + self.record_deferred_call_resolution(def_id, DeferredCallResolution { + call_expr, + callee_expr, + adjusted_ty, + adjustments, + fn_sig, + closure_def_id: def_id, + }); return Some(CallStep::DeferredClosure(fn_sig)); } } @@ -137,47 +134,54 @@ 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 mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + adjustments.extend(autoref); + self.apply_adjustments(callee_expr, adjustments); + 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>, + 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")), - (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut")), - (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"))] { + for &(opt_trait_def_id, method_name, borrow) in + &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call"), true), + (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut"), true), + (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"), false)] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, None => continue, }; - 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) { + match self.lookup_method_in_trait(call_expr.span, + 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); + let method = self.register_infer_ok_obligations(ok); + let mut autoref = None; + if borrow { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + autoref = Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }); + } + } + return Some((autoref, method)); } } } @@ -301,42 +305,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn confirm_overloaded_call(&self, call_expr: &hir::Expr, - callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [hir::Expr], expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) + method_callee: MethodCallee<'tcx>) -> Ty<'tcx> { let output_type = self.check_method_argument_types(call_expr.span, - method_callee.ty, - callee_expr, + Ok(method_callee), arg_exprs, TupleArgumentsFlag::TupleArguments, expected); - self.write_overloaded_call_method_map(call_expr, method_callee); + self.write_method_call(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, + adjustments: 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 +340,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 @@ -357,9 +350,7 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc // can't because of the annoying need for a TypeTrace. // (This always bites me, should find a way to // refactor it.) - let method_sig = fcx.tcx - .no_late_bound_regions(&method_callee.ty.fn_sig()) - .unwrap(); + let method_sig = method_callee.sig; debug!("attempt_resolution: method_callee={:?}", method_callee); @@ -370,7 +361,11 @@ 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); + let mut adjustments = self.adjustments; + adjustments.extend(autoref); + fcx.apply_adjustments(self.callee_expr, adjustments); + + fcx.write_method_call(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 883a0a9d88a1c..a962cdb8f728f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; +type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,23 +108,18 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } -fn identity<'tcx>() -> Adjust<'tcx> { - Adjust::DerefRef { - autoderefs: 0, - autoref: None, - unsize: false, - } +fn identity(_: Ty) -> Vec { vec![] } + +fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> { + move |target| vec![Adjustment { kind, target }] } -fn success<'tcx>(kind: Adjust<'tcx>, +fn success<'tcx>(adj: Vec>, target: Ty<'tcx>, obligations: traits::PredicateObligations<'tcx>) -> CoerceResult<'tcx> { Ok(InferOk { - value: Adjustment { - kind, - target - }, + value: (adj, target), obligations }) } @@ -150,26 +145,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) - -> CoerceResult<'tcx> { + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) + -> CoerceResult<'tcx> + where F: FnOnce(Ty<'tcx>) -> Vec> + { self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { - success(kind, ty, obligations) + success(f(ty), ty, obligations) }) } - 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); // Just ignore error types. if a.references_error() || b.references_error() { - return success(identity(), b, vec![]); + return success(vec![], b, vec![]); } if a.is_never() { @@ -186,9 +177,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(self.cause.span)); - self.unify_and(&b, &diverging_ty, Adjust::NeverToAny) + self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) } else { - success(Adjust::NeverToAny, b, vec![]) + success(simple(Adjust::NeverToAny)(b), b, vec![]) }; } @@ -210,7 +201,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); } _ => {} @@ -237,7 +228,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and(a, b, identity()) + self.unify_and(a, b, identity) } } } @@ -245,15 +236,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); @@ -268,7 +256,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and(a, b, identity()), + _ => return self.unify_and(a, b, identity), }; let span = self.cause.span; @@ -375,7 +363,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 +379,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 +388,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 @@ -413,29 +401,31 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return success(identity(), ty, obligations); + return success(vec![], ty, obligations); } + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + let InferOk { value: mut adjustments, obligations: o } + = autoderef.adjust_steps_as_infer_ok(pref); + obligations.extend(o); + obligations.extend(autoderef.into_obligations()); + // Now apply the autoref. We have to extract the region out of // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; - let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); - debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", - ty, - autoderefs, - autoref); + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)), + target: ty + }); - let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations); + debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", + ty, + adjustments); - success(Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: false, - }, ty, obligations) + success(adjustments, ty, obligations) } @@ -460,27 +450,40 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // that, at which point we will need extra checks on the target here. // Handle reborrows before selecting `Source: CoerceUnsized`. - let (source, reborrow) = match (&source.sty, &target.sty) { + let reborrow = match (&source.sty, &target.sty) { (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; let coercion = Coercion(self.cause.span); let r_borrow = self.next_region_var(coercion); - (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) + Some((Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)), + target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut { + mutbl: mt_b.mutbl, + ty: mt_a.ty + }) + })) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl))) - } - _ => (source, None), - }; - let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); - let adjust = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, + Some((Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.mutbl)), + target: self.tcx.mk_ptr(ty::TypeAndMut { + mutbl: mt_b.mutbl, + ty: mt_a.ty + }) + })) + } + _ => None, }; + let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target); // Setup either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. @@ -488,7 +491,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // for the former and let type inference do the rest. let origin = TypeVariableOrigin::MiscVariable(self.cause.span); let coerce_target = self.next_ty_var(origin); - let mut coercion = self.unify_and(coerce_target, target, adjust)?; + let mut coercion = self.unify_and(coerce_target, target, |target| { + let unsize = Adjustment { + kind: Adjust::Unsize, + target + }; + match reborrow { + None => vec![unsize], + Some((ref deref, ref autoref)) => { + vec![deref.clone(), autoref.clone(), unsize] + } + } + })?; let mut selcx = traits::SelectionContext::new(self); @@ -541,13 +555,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { Ok(coercion) } - fn coerce_from_safe_fn(&self, - a: Ty<'tcx>, - fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>, - to_unsafe: Adjust<'tcx>, - normal: Adjust<'tcx>) - -> CoerceResult<'tcx> { + fn coerce_from_safe_fn(&self, + a: Ty<'tcx>, + fn_ty_a: ty::PolyFnSig<'tcx>, + b: Ty<'tcx>, + to_unsafe: F, + normal: G) + -> CoerceResult<'tcx> + where F: FnOnce(Ty<'tcx>) -> Vec>, + G: FnOnce(Ty<'tcx>) -> Vec> + { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { @@ -573,7 +590,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); self.coerce_from_safe_fn(a, fn_ty_a, b, - Adjust::UnsafeFnPointer, identity()) + simple(Adjust::UnsafeFnPointer), identity) } fn coerce_from_fn_item(&self, @@ -592,9 +609,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, - Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) + simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer)) } - _ => self.unify_and(a, b, identity()), + _ => self.unify_and(a, b, identity), } } @@ -636,9 +653,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) + self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer)) } - _ => self.unify_and(a, b, identity()), + _ => self.unify_and(a, b, identity), } } @@ -653,7 +670,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and(a, b, identity()); + return self.unify_and(a, b, identity); } }; @@ -666,17 +683,21 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - self.unify_and(a_unsafe, b, if is_ref { - Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - } + if is_ref { + self.unify_and(a_unsafe, b, |target| { + vec![Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + target + }] + }) } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer + self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer)) } else { - identity() - }) + self.unify_and(a_unsafe, b, identity) + } } } @@ -703,14 +724,10 @@ 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 adjustment = self.register_infer_ok_obligations(ok); - self.apply_adjustment(expr.id, adjustment); + let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; - // We should now have added sufficient adjustments etc to - // ensure that the type of expression, post-adjustment, is - // a subtype of target. + let (adjustments, _) = self.register_infer_ok_obligations(ok); + self.apply_adjustments(expr, adjustments); Ok(target) } @@ -721,7 +738,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, @@ -779,10 +796,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { // The only adjustment that can produce an fn item is // `NeverToAny`, so this should always be valid. - self.apply_adjustment(expr.id, Adjustment { + self.apply_adjustments(expr, vec![Adjustment { kind: Adjust::ReifyFnPointer, target: fn_ptr - }); + }]); } return Ok(fn_ptr); } @@ -796,12 +813,12 @@ 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); - self.apply_adjustment(new.id, adjustment); - return Ok(adjustment.target); + let (adjustments, target) = self.register_infer_ok_obligations(ok); + self.apply_adjustments(new, adjustments); + return Ok(target); } Err(e) => first_error = Some(e), } @@ -812,25 +829,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs { 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, - autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), - unsize: false - }) => { + let noop = match self.tables.borrow().expr_adjustments(expr) { + &[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. } + ] => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore, because - // the next adjustment can only be a DerefRef + // the next adjustment can only be a Deref // which will be merged into it. mutbl_adj == mt_orig.mutbl } _ => false, } } - Some(Adjust::NeverToAny) => true, - Some(_) => false, - None => true, + &[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true, + _ => false, }; if !noop { @@ -841,7 +856,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 { @@ -854,12 +869,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } Ok(ok) => { - let adjustment = self.register_infer_ok_obligations(ok); + let (adjustments, target) = self.register_infer_ok_obligations(ok); for expr in exprs { let expr = expr.as_coercion_site(); - self.apply_adjustment(expr.id, adjustment); + self.apply_adjustments(expr, adjustments.clone()); } - Ok(adjustment.target) + Ok(target) } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a9e82a0601fee..34e8d6b95a926 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::probe; +use super::{probe, MethodCallee}; use check::{FnCtxt, LvalueOp, callee}; use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; -use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use syntax_pos::Span; @@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> { + -> MethodCallee<'tcx> { debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", unadjusted_self_ty, pick, @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> { + -> MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); @@ -88,19 +88,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs); + let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs); // Unify the (adjusted) self type with what the method expects. - self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder()); + self.unify_receivers(self_ty, method_sig.inputs()[0]); // Add any trait/regions obligations specified on the method's type parameters. + let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig)); self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. - let callee = ty::MethodCallee { + let callee = MethodCallee { def_id: pick.item.def_id, - ty: method_ty, substs: all_substs, + sig: method_sig, }; if let Some(hir::MutMutable) = pick.autoref { @@ -117,40 +118,49 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - let autoref = if let Some(mutbl) = pick.autoref { + // Commit the autoderefs by calling `autoderef` again, but this + // time writing the results into the various tables. + let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let (_, n) = autoderef.nth(pick.autoderefs).unwrap(); + assert_eq!(n, pick.autoderefs); + + let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); + + let mut target = autoderef.unambiguous_final_ty(); + + if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); - Some(AutoBorrow::Ref(region, mutbl)) + target = self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl, + ty: target + }); + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + target + }); + + if let Some(unsize_target) = pick.unsize { + target = self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl, + ty: unsize_target + }); + adjustments.push(Adjustment { + kind: Adjust::Unsize, + target + }); + } } else { // No unsizing should be performed without autoref (at // least during method dispach). This is because we // currently only unsize `[T;N]` to `[T]`, and naturally // that must occur being a reference. assert!(pick.unsize.is_none()); - None - }; - - - // Commit the autoderefs by calling `autoderef` again, but this - // time writing the results into the various tables. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); - let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap(); - assert_eq!(n, pick.autoderefs); - - autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); + } - let target = pick.unsize.unwrap_or(autoderefd_ty); - let target = target.adjust_for_autoref(self.tcx, autoref); + autoderef.finalize(); - // Write out the final adjustment. - self.apply_adjustment(self.self_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, - unsize: pick.unsize.is_some(), - }, - target: target - }); + // Write out the final adjustments. + self.apply_adjustments(self.self_expr, adjustments); target } @@ -349,7 +359,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) { + -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -380,8 +390,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); - (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)), - method_predicates) + (method_sig, method_predicates) } fn add_obligations(&mut self, @@ -436,19 +445,23 @@ 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 mut source = self.node_ty(expr.id); + if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { + let pref = LvaluePreference::PreferMutLvalue; + for adjustment in adjustments { + if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind { + if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) { + let method = self.register_infer_ok_obligations(ok); + if let ty::TyRef(region, mt) = method.sig.output().sty { + *deref = OverloadedDeref { + region, + mutbl: mt.mutbl + }; + } + } + } + source = adjustment.target; + } } match expr.node { @@ -474,13 +487,12 @@ 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().is_method_call(expr) { debug!("convert_lvalue_op_to_mutable - builtin, nothing to do"); return } - let base_ty = self.tables.borrow().adjustments.get(&base_expr.id) + let base_ty = self.tables.borrow().expr_adjustments(base_expr).last() .map_or_else(|| self.node_ty(expr.id), |adj| adj.target); let base_ty = self.resolve_type_vars_if_possible(&base_ty); @@ -490,34 +502,44 @@ 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); - let ok = match method { - Some(method) => method, + expr.span, base_ty, arg_tys, PreferMutLvalue, op); + let method = match method { + Some(ok) => self.register_infer_ok_obligations(ok), None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; - 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.write_method_call(expr.id, method); + + let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty { + (r, mt.mutbl) + } else { + span_bug!(expr.span, "input to lvalue op is not a ref?"); + }; // Convert the autoref in the base expr to mutable with the correct // region and mutability. - if let Some(&mut Adjustment { - ref mut target, kind: Adjust::DerefRef { - autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. + let base_expr_ty = self.node_ty(base_expr.id); + if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { + let mut source = base_expr_ty; + for adjustment in &mut adjustments[..] { + if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { + debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment); + adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl)); + adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut { + ty: source, + mutbl + }); + } + source = adjustment.target; } - }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { - debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); - - // extract method return type, which will be &mut T; - // all LB regions should have been instantiated during method lookup - let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap(); - *target = method_sig.inputs()[0]; - if let ty::TyRef(r_, mt) = target.sty { - *r = r_; - *mutbl = mt.mutbl; - } else { - span_bug!(expr.span, "input to lvalue op is not a ref?"); + // If we have an autoref followed by unsizing at the end, fix the unsize target. + match adjustments[..] { + [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + Adjustment { kind: Adjust::Unsize, ref mut target }] => { + *target = method.sig.inputs()[0]; + } + _ => {} } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 43bf702935ac3..b0ac61d2cc34a 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,13 +10,12 @@ //! 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::subst::Subst; use rustc::infer::{self, InferOk}; @@ -36,6 +35,18 @@ mod suggest; use self::probe::IsSuggestion; +#[derive(Clone, Copy, Debug)] +pub struct MethodCallee<'tcx> { + /// Impl method ID, for inherent methods, or trait method ID, otherwise. + pub def_id: DefId, + pub substs: &'tcx Substs<'tcx>, + + /// Instantiated method signature, i.e. it has been + /// substituted, normalized, and has had late-bound + /// lifetimes replaced with inference variables. + pub sig: ty::FnSig<'tcx>, +} + pub enum MethodError<'tcx> { // Did not find an applicable method, but we did find various near-misses that may work. NoMatch(NoMatchData<'tcx>), @@ -125,7 +136,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_method_types: Vec>, call_expr: &'gcx hir::Expr, self_expr: &'gcx hir::Expr) - -> Result, MethodError<'tcx>> { + -> Result, MethodError<'tcx>> { debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", method_name, self_ty, @@ -153,29 +164,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_method_types)) } - /// `lookup_in_trait_adjusted` is used for overloaded operators. + /// `lookup_method_in_trait` is used for overloaded operators. /// It does a very narrow slice of what the normal probe/confirm path does. /// In particular, it doesn't really do any probing: it simply constructs /// an obligation for aparticular trait with the given self-type and checks /// whether that trait is implemented. /// /// FIXME(#18741) -- It seems likely that we can consolidate some of this - /// code with the other method-lookup code. In particular, autoderef on - /// index is basically identical to autoderef with normal probes, except - /// that the test also looks for built-in indexing. Also, the second half of - /// 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={:?}, \ + /// code with the other method-lookup code. In particular, the second half + /// of this method is basically the same as confirmation. + pub fn lookup_method_in_trait(&self, + span: Span, + m_name: ast::Name, + trait_def_id: DefId, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option<&[ty::Ty<'tcx>]>) + -> Option>> { + debug!("lookup_in_trait_adjusted(self_ty={:?}, \ m_name={}, trait_def_id={:?})", self_ty, - self_info, m_name, trait_def_id); @@ -225,8 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.type_of(def_id); - let fn_sig = original_method_ty.fn_sig(); + let fn_sig = tcx.type_of(def_id).fn_sig(); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; @@ -237,12 +243,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={:?}", - method_ty, - obligation); // Register obligations for the parameters. This will include the // `Self` parameter, which in turn has a bound of the main trait, @@ -265,43 +265,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); // Also add an obligation for the method type being well-formed. + let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig)); + debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + method_ty, + obligation); 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 callee = ty::MethodCallee { + let callee = MethodCallee { def_id: def_id, - ty: method_ty, substs: trait_ref.substs, + sig: fn_sig, }; debug!("callee = {:?}", callee); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a6fd51693e73..32c3f5c8a5edd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -52,7 +52,7 @@ can be broken down into several distinct phases: While type checking a function, the intermediate types for the expressions, blocks, and so forth contained within the function are -stored in `fcx.node_types` and `fcx.item_substs`. These types +stored in `fcx.node_types` and `fcx.node_substs`. These types may contain unresolved type variables. After type checking is complete, the functions in the writeback module are used to take the types from this table, resolve them, and then write them into their @@ -77,8 +77,11 @@ 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::method::MethodCallee; use self::TupleArgumentsFlag::*; use astconv::AstConv; @@ -93,7 +96,6 @@ 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::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 { @@ -1769,65 +1758,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { - if !substs.substs.is_noop() { + pub fn write_method_call(&self, node_id: ast::NodeId, method: MethodCallee<'tcx>) { + self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id)); + self.write_substs(node_id, method.substs); + } + + pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) { + if !substs.is_noop() { debug!("write_substs({}, {:?}) in fcx {}", node_id, substs, self.tag()); - self.tables.borrow_mut().item_substs.insert(node_id, substs); + self.tables.borrow_mut().node_substs.insert(node_id, substs); } } - pub fn apply_autoderef_adjustment(&self, - node_id: ast::NodeId, - derefs: usize, - adjusted_ty: Ty<'tcx>) { - self.apply_adjustment(node_id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: derefs, - autoref: None, - unsize: false - }, - target: adjusted_ty - }); - } - - pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) { - debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj); + pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - if adj.is_identity() { + if adj.is_empty() { return; } - match self.tables.borrow_mut().adjustments.entry(node_id) { + match self.tables.borrow_mut().adjustments.entry(expr.id) { 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()[..], &adj[..]) { // Applying any adjustment on top of a NeverToAny // is a valid NeverToAny adjustment, because it can't // be reached. - (Adjust::NeverToAny, _) => Adjust::NeverToAny, - (Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::Ref(..)), - unsize: false - }, Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { + (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, + (&[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + ], &[ + Adjustment { kind: Adjust::Deref(_), .. }, + .. // Any following adjustments are allowed. + ]) => { // A reborrow has no effect before a dereference. - adj.kind } // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. _ => - bug!("while adjusting {}, can't compose {:?} and {:?}", - node_id, entry.get(), adj) - }; - *entry.get_mut() = Adjustment { - kind: composed_kind, - target: adj.target + bug!("while adjusting {:?}, can't compose {:?} and {:?}", + expr, entry.get(), adj) }; + *entry.get_mut() = adj; } } } @@ -1972,16 +1950,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn opt_node_ty_substs(&self, - id: ast::NodeId, - f: F) where - F: FnOnce(&ty::ItemSubsts<'tcx>), - { - if let Some(s) = self.tables.borrow().item_substs.get(&id) { - f(s); - } - } - /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. pub fn register_region_obligation(&self, @@ -2169,8 +2137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { // extract method return type, which will be &T; // all LB regions should have been instantiated during method lookup - let ret_ty = method.ty.fn_ret(); - let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap(); + let ret_ty = method.sig.output(); // method returns &T, but the type as visible to user is T, so deref ret_ty.builtin_deref(true, NoPreference).unwrap() @@ -2189,32 +2156,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 +2170,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 adjusted_ty = autoderef.unambiguous_final_ty(); debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", expr, @@ -2240,35 +2185,67 @@ 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 adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base_expr, adjustments); + 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); - - 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) - }) + for &unsize in &[false, true] { + let mut self_ty = adjusted_ty; + if unsize { + // We only unsize arrays here. + if let ty::TyArray(element_ty, _) = adjusted_ty.sty { + self_ty = self.tcx.mk_slice(element_ty); + } else { + continue; + } + } + + // 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, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index); + + let result = method.map(|ok| { + debug!("try_index_step: success, using overloaded indexing"); + let method = self.register_infer_ok_obligations(ok); + + let mut adjustments = autoderef.adjust_steps(lvalue_pref); + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: self.tcx.mk_ref(region, ty::TypeAndMut { + mutbl: mt.mutbl, + ty: adjusted_ty + }) + }); + } + if unsize { + adjustments.push(Adjustment { + kind: Adjust::Unsize, + target: method.sig.inputs()[0] + }); + } + self.apply_adjustments(base_expr, adjustments); + + self.write_method_call(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 +2264,14 @@ 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>> { - debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?},{:?})", + debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})", span, - base_expr, base_ty, lvalue_pref, op); @@ -2305,12 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true); 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())) + self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys)) } _ => None, }; @@ -2319,12 +2289,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false); 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())) + self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys)) } (method, _) => method, }; @@ -2334,13 +2299,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_method_argument_types(&self, sp: Span, - method_fn_ty: Ty<'tcx>, - callee_expr: &'gcx hir::Expr, + method: Result, ()>, args_no_rcvr: &'gcx [hir::Expr], tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx>) -> Ty<'tcx> { - if method_fn_ty.references_error() { + let has_error = match method { + Ok(method) => { + method.substs.references_error() || method.sig.references_error() + } + Err(_) => true + }; + if has_error { let err_inputs = self.err_args(args_no_rcvr.len()); let err_inputs = match tuple_arguments { @@ -2350,27 +2320,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, false, tuple_arguments, None); - self.tcx.types.err - } else { - match method_fn_ty.sty { - ty::TyFnDef(def_id, .., ref fty) => { - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( - sp, - expected, - fty.0.output(), - &fty.0.inputs()[1..] - ); - self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..], - args_no_rcvr, fty.0.variadic, tuple_arguments, - self.tcx.hir.span_if_local(def_id)); - fty.0.output() - } - _ => { - span_bug!(callee_expr.span, "method without bare fn type"); - } - } + return self.tcx.types.err; } + + let method = method.unwrap(); + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_inputs_for_expected_output( + sp, + expected, + method.sig.output(), + &method.sig.inputs()[1..] + ); + self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..], + args_no_rcvr, method.sig.variadic, tuple_arguments, + self.tcx.hir.span_if_local(method.def_id)); + method.sig.output() } /// Generic function that factors out common logic from function calls, @@ -2669,10 +2633,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(expr.span)); - self.apply_adjustment(expr.id, Adjustment { + self.apply_adjustments(expr, vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty - }); + }]); ty = adj_ty; } @@ -2795,17 +2759,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_t = self.structurally_resolved_type(expr.span, rcvr_t); let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>(); - let fn_ty = match self.lookup_method(method_name.span, - method_name.node, - expr_t, - tps, - expr, - rcvr) { + let method = match self.lookup_method(method_name.span, + method_name.node, + expr_t, + tps, + 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.write_method_call(expr.id, method); + Ok(method) } Err(error) => { if method_name.node != keywords::Invalid.name() { @@ -2816,18 +2778,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { error, Some(args)); } - self.write_error(expr.id); - self.tcx.types.err + Err(()) } }; // Call the generic checker. - let ret_ty = self.check_method_argument_types(method_name.span, fn_ty, - expr, &args[1..], - DontTupleArguments, - expected); - - ret_ty + self.check_method_argument_types(method_name.span, method, + &args[1..], + DontTupleArguments, + expected) } fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { @@ -2912,7 +2871,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 +2881,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); - self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + let adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base, adjustments); + autoderef.finalize(); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3020,7 +2980,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 +3015,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, base); - self.apply_autoderef_adjustment(base.id, autoderefs, base_t); + let adjustments = autoderef.adjust_steps(lvalue_pref); + self.apply_adjustments(base, adjustments); + autoderef.finalize(); return field_ty; } } @@ -3463,18 +3424,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref); if !oprnd_t.references_error() { + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); match unop { hir::UnDeref => { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); - 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) { + expr.span, oprnd_t, lvalue_pref) { let method = self.register_infer_ok_obligations(ok); + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + self.apply_adjustments(oprnd, vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }]); + } oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), - method); + self.write_method_call(expr.id, method); } else { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ @@ -3484,22 +3449,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::UnNot => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop("!", "not", - tcx.lang_items.not_trait(), - expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { oprnd_t = result; } } hir::UnNeg => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop("-", "neg", - tcx.lang_items.neg_trait(), - expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { oprnd_t = result; @@ -3561,9 +3518,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - self.opt_node_ty_substs(expr.id, |item_substs| { - self.add_wf_bounds(&item_substs.substs, expr); - }); + let substs = self.tables.borrow().node_substs(expr.id); + self.add_wf_bounds(substs, expr); ty } @@ -3940,7 +3896,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_relative_path_defs`. + // The newly resolved definition is written into `type_dependent_defs`. fn finish_resolving_struct_path(&self, qpath: &hir::QPath, path_span: Span, @@ -3965,7 +3921,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty, def, segment); // Write back the new resolution. - self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def); + self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); (def, ty) } @@ -3973,7 +3929,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Resolve associated value path into a base type and associated constant or method definition. - // The newly resolved definition is written into `type_relative_path_defs`. + // The newly resolved definition is written into `type_dependent_defs`. pub fn resolve_ty_and_def_ufcs<'b>(&self, qpath: &'b hir::QPath, node_id: ast::NodeId, @@ -4006,7 +3962,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Write back the new resolution. - self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def); + self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); (def, Some(ty), slice::ref_slice(&**item_segment)) } @@ -4386,9 +4342,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.local_ty(span, nid); let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(node_id, ty); - self.write_substs(node_id, ty::ItemSubsts { - substs: self.tcx.intern_substs(&[]) - }); return ty; } _ => {} @@ -4520,9 +4473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - self.write_substs(node_id, ty::ItemSubsts { - substs: substs - }); + self.write_substs(node_id, substs); ty_substituted } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 3709260acc997..8e5b7a6546973 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -11,12 +11,13 @@ //! Code related to processing overloaded binary and unary operators. use super::FnCtxt; -use hir::def_id::DefId; -use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; +use super::method::MethodCallee; +use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; -use syntax::ast; +use syntax_pos::Span; use syntax::symbol::Symbol; use rustc::hir; @@ -174,8 +175,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty, is_assign); - let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign); - // NB: As we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason // for this indirection is so that, below, we can check the expr @@ -184,15 +183,41 @@ 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], - Symbol::intern(name), trait_def_id, - lhs_expr); + let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - let return_ty = match return_ty { - Ok(return_ty) => return_ty, + let return_ty = match result { + Ok(method) => { + let by_ref_binop = !op.node.is_by_value(); + if is_assign == IsAssign::Yes || by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }; + self.apply_adjustments(lhs_expr, vec![autoref]); + } + } + if by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[1] + }; + // HACK(eddyb) Bypass checks due to reborrows being in + // some cases applied on the RHS, on top of which we need + // to autoref, which is not allowed by apply_adjustments. + // self.apply_adjustments(rhs_expr, vec![autoref]); + self.tables.borrow_mut().adjustments.entry(rhs_expr.id) + .or_insert(vec![]).push(autoref); + } + } + self.write_method_call(expr.id, method); + + method.sig.output() + } Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { @@ -214,9 +239,8 @@ 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], - Symbol::intern(name), trait_def_id, - lhs_expr).is_ok() { + self.lookup_op_method(ty_mut.ty, &[rhs_ty], + Op::Binary(op, is_assign)).is_ok() { err.note( &format!( "this is a reference to a type that `{}` can be applied \ @@ -302,38 +326,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_user_unop(&self, - op_str: &str, - mname: &str, - trait_did: Option, ex: &'gcx hir::Expr, - operand_expr: &'gcx hir::Expr, operand_ty: Ty<'tcx>, op: hir::UnOp) -> Ty<'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) { - Ok(t) => t, + match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { + Ok(method) => { + self.write_method_call(ex.id, method); + method.sig.output() + } Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); if !actual.references_error() { struct_span_err!(self.tcx.sess, ex.span, E0600, "cannot apply unary operator `{}` to type `{}`", - op_str, actual).emit(); + op.as_str(), actual).emit(); } self.tcx.types.err } } } - fn name_and_trait_def_id(&self, - op: hir::BinOp, - is_assign: IsAssign) - -> (&'static str, Option) { + fn lookup_op_method(&self, lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op) + -> Result, ()> + { let lang = &self.tcx.lang_items; - if let IsAssign::Yes = is_assign { + let span = match op { + Op::Binary(op, _) => op.span, + Op::Unary(_, span) => span + }; + let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { match op.node { hir::BiAdd => ("add_assign", lang.add_assign_trait()), hir::BiSub => ("sub_assign", lang.sub_assign_trait()), @@ -349,12 +374,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd | hir::BiOr => { - span_bug!(op.span, + span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) } } - } else { + } else if let Op::Binary(op, IsAssign::No) = op { match op.node { hir::BiAdd => ("add", lang.add_trait()), hir::BiSub => ("sub", lang.sub_trait()), @@ -373,59 +398,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { - span_bug!(op.span, "&& and || are not overloadable") + span_bug!(span, "&& and || are not overloadable") } } - } - } + } else if let Op::Unary(hir::UnNot, _) = op { + ("not", lang.not_trait()) + } else if let Op::Unary(hir::UnNeg, _) = op { + ("neg", lang.neg_trait()) + } else { + bug!("lookup_op_method: op not supported: {:?}", op) + }; - fn lookup_op_method(&self, - expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: Vec>, - opname: ast::Name, - trait_did: Option, - lhs_expr: &'a hir::Expr) - -> Result,()> - { - debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \ - trait_did={:?}, lhs_expr={:?})", - expr, + debug!("lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", lhs_ty, + op, opname, - trait_did, - lhs_expr); - - 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, - Some(other_tys)) - } - None => None - }; + trait_did); + + let method = trait_did.and_then(|trait_did| { + let opname = Symbol::intern(opname); + self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) + }); match method { Some(ok) => { let 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); - - // extract return type for method; all late bound regions - // should have been instantiated by now - let ret_ty = method_ty.fn_ret(); - Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap()) + Ok(method) } None => { Err(()) @@ -491,12 +491,18 @@ impl BinOpCategory { } /// Whether the binary operation is an assignment (`a += b`), or not (`a + b`) -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] enum IsAssign { No, Yes, } +#[derive(Clone, Copy, Debug)] +enum Op { + Binary(hir::BinOp, IsAssign), + Unary(hir::UnOp, Span), +} + /// Returns true if this is a built-in arithmetic operation (e.g. u32 /// + u32, i16x4 == i16x4) and false if these types would have to be /// overloaded to be legal. There are two reasons that we distinguish diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index fd26ff65661ca..afc003b986d41 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,15 +520,13 @@ 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 has_method_map = opt_method_callee.is_some(); + let is_method_call = self.tables.borrow().is_method_call(expr); // If we are calling a method (either explicitly or via an // overloaded operator), check that all of the types provided as // arguments for its type parameters are well-formed, and all the regions // provided as arguments outlive the call. - if let Some(callee) = opt_method_callee { + if is_method_call { let origin = match expr.node { hir::ExprMethodCall(..) => infer::ParameterOrigin::MethodCall, @@ -538,66 +536,16 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { infer::ParameterOrigin::OverloadedOperator }; - self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region); - self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span), - callee.ty, expr_region); + let substs = self.tables.borrow().node_substs(expr.id); + self.substs_wf_in_scope(origin, substs, expr.span, expr_region); + // Arguments (sub-expressions) are checked via `constrain_call`, below. } // Check any autoderefs or autorefs that appear. - let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); - 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); - if let Some(ref autoref) = *autoref { - self.link_autoref(expr, autoderefs, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), - expr.id, expr_region); - } - } - /* - adjustment::AutoObject(_, ref bounds, ..) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type - // of the source obeys the new region bound. - let source_ty = self.resolve_node_type(expr.id); - self.type_must_outlive(infer::RelateObjectBound(expr.span), - source_ty, bounds.region_bound); - } - */ - _ => {} - } - - // If necessary, constrain destructors in the unadjusted form of this - // expression. - let cmt_result = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr_unadjusted(expr) - }; - match cmt_result { - Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, - expr.span); - } - Err(..) => { - self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd"); - } - } - } + let cmt_result = self.constrain_adjustments(expr); // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. - let cmt_result = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr(expr) - }; match cmt_result { Ok(head_cmt) => { self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); @@ -611,57 +559,45 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { expr, self.repeating_scope); match expr.node { hir::ExprPath(_) => { - self.fcx.opt_node_ty_substs(expr.id, |item_substs| { - let origin = infer::ParameterOrigin::Path; - self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region); - }); + let substs = self.tables.borrow().node_substs(expr.id); + let origin = infer::ParameterOrigin::Path; + self.substs_wf_in_scope(origin, substs, expr.span, expr_region); } hir::ExprCall(ref callee, ref args) => { - if has_method_map { - self.constrain_call(expr, Some(&callee), - args.iter().map(|e| &*e), false); + if is_method_call { + self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e)); } else { self.constrain_callee(callee.id, expr, &callee); - self.constrain_call(expr, None, - args.iter().map(|e| &*e), false); + self.constrain_call(expr, None, args.iter().map(|e| &*e)); } intravisit::walk_expr(self, expr); } hir::ExprMethodCall(.., ref args) => { - self.constrain_call(expr, Some(&args[0]), - args[1..].iter().map(|e| &*e), false); + self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e)); intravisit::walk_expr(self, expr); } hir::ExprAssignOp(_, ref lhs, ref rhs) => { - if has_method_map { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), false); + if is_method_call { + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); } intravisit::walk_expr(self, expr); } - hir::ExprIndex(ref lhs, ref rhs) if has_method_map => { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), true); + hir::ExprIndex(ref lhs, ref rhs) if is_method_call => { + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); }, - hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => { - let implicitly_ref_args = !op.node.is_by_value(); - - // As `expr_method_call`, but the call is via an - // overloaded op. Note that we (sadly) currently use an - // implicit "by ref" sort of passing style here. This - // should be converted to an adjustment! - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), implicitly_ref_args); + hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => { + // As `ExprMethodCall`, but the call is via an overloaded op. + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); } @@ -678,29 +614,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprUnary(op, ref lhs) if has_method_map => { - let implicitly_ref_args = !op.is_by_value(); - - // As above. - self.constrain_call(expr, Some(&lhs), - None::.iter(), implicitly_ref_args); - - intravisit::walk_expr(self, expr); - } - 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) { - Some(method) => { - self.constrain_call(expr, Some(&base), - None::.iter(), true); - // late-bound regions in overloaded method calls are instantiated - let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret()); - fn_ret.unwrap() - } - None => self.resolve_node_type(base.id) - }; + if is_method_call { + self.constrain_call(expr, Some(base), None::.iter()); + } + // For overloaded derefs, base_ty is the input to `Deref::deref`, + // but it's a reference type uing the same region as the output. + let base_ty = self.resolve_expr_type_adjusted(base); if let ty::TyRef(r_ptr, _) = base_ty.sty { self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr); } @@ -708,6 +629,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } + hir::ExprUnary(_, ref lhs) if is_method_call => { + // As above. + self.constrain_call(expr, Some(&lhs), None::.iter()); + + intravisit::walk_expr(self, expr); + } + hir::ExprIndex(ref vec_expr, _) => { // For a[b], the lifetime of a must enclose the deref let vec_type = self.resolve_expr_type_adjusted(&vec_expr); @@ -859,19 +787,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn constrain_call<'b, I: Iterator>(&mut self, call_expr: &hir::Expr, receiver: Option<&hir::Expr>, - arg_exprs: I, - implicitly_ref_args: bool) { + arg_exprs: I) { //! Invoked on every call site (i.e., normal calls, method calls, //! and overloaded operators). Constrains the regions which appear //! in the type of the function. Also constrains the regions that //! appear in the arguments appropriately. - debug!("constrain_call(call_expr={:?}, \ - receiver={:?}, \ - implicitly_ref_args={})", + debug!("constrain_call(call_expr={:?}, receiver={:?})", call_expr, - receiver, - implicitly_ref_args); + receiver); // `callee_region` is the scope representing the time in which the // call occurs. @@ -889,14 +813,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // valid for at least the lifetime of the function: self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), arg_expr.id, callee_region); - - // unfortunately, there are two means of taking implicit - // references, and we need to propagate constraints as a - // result. modes are going away and the "DerefArgs" code - // should be ported to use adjustments - if implicitly_ref_args { - self.link_by_ref(arg_expr, callee_scope); - } } // as loop above, but for receiver @@ -904,89 +820,83 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("receiver: {:?}", r); self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.id, callee_region); - if implicitly_ref_args { - self.link_by_ref(&r, callee_scope); - } } } - /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being + /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// 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>) - { - debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})", - deref_expr, - derefs, - derefd_ty); - - 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); - - let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); - - 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); - } + fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { + debug!("constrain_adjustments(expr={:?})", expr); - // 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 - }; + let mut cmt = { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + mc.cat_expr_unadjusted(expr)? + }; + + //NOTE(@jroesch): mixed RefCell borrow causes crash + let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec(); + if adjustments.is_empty() { + return Ok(cmt); + } - if let ty::TyRef(r_ptr, _) = derefd_ty.sty { - self.mk_subregion_due_to_dereference(deref_expr.span, - r_deref_expr, r_ptr); + debug!("constrain_adjustments: adjustments={:?}", adjustments); + + // If necessary, constrain destructors in the unadjusted form of this + // expression. + self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span); + + let expr_region = self.tcx.node_scope_region(expr.id); + for adjustment in adjustments { + debug!("constrain_adjustments: adjustment={:?}, cmt={:?}", + adjustment, cmt); + + if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind { + debug!("constrain_adjustments: overloaded deref: {:?}", deref); + + // Treat overloaded autoderefs as if an AutoBorrow adjustment + // was applied on the base type, as that is always the case. + let input = self.tcx.mk_ref(deref.region, ty::TypeAndMut { + ty: cmt.ty, + mutbl: deref.mutbl, + }); + let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut { + ty: adjustment.target, + mutbl: deref.mutbl, + }); + + self.link_region(expr.span, deref.region, + ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone()); + + // Specialized version of constrain_call. + self.type_must_outlive(infer::CallRcvr(expr.span), + input, expr_region); + self.type_must_outlive(infer::CallReturn(expr.span), + output, expr_region); + } + + if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { + self.link_autoref(expr, cmt.clone(), autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), + expr.id, expr_region); + } + + { + let mc = mc::MemCategorizationContext::new(self, &self.region_maps); + cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?; } - 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 + if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { + self.mk_subregion_due_to_dereference(expr.span, + expr_region, r_ptr); } } + + Ok(cmt) } pub fn mk_subregion_due_to_dereference(&mut self, @@ -1053,7 +963,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = self.resolve_node_type(id); - let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target); + let ty = self.tables.borrow().adjustments.get(&id) + .and_then(|adj| adj.last()) + .map_or(ty0, |adj| adj.target); let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", @@ -1151,13 +1063,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) => { @@ -1172,19 +1081,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and - /// must outlive `callee_scope`. - fn link_by_ref(&self, - expr: &hir::Expr, - callee_scope: CodeExtent) { - debug!("link_by_ref(expr={:?}, callee_scope={:?})", - expr, callee_scope); - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope)); - self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt); - } - /// Like `link_region()`, except that the region is extracted from the type of `id`, /// which must be some reference (`&T`, `&str`, etc). fn link_region_from_node_type(&self, @@ -1224,10 +1120,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind, borrow_cmt); match borrow_cmt.cat.clone() { - Categorization::Deref(ref_cmt, _, - mc::Implicit(ref_kind, ref_region)) | - Categorization::Deref(ref_cmt, _, - mc::BorrowedPtr(ref_kind, ref_region)) => { + Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | + Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, borrow_region, borrow_kind, ref_cmt, ref_region, ref_kind, @@ -1243,7 +1137,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } Categorization::Downcast(cmt_base, _) | - Categorization::Deref(cmt_base, _, mc::Unique) | + Categorization::Deref(cmt_base, mc::Unique) | Categorization::Interior(cmt_base, _) => { // Borrowing interior or owned data requires the base // to be valid and borrowable in the same fashion. @@ -1251,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind = borrow_kind; } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Upvar(..) | Categorization::Local(..) | diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 114290c52d195..286d0ad1b35a3 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); } } @@ -281,8 +281,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", guarantor); match guarantor.cat { - Categorization::Deref(.., mc::BorrowedPtr(..)) | - Categorization::Deref(.., mc::Implicit(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) | + Categorization::Deref(_, mc::Implicit(..)) => { match cmt.note { mc::NoteUpvarRef(upvar_id) => { debug!("adjust_upvar_borrow_kind_for_consume: \ @@ -327,7 +327,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { cmt); match cmt.cat.clone() { - Categorization::Deref(base, _, mc::Unique) | + Categorization::Deref(base, mc::Unique) | Categorization::Interior(base, _) | Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is @@ -335,8 +335,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_mut(base); } - Categorization::Deref(base, _, mc::BorrowedPtr(..)) | - Categorization::Deref(base, _, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) | + Categorization::Deref(base, mc::Implicit(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the @@ -346,7 +346,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Rvalue(..) | Categorization::Local(_) | @@ -361,7 +361,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { cmt); match cmt.cat.clone() { - Categorization::Deref(base, _, mc::Unique) | + Categorization::Deref(base, mc::Unique) | Categorization::Interior(base, _) | Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is @@ -369,8 +369,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_unique(base); } - Categorization::Deref(base, _, mc::BorrowedPtr(..)) | - Categorization::Deref(base, _, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) | + Categorization::Deref(base, mc::Implicit(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique @@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(.., mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | Categorization::Rvalue(..) | Categorization::Local(_) | diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b43e2423757d1..012fde16d875e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,8 +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::adjustment; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::util::nodemap::DefIdSet; use syntax::ast; @@ -106,7 +105,9 @@ 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)); + let mut tables = self.fcx.tables.borrow_mut(); + tables.type_dependent_defs.remove(&e.id); + tables.node_substs.remove(&e.id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | @@ -118,20 +119,19 @@ 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)); + let mut tables = self.fcx.tables.borrow_mut(); + tables.type_dependent_defs.remove(&e.id); + tables.node_substs.remove(&e.id); - // weird but true: the by-ref binops put an - // adjustment on the lhs but not the rhs; the - // adjustment for rhs is kind of baked into the - // system. match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); + tables.adjustments.get_mut(&rhs.id).map(|a| a.pop()); } }, hir::ExprAssignOp(..) => { - self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); }, _ => {}, } @@ -164,7 +164,6 @@ 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)); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); @@ -280,9 +279,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) { - // Export associated path extensions. - if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) { - self.tables.type_relative_path_defs.insert(node_id, def); + // Export associated path extensions and method resultions. + if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs.remove(&node_id) { + self.tables.type_dependent_defs.insert(node_id, def); } // Resolve any borrowings for the node with id `node_id` @@ -295,94 +294,29 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { debug!("Node {} has type {:?}", node_id, n_ty); // Resolve any substitutions - self.fcx.opt_node_ty_substs(node_id, |item_substs| { - let item_substs = self.resolve(item_substs, &span); - if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs); - assert!(!item_substs.substs.needs_infer()); - self.tables.item_substs.insert(node_id, item_substs); - } - }); + if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) { + let substs = self.resolve(&substs, &span); + debug!("write_substs_to_tcx({}, {:?})", node_id, substs); + assert!(!substs.needs_infer()); + self.tables.node_substs.insert(node_id, substs); + } } fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { - let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); - match adjustments { + let adjustment = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); + match adjustment { None => { debug!("No adjustments for node {}", node_id); } Some(adjustment) => { - let resolved_adjustment = match adjustment.kind { - adjustment::Adjust::NeverToAny => { - adjustment::Adjust::NeverToAny - } - - adjustment::Adjust::ReifyFnPointer => { - adjustment::Adjust::ReifyFnPointer - } - - adjustment::Adjust::MutToConstPointer => { - adjustment::Adjust::MutToConstPointer - } - - adjustment::Adjust::ClosureFnPointer => { - adjustment::Adjust::ClosureFnPointer - } - - adjustment::Adjust::UnsafeFnPointer => { - adjustment::Adjust::UnsafeFnPointer - } - - 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, - autoref: self.resolve(&autoref, &span), - unsize: unsize, - } - } - }; - let resolved_adjustment = adjustment::Adjustment { - kind: resolved_adjustment, - target: self.resolve(&adjustment.target, &span) - }; + let resolved_adjustment = self.resolve(&adjustment, &span); debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment); self.tables.adjustments.insert(node_id, resolved_adjustment); } } } - fn visit_method_map_entry(&mut self, - method_span: Span, - method_call: MethodCall) { - // Resolve any method map entry - let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) { - Some(method) => { - debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})", - method_call, - method); - let new_method = 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); - } - } - fn visit_liberated_fn_sigs(&mut self) { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { let fn_sig = self.resolve(fn_sig, &node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 699b5f330d457..baef48fe7d2cd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -73,12 +73,14 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] +#![feature(advanced_slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] #![feature(never_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_patterns)] #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))] #![cfg_attr(stage0, feature(rustc_private))] diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 744868e2e2396..40b3e789ce4a3 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1953,7 +1953,7 @@ mod tests { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = channel::>(); tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } #[test] @@ -2010,7 +2010,7 @@ mod tests { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::>(); let _t = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }); tx.send(box 10).unwrap(); @@ -2023,7 +2023,7 @@ mod tests { drop(tx); }); let res = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }).join(); assert!(res.is_err()); } @@ -2077,7 +2077,7 @@ mod tests { let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } } @@ -2102,7 +2102,7 @@ mod tests { if i == 10 { return } thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); }); } @@ -2639,7 +2639,7 @@ mod sync_tests { fn oneshot_single_thread_send_then_recv() { let (tx, rx) = sync_channel::>(1); tx.send(box 10).unwrap(); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } #[test] @@ -2711,7 +2711,7 @@ mod sync_tests { fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::>(0); let _t = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }); tx.send(box 10).unwrap(); @@ -2724,7 +2724,7 @@ mod sync_tests { drop(tx); }); let res = thread::spawn(move|| { - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); }).join(); assert!(res.is_err()); } @@ -2778,7 +2778,7 @@ mod sync_tests { let _t = thread::spawn(move|| { tx.send(box 10).unwrap(); }); - assert!(rx.recv().unwrap() == box 10); + assert!(*rx.recv().unwrap() == 10); } } @@ -2803,7 +2803,7 @@ mod sync_tests { if i == 10 { return } thread::spawn(move|| { - assert!(rx.recv().unwrap() == box i); + assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); }); } diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index a08e77a2151e2..2206234b77744 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -8,10 +8,10 @@ error[E0308]: mismatched types found type `u32` error[E0277]: the trait bound `u32: std::ops::Add` is not satisfied - --> $DIR/equality.rs:34:9 + --> $DIR/equality.rs:34:11 | 34 | n + sum_to(n - 1) - | ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo` + | ^ no implementation for `u32 + impl Foo` | = help: the trait `std::ops::Add` is not implemented for `u32` diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index d97c78137089e..1faf72cd760b7 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,56 +1,56 @@ error[E0277]: the trait bound `{integer}: std::ops::Add>` is not satisfied - --> $DIR/binops.rs:12:5 + --> $DIR/binops.rs:12:7 | 12 | 1 + Some(1); - | ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>` + | ^ no implementation for `{integer} + std::option::Option<{integer}>` | = help: the trait `std::ops::Add>` is not implemented for `{integer}` error[E0277]: the trait bound `usize: std::ops::Sub>` is not satisfied - --> $DIR/binops.rs:13:5 + --> $DIR/binops.rs:13:16 | 13 | 2 as usize - Some(1); - | ^^^^^^^^^^^^^^^^^^^^ no implementation for `usize - std::option::Option<{integer}>` + | ^ no implementation for `usize - std::option::Option<{integer}>` | = help: the trait `std::ops::Sub>` is not implemented for `usize` error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied - --> $DIR/binops.rs:14:5 + --> $DIR/binops.rs:14:7 | 14 | 3 * (); - | ^^^^^^ no implementation for `{integer} * ()` + | ^ no implementation for `{integer} * ()` | = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied - --> $DIR/binops.rs:15:5 + --> $DIR/binops.rs:15:7 | 15 | 4 / ""; - | ^^^^^^ no implementation for `{integer} / &str` + | ^ no implementation for `{integer} / &str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialEq` is not satisfied - --> $DIR/binops.rs:16:5 + --> $DIR/binops.rs:16:7 | 16 | 5 < String::new(); - | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String` + | ^ can't compare `{integer}` with `std::string::String` | = help: the trait `std::cmp::PartialEq` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied - --> $DIR/binops.rs:16:5 + --> $DIR/binops.rs:16:7 | 16 | 5 < String::new(); - | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String` + | ^ can't compare `{integer}` with `std::string::String` | = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied - --> $DIR/binops.rs:17:5 + --> $DIR/binops.rs:17:7 | 17 | 6 == Ok(1); - | ^^^^^^^^^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` + | ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` | = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 057f8fe6ee274..0224cef8da123 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,13 +1,8 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied - --> $DIR/multiline-span-simple.rs:23:9 + --> $DIR/multiline-span-simple.rs:23:18 | -23 | foo(1 as u32 + - | _________^ -24 | | -25 | | bar(x, -26 | | -27 | | y), - | |______________^ no implementation for `u32 + ()` +23 | foo(1 as u32 + + | ^ no implementation for `u32 + ()` | = help: the trait `std::ops::Add<()>` is not implemented for `u32`