about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-03-08 01:31:04 -0800
committerbors <bors@rust-lang.org>2016-03-08 01:31:04 -0800
commit3af60f831f75ae2632bbfd4c1aa66049ec2d486a (patch)
tree211677e1c9a46740ec3fc9cba30c5f7346ad675d /src/test
parenta9ffe67f98366c58f13e89851d025e8e063f0bb2 (diff)
parent2de4932453a99a19e9033edb47db7a66a612188c (diff)
downloadrust-3af60f831f75ae2632bbfd4c1aa66049ec2d486a.tar.gz
rust-3af60f831f75ae2632bbfd4c1aa66049ec2d486a.zip
Auto merge of #31954 - japaric:rfc243, r=nikomatsakis
implement the `?` operator

The `?` postfix operator is sugar equivalent to the try! macro, but is more amenable to chaining:
`File::open("foo")?.metadata()?.is_dir()`.

`?` is accepted on any *expression* that can return a `Result`, e.g. `x()?`, `y!()?`, `{z}?`,
`(w)?`, etc. And binds more tightly than unary operators, e.g. `!x?` is parsed as `!(x?)`.

cc #31436

---

cc @aturon @eddyb
Diffstat (limited to 'src/test')
-rw-r--r--src/test/compile-fail/feature-gate-try-operator.rs20
-rw-r--r--src/test/parse-fail/issue-19096.rs2
-rw-r--r--src/test/parse-fail/issue-3036.rs2
-rw-r--r--src/test/parse-fail/macros-no-semicolon.rs2
-rw-r--r--src/test/parse-fail/match-refactor-to-expr.rs2
-rw-r--r--src/test/parse-fail/range-3.rs2
-rw-r--r--src/test/parse-fail/range-4.rs2
-rw-r--r--src/test/parse-fail/raw-str-unbalanced.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-mut-vec-expr.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-uniq-mut-expr.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-with-1.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-for.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-if.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-match-discriminant.rs2
-rw-r--r--src/test/parse-fail/struct-literal-in-while.rs2
-rw-r--r--src/test/run-pass/try-operator-hygiene.rs34
-rw-r--r--src/test/run-pass/try-operator.rs200
17 files changed, 268 insertions, 14 deletions
diff --git a/src/test/compile-fail/feature-gate-try-operator.rs b/src/test/compile-fail/feature-gate-try-operator.rs
new file mode 100644
index 00000000000..184aa63b234
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-try-operator.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 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.
+
+macro_rules! id {
+    ($e:expr) => { $e }
+}
+
+fn main() {
+    id!(x?);  //~ error: the `?` operator is not stable (see issue #31436)
+    //~^ help: add #![feature(question_mark)] to the crate attributes to enable
+    y?;  //~ error: the `?` operator is not stable (see issue #31436)
+    //~^ help: add #![feature(question_mark)] to the crate attributes to enable
+}
diff --git a/src/test/parse-fail/issue-19096.rs b/src/test/parse-fail/issue-19096.rs
index 0d9a111045a..6ba0fb5f15b 100644
--- a/src/test/parse-fail/issue-19096.rs
+++ b/src/test/parse-fail/issue-19096.rs
@@ -12,5 +12,5 @@
 
 fn main() {
     let t = (42, 42);
-    t.0::<isize>; //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `::`
+    t.0::<isize>; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `::`
 }
diff --git a/src/test/parse-fail/issue-3036.rs b/src/test/parse-fail/issue-3036.rs
index 1946e984e5d..229b12136fc 100644
--- a/src/test/parse-fail/issue-3036.rs
+++ b/src/test/parse-fail/issue-3036.rs
@@ -15,4 +15,4 @@
 fn main()
 {
     let x = 3
-} //~ ERROR: expected one of `.`, `;`, or an operator, found `}`
+} //~ ERROR: expected one of `.`, `;`, `?`, or an operator, found `}`
diff --git a/src/test/parse-fail/macros-no-semicolon.rs b/src/test/parse-fail/macros-no-semicolon.rs
index 5931631ccee..1c55d70f607 100644
--- a/src/test/parse-fail/macros-no-semicolon.rs
+++ b/src/test/parse-fail/macros-no-semicolon.rs
@@ -12,6 +12,6 @@
 
 fn main() {
     assert_eq!(1, 2)
-    assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert_eq`
+    assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq`
     println!("hello");
 }
diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs
index b99d0493ff7..37b66601e70 100644
--- a/src/test/parse-fail/match-refactor-to-expr.rs
+++ b/src/test/parse-fail/match-refactor-to-expr.rs
@@ -14,7 +14,7 @@ fn main() {
     let foo =
         match //~ NOTE did you mean to remove this `match` keyword?
         Some(4).unwrap_or_else(5)
-        ; //~ ERROR expected one of `.`, `{`, or an operator, found `;`
+        ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;`
 
     println!("{}", foo)
 }
diff --git a/src/test/parse-fail/range-3.rs b/src/test/parse-fail/range-3.rs
index 284cdb8c653..95aa71b0cdf 100644
--- a/src/test/parse-fail/range-3.rs
+++ b/src/test/parse-fail/range-3.rs
@@ -14,5 +14,5 @@
 
 pub fn main() {
     let r = 1..2..3;
-    //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
+    //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..`
 }
diff --git a/src/test/parse-fail/range-4.rs b/src/test/parse-fail/range-4.rs
index 69898612771..4500df116a2 100644
--- a/src/test/parse-fail/range-4.rs
+++ b/src/test/parse-fail/range-4.rs
@@ -14,5 +14,5 @@
 
 pub fn main() {
     let r = ..1..2;
-    //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
+    //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..`
 }
diff --git a/src/test/parse-fail/raw-str-unbalanced.rs b/src/test/parse-fail/raw-str-unbalanced.rs
index ce8960edde1..5c09f68970b 100644
--- a/src/test/parse-fail/raw-str-unbalanced.rs
+++ b/src/test/parse-fail/raw-str-unbalanced.rs
@@ -12,5 +12,5 @@
 
 static s: &'static str =
     r#"
-      "## //~ ERROR expected one of `.`, `;`, or an operator, found `#`
+      "## //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `#`
 ;
diff --git a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
index ab9ff7ac19e..301bd0e8b1c 100644
--- a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
+++ b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs
@@ -13,5 +13,5 @@
 fn f() {
     let v = [mut 1, 2, 3, 4];
     //~^  ERROR expected identifier, found keyword `mut`
-    //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `]`, `{`, or an operator, found `1`
+    //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `?`, `]`, `{`, or an operator, found `1`
 }
diff --git a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
index ea686aeb6e0..2f637cf0b4e 100644
--- a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
+++ b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs
@@ -13,5 +13,5 @@
 fn f() {
     let a_box = box mut 42;
     //~^  ERROR expected identifier, found keyword `mut`
-    //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, or an operator, found `42`
+    //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `42`
 }
diff --git a/src/test/parse-fail/removed-syntax-with-1.rs b/src/test/parse-fail/removed-syntax-with-1.rs
index e9de52c013b..156b172a944 100644
--- a/src/test/parse-fail/removed-syntax-with-1.rs
+++ b/src/test/parse-fail/removed-syntax-with-1.rs
@@ -18,5 +18,5 @@ fn removed_with() {
 
     let a = S { foo: (), bar: () };
     let b = S { foo: () with a };
-    //~^ ERROR expected one of `,`, `.`, `}`, or an operator, found `with`
+    //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
 }
