]> git.lizzy.rs Git - rust.git/commitdiff
elide noop coercions
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 18 Mar 2016 21:19:52 +0000 (17:19 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 18 Mar 2016 21:19:52 +0000 (17:19 -0400)
src/librustc_typeck/check/coercion.rs

index a2c0b5b89342c353b8cf9f752007afd5d283bf1d..164503980cd0b7d56f7d5d914af0363db8967ae5 100644 (file)
@@ -218,10 +218,10 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
         // to type check, we will construct the type that `&M*expr` would
         // yield.
 
-        let r_a = match a.sty {
+        let (r_a, mt_a) = match a.sty {
             ty::TyRef(r_a, mt_a) => {
                 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
-                r_a
+                (r_a, mt_a)
             }
             _ => return self.unify_and_identity(a, b)
         };
@@ -355,6 +355,20 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
 
         // Now apply the autoref. We have to extract the region out of
         // the final ref type we got.
+        if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 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
+            // altogether. This is just an optimization.
+            //
+            // Note that for `&mut`, we DO want to reborrow --
+            // otherwise, this would be a move, which might be an
+            // error. For example `foo(self.x)` where `self` and
+            // `self.x` both have `&mut `type would be a move of
+            // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
+            // which is a borrow.
+            return self.identity(ty);
+        }
         let r_borrow = match ty.sty {
             ty::TyRef(r_borrow, _) => r_borrow,
             _ => self.tcx().sess.span_bug(span,