Skip to content

Commit

Permalink
Use closure parse code
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino committed Dec 26, 2024
1 parent 8129aea commit 73fa299
Show file tree
Hide file tree
Showing 19 changed files with 119 additions and 61 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,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 ()|`.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,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);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,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 => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/borrowck_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2159,6 +2159,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 => {}
}
}
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,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),
};

Expand Down Expand Up @@ -1161,7 +1163,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;
Expand Down Expand Up @@ -1288,7 +1290,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;
Expand Down Expand Up @@ -1685,10 +1687,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)
}
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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} @`
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,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 {
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,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()
{
Expand Down Expand Up @@ -2445,6 +2446,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)
}
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/ergonomic-clones/closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ check-pass

#![feature(ergonomic_clones)]

fn ergonomic_clone_closure() -> i32 {
let cl = use || {
1
};
cl()
}

fn main() {}
5 changes: 3 additions & 2 deletions tests/ui/feature-gates/feature-gate-ergonomic-clones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}
Expand Down
76 changes: 42 additions & 34 deletions tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr
Original file line number Diff line number Diff line change
@@ -1,49 +1,57 @@
error: incorrect use of `use`
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
error[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
|
LL | let s2 = use || {
| ______________^
LL | |
LL | | s1
LL | | };
| |_____^
LL | x.use
| ^^^
|
help: `use` is a postfix operation
= 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[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:9:14
|
LL ~ let s2 = || {
LL |
LL | s1
LL ~ }.use;
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

error: incorrect use of `use`
error[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
|
LL | let s3 = use || {
| ______________^
LL | |
LL | | s1
LL | | };
| |_____^
LL | let s3 = use || {
| ^^^
|
help: `use` is a postfix operation
= 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 s3 = || {
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
LL ~ }.use;
|

error[E0658]: `.use` calls are experimental
--> $DIR/feature-gate-ergonomic-clones.rs:2:7
| -- 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
|
LL | x.use
| ^^^
help: consider cloning the value if the performance cost is acceptable
|
= 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
LL | s1.clone()
| ++++++++

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0658`.
Some errors have detailed explanations: E0382, E0658.
For more information about an error, try `rustc --explain E0382`.
2 changes: 1 addition & 1 deletion tests/ui/parser/block-no-opening-brace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/block-no-opening-brace.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/parser/misspelled-keywords/async-move.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/parser/recover/recover-quantified-closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions tests/ui/parser/recover/recover-quantified-closure.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 73fa299

Please sign in to comment.