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:
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user