1
Fork 0

Use closure parse code

This commit is contained in:
Santiago Pastorino 2024-11-01 18:37:32 -03:00
parent 05c516446a
commit 81a926cc2a
No known key found for this signature in database
GPG key ID: 8131A24E0C79EFAF
20 changed files with 137 additions and 68 deletions

View file

@ -1762,6 +1762,11 @@ pub enum CaptureBy {
}, },
/// `move` keyword was not specified. /// `move` keyword was not specified.
Ref, 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 ()|`. /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.

View file

@ -1899,6 +1899,9 @@ fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
CaptureBy::Value { move_kw } => { CaptureBy::Value { move_kw } => {
vis.visit_span(move_kw); vis.visit_span(move_kw);
} }
CaptureBy::Use { use_kw } => {
vis.visit_span(use_kw);
}
} }
} }

View file

@ -893,6 +893,7 @@ impl<'a> State<'a> {
fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
match capture_clause { match capture_clause {
ast::CaptureBy::Value { .. } => self.word_space("move"), ast::CaptureBy::Value { .. } => self.word_space("move"),
ast::CaptureBy::Use { .. } => self.word_space("use"),
ast::CaptureBy::Ref => {} ast::CaptureBy::Ref => {}
} }
} }

View file

@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
.expect_closure(); .expect_closure();
let span = match capture_clause { let span = match capture_clause {
rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), 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(), rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
}; };
diag.span_suggestion_verbose( diag.span_suggestion_verbose(

View file

@ -2305,6 +2305,7 @@ impl<'a> State<'a> {
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
match capture_clause { match capture_clause {
hir::CaptureBy::Value { .. } => self.word_space("move"), hir::CaptureBy::Value { .. } => self.word_space("move"),
hir::CaptureBy::Use { .. } => self.word_space("use"),
hir::CaptureBy::Ref => {} hir::CaptureBy::Ref => {}
} }
} }

View file

@ -670,7 +670,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
origin = updated.1; origin = updated.1;
let (place, capture_kind) = match capture_clause { 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), 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 { let ty = match closure_clause {
hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value 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 // For non move closure the capture kind is the max capture kind of all captures
// according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue
let mut max_capture_info = root_var_min_capture_list.first().unwrap().info; 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 }); .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
return Some(diagnostics_info); return Some(diagnostics_info);
} }
hir::CaptureBy::Ref => {} hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {}
} }
return None; 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 // 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. // 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 ty::UpvarCapture::ByValue
} }
hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => { hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => {
ty::UpvarCapture::ByRef(BorrowKind::Immutable) ty::UpvarCapture::ByRef(BorrowKind::Immutable)
} }
} }

View file

@ -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 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
.suggestion = try switching the order .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 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} @` .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`

View file

@ -1512,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect {
pub span: Span, 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)] #[derive(Diagnostic)]
#[diag(parse_double_colon_in_bound)] #[diag(parse_double_colon_in_bound)]
pub(crate) struct DoubleColonInBound { pub(crate) struct DoubleColonInBound {

View file

@ -1404,6 +1404,7 @@ impl<'a> Parser<'a> {
} else if this.check_path() { } else if this.check_path() {
this.parse_expr_path_start() this.parse_expr_path_start()
} else if this.check_keyword(exp!(Move)) } else if this.check_keyword(exp!(Move))
|| this.check_keyword(exp!(Use))
|| this.check_keyword(exp!(Static)) || this.check_keyword(exp!(Static))
|| this.check_const_closure() || this.check_const_closure()
{ {
@ -2395,7 +2396,7 @@ impl<'a> Parser<'a> {
Ok(closure) 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> { fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
if self.eat_keyword(exp!(Move)) { if self.eat_keyword(exp!(Move)) {
let move_kw_span = self.prev_token.span; let move_kw_span = self.prev_token.span;
@ -2408,6 +2409,16 @@ impl<'a> Parser<'a> {
} else { } else {
Ok(CaptureBy::Value { move_kw: move_kw_span }) 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 { } else {
Ok(CaptureBy::Ref) Ok(CaptureBy::Ref)
} }
@ -3422,7 +3433,7 @@ impl<'a> Parser<'a> {
self.is_keyword_ahead(lookahead, &[kw]) self.is_keyword_ahead(lookahead, &[kw])
&& (( && ((
// `async move {` // `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| { && self.look_ahead(lookahead + 2, |t| {
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
}) })

