diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-05-20 23:52:52 +0300 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-06-01 08:59:47 +0300 |
| commit | 91d603a2a7ad6caed2275da0c7ae21d845ed72d1 (patch) | |
| tree | 5813dcfc2005240f19eb62696800e735a711d7e2 | |
| parent | 4a754f224d2ec61268649bc2421b7843b686375b (diff) | |
| download | rust-91d603a2a7ad6caed2275da0c7ae21d845ed72d1.tar.gz rust-91d603a2a7ad6caed2275da0c7ae21d845ed72d1.zip | |
rustc: move autoref and unsize from Adjust::DerefRef to Adjustment.
| -rw-r--r-- | src/librustc/ich/impls_ty.rs | 6 | ||||
| -rw-r--r-- | src/librustc/middle/expr_use_visitor.rs | 29 | ||||
| -rw-r--r-- | src/librustc/middle/mem_categorization.rs | 9 | ||||
| -rw-r--r-- | src/librustc/ty/adjustment.rs | 169 | ||||
| -rw-r--r-- | src/librustc/ty/structural_impls.rs | 35 | ||||
| -rw-r--r-- | src/librustc_lint/builtin.rs | 2 | ||||
| -rw-r--r-- | src/librustc_lint/unused.rs | 24 | ||||
| -rw-r--r-- | src/librustc_mir/hair/cx/expr.rs | 113 | ||||
| -rw-r--r-- | src/librustc_passes/consts.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/callee.rs | 16 | ||||
| -rw-r--r-- | src/librustc_typeck/check/coercion.rs | 116 | ||||
| -rw-r--r-- | src/librustc_typeck/check/method/confirm.rs | 17 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 40 | ||||
| -rw-r--r-- | src/librustc_typeck/check/op.rs | 8 | ||||
| -rw-r--r-- | src/librustc_typeck/check/regionck.rs | 8 |
15 files changed, 290 insertions, 304 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 22ef88e0e5a..f0fdb94b81b 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -100,16 +100,14 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Ad ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => {} - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { + ty::adjustment::Adjust::Deref(ref autoderefs) => { autoderefs.hash_stable(hcx, hasher); - 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::adjustment::Adjustment<'tcx> { kind, autoref, unsize, target }); impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target }); impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f75f3a145f5..9120990777d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -707,9 +707,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let infcx = self.mc.infcx; //NOTE(@jroesch): mixed RefCell borrow causes crash let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned(); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); + let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); if let Some(adjustment) = adj { + debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::ReifyFnPointer | @@ -718,23 +718,20 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { adjustment::Adjust::MutToConstPointer => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - debug!("walk_adjustment: trivial adjustment"); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + self.delegate_consume(expr.id, expr.span, cmt); + assert!(adjustment.autoref.is_none() && !adjustment.unsize); + return; } - adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize } => { - debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); - - let cmt_derefd = - return_if_err!(self.walk_autoderefs(expr, cmt_unadjusted, autoderefs)); + adjustment::Adjust::Deref(ref autoderefs) => { + cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs)); + } + } - let cmt_refd = - self.walk_autoref(expr, cmt_derefd, autoref); + cmt = self.walk_autoref(expr, cmt, adjustment.autoref); - if unsize { - // Unsizing consumes the thin pointer and produces a fat one. - self.delegate_consume(expr.id, expr.span, cmt_refd); - } - } + if adjustment.unsize { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt); } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 68c56177490..707b52a1a22 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -475,11 +475,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Some(adjustment) => { debug!("cat_expr({:?}): {:?}", adjustment, expr); match adjustment.kind { - adjustment::Adjust::DerefRef { - ref autoderefs, - autoref: None, - unsize: false - } => { + adjustment::Adjust::Deref(ref autoderefs) + if adjustment.autoref.is_none() && !adjustment.unsize => { // Equivalent to *expr or something similar. let mut cmt = self.cat_expr_unadjusted(expr)?; debug!("cat_expr: autoderefs={:?}, cmt={:?}", @@ -499,7 +496,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::UnsafeFnPointer | adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | - adjustment::Adjust::DerefRef {..} => { + adjustment::Adjust::Deref(_) => { // Result is an rvalue. let expr_ty = self.expr_ty_adjusted(expr)?; Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 55f85ef003b..e2e017e9f51 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -13,10 +13,83 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt, TypeAndMut}; use ty::subst::Substs; + +/// Represents coercing a value to a different type of value. +/// +/// We transform values by following the following steps in order: +/// 1. Apply a step of `Adjust` (see its variants for details). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `true`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// 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 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: +/// +/// ``` +/// Adjustment { +/// kind: Adjust::Deref(vec![None]),// &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] +/// unsize: true, // &[i32; 4] -> &[i32] +/// target: `[i32]`, +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo<T> { 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<T>` to `Box<Trait>` 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: +/// +/// ``` +/// Adjustment { +/// kind: Adjust::Deref(vec![]), +/// autoref: None, +/// unsize: true, +/// target: `Box<[i32]>`, +/// } +/// ``` #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { + /// Step 1. pub kind: Adjust<'tcx>, - pub target: Ty<'tcx> + + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option<AutoBorrow<'tcx>>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + pub unsize: bool, + + pub target: Ty<'tcx>, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] @@ -36,103 +109,25 @@ 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 through `self.autoderefs` steps (may be no steps). - /// 2. If `autoref` is `Some(_)`, then take the address and produce either a - /// `&` or `*` pointer. - /// 3. If `unsize` is `true`, then apply the unsize transformation, - /// which will do things like convert thin pointers to fat - /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat - /// 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 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: - /// - /// ``` - /// Adjustment { - /// kind: Adjust::DerefRef { - /// autoderefs: vec![None], // &[i32; 4] -> [i32; 4] - /// autoref: Some(AutoBorrow::Ref), // [i32; 4] -> &[i32; 4] - /// unsize: true, // &[i32; 4] -> &[i32] - /// }, - /// target: `[i32]`, - /// } - /// ``` - /// - /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. - /// E.g., `struct Foo<T> { 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<T>` to `Box<Trait>` 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: - /// - /// ``` - /// Adjustment { - /// Adjust::DerefRef { - /// autoderefs: vec![], - /// autoref: None, - /// unsize: true, - /// }, - /// target: `Box<[i32]>`, - /// } - /// ``` - DerefRef { - /// Step 1. Apply a number of dereferences, producing an lvalue. - autoderefs: Vec<Option<OverloadedDeref<'tcx>>>, - - /// Step 2. Optionally produce a pointer/reference from the value. - autoref: Option<AutoBorrow<'tcx>>, - - /// 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, - } + /// Apply a number of dereferences, producing an lvalue, + /// if there are more than 0 dereferences. + Deref(Vec<Option<OverloadedDeref<'tcx>>>), } impl<'tcx> Adjustment<'tcx> { pub fn is_identity(&self) -> bool { + if self.autoref.is_some() || self.unsize { + return false; + } match self.kind { Adjust::NeverToAny => self.target.is_never(), - Adjust::DerefRef { - ref autoderefs, - autoref: None, - unsize: false - } if autoderefs.is_empty() => true, + Adjust::Deref(ref autoderefs) => autoderefs.is_empty(), Adjust::ReifyFnPointer | Adjust::UnsafeFnPointer | Adjust::ClosureFnPointer | - Adjust::MutToConstPointer | - Adjust::DerefRef {..} => false, + Adjust::MutToConstPointer => false, } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 811b383324d..cd34ebc7650 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -224,8 +224,13 @@ 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<Self::Lifted> { tcx.lift(&self.kind).and_then(|kind| { - tcx.lift(&self.target).map(|target| { - ty::adjustment::Adjustment { kind, target } + tcx.lift(&(self.autoref, self.target)).map(|(autoref, target)| { + ty::adjustment::Adjustment { + kind, + autoref, + unsize: self.unsize, + target, + } }) }) } @@ -245,12 +250,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { Some(ty::adjustment::Adjust::ClosureFnPointer), ty::adjustment::Adjust::MutToConstPointer => Some(ty::adjustment::Adjust::MutToConstPointer), - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { - tcx.lift(autoderefs).and_then(|autoderefs| { - tcx.lift(autoref).map(|autoref| { - ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } - }) - }) + ty::adjustment::Adjust::Deref(ref autoderefs) => { + tcx.lift(autoderefs).map(ty::adjustment::Adjust::Deref) } } } @@ -684,12 +685,16 @@ 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::adjustment::Adjustment { kind: self.kind.fold_with(folder), + autoref: self.autoref.fold_with(folder), + unsize: self.unsize, target: self.target.fold_with(folder), } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.kind.visit_with(visitor) || self.target.visit_with(visitor) + self.kind.visit_with(visitor) || + self.autoref.visit_with(visitor) || + self.target.visit_with(visitor) } } @@ -701,12 +706,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => self.clone(), - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => { - ty::adjustment::Adjust::DerefRef { - autoderefs: autoderefs.fold_with(folder), - autoref: autoref.fold_with(folder), - unsize, - } + ty::adjustment::Adjust::Deref(ref autoderefs) => { + ty::adjustment::Adjust::Deref(autoderefs.fold_with(folder)) } } } @@ -718,8 +719,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> { ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer => false, - ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize: _ } => { - autoderefs.visit_with(visitor) || autoref.visit_with(visitor) + ty::adjustment::Adjust::Deref(ref autoderefs) => { + autoderefs.visit_with(visitor) } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b0bfda4a658..e4a8a1267f0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -890,7 +890,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check for overloaded autoderef method calls. if let Some(&Adjustment { - kind: Adjust::DerefRef { ref autoderefs, .. }, .. + kind: Adjust::Deref(ref autoderefs), .. }) = cx.tables.adjustments.get(&id) { let mut source = cx.tables.expr_ty(expr); for &overloaded in autoderefs { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 93ff609a280..4db27647d42 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -469,20 +469,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { } 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"); - } - _ => (), + match adjustment.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"); + } + _ => (), } } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 05f6381d934..dbf35971fa3 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -86,8 +86,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize }, - adjusted_ty)) => { + Some((&ty::adjustment::Adjust::Deref(ref autoderefs), _)) => { for &overloaded in autoderefs { let source = expr.ty; let target; @@ -143,64 +142,66 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { 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 let Some(adj) = adj { + if let Some(autoref) = adj.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() }, - }; - } + if adj.unsize { + expr = Expr { + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: adj.target, + span: self.span, + kind: ExprKind::Unsize { source: expr.to_ref() }, + }; } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f73ae9d42f6..e7aa74494f9 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -449,7 +449,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp Some(&Adjust::ClosureFnPointer) | Some(&Adjust::MutToConstPointer) => {} - Some(&Adjust::DerefRef { ref autoderefs, .. }) => { + Some(&Adjust::Deref(ref autoderefs)) => { if autoderefs.iter().any(|overloaded| overloaded.is_some()) { v.promotable = false; } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index b498d0f8082..579bcda8dc6 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -144,11 +144,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { let autoderefs = autoderef.adjust_steps(LvaluePreference::NoPreference); self.apply_adjustment(callee_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize: false - }, + kind: Adjust::Deref(autoderefs), + autoref, + unsize: false, target: method.sig.inputs()[0] }); CallStep::Overloaded(method) @@ -356,11 +354,9 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); fcx.apply_adjustment(self.callee_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: self.autoderefs, - autoref, - unsize: false - }, + kind: Adjust::Deref(self.autoderefs), + autoref, + unsize: false, target: method_sig.inputs()[0] }); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 78559e470ae..dc373610814 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -108,23 +108,24 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } -fn identity<'tcx>() -> Adjust<'tcx> { - Adjust::DerefRef { - autoderefs: vec![], +fn identity<'tcx>(target: Ty<'tcx>) -> Adjustment<'tcx> { + simple(Adjust::Deref(vec![]))(target) +} + +fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Adjustment<'tcx> { + move |target| Adjustment { + kind, autoref: None, unsize: false, + target } } -fn success<'tcx>(kind: Adjust<'tcx>, - target: Ty<'tcx>, +fn success<'tcx>(adj: Adjustment<'tcx>, obligations: traits::PredicateObligations<'tcx>) -> CoerceResult<'tcx> { Ok(InferOk { - value: Adjustment { - kind, - target - }, + value: adj, obligations }) } @@ -150,10 +151,12 @@ 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<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) + -> CoerceResult<'tcx> + where F: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + { self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { - success(kind, ty, obligations) + success(f(ty), obligations) }) } @@ -163,7 +166,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return success(identity(), b, vec![]); + return success(identity(b), vec![]); } if a.is_never() { @@ -180,9 +183,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), vec![]) }; } @@ -231,7 +234,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) } } } @@ -259,7 +262,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; @@ -404,7 +407,7 @@ 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(identity(ty), obligations); } // Now apply the autoref. We have to extract the region out of @@ -426,11 +429,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { autoderefs, autoref); - success(Adjust::DerefRef { - autoderefs, + success(Adjustment { + kind: Adjust::Deref(autoderefs), autoref, unsize: false, - }, ty, obligations) + target: ty + }, obligations) } @@ -471,19 +475,18 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); - let adjust = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { vec![None] } else { vec![] }, - autoref: reborrow, - unsize: true, - }; - // Setup either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // 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| Adjustment { + kind: Adjust::Deref(if reborrow.is_some() { vec![None] } else { vec![] }), + autoref: reborrow, + unsize: true, + target + })?; let mut selcx = traits::SelectionContext::new(self); @@ -536,13 +539,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<F, G>(&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>) -> Adjustment<'tcx>, + G: FnOnce(Ty<'tcx>) -> Adjustment<'tcx> + { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { @@ -568,7 +574,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, @@ -587,9 +593,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), } } @@ -631,9 +637,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), } } @@ -648,7 +654,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); } }; @@ -661,17 +667,18 @@ 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: vec![None], + if is_ref { + self.unify_and(a_unsafe, b, |target| Adjustment { + kind: Adjust::Deref(vec![None]), autoref: Some(AutoBorrow::RawPtr(mutbl_b)), unsize: false, - } + 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) + } } } @@ -776,6 +783,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `NeverToAny`, so this should always be valid. self.apply_adjustment(expr.id, Adjustment { kind: Adjust::ReifyFnPointer, + autoref: None, + unsize: false, target: fn_ptr }); } @@ -808,11 +817,12 @@ 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 { - ref autoderefs, + let noop = match self.tables.borrow().adjustments.get(&expr.id) { + Some(&Adjustment { + kind: Adjust::Deref(ref autoderefs), autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), - unsize: false + unsize: false, + target: _ }) if autoderefs.len() == 1 => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { @@ -824,7 +834,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } - Some(&Adjust::NeverToAny) => true, + Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => true, Some(_) => false, None => true, }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index ad05a839189..bdbc7f677e4 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -147,12 +147,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Write out the final adjustment. self.apply_adjustment(self.self_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize: pick.unsize.is_some(), - }, - target: target + kind: Adjust::Deref(autoderefs), + autoref, + unsize: pick.unsize.is_some(), + target, }); target @@ -440,7 +438,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // the correct region. let expr_ty = self.node_ty(expr.id); if let Some(adj) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) { - if let Adjust::DerefRef { ref mut autoderefs, .. } = adj.kind { + if let Adjust::Deref(ref mut autoderefs) = adj.kind { let mut autoderef = self.autoderef(expr.span, expr_ty); autoderef.nth(autoderefs.len()).unwrap_or_else(|| { span_bug!(expr.span, @@ -502,9 +500,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // 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)), .. - } + ref mut target, + autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), .. }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bc76c56599d..e6d43f00403 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1779,11 +1779,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { autoderefs: Vec<Option<OverloadedDeref<'tcx>>>, adjusted_ty: Ty<'tcx>) { self.apply_adjustment(node_id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref: None, - unsize: false - }, + kind: Adjust::Deref(autoderefs), + autoref: None, + unsize: false, target: adjusted_ty }); } @@ -1799,17 +1797,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); - 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, _) => return, - (&Adjust::DerefRef { - autoderefs: ref old, + (&Adjustment { kind: Adjust::NeverToAny, .. }, _) => return, + (&Adjustment { + kind: Adjust::Deref(ref old), autoref: Some(AutoBorrow::Ref(..)), - unsize: false - }, &Adjust::DerefRef { - autoderefs: ref new, .. + unsize: false, .. + }, &Adjustment { + kind: Adjust::Deref(ref new), .. }) if old.len() == 1 && new.len() >= 1 => { // A reborrow has no effect before a dereference. } @@ -2235,11 +2233,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let autoderefs = autoderef.adjust_steps(lvalue_pref); self.apply_adjustment(base_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs, - autoref, - unsize - }, + kind: Adjust::Deref(autoderefs), + autoref, + unsize, target: method.sig.inputs()[0] }); @@ -2651,6 +2647,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TypeVariableOrigin::AdjustmentType(expr.span)); self.apply_adjustment(expr.id, Adjustment { kind: Adjust::NeverToAny, + autoref: None, + unsize: false, target: adj_ty }); ty = adj_ty; @@ -3450,11 +3448,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, oprnd_t, lvalue_pref) { let (autoref, method) = self.register_infer_ok_obligations(ok); self.apply_adjustment(oprnd.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: vec![], - autoref, - unsize: false - }, + kind: Adjust::Deref(vec![]), + autoref, + unsize: false, target: method.sig.inputs()[0] }); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 0c820d2404a..8d442aae70e 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -414,11 +414,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); self.apply_adjustment(lhs_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: vec![], - autoref, - unsize: false - }, + kind: Adjust::Deref(vec![]), + autoref, + unsize: false, target: method.sig.inputs()[0] }); self.write_method_call(expr.id, method); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 7fff0ceb778..119ae748f85 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -546,9 +546,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); match adjustment.kind { - adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, .. } => { + adjustment::Adjust::Deref(ref autoderefs) => { let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs)); - if let Some(ref autoref) = *autoref { + if let Some(ref autoref) = adjustment.autoref { self.link_autoref(expr, cmt, autoref); // Require that the resulting region encompasses @@ -569,7 +569,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { source_ty, bounds.region_bound); } */ - _ => {} + _ => { + assert!(adjustment.autoref.is_none()); + } } // If necessary, constrain destructors in the unadjusted form of this |
