Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move async || ... closures into #![feature(async_closure)] #62292

Merged
merged 2 commits into from
Jul 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 28 additions & 24 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::tokenstream::TokenTree;

use errors::{Applicability, DiagnosticBuilder, Handler};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lock;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use log::debug;
Expand Down Expand Up @@ -573,6 +574,9 @@ declare_features! (
// Allows `impl Trait` with multiple unrelated lifetimes.
(active, member_constraints, "1.37.0", Some(61977), None),

// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -2191,9 +2195,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"labels on blocks are unstable");
}
}
ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => {
gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
}
ast::ExprKind::Async(..) => {
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
}
Expand Down Expand Up @@ -2527,6 +2528,10 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
features
}

fn for_each_in_lock<T>(vec: &Lock<Vec<T>>, f: impl Fn(&T)) {
vec.borrow().iter().for_each(f);
}

pub fn check_crate(krate: &ast::Crate,
sess: &ParseSess,
features: &Features,
Expand All @@ -2539,27 +2544,26 @@ pub fn check_crate(krate: &ast::Crate,
plugin_attributes,
};

sess
.param_attr_spans
.borrow()
.iter()
.for_each(|span| gate_feature!(
&ctx,
param_attrs,
*span,
"attributes on function parameters are unstable"
));

sess
.let_chains_spans
.borrow()
.iter()
.for_each(|span| gate_feature!(
&ctx,
let_chains,
*span,
"`let` expressions in this position are experimental"
));
for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!(
&ctx,
param_attrs,
*span,
"attributes on function parameters are unstable"
));

for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!(
&ctx,
let_chains,
*span,
"`let` expressions in this position are experimental"
));

for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!(
&ctx,
async_closure,
*span,
"async closures are unstable"
));

let visitor = &mut PostExpansionVisitor {
context: &ctx,
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,7 @@ mod tests {
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub struct ParseSess {
pub param_attr_spans: Lock<Vec<Span>>,
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
pub let_chains_spans: Lock<Vec<Span>>,
// Places where `async || ..` exprs were used and should be feature gated.
pub async_closure_spans: Lock<Vec<Span>>,
}

impl ParseSess {
Expand Down Expand Up @@ -84,6 +86,7 @@ impl ParseSess {
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
}
}

Expand Down
36 changes: 21 additions & 15 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3221,21 +3221,24 @@ impl<'a> Parser<'a> {
-> PResult<'a, P<Expr>>
{
let lo = self.token.span;

let movability = if self.eat_keyword(kw::Static) {
Movability::Static
} else {
Movability::Movable
};

let asyncness = if self.token.span.rust_2018() {
self.parse_asyncness()
} else {
IsAsync::NotAsync
};
let capture_clause = if self.eat_keyword(kw::Move) {
CaptureBy::Value
} else {
CaptureBy::Ref
};
if asyncness.is_async() {
// Feature gate `async ||` closures.
self.sess.async_closure_spans.borrow_mut().push(self.prev_span);
}

let capture_clause = self.parse_capture_clause();
let decl = self.parse_fn_block_decl()?;
let decl_hi = self.prev_span;
let body = match decl.output {
Expand All @@ -3257,7 +3260,7 @@ impl<'a> Parser<'a> {
attrs))
}

// `else` token already eaten
/// `else` token already eaten
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
if self.eat_keyword(kw::If) {
return self.parse_if_expr(ThinVec::new());
Expand Down Expand Up @@ -3306,7 +3309,7 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs))
}

// parse `loop {...}`, `loop` token already eaten
/// Parse `loop {...}`, `loop` token already eaten.
fn parse_loop_expr(&mut self, opt_label: Option<Label>,
span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
Expand All @@ -3316,17 +3319,20 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
}

/// Parses an `async move {...}` expression.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>>
{
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = if self.eat_keyword(kw::Move) {
/// Parse an optional `move` prefix to a closure lke construct.
fn parse_capture_clause(&mut self) -> CaptureBy {
if self.eat_keyword(kw::Move) {
CaptureBy::Value
} else {
CaptureBy::Ref
};
}
}

/// Parses an `async move? {...}` expression.
pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let span_lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = self.parse_capture_clause();
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
Ok(self.mk_expr(
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ symbols! {
associated_type_defaults,
associated_types,
async_await,
async_closure,
attr,
attributes,
attr_literals,
Expand Down
8 changes: 0 additions & 8 deletions src/test/ui/async-await/async-await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,6 @@ fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
wake_and_yield_once().await;
x
})(x)
}

async fn async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
Expand Down Expand Up @@ -180,7 +173,6 @@ fn main() {
test! {
async_block,
async_nonmove_block,
async_closure,
async_fn,
generic_async_fn,
async_fn_with_internal_borrow,
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/async-await/async-closure-matches-expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// compile-pass
// edition:2018

#![feature(async_await, async_closure)]

macro_rules! match_expr {
($x:expr) => {}
}

fn main() {
match_expr!(async || {});
}
81 changes: 81 additions & 0 deletions src/test/ui/async-await/async-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// run-pass

// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, async_closure)]

extern crate arc_wake;

use std::pin::Pin;
use std::future::Future;
use std::sync::{
Arc,
atomic::{self, AtomicUsize},
};
use std::task::{Context, Poll};
use arc_wake::ArcWake;

struct Counter {
wakes: AtomicUsize,
}

impl ArcWake for Counter {
fn wake(self: Arc<Self>) {
Self::wake_by_ref(&self)
}
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
}
}

struct WakeOnceThenComplete(bool);

fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }

impl Future for WakeOnceThenComplete {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
cx.waker().wake_by_ref();
self.0 = true;
Poll::Pending
}
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
wake_and_yield_once().await;
x
})(x)
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
F: FnOnce(u8) -> Fut,
Fut: Future<Output = u8>,
{
let mut fut = Box::pin(f(9));
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
let waker = ArcWake::into_waker(counter.clone());
let mut cx = Context::from_waker(&waker);
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
}

fn main() {
macro_rules! test {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns($fn_name);
)* }
}

test! {
async_closure,
}
}
3 changes: 1 addition & 2 deletions src/test/ui/async-await/async-matches-expr.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// compile-pass
// edition:2018

#![feature(async_await, await_macro)]
#![feature(async_await)]

macro_rules! match_expr {
($x:expr) => {}
}

fn main() {
match_expr!(async {});
match_expr!(async || {});
}
2 changes: 1 addition & 1 deletion src/test/ui/async-await/await-macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, await_macro)]
#![feature(async_await, async_closure, await_macro)]

extern crate arc_wake;

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/async-await/feature-async-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// edition:2018
// gate-test-async_closure

fn f() {
let _ = async || {}; //~ ERROR async closures are unstable
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/async-await/feature-async-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0658]: async closures are unstable
--> $DIR/feature-async-closure.rs:5:13
|
LL | let _ = async || {};
| ^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62290
= help: add #![feature(async_closure)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ fn main() {
//~^ ERROR `await` is only allowed inside `async` functions and blocks
let task1 = print_dur().await;
}.await;
(async || 2333)().await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
(|_| 2333).await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
//~^^ ERROR
Expand Down
Loading