View file

@ -1290,7 +1290,7 @@ impl<'a> Parser<'a> {
if self.check_keyword(exp!(Static)) { if self.check_keyword(exp!(Static)) {
// Check if this could be a closure. // Check if this could be a closure.
!self.look_ahead(1, |token| { !self.look_ahead(1, |token| {
if token.is_keyword(kw::Move) { if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
return true; return true;
} }
matches!(token.kind, token::Or | token::OrOr) matches!(token.kind, token::Or | token::OrOr)

View file

@ -44,22 +44,22 @@ note: while trying to match `r#async`
LL | (r#async) => (1) 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 --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
| |
LL | ($i: ident) => ($i) LL | ($i: ident) => ($i)
| ^ expected one of `move`, `|`, or `||` | ^ expected one of `move`, `use`, `|`, or `||`
| |
::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8 ::: $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 LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
| -------------------- in this macro invocation | -------------------- 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 --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
| |
LL | if passes_tt!(async) == 1 {} LL | if passes_tt!(async) == 1 {}
| ^ expected one of `move`, `|`, or `||` | ^ expected one of `move`, `use`, `|`, or `||`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33

View file

@ -44,34 +44,34 @@ note: while trying to match `r#async`
LL | (r#async) => (1) 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 --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
| |
LL | ($i: ident) => ($i) LL | ($i: ident) => ($i)
| ^ expected one of `move`, `|`, or `||` | ^ expected one of `move`, `use`, `|`, or `||`
| |
::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8 ::: $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 LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
| -------------------- in this macro invocation | -------------------- 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 --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
| |
LL | if passes_tt!(async) == 1 {} 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 --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
| |
LL | ($i: ident) => ($i) 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 --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
| |
LL | if local_passes_tt!(async) == 1 {} LL | if local_passes_tt!(async) == 1 {}
| ^ expected one of `move`, `|`, or `||` | ^ expected one of `move`, `use`, `|`, or `||`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33

View 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() {}

View file

@ -7,12 +7,13 @@ fn ergonomic_closure_clone() {
let s1 = String::from("hi!"); let s1 = String::from("hi!");
let s2 = use || { let s2 = use || {
//~^ ERROR incorrect use of `use` //~^ ERROR `.use` calls are experimental [E0658]
s1 s1
}; };
let s3 = use || { let s3 = use || {
//~^ ERROR incorrect use of `use` //~^ ERROR `.use` calls are experimental [E0658]
//~| ERROR use of moved value: `s1` [E0382]
s1 s1
}; };
} }

View file

@ -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 error[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:2:7 --> $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 = 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 = 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`.

View file

@ -30,7 +30,7 @@ fn in_try() {
// FIXME(#80931) // FIXME(#80931)
fn in_async() { fn in_async() {
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) // FIXME(#78168)

View file

@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
LL | try LL | try
| ^^^ expected expression | ^^^ 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 --> $DIR/block-no-opening-brace.rs:33:9
| |
LL | async LL | async
| - expected one of `move`, `|`, or `||` | - expected one of `move`, `use`, `|`, or `||`
LL | let x = 0; LL | let x = 0;
| ^^^ unexpected token | ^^^ unexpected token

View file

@ -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 --> $DIR/async-move.rs:4:11
| |
LL | async Move {} LL | async Move {}
| ^^^^ expected one of `move`, `|`, or `||` | ^^^^ expected one of `move`, `use`, `|`, or `||`
| |
help: write keyword `move` in lowercase help: write keyword `move` in lowercase
| |

View file

@ -7,6 +7,6 @@ fn main() {
enum Foo { Bar } enum Foo { Bar }
fn foo(x: impl Iterator<Item = Foo>) { fn foo(x: impl Iterator<Item = Foo>) {
for <Foo>::Bar in x {} 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 //~^^ ERROR `for<...>` binders for closures are experimental
} }

View file

@ -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 --> $DIR/recover-quantified-closure.rs:9:14
| |
LL | for <Foo>::Bar in x {} 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 error[E0658]: `for<...>` binders for closures are experimental
--> $DIR/recover-quantified-closure.rs:2:5 --> $DIR/recover-quantified-closure.rs:2:5