diff --git a/src/chains.rs b/src/chains.rs index fbaf0831f6d..9ab20b355fb 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -195,6 +195,7 @@ enum ChainItemKind { StructField(symbol::Ident), TupleField(symbol::Ident, bool), Await, + Use, Yield, Comment(String, CommentPosition), } @@ -207,6 +208,7 @@ impl ChainItemKind { | ChainItemKind::StructField(..) | ChainItemKind::TupleField(..) | ChainItemKind::Await + | ChainItemKind::Use | ChainItemKind::Yield | ChainItemKind::Comment(..) => false, } @@ -262,6 +264,10 @@ impl ChainItemKind { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Await, span) } + ast::ExprKind::Use(ref nested, _) => { + let span = mk_sp(nested.span.hi(), expr.span.hi()); + (ChainItemKind::Use, span) + } ast::ExprKind::Yield(ast::YieldKind::Postfix(ref nested)) => { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Yield, span) @@ -313,6 +319,7 @@ impl Rewrite for ChainItem { rewrite_ident(context, ident) ), ChainItemKind::Await => ".await".to_owned(), + ChainItemKind::Use => ".use".to_owned(), ChainItemKind::Yield => ".yield".to_owned(), ChainItemKind::Comment(ref comment, _) => { rewrite_comment(comment, false, shape, context.config)? @@ -517,6 +524,7 @@ impl Chain { ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) | ast::ExprKind::Await(ref subexpr, _) + | ast::ExprKind::Use(ref subexpr, _) | ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr { expr: Self::convert_try(subexpr, context), is_method_call_receiver: false, diff --git a/src/closures.rs b/src/closures.rs index c4bc00fc75a..ca733e7aaaf 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -294,14 +294,14 @@ fn rewrite_closure_fn_decl( Some(ast::CoroutineKind::AsyncGen { .. }) => "async gen ", None => "", }; - let mover = if matches!(capture, ast::CaptureBy::Value { .. }) { - "move " - } else { - "" + let capture_str = match capture { + ast::CaptureBy::Value { .. } => "move ", + ast::CaptureBy::Use { .. } => "use ", + ast::CaptureBy::Ref => "", }; // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. - let offset = binder.len() + const_.len() + immovable.len() + coro.len() + mover.len(); + let offset = binder.len() + const_.len() + immovable.len() + coro.len() + capture_str.len(); let nested_shape = shape.shrink_left(offset, span)?.sub_width(4, span)?; // 1 = | @@ -339,7 +339,7 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{binder}{const_}{immovable}{coro}{mover}|{list_str}|"); + let mut prefix = format!("{binder}{const_}{immovable}{coro}{capture_str}|{list_str}|"); if !ret_str.is_empty() { if prefix.contains('\n') { diff --git a/src/expr.rs b/src/expr.rs index 746e4680346..ec96b3edce8 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -161,10 +161,6 @@ pub(crate) fn format_expr( ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) } - ast::ExprKind::Use(_, _) => { - // FIXME: properly implement this - Ok(context.snippet(expr.span()).to_owned()) - } ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr), ast::ExprKind::If(..) | ast::ExprKind::ForLoop { .. } @@ -276,6 +272,7 @@ pub(crate) fn format_expr( | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Await(_, _) + | ast::ExprKind::Use(_, _) | ast::ExprKind::Yield(ast::YieldKind::Postfix(_)) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, context, shape, MacroPosition::Expression).or_else(|_| { diff --git a/tests/source/ergonomic_clones.rs b/tests/source/ergonomic_clones.rs new file mode 100644 index 00000000000..febed25b6a9 --- /dev/null +++ b/tests/source/ergonomic_clones.rs @@ -0,0 +1,73 @@ +// rustfmt-edition: 2018 + +#![feature(ergonomic_clones)] + +mod closure_syntax { + fn ergonomic_clone_closure_no_captures() -> i32 { + let cl = use || { + 1 + }; + cl() + } + + fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + let cl = use || { + s + }; + cl() + } + + fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + let f1 = use || { + f + }; + + let f2 = use || { + f + }; + + f + } + + fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + let i1 = use || { + i + }; + + let i2 = use || { + i + }; + + i + } + + fn nested() { + let a = Box::new(Foo); + foo(use || { foo(use || { work(a) }) }); + let x = use || { use || { Foo } }; + let _y = x(); + } + + fn with_binders() { + for<'a> use || -> () {}; + } +} + +mod dotuse { + fn basic_test(x: i32) -> i32 { + x.use + .use + .abs() + } + + fn do_not_move_test(x: Foo) -> Foo { + let s = x.use; + x + } +} diff --git a/tests/target/ergonomic_clones.rs b/tests/target/ergonomic_clones.rs new file mode 100644 index 00000000000..1a8c3b6cbbe --- /dev/null +++ b/tests/target/ergonomic_clones.rs @@ -0,0 +1,59 @@ +// rustfmt-edition: 2018 + +#![feature(ergonomic_clones)] + +mod closure_syntax { + fn ergonomic_clone_closure_no_captures() -> i32 { + let cl = use || 1; + cl() + } + + fn ergonomic_clone_closure_move() -> String { + let s = String::from("hi"); + + let cl = use || s; + cl() + } + + fn ergonomic_clone_closure_use_cloned() -> Foo { + let f = Foo; + + let f1 = use || f; + + let f2 = use || f; + + f + } + + fn ergonomic_clone_closure_copy() -> i32 { + let i = 1; + + let i1 = use || i; + + let i2 = use || i; + + i + } + + fn nested() { + let a = Box::new(Foo); + foo(use || foo(use || work(a))); + let x = use || use || Foo; + let _y = x(); + } + + fn with_binders() { + for<'a> use || -> () {}; + } +} + +mod dotuse { + fn basic_test(x: i32) -> i32 { + x.use.use.abs() + } + + fn do_not_move_test(x: Foo) -> Foo { + let s = x.use; + x + } +}