diff options
| author | bors <bors@rust-lang.org> | 2016-03-08 01:31:04 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-03-08 01:31:04 -0800 |
| commit | 3af60f831f75ae2632bbfd4c1aa66049ec2d486a (patch) | |
| tree | 211677e1c9a46740ec3fc9cba30c5f7346ad675d /src/test | |
| parent | a9ffe67f98366c58f13e89851d025e8e063f0bb2 (diff) | |
| parent | 2de4932453a99a19e9033edb47db7a66a612188c (diff) | |
| download | rust-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.rs | 20 | ||||
| -rw-r--r-- | src/test/parse-fail/issue-19096.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/issue-3036.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/macros-no-semicolon.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/match-refactor-to-expr.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/range-3.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/range-4.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/raw-str-unbalanced.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/removed-syntax-mut-vec-expr.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/removed-syntax-uniq-mut-expr.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/removed-syntax-with-1.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/struct-literal-in-for.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/struct-literal-in-if.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/struct-literal-in-match-discriminant.rs | 2 | ||||
| -rw-r--r-- | src/test/parse-fail/struct-literal-in-while.rs | 2 | ||||
| -rw-r--r-- | src/test/run-pass/try-operator-hygiene.rs | 34 | ||||
| -rw-r--r-- | src/test/run-pass/try-operator.rs | 200 |
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) + } +} |
