about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2017-11-07 15:52:15 +0800
committerkennytm <kennytm@gmail.com>2017-11-07 22:40:20 +0800
commit0d53ecd0c788d5c492cf5023c8c76420ef349244 (patch)
tree67cdcf6f5cf391b20eb76b4f09ac77b028a2e3b3
parent1683b830a88c99c5072563150acb3f7feaac0d04 (diff)
parentaa38a1ee5092fb81e23b0cbd215535de08ae7b28 (diff)
downloadrust-0d53ecd0c788d5c492cf5023c8c76420ef349244.tar.gz
rust-0d53ecd0c788d5c492cf5023c8c76420ef349244.zip
Rollup merge of #45784 - harpocrates:fix/print-parens-cast-lt, r=kennytm
Pretty print parens around casts on the LHS of `<`/`<<`

When pretty printing a cast expression occuring on the LHS of a `<` or `<<` expression, we should add parens around the cast. Otherwise, the `<`/`<<` gets interpreted as the beginning of the generics for the type on the RHS of the cast.

Consider:

    $ cat parens_cast.rs
    macro_rules! negative {
        ($e:expr) => { $e < 0 }
    }

    fn main() {
        negative!(1 as i32);
    }

Before this PR, the output of the following is not valid Rust:

    $ rustc -Z unstable-options --pretty=expanded parens_cast.rs
    #![feature(prelude_import)]
    #![no_std]
    #[prelude_import]
    use std::prelude::v1::*;
    #[macro_use]
    extern crate std as std;
    macro_rules! negative(( $ e : expr ) => { $ e < 0 });

    fn main() { 1 as i32 < 0; }

After this PR, the output of the following is valid Rust:

    $ rustc -Z unstable-options --pretty=expanded parens_cast.rs
    #![feature(prelude_import)]
    #![no_std]
    #[prelude_import]
    use std::prelude::v1::*;
    #[macro_use]
    extern crate std as std;
    macro_rules! negative(( $ e : expr ) => { $ e < 0 });

    fn main() { (1 as i32) < 0; }

I've gone through several README/wiki style documents but I'm still not sure where to test this though. I'm not even sure if this sort of thing is tested...
-rw-r--r--src/librustc/hir/print.rs9
-rw-r--r--src/libsyntax/print/pprust.rs9
-rw-r--r--src/test/pretty/cast-lt.pp24
-rw-r--r--src/test/pretty/cast-lt.rs22
4 files changed, 64 insertions, 0 deletions
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 7b4881f5486..7d0f26ba34d 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1254,6 +1254,15 @@ impl<'a> State<'a> {
             Fixity::None => (prec + 1, prec + 1),
         };
 
+        let left_prec = match (&lhs.node, op.node) {
+            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+            (&hir::ExprCast { .. }, hir::BinOp_::BiLt) |
+            (&hir::ExprCast { .. }, hir::BinOp_::BiShl) => parser::PREC_FORCE_PAREN,
+            _ => left_prec,
+        };
+
         self.print_expr_maybe_paren(lhs, left_prec)?;
         self.s.space()?;
         self.word_space(op.node.as_str())?;
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 227db93cf65..5cb8e8694cf 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1987,6 +1987,15 @@ impl<'a> State<'a> {
             Fixity::None => (prec + 1, prec + 1),
         };
 
+        let left_prec = match (&lhs.node, op.node) {
+            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt) |
+            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Shl) => parser::PREC_FORCE_PAREN,
+            _ => left_prec,
+        };
+
         self.print_expr_maybe_paren(lhs, left_prec)?;
         self.s.space()?;
         self.word_space(op.node.to_string())?;
diff --git a/src/test/pretty/cast-lt.pp b/src/test/pretty/cast-lt.pp
new file mode 100644
index 00000000000..b21158abfe5
--- /dev/null
+++ b/src/test/pretty/cast-lt.pp
@@ -0,0 +1,24 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use std::prelude::v1::*;
+#[macro_use]
+extern crate std as std;
+// Copyright 2017 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.
+
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:cast-lt.pp
+
+macro_rules! negative(( $ e : expr ) => { $ e < 0 });
+
+fn main() { (1 as i32) < 0; }
+
diff --git a/src/test/pretty/cast-lt.rs b/src/test/pretty/cast-lt.rs
new file mode 100644
index 00000000000..87b5274545f
--- /dev/null
+++ b/src/test/pretty/cast-lt.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 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.
+
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:cast-lt.pp
+
+macro_rules! negative {
+      ($e:expr) => { $e < 0 }
+}
+
+fn main() {
+      negative!(1 as i32);
+}
+