Use closure parse code
This commit is contained in:
parent
05c516446a
commit
81a926cc2a
20 changed files with 137 additions and 68 deletions
|
@ -1762,6 +1762,11 @@ pub enum CaptureBy {
|
|||
},
|
||||
/// `move` keyword was not specified.
|
||||
Ref,
|
||||
/// `use |x| y + x`.
|
||||
Use {
|
||||
/// The span of the `use` keyword.
|
||||
use_kw: Span,
|
||||
},
|
||||
}
|
||||
|
||||
/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
|
||||
|
|
|
@ -1899,6 +1899,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
|
|||
CaptureBy::Value { move_kw } => {
|
||||
vis.visit_span(move_kw);
|
||||
}
|
||||
CaptureBy::Use { use_kw } => {
|
||||
vis.visit_span(use_kw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -893,6 +893,7 @@ impl<'a> State<'a> {
|
|||
fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
|
||||
match capture_clause {
|
||||
ast::CaptureBy::Value { .. } => self.word_space("move"),
|
||||
ast::CaptureBy::Use { .. } => self.word_space("use"),
|
||||
ast::CaptureBy::Ref => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
.expect_closure();
|
||||
let span = match capture_clause {
|
||||
rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
|
||||
rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(),
|
||||
rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
|
||||
};
|
||||
diag.span_suggestion_verbose(
|
||||
|
|
|
@ -2305,6 +2305,7 @@ impl<'a> State<'a> {
|
|||
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
|
||||
match capture_clause {
|
||||
hir::CaptureBy::Value { .. } => self.word_space("move"),
|
||||
hir::CaptureBy::Use { .. } => self.word_space("use"),
|
||||
hir::CaptureBy::Ref => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -670,7 +670,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
origin = updated.1;
|
||||
|
||||
let (place, capture_kind) = match capture_clause {
|
||||
hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
|
||||
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } => {
|
||||
adjust_for_move_closure(place, capture_kind)
|
||||
}
|
||||
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
|
||||
};
|
||||
|
||||
|
@ -1165,7 +1167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let ty = match closure_clause {
|
||||
hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value
|
||||
hir::CaptureBy::Ref => {
|
||||
hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {
|
||||
// For non move closure the capture kind is the max capture kind of all captures
|
||||
// according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
|
||||
let mut max_capture_info = root_var_min_capture_list.first().unwrap().info;
|
||||
|
@ -1292,7 +1294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
|
||||
return Some(diagnostics_info);
|
||||
}
|
||||
hir::CaptureBy::Ref => {}
|
||||
hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {}
|
||||
}
|
||||
|
||||
return None;
|
||||
|
@ -1689,10 +1691,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
//
|
||||
// If the data will be moved out of this place, then the place will be truncated
|
||||
// at the first Deref in `adjust_for_move_closure` and then moved into the closure.
|
||||
hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => {
|
||||
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. }
|
||||
if !place.deref_tys().any(Ty::is_ref) =>
|
||||
{
|
||||
ty::UpvarCapture::ByValue
|
||||
}
|
||||
hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => {
|
||||
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => {
|
||||
ty::UpvarCapture::ByRef(BorrowKind::Immutable)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
|
|||
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
|
||||
.suggestion = try switching the order
|
||||
|
||||
parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
|
||||
.suggestion = try switching the order
|
||||
|
||||
parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
|
||||
.suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
|
||||
|
||||
|
|
|
@ -1512,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_async_use_order_incorrect)]
|
||||
pub(crate) struct AsyncUseOrderIncorrect {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_double_colon_in_bound)]
|
||||
pub(crate) struct DoubleColonInBound {
|
||||
|
|
|
@ -1404,6 +1404,7 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check_path() {
|
||||
this.parse_expr_path_start()
|
||||
} else if this.check_keyword(exp!(Move))
|
||||
|| this.check_keyword(exp!(Use))
|
||||
|| this.check_keyword(exp!(Static))
|
||||
|| this.check_const_closure()
|
||||
{
|
||||
|
@ -2395,7 +2396,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(closure)
|
||||
}
|
||||
|
||||
/// Parses an optional `move` prefix to a closure-like construct.
|
||||
/// Parses an optional `move` or `use` prefix to a closure-like construct.
|
||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||
if self.eat_keyword(exp!(Move)) {
|
||||
let move_kw_span = self.prev_token.span;
|
||||
|
@ -2408,6 +2409,16 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
Ok(CaptureBy::Value { move_kw: move_kw_span })
|
||||
}
|
||||
} else if self.eat_keyword(exp!(Use)) {
|
||||
let use_kw_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
|
||||
// Check for `use async` and recover
|
||||
if self.check_keyword(exp!(Async)) {
|
||||
let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
|
||||
Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
|
||||
} else {
|
||||
Ok(CaptureBy::Use { use_kw: use_kw_span })
|
||||
}
|
||||
} else {
|
||||
Ok(CaptureBy::Ref)
|
||||
}
|
||||
|
@ -3422,7 +3433,7 @@ impl<'a> Parser<'a> {
|
|||
self.is_keyword_ahead(lookahead, &[kw])
|
||||
&& ((
|
||||
// `async move {`
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move])
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
|
||||
&& self.look_ahead(lookahead + 2, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
|
||||
})
|
||||
|
|
|
@ -1290,7 +1290,7 @@ impl<'a> Parser<'a> {
|
|||
if self.check_keyword(exp!(Static)) {
|
||||
// Check if this could be a closure.
|
||||
!self.look_ahead(1, |token| {
|
||||
if token.is_keyword(kw::Move) {
|
||||
if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
|
||||
return true;
|
||||
}
|
||||
matches!(token.kind, token::Or | token::OrOr)
|
||||
|
|
|
@ -44,22 +44,22 @@ note: while trying to match `r#async`
|
|||
LL | (r#async) => (1)
|
||||
| ^^^^^^^
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
|
||||
|
|
||||
LL | ($i: ident) => ($i)
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
|
||||
::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
|
||||
|
|
||||
LL | if passes_tt!(async) == 1 {}
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
|
||||
|
|
|
@ -44,34 +44,34 @@ note: while trying to match `r#async`
|
|||
LL | (r#async) => (1)
|
||||
| ^^^^^^^
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
|
||||
|
|
||||
LL | ($i: ident) => ($i)
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
|
||||
::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8
|
||||
|
|
||||
LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
|
||||
|
|
||||
LL | if passes_tt!(async) == 1 {}
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
|
||||
|
|
||||
LL | ($i: ident) => ($i)
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
|
||||
error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
|
||||
|
|
||||
LL | if local_passes_tt!(async) == 1 {}
|
||||
| ^ expected one of `move`, `|`, or `||`
|
||||
| ^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
|
||||
|
|
23
tests/ui/ergonomic-clones/closure.rs
Normal file
23
tests/ui/ergonomic-clones/closure.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
//@ check-pass
|
||||
//@ edition:2018
|
||||
|
||||
#![feature(ergonomic_clones)]
|
||||
|
||||
fn ergonomic_clone_closure() -> i32 {
|
||||
let cl = use || {
|
||||
1
|
||||
};
|
||||
cl()
|
||||
}
|
||||
|
||||
fn ergonomic_clone_async_closures() -> String {
|
||||
let s = String::from("hi");
|
||||
|
||||
async use {
|
||||
22
|
||||
};
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -7,12 +7,13 @@ fn ergonomic_closure_clone() {
|
|||
let s1 = String::from("hi!");
|
||||
|
||||
let s2 = use || {
|
||||
//~^ ERROR incorrect use of `use`
|
||||
//~^ ERROR `.use` calls are experimental [E0658]
|
||||
s1
|
||||
};
|
||||
|
||||
let s3 = use || {
|
||||
//~^ ERROR incorrect use of `use`
|
||||
//~^ ERROR `.use` calls are experimental [E0658]
|
||||
//~| ERROR use of moved value: `s1` [E0382]
|
||||
s1
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,39 +1,3 @@
|
|||
error: incorrect use of `use`
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
|
||||
|
|
||||
LL | let s2 = use || {
|
||||
| ______________^
|
||||
LL | |
|
||||
LL | | s1
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
help: `use` is a postfix operation
|
||||
|
|
||||
LL ~ let s2 = || {
|
||||
LL |
|
||||
LL | s1
|
||||
LL ~ }.use;
|
||||
|
|
||||
|
||||
error: incorrect use of `use`
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
||||
|
|
||||
LL | let s3 = use || {
|
||||
| ______________^
|
||||
LL | |
|
||||
LL | | s1
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
help: `use` is a postfix operation
|
||||
|
|
||||
LL ~ let s3 = || {
|
||||
LL |
|
||||
LL | s1
|
||||
LL ~ }.use;
|
||||
|
|
||||
|
||||
error[E0658]: `.use` calls are experimental
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
|
||||
|
|
||||
|
@ -44,6 +8,50 @@ LL | x.use
|
|||
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0658]: `.use` calls are experimental
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
|
||||
|
|
||||
LL | let s2 = use || {
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
|
||||
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
error[E0658]: `.use` calls are experimental
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
||||
|
|
||||
LL | let s3 = use || {
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
|
||||
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0382]: use of moved value: `s1`
|
||||
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
||||
|
|
||||
LL | let s1 = String::from("hi!");
|
||||
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | let s2 = use || {
|
||||
| ------ value moved into closure here
|
||||
LL |
|
||||
LL | s1
|
||||
| -- variable moved due to use in closure
|
||||
...
|
||||
LL | let s3 = use || {
|
||||
| ^^^^^^ value used here after move
|
||||
...
|
||||
LL | s1
|
||||
| -- use occurs due to use in closure
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | s1.clone()
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0382, E0658.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
||||
|
|
|
@ -30,7 +30,7 @@ fn in_try() {
|
|||
// FIXME(#80931)
|
||||
fn in_async() {
|
||||
async
|
||||
let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
|
||||
let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let`
|
||||
}
|
||||
|
||||
// FIXME(#78168)
|
||||
|
|
|
@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
|
|||
LL | try
|
||||
| ^^^ expected expression
|
||||
|
||||
error: expected one of `move`, `|`, or `||`, found keyword `let`
|
||||
error: expected one of `move`, `use`, `|`, or `||`, found keyword `let`
|
||||
--> $DIR/block-no-opening-brace.rs:33:9
|
||||
|
|
||||
LL | async
|
||||
| - expected one of `move`, `|`, or `||`
|
||||
| - expected one of `move`, `use`, `|`, or `||`
|
||||
LL | let x = 0;
|
||||
| ^^^ unexpected token
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: expected one of `move`, `|`, or `||`, found `Move`
|
||||
error: expected one of `move`, `use`, `|`, or `||`, found `Move`
|
||||
--> $DIR/async-move.rs:4:11
|
||||
|
|
||||
LL | async Move {}
|
||||
| ^^^^ expected one of `move`, `|`, or `||`
|
||||
| ^^^^ expected one of `move`, `use`, `|`, or `||`
|
||||
|
|
||||
help: write keyword `move` in lowercase
|
||||
|
|
||||
|
|
|
@ -7,6 +7,6 @@ fn main() {
|
|||
enum Foo { Bar }
|
||||
fn foo(x: impl Iterator<Item = Foo>) {
|
||||
for <Foo>::Bar in x {}
|
||||
//~^ ERROR expected one of `move`, `static`, `|`
|
||||
//~^ ERROR expected one of `move`, `static`, `use`, `|`
|
||||
//~^^ ERROR `for<...>` binders for closures are experimental
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: expected one of `move`, `static`, `|`, or `||`, found `::`
|
||||
error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::`
|
||||
--> $DIR/recover-quantified-closure.rs:9:14
|
||||
|
|
||||
LL | for <Foo>::Bar in x {}
|
||||
| ^^ expected one of `move`, `static`, `|`, or `||`
|
||||
| ^^ expected one of `move`, `static`, `use`, `|`, or `||`
|
||||
|
||||
error[E0658]: `for<...>` binders for closures are experimental
|
||||
--> $DIR/recover-quantified-closure.rs:2:5
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue