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
This commit is contained in:
Jorge Aparicio
2016-02-28 17:38:48 -05:00
parent c116ae35cf
commit 210dd611aa
12 changed files with 355 additions and 2 deletions

View File

@@ -1022,6 +1022,9 @@ pub enum ExprKind {
/// No-op: used solely so we can pretty-print faithfully
Paren(P<Expr>),
/// `expr?`
Try(P<Expr>),
}
/// The explicit Self type in a "qualified path". The actual

View File

@@ -245,6 +245,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
// a...b and ...b
("inclusive_range_syntax", "1.7.0", Some(28237), Active),
// `expr?`
("question_mark", "1.9.0", Some(31436), Active)
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
@@ -570,6 +573,7 @@ pub struct Features {
pub staged_api: bool,
pub stmt_expr_attributes: bool,
pub deprecated: bool,
pub question_mark: bool,
}
impl Features {
@@ -603,6 +607,7 @@ impl Features {
staged_api: false,
stmt_expr_attributes: false,
deprecated: false,
question_mark: false,
}
}
}
@@ -1001,6 +1006,9 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
e.span,
"inclusive range syntax is experimental");
}
ast::ExprKind::Try(..) => {
self.gate_feature("question_mark", e.span, "the `?` operator is not stable");
}
_ => {}
}
visit::walk_expr(self, e);
@@ -1203,6 +1211,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
staged_api: cx.has_feature("staged_api"),
stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
deprecated: cx.has_feature("deprecated"),
question_mark: cx.has_feature("question_mark"),
}
}

View File

@@ -1332,7 +1332,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
fields.move_map(|x| folder.fold_field(x)),
maybe_expr.map(|x| folder.fold_expr(x)))
},
ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex))
ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex)),
ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
},
span: folder.new_span(span),
attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)),

View File

@@ -2534,6 +2534,12 @@ impl<'a> Parser<'a> {
let mut e = e0;
let mut hi;
loop {
// expr?
while self.eat(&token::Question) {
let hi = self.span.hi;
e = self.mk_expr(lo, hi, ExprKind::Try(e), None);
}
// expr.f
if self.eat(&token::Dot) {
match self.token {
@@ -2907,7 +2913,6 @@ impl<'a> Parser<'a> {
}
};
if self.expr_is_complete(&lhs) {
// Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
return Ok(lhs);

View File

@@ -2277,6 +2277,10 @@ impl<'a> State<'a> {
try!(self.print_inner_attributes_inline(attrs));
try!(self.print_expr(&e));
try!(self.pclose());
},
ast::ExprKind::Try(ref e) => {
try!(self.print_expr(e));
try!(word(&mut self.s, "?"))
}
}
try!(self.ann.post(self, NodeExpr(expr)));

View File

@@ -793,6 +793,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_expr(&output.expr)
}
}
ExprKind::Try(ref subexpression) => {
visitor.visit_expr(subexpression)
}
}
visitor.visit_expr_post(expression)