diff --git a/src/test/parse-fail/struct-literal-in-for.rs b/src/test/parse-fail/struct-literal-in-for.rs
index e57298f7280..93098455560 100644
--- a/src/test/parse-fail/struct-literal-in-for.rs
+++ b/src/test/parse-fail/struct-literal-in-for.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     for x in Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-if.rs b/src/test/parse-fail/struct-literal-in-if.rs
index 6bf41b7a450..db6a360a567 100644
--- a/src/test/parse-fail/struct-literal-in-if.rs
+++ b/src/test/parse-fail/struct-literal-in-if.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     if Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-match-discriminant.rs b/src/test/parse-fail/struct-literal-in-match-discriminant.rs
index 679f4542824..7038cc798c4 100644
--- a/src/test/parse-fail/struct-literal-in-match-discriminant.rs
+++ b/src/test/parse-fail/struct-literal-in-match-discriminant.rs
@@ -20,6 +20,6 @@ fn main() {
     } {
         Foo {
             x: x
-        } => {} //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `=>`
+        } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>`
     }
 }
diff --git a/src/test/parse-fail/struct-literal-in-while.rs b/src/test/parse-fail/struct-literal-in-while.rs
index b388aac2c54..75e4eb3de07 100644
--- a/src/test/parse-fail/struct-literal-in-while.rs
+++ b/src/test/parse-fail/struct-literal-in-while.rs
@@ -23,7 +23,7 @@ impl Foo {
 fn main() {
     while Foo {
         x: 3    //~ ERROR expected type, found `3`
-    }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{`
+    }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
         println!("yo");
     }
 }
