From b35a587da144848e6f2ebe16018df3cf1c1b2a0e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 14 Apr 2015 11:44:26 +1200 Subject: [PATCH] Reviewer comments --- src/librustc/middle/expr_use_visitor.rs | 28 +++----- src/librustc/middle/ty.rs | 78 ++++++++++++++------- src/librustc_typeck/check/method/confirm.rs | 5 +- src/test/compile-fail/issue-21950.rs | 2 +- 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c0b4800bb05..5235bbdf9cf 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -848,26 +848,16 @@ fn walk_autoderefref(&mut self, self.walk_autoderefs(expr, adj.autoderefs); - // Weird hacky special case: AutoUnsizeUniq, which converts - // from a ~T to a ~Trait etc, always comes in a stylized - // fashion. In particular, we want to consume the ~ pointer - // being dereferenced, not the dereferenced content (as the - // content is, at least for upcasts, unsized). - if let Some(ty) = adj.unsize { - if let ty::ty_uniq(_) = ty.sty { - assert!(adj.autoderefs == 0, - format!("Expected no derefs with unsize AutoRefs, found: {}", - adj.repr(self.tcx()))); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - return; - } - } + let cmt_derefd = + return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); - self.walk_autoref(expr, cmt_derefd, adj.autoref); + let cmt_refd = + self.walk_autoref(expr, cmt_derefd, adj.autoref); + + if adj.unsize.is_some() { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt_refd); + } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ce543845717..be126b0b54c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -283,58 +283,84 @@ pub enum Variance { #[derive(Copy, Clone, Debug)] pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer AdjustDerefRef(AutoDerefRef<'tcx>), } /// 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. -/// 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 -/// 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. /// -/// A DST 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: +/// 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 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: +/// +/// ``` /// AutoDerefRef { /// autoderefs: 1, // &[i32; 4] -> [i32; 4] -/// unsize: Some([i32]), // [i32; 4] -> [i32] /// autoref: Some(AutoPtr), // [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]`. /// -/// Box pointers are treated somewhat differently, the last deref is not counted, -/// nor is the 'ref' to a `Box<_>`. Imagine them more like structs. -/// E.g., Box<[i32; 4]> -> Box<[i32]> is represented by: +/// 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: +/// +/// ``` /// AutoDerefRef { /// autoderefs: 0, -/// unsize: Some(Box<[i32]>), /// autoref: None, +/// unsize: Some(Box<[i32]>), /// } +/// ``` #[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { - // FIXME with more powerful date structures we could have a better design - // here. - - /// Apply a number of dereferences, producing an lvalue. + /// Step 1. Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, - /// Produce a pointer/reference from the value. + /// Step 2. Optionally produce a pointer/reference from the value. pub autoref: Option>, - /// Unsize a pointer/reference value, e.g. &[T; n] to &[T]. - /// The stored type is the target pointer type. + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. The stored type is the target pointer type. Note that + /// the source could be a thin or fat pointer. pub unsize: Option>, } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 4e62542854f..7eb15a14796 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -143,7 +143,10 @@ fn adjust_self_ty(&mut self, ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) })) } else { - // No unsizing should be performed without autoref. + // 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, None) }; diff --git a/src/test/compile-fail/issue-21950.rs b/src/test/compile-fail/issue-21950.rs index 315a4cd90c5..900ad5ce812 100644 --- a/src/test/compile-fail/issue-21950.rs +++ b/src/test/compile-fail/issue-21950.rs @@ -14,7 +14,7 @@ fn main() { let x = &10 as - //~^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified &Add; //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self` + //~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified }