From f2a06f760bee698d3c9e1fe4cad33bf1558e3c78 Mon Sep 17 00:00:00 2001
From: Seo Sanghyeon <sanxiyn@gmail.com>
Date: Fri, 2 Jan 2015 20:55:31 +0900
Subject: [PATCH 1/2] Make type in ast::Local optional

---
 src/librustc/middle/region.rs    |  5 ++++-
 src/librustc_resolve/lib.rs      |  4 +++-
 src/librustc_trans/save/mod.rs   |  2 +-
 src/librustc_typeck/check/mod.rs |  6 +++---
 src/libsyntax/ast.rs             |  2 +-
 src/libsyntax/ext/build.rs       |  4 ++--
 src/libsyntax/ext/expand.rs      |  2 +-
 src/libsyntax/fold.rs            |  2 +-
 src/libsyntax/parse/parser.rs    |  8 ++------
 src/libsyntax/print/pprust.rs    | 10 ++++------
 src/libsyntax/visit.rs           | 14 +++++++++-----
 11 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index be89b32cdaa..0e47f338bb9 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -649,7 +649,10 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) {
         Some(ref expr) => {
             record_rvalue_scope_if_borrow_expr(visitor, &**expr, blk_scope);
 
-            if is_binding_pat(&*local.pat) || is_borrowed_ty(&*local.ty) {
+            let is_borrow =
+                if let Some(ref ty) = local.ty { is_borrowed_ty(&**ty) } else { false };
+
+            if is_binding_pat(&*local.pat) || is_borrow {
                 record_rvalue_scope(visitor, &**expr, blk_scope);
             }
         }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 10756f21551..b22b4bdc211 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3401,7 +3401,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
     fn resolve_local(&mut self, local: &Local) {
         // Resolve the type.
-        self.resolve_type(&*local.ty);
+        if let Some(ref ty) = local.ty {
+            self.resolve_type(&**ty);
+        }
 
         // Resolve the initializer, if necessary.
         match local.init {
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 51ea0af8e10..4396740de4e 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -1496,7 +1496,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
         self.collected_paths.clear();
 
         // Just walk the initialiser and type (don't want to walk the pattern again).
-        self.visit_ty(&*l.ty);
+        visit::walk_ty_opt(self, &l.ty);
         visit::walk_expr_opt(self, &l.init);
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 60bb96a2b84..c0ca540841f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -485,9 +485,9 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
 impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> {
     // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &ast::Local) {
-        let o_ty = match local.ty.node {
-            ast::TyInfer => None,
-            _ => Some(self.fcx.to_ty(&*local.ty))
+        let o_ty = match local.ty {
+            Some(ref ty) => Some(self.fcx.to_ty(&**ty)),
+            None => None
         };
         self.assign(local.span, local.id, o_ty);
         debug!("Local variable {} is assigned type {}",
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 12432c8c78f..93750867750 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -643,8 +643,8 @@ pub enum LocalSource {
 /// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
 #[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub struct Local {
-    pub ty: P<Ty>,
     pub pat: P<Pat>,
+    pub ty: Option<P<Ty>>,
     pub init: Option<P<Expr>>,
     pub id: NodeId,
     pub span: Span,
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 239af188909..ea345f3a458 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -482,8 +482,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             self.pat_ident(sp, ident)
         };
         let local = P(ast::Local {
-            ty: self.ty_infer(sp),
             pat: pat,
+            ty: None,
             init: Some(ex),
             id: ast::DUMMY_NODE_ID,
             span: sp,
@@ -506,8 +506,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             self.pat_ident(sp, ident)
         };
         let local = P(ast::Local {
-            ty: typ,
             pat: pat,
+            ty: Some(typ),
             init: Some(ex),
             id: ast::DUMMY_NODE_ID,
             span: sp,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5de7068563d..dcf25a26e2c 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -712,7 +712,7 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE
                 let rewritten_local = local.map(|Local {id, pat, ty, init, source, span}| {
                     // expand the ty since TyFixedLengthVec contains an Expr
                     // and thus may have a macro use
-                    let expanded_ty = fld.fold_ty(ty);
+                    let expanded_ty = ty.map(|t| fld.fold_ty(t));
                     // expand the pat (it might contain macro uses):
                     let expanded_pat = fld.fold_pat(pat);
                     // find the PatIdents in the pattern:
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4f0169e31f2..c134b11a0eb 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -553,7 +553,7 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
     l.map(|Local {id, pat, ty, init, source, span}| Local {
         id: fld.new_id(id),
-        ty: fld.fold_ty(ty),
+        ty: ty.map(|t| fld.fold_ty(t)),
         pat: fld.fold_pat(pat),
         init: init.map(|e| fld.fold_expr(e)),
         source: source,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 457085f5cc8..c7327a24bb6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3627,13 +3627,9 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         let pat = self.parse_pat();
 
-        let mut ty = P(Ty {
-            id: ast::DUMMY_NODE_ID,
-            node: TyInfer,
-            span: mk_sp(lo, lo),
-        });
+        let mut ty = None;
         if self.eat(&token::Colon) {
-            ty = self.parse_ty_sum();
+            ty = Some(self.parse_ty_sum());
         }
         let init = self.parse_initializer();
         P(ast::Local {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 02a03285d3b..3f3af4ed709 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1858,13 +1858,11 @@ impl<'a> State<'a> {
 
     pub fn print_local_decl(&mut self, loc: &ast::Local) -> IoResult<()> {
         try!(self.print_pat(&*loc.pat));
-        match loc.ty.node {
-            ast::TyInfer => Ok(()),
-            _ => {
-                try!(self.word_space(":"));
-                self.print_type(&*loc.ty)
-            }
+        if let Some(ref ty) = loc.ty {
+            try!(self.word_space(":"));
+            try!(self.print_type(&**ty));
         }
+        Ok(())
     }
 
     pub fn print_decl(&mut self, decl: &ast::Decl) -> IoResult<()> {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 40ca6354ca6..e532c76347f 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -211,7 +211,7 @@ pub fn walk_view_item<'v, V: Visitor<'v>>(visitor: &mut V, vi: &'v ViewItem) {
 
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     visitor.visit_pat(&*local.pat);
-    visitor.visit_ty(&*local.ty);
+    walk_ty_opt(visitor, &local.ty);
     walk_expr_opt(visitor, &local.init);
 }
 
@@ -381,6 +381,13 @@ pub fn skip_ty<'v, V: Visitor<'v>>(_: &mut V, _: &'v Ty) {
     // Empty!
 }
 
+pub fn walk_ty_opt<'v, V: Visitor<'v>>(visitor: &mut V, optional_type: &'v Option<P<Ty>>) {
+    match *optional_type {
+        Some(ref ty) => visitor.visit_ty(&**ty),
+        None => ()
+    }
+}
+
 pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
     match typ.node {
         TyVec(ref ty) | TyParen(ref ty) => {
@@ -583,10 +590,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V,
 pub fn walk_ty_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v TyParam) {
     visitor.visit_ident(param.span, param.ident);
     walk_ty_param_bounds_helper(visitor, &param.bounds);
-    match param.default {
-        Some(ref ty) => visitor.visit_ty(&**ty),
-        None => {}
-    }
+    walk_ty_opt(visitor, &param.default);
 }
 
 pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {

From 4ae7c38e7b3edce3343dee520fe588130f140dc8 Mon Sep 17 00:00:00 2001
From: Seo Sanghyeon <sanxiyn@gmail.com>
Date: Fri, 2 Jan 2015 22:28:53 +0900
Subject: [PATCH 2/2] Add a pretty-print test

---
 src/test/pretty/let.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 src/test/pretty/let.rs

diff --git a/src/test/pretty/let.rs b/src/test/pretty/let.rs
new file mode 100644
index 00000000000..736ea3a0d10
--- /dev/null
+++ b/src/test/pretty/let.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pp-exact
+
+// Check that `let x: _ = 0;` does not print as `let x = 0;`.
+
+fn main() {
+    let x: _ = 0;
+
+    let _ = x;
+}