diff --git a/src/test/run-pass/try-operator-hygiene.rs b/src/test/run-pass/try-operator-hygiene.rs
new file mode 100644
index 00000000000..233c03df4e5
--- /dev/null
+++ b/src/test/run-pass/try-operator-hygiene.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 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.
+
+// `expr?` expands to:
+//
+// match expr {
+//     Ok(val) => val,
+//     Err(err) => return From::from(err),
+// }
+//
+// This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and
+// `err` bindings that may be in scope.
+
+#![feature(question_mark)]
+
+use std::num::ParseIntError;
+
+fn main() {
+    assert_eq!(parse(), Ok(1));
+}
+
+fn parse() -> Result<i32, ParseIntError> {
+    const val: char = 'a';
+    const err: char = 'b';
+
+    Ok("1".parse::<i32>()?)
+}
diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs
new file mode 100644
index 00000000000..de5ccf09c59
--- /dev/null
+++ b/src/test/run-pass/try-operator.rs
@@ -0,0 +1,200 @@
+// Copyright 2016 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.
+
+#![feature(question_mark)]
+
+use std::fs::File;
+use std::io::{Read, self};
+use std::num::ParseIntError;
+use std::str::FromStr;
+
+fn on_method() -> Result<i32, ParseIntError> {
+    Ok("1".parse::<i32>()? + "2".parse::<i32>()?)
+}
+
+fn in_chain() -> Result<String, ParseIntError> {
+    Ok("3".parse::<i32>()?.to_string())
+}
+
+fn on_call() -> Result<i32, ParseIntError> {
+    fn parse<T: FromStr>(s: &str) -> Result<T, T::Err> {
+        s.parse()
+    }
+
+    Ok(parse("4")?)
+}
+
+fn nested() -> Result<i32, ParseIntError> {
+    Ok("5".parse::<i32>()?.to_string().parse()?)
+}
+
+fn on_path() -> Result<i32, ParseIntError> {
+    let x = "6".parse::<i32>();
+
+    Ok(x?)
+}
+
+fn on_macro() -> Result<i32, ParseIntError> {
+    macro_rules! id {
+        ($e:expr) => { $e }
+    }
+
+    Ok(id!("7".parse::<i32>())?)
+}
+
+fn on_parens() -> Result<i32, ParseIntError> {
+    let x = "8".parse::<i32>();
+
+    Ok((x)?)
+}
+
+fn on_block() -> Result<i32, ParseIntError> {
+    let x = "9".parse::<i32>();
+
+    Ok({x}?)
+}
+
+fn on_field() -> Result<i32, ParseIntError> {
+    struct Pair<A, B> { a: A, b: B }
+
+    let x = Pair { a: "10".parse::<i32>(), b: 0 };
+
+    Ok(x.a?)
+}
+
+fn on_tuple_field() -> Result<i32, ParseIntError> {
+    let x = ("11".parse::<i32>(), 0);
+
+    Ok(x.0?)
+}
+
+fn on_try() -> Result<i32, ParseIntError> {
+    let x = "12".parse::<i32>().map(|i| i.to_string().parse::<i32>());
+
+    Ok(x??)
+}
+
+fn on_binary_op() -> Result<i32, ParseIntError> {
+    let x = 13 - "14".parse::<i32>()?;
+    let y = "15".parse::<i32>()? - 16;
+    let z = "17".parse::<i32>()? - "18".parse::<i32>()?;
+
+    Ok(x + y + z)
+}
+
+fn on_index() -> Result<i32, ParseIntError> {
+    let x = [19];
+    let y = "0".parse::<usize>();
+
+    Ok(x[y?])
+}
+
+fn on_args() -> Result<i32, ParseIntError> {
+    fn sub(x: i32, y: i32) -> i32 { x - y }
+
+    let x = "20".parse();
+    let y = "21".parse();
+
+    Ok(sub(x?, y?))
+}
+
+fn on_if() -> Result<i32, ParseIntError> {
+    Ok(if true {
+        "22".parse::<i32>()
+    } else {
+        "23".parse::<i32>()
+    }?)
+}
+
+fn on_if_let() -> Result<i32, ParseIntError> {
+    Ok(if let Ok(..) = "24".parse::<i32>() {
+        "25".parse::<i32>()
+    } else {
+        "26".parse::<i32>()
+    }?)
+}
+
+fn on_match() -> Result<i32, ParseIntError> {
+    Ok(match "27".parse::<i32>() {
+        Err(..) => "28".parse::<i32>(),
+        Ok(..) => "29".parse::<i32>(),
+    }?)
+}
+
+fn tight_binding() -> Result<bool, ()> {
+    fn ok<T>(x: T) -> Result<T, ()> { Ok(x) }
+
+    let x = ok(true);
+    Ok(!x?)
+}
+
+// just type check
+fn merge_error() -> Result<i32, Error> {
+    let mut s = String::new();
+
+    File::open("foo.txt")?.read_to_string(&mut s)?;
+
+    Ok(s.parse::<i32>()? + 1)
+}
+
+fn main() {
+    assert_eq!(Ok(3), on_method());
+
+    assert_eq!(Ok("3".to_string()), in_chain());
+
+    assert_eq!(Ok(4), on_call());
+
+    assert_eq!(Ok(5), nested());
+
+    assert_eq!(Ok(6), on_path());
+
+    assert_eq!(Ok(7), on_macro());
+
+    assert_eq!(Ok(8), on_parens());
+
+    assert_eq!(Ok(9), on_block());
+
+    assert_eq!(Ok(10), on_field());
+
+    assert_eq!(Ok(11), on_tuple_field());
+
+    assert_eq!(Ok(12), on_try());
+
+    assert_eq!(Ok(-3), on_binary_op());
+
+    assert_eq!(Ok(19), on_index());
+
+    assert_eq!(Ok(-1), on_args());
+
+    assert_eq!(Ok(22), on_if());
+
+    assert_eq!(Ok(25), on_if_let());
+
+    assert_eq!(Ok(29), on_match());
+
+    assert_eq!(Ok(false), tight_binding());
+}
+
+enum Error {
+    Io(io::Error),
+    Parse(ParseIntError),
+}
+
+impl From<io::Error> for Error {
+    fn from(e: io::Error) -> Error {
+        Error::Io(e)
+    }
+}
+
+impl From<ParseIntError> for Error {
+    fn from(e: ParseIntError) -> Error {
+        Error::Parse(e)
+    }